让CAKEPHP考虑两条不同路径/模型的相同路径?

让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' =

我有一个网站,有用户和条目,这两个都存储在数据库中。每个条目都有自己的页面(使用其slug),每个用户都有一个公共配置文件(使用其用户名)。它们各自的URL可能如下所示:

  • 条目:
    https://example.com/hello-world
  • 用户:
    https://example.com/test-user
用CakePHP 3.4(最初是用“香草”PHP构建的)重构上述网站,我实现了以下路线:

$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']
);