用于表单提交的 Cakephp3 前缀路由不起作用
Cakephp3 prefix routing for form submissions is not working
我正在研究路由。我想要实现的是 URL 像 "customer/customer_slug/...",所以,它将是 /customer/test/hosts/add 或 /customer/acme/networks/list。我已经设置了以下路线...
Router::prefix('customer', function (RouteBuilder $routes){
$routes->connect('/',['controller' => 'Customers', 'action' => 'index']);
// ->setMethods(['GET','POST']);
$routes->connect('/add',['controller' => 'Customers', 'action' => 'add'])
->setMethods(['GET','POST']);
$routes->connect('/:slug/edit',['controller' => 'Customers', 'action' => 'edit'])
->setMethods(['GET','POST'])
->setPatterns(['slug'=>'[a-z0-9-_]+'])
->setPass(['slug']);
$routes->connect('/:slug',['controller' => 'Customers', 'action' => 'overview'])
->setMethods(['GET','POST'])
->setPatterns(['slug'=>'[a-z0-9-_]+'])
->setPass(['slug']);
$routes->connect('/:slug/:controller', ['action' => 'index'],['routeClass' => DashedRoute::class])
->setMethods(['GET','POST'])
->setPatterns(['slug'=>'[a-z0-9-_]+'])
->setPass(['slug']);
$routes->connect('/:slug/:controller/:action', ['param'=>'slug'],['routeClass' => DashedRoute::class])
->setMethods(['GET','POST'])
->setPatterns(['slug'=>'[a-z0-9-_]+'])
->setPass(['slug']);
$routes->connect('/:slug/:controller/:action/*', [],['routeClass' => DashedRoute::class])
->setMethods(['GET','POST'])
->setPatterns(['slug'=>'[a-z0-9-_]+'])
->setPass(['slug']);
// TODO: Understand and look to remove this
$routes->fallbacks(DashedRoute::class);
});
我可以在测试中进入 URLs,这很好。但是,当我转到 /customer/acme/edit 时,我得到了 Customer/CustomersController.php 上的编辑操作,它显示了适当的表单。查看路由是调试工具包,它说它正在使用以下路由:
customer:customers:edit /customer/:slug/edit
{
"controller": "Customers",
"action": "edit",
"prefix": "customer",
"plugin": null,
"_method": [
"GET",
"POST"
]
}
这是我所期望的。但是,当我提交表单时,它会将路由更改为:
customer:_controller:_action /customer/{controller}/{action}/*
{
"prefix": "customer",
"plugin": null,
"action": "index"
}
如果我从前缀部分删除 $routes->fallbacks(...
,则会收到 CSRF 错误。
我的编辑页面很简单
<?php $this->extend('../../Layout/TwitterBootstrap/dashboard'); ?>
<?php $this->start('tb_actions'); ?>
<li><?= $this->Form->postLink(__('Delete'), ['action' => 'delete', $customer->id], ['confirm' => __('Are you sure you want to delete # {0}?', $customer->id), 'class' => 'nav-link']) ?></li>
<li><?= $this->Html->link(__('List Customers'), ['action' => 'index'], ['class' => 'nav-link']) ?></li>
<?php $this->end(); ?>
<?php $this->assign('tb_sidebar', '<ul class="nav flex-column">' . $this->fetch('tb_actions') . '</ul>'); ?>
<div class="customers form content">
<?= $this->Form->create($customer) ?>
<fieldset>
<legend><?= __('Edit Customer') ?></legend>
<?php
echo $this->Form->control('name');
?>
</fieldset>
<?= $this->Form->button(__('Submit')) ?>
<?= $this->Form->end() ?>
</div>
来自控制器的相关代码是
public function edit($slug = null)
{
$customer = $this->Customers->getbySlugID($slug);
if ($this->request->is(['patch', 'post', 'put'])) {
$customer = $this->Customers->patchEntity($customer, $this->request->getData());
if ($this->Customers->save($customer)) {
$this->Flash->success(__('The customer has been saved.'));
exit;
return $this->redirect(['controller'=>false, 'action' => 'index', $customer->slug]);
}
$this->Flash->error(__('The customer could not be saved. Please, try again.'));
}
$this->set(compact('customer'));
}
查看生成的 URL 代码
<form method="post" accept-charset="utf-8" role="form" action="/customer/customer4/edit"><div style="display:none;"><input type="hidden" name="_method" value="PUT"></div> <fieldset>
<legend>Edit Customer</legend>
<div class="form-group text required"><label for="name">Name</label><input type="text" name="name" required="required" maxlength="40" id="name" class="form-control" value="Customer4"></div> </fieldset>
<button type="submit" class="btn btn-secondary">Submit</button> </form>
所以它看起来应该发布到正确的位置(customer4 是记录的 slug)。
问题是,为什么Cake在请求编辑页面时能够获取到正确的路由,而在发布时却选择了不同的路由?
注意:我认为还有一些其他的路由错误,如果我删除了回退,那么我的 / 路由就不起作用了。
对于上下文,以下工作正常:
/customer/add 用于编辑和表单提交。
CakePHP 版本为 3.8.8
CakePHP 表单默认使用(模拟)PUT
进行更新(请参阅生成表单中隐藏的 _method
字段。是的,是否应该更好地使用 PATCH
,但它就是这样),并且您将路由限制为 GET
和 POST
,因此其中 none 将在提交表单时匹配,并且后备路由将匹配而是请求,因为它们不应用任何 HTTP 方法限制。
长话短说,请确保您的 /edit
路由也至少接受 PUT
:
$routes
->connect('/:slug/edit',['controller' => 'Customers', 'action' => 'edit'])
->setMethods(['GET', 'POST', 'PUT']) // <<<<<< there
->setPatterns(['slug'=>'[a-z0-9-_]+'])
->setPass(['slug']);
您的控制器也接受 PATCH
,这是 Bake 创建的默认设置,但如果您实际上不使用或不想接受 PATCH
请求,那么您当然可以放弃它。
另见
我正在研究路由。我想要实现的是 URL 像 "customer/customer_slug/...",所以,它将是 /customer/test/hosts/add 或 /customer/acme/networks/list。我已经设置了以下路线...
Router::prefix('customer', function (RouteBuilder $routes){
$routes->connect('/',['controller' => 'Customers', 'action' => 'index']);
// ->setMethods(['GET','POST']);
$routes->connect('/add',['controller' => 'Customers', 'action' => 'add'])
->setMethods(['GET','POST']);
$routes->connect('/:slug/edit',['controller' => 'Customers', 'action' => 'edit'])
->setMethods(['GET','POST'])
->setPatterns(['slug'=>'[a-z0-9-_]+'])
->setPass(['slug']);
$routes->connect('/:slug',['controller' => 'Customers', 'action' => 'overview'])
->setMethods(['GET','POST'])
->setPatterns(['slug'=>'[a-z0-9-_]+'])
->setPass(['slug']);
$routes->connect('/:slug/:controller', ['action' => 'index'],['routeClass' => DashedRoute::class])
->setMethods(['GET','POST'])
->setPatterns(['slug'=>'[a-z0-9-_]+'])
->setPass(['slug']);
$routes->connect('/:slug/:controller/:action', ['param'=>'slug'],['routeClass' => DashedRoute::class])
->setMethods(['GET','POST'])
->setPatterns(['slug'=>'[a-z0-9-_]+'])
->setPass(['slug']);
$routes->connect('/:slug/:controller/:action/*', [],['routeClass' => DashedRoute::class])
->setMethods(['GET','POST'])
->setPatterns(['slug'=>'[a-z0-9-_]+'])
->setPass(['slug']);
// TODO: Understand and look to remove this
$routes->fallbacks(DashedRoute::class);
});
我可以在测试中进入 URLs,这很好。但是,当我转到 /customer/acme/edit 时,我得到了 Customer/CustomersController.php 上的编辑操作,它显示了适当的表单。查看路由是调试工具包,它说它正在使用以下路由:
customer:customers:edit /customer/:slug/edit
{
"controller": "Customers",
"action": "edit",
"prefix": "customer",
"plugin": null,
"_method": [
"GET",
"POST"
]
}
这是我所期望的。但是,当我提交表单时,它会将路由更改为:
customer:_controller:_action /customer/{controller}/{action}/*
{
"prefix": "customer",
"plugin": null,
"action": "index"
}
如果我从前缀部分删除 $routes->fallbacks(...
,则会收到 CSRF 错误。
我的编辑页面很简单
<?php $this->extend('../../Layout/TwitterBootstrap/dashboard'); ?>
<?php $this->start('tb_actions'); ?>
<li><?= $this->Form->postLink(__('Delete'), ['action' => 'delete', $customer->id], ['confirm' => __('Are you sure you want to delete # {0}?', $customer->id), 'class' => 'nav-link']) ?></li>
<li><?= $this->Html->link(__('List Customers'), ['action' => 'index'], ['class' => 'nav-link']) ?></li>
<?php $this->end(); ?>
<?php $this->assign('tb_sidebar', '<ul class="nav flex-column">' . $this->fetch('tb_actions') . '</ul>'); ?>
<div class="customers form content">
<?= $this->Form->create($customer) ?>
<fieldset>
<legend><?= __('Edit Customer') ?></legend>
<?php
echo $this->Form->control('name');
?>
</fieldset>
<?= $this->Form->button(__('Submit')) ?>
<?= $this->Form->end() ?>
</div>
来自控制器的相关代码是
public function edit($slug = null)
{
$customer = $this->Customers->getbySlugID($slug);
if ($this->request->is(['patch', 'post', 'put'])) {
$customer = $this->Customers->patchEntity($customer, $this->request->getData());
if ($this->Customers->save($customer)) {
$this->Flash->success(__('The customer has been saved.'));
exit;
return $this->redirect(['controller'=>false, 'action' => 'index', $customer->slug]);
}
$this->Flash->error(__('The customer could not be saved. Please, try again.'));
}
$this->set(compact('customer'));
}
查看生成的 URL 代码
<form method="post" accept-charset="utf-8" role="form" action="/customer/customer4/edit"><div style="display:none;"><input type="hidden" name="_method" value="PUT"></div> <fieldset>
<legend>Edit Customer</legend>
<div class="form-group text required"><label for="name">Name</label><input type="text" name="name" required="required" maxlength="40" id="name" class="form-control" value="Customer4"></div> </fieldset>
<button type="submit" class="btn btn-secondary">Submit</button> </form>
所以它看起来应该发布到正确的位置(customer4 是记录的 slug)。
问题是,为什么Cake在请求编辑页面时能够获取到正确的路由,而在发布时却选择了不同的路由?
注意:我认为还有一些其他的路由错误,如果我删除了回退,那么我的 / 路由就不起作用了。
对于上下文,以下工作正常:
/customer/add 用于编辑和表单提交。
CakePHP 版本为 3.8.8
CakePHP 表单默认使用(模拟)PUT
进行更新(请参阅生成表单中隐藏的 _method
字段。是的,是否应该更好地使用 PATCH
,但它就是这样),并且您将路由限制为 GET
和 POST
,因此其中 none 将在提交表单时匹配,并且后备路由将匹配而是请求,因为它们不应用任何 HTTP 方法限制。
长话短说,请确保您的 /edit
路由也至少接受 PUT
:
$routes
->connect('/:slug/edit',['controller' => 'Customers', 'action' => 'edit'])
->setMethods(['GET', 'POST', 'PUT']) // <<<<<< there
->setPatterns(['slug'=>'[a-z0-9-_]+'])
->setPass(['slug']);
您的控制器也接受 PATCH
,这是 Bake 创建的默认设置,但如果您实际上不使用或不想接受 PATCH
请求,那么您当然可以放弃它。
另见