让CAKEPHP考虑两条不同路径/模型的相同路径?
我有一个网站,有用户和条目,这两个都存储在数据库中。每个条目都有自己的页面(使用其slug),每个用户都有一个公共配置文件(使用其用户名)。它们各自的URL可能如下所示:让CAKEPHP考虑两条不同路径/模型的相同路径?,cakephp,routes,Cakephp,Routes,我有一个网站,有用户和条目,这两个都存储在数据库中。每个条目都有自己的页面(使用其slug),每个用户都有一个公共配置文件(使用其用户名)。它们各自的URL可能如下所示: 条目:https://example.com/hello-world 用户:https://example.com/test-user 用CakePHP 3.4(最初是用“香草”PHP构建的)重构上述网站,我实现了以下路线: $routes->connect('/:slug', ['controller' =
- 条目:
https://example.com/hello-world
- 用户:
https://example.com/test-user
$routes->connect('/:slug',
['controller' => 'Entries', 'action' => 'view'],
['pass' => ['slug']]
);
$routes->connect('/:username',
['controller' => 'Users', 'action' => 'view'],
['pass' => ['username']]
);
条目页面的工作方式就像一个符咒——没有问题——但是当我尝试访问用户配置文件时,Cake抛出一个RecordNotFoundException
。这是有意义的,因为它正在寻找一个不存在的条目
我希望在EntriesController
中从first或fail切换到find
将允许应用程序继续执行下一条路线(因为不会引发异常),但结果实际上更糟:它尝试在没有对象的情况下渲染条目视图,在其他空布局上引起PHP通知
我已经阅读了CakePHP文档(“书”),但找不到解决这个(我认为是一般性的)问题的方法。我也尝试过许多其他(通常不太明显的)路线设置,但也没有运气
现在我的脑子一直在想EntryOrUserController
,但我怀疑这是最好的解决方案,甚至是一个好的解决方案。坦率地说,我认为这很愚蠢。我想我真的希望有一些控制器或中间件功能能够完全满足我的要求,但任何优雅的解决方案都可以
另外,我确实意识到,默认的CakePHP/MVC方式是让URL更像这样:
- 条目:
https://example.com/entries/hello-world
- 用户:
https://example.com/users/test-user
…但在这种情况下,这不是一个选项,所以谢谢,但不。☺ 感谢ndm为我指明了正确的方向。经过一些修补,我有了一个很好的解决方案。在这里发布,因为它可能对其他人有用。有三个步骤
1.创建自定义路由类
/src/Routing/Route/SlugRoute.php
:
namespace App\Routing\Route;
use Cake\Routing\Route\Route;
use Cake\ORM\Locator\LocatorAwareTrait;
class SlugRoute extends Route
{
use LocatorAwareTrait;
public function parse($url, $method = '')
{
$params = parent::parse($url, $method);
if (!$params ||
!isset($this->options['model']) ||
!isset($this->options['pass'][0])
) {
return false;
}
$count = $this
->tableLocator()
->get($this->options['model'])
->find()
->where([
$this->options['pass'][0] => $params['pass'][0]
])
->count();
if ($count !== 1) {
return false;
}
return $params;
}
}
2.将新路由类应用于相关路由
3.考虑几件事
- 我还告诉路线使用哪种型号。如果routing类能够自己解决这一问题,那就太好了
- routing类假设我们要查找
pass
数组的第一个值。在这种情况下这很好(只传递slug
和username
),但它不是很透明,很容易被破坏
一个选项是测试记录存在性的自定义路由类:谢谢,@ndm!我根据我的发现在那里发布了一个答案。
$routes->connect('/:slug',
['controller' => 'Entries', 'action' => 'view'],
['pass' => ['slug', 'name'], 'routeClass' => 'SlugRoute', 'model' => 'Entries']
);
$routes->connect('/:username',
['controller' => 'Users', 'action' => 'view'],
['pass' => ['username'], 'routeClass' => 'SlugRoute', 'model' => 'Users']
);