【问题标题】:Make CakePHP consider two different routes/models for same path?让 CakePHP 为同一路径考虑两个不同的路由/模型?
【发布时间】:2017-08-04 16:38:26
【问题描述】:

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

  • 条目:https://example.com/hello-world
  • 用户:https://example.com/test-user

用 CakePHP 3.4 重构上述网站(原来是用“vanilla” PHP 构建的),我实现了以下路线:

$routes->connect('/:slug',
    ['controller' => 'Entries', 'action' => 'view'],
    ['pass' => ['slug']]
);

$routes->connect('/:username',
    ['controller' => 'Users', 'action' => 'view'],
    ['pass' => ['username']]
);

入口页面就像一个魅力——在那里没有问题——但是当我尝试访问用户个人资料时,Cake 抛出一个RecordNotFoundException。这是有道理的,因为它正在寻找一个不存在的条目。

我希望在EntriesController 中从firstOrFail 切换到find 将允许应用程序继续下一条路线(因为不会抛出异常),但结果实际上更糟:它尝试在没有对象的情况下呈现条目视图,从而导致 PHP 通知在原本为空的布局上。

我已经阅读了 CakePHP 文档(“书”),但无法找到解决这个(我认为是通用的)问题的方法。我还尝试了许多其他(通常不太明显)的路线设置,但也没有运气。

现在我一直在想EntryOrUserController 之类的东西,但我怀疑这是否是最好的解决方案,甚至是一个好的解决方案。坦率地说,我认为这很愚蠢。我想我真的希望有一些控制器或中间件功能可以完全满足我的要求,但任何优雅的解决方案都可以。

附:我确实意识到默认的 CakePHP/MVC 方法是让 URL 更像这样:

  • 条目:https://example.com/entries/hello-world
  • 用户:https://example.com/users/test-user

...但在这种情况下,这不是一个选项,所以谢谢,但不是。 ☺

【问题讨论】:

标签: cakephp routes


【解决方案1】:

感谢 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。将新路由类应用于相关路由

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

3。考虑一些事情

  • 我还要告诉路线使用哪些模型。如果路由类自己解决这个问题可能会很好。
  • 路由类假定我们要查找pass 数组的第一个值。在这种情况下这很好(只有 slugusername 被传递),但它不是很透明并且很容易被破坏。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2021-10-13
    • 2018-10-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-12-12
    相关资源
    最近更新 更多