【问题标题】:Mapping slugs from database in routing在路由中映射数据库中的 slug
【发布时间】:2015-12-18 17:05:29
【问题描述】:

我必须支持一个项目的 url 友好结构。

有多个带有 slug 列的表,在 cakephp 中如何以最有效的方式将 slug 路由到控制器。

起初我在检查表中是否存在 slug,如果存在 slug 使用路由:

    $c = TableRegistry::get('cateogories');
    $result= $c->find()->select(['id'])->where(['url'=>$slug])->toArray();
    if(count($result) > 0) {
        $routes->connect(
            '/:slug',
            ['controller' => 'Categories', 'action' => 'index', 'id' => $result[0]['id']]
        );
    }

问题是我有多个检查,如上述检查,并且每个检查都在运行,即使路由先前匹配(不需要运行,因此正在调用额外的查询)。

那么我怎样才能添加某种条件语句,以便它只检查路由是否匹配,如果之前的路由都不匹配。

【问题讨论】:

  • 而且永远不会有任何冲突,即 slug 在多个表中是唯一的?
  • 是的,不会有冲突

标签: php cakephp cakephp-3.0


【解决方案1】:

我建议使用一个自定义路由类来处理这个问题。虽然您可以查询路线文件中的数据,但这是

  • 不要过度测试友好
  • 不是很干燥
  • 反向路由不安全

后一点的意思是,当不连接所有路由时,尝试从路由数组中为未连接的路由生成 URL 可能会触发异常,或者匹配错误的路由。

使用自定义路由类,您可以在连接路由时简单地在选项中传递模型,并在 parsing the URL 之后的路由类中,查询给定 slug 的模型,并相应地返回 false 或解析的数据.真的很简单,看看现有的路由类做了什么。

这是一个非常基本的例子,应该是不言自明的。

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)
    {
        $params = parent::parse($url);
        if (!$params ||
            !isset($this->options['model'])
        ) {
            return false;
        }

        $count = $this
            ->tableLocator()
            ->get($this->options['model'])
            ->find()
            ->where([
                'slug' => $params['slug']
            ])
            ->count();

        if ($count !== 1) {
            return false;
        }

        return $params;
    }
}

此示例假定在控制器中,您将使用 slug 检索记录。如果您想传递 ID,那么您可以获取 ID 并将其传递到解析的数据中,而不是使用 count(),例如:

$params['pass'][] = $id;

它最终会作为控制器动作的第二个参数传递。

routes.php

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

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

// ...

这将首先检查 Articles 模型,然后检查 Categories 模型等,并在其中一个路由找到给定 slug 的记录时停止。


另见

【讨论】:

    猜你喜欢
    • 2016-06-18
    • 1970-01-01
    • 2016-06-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-27
    • 2019-03-01
    • 1970-01-01
    相关资源
    最近更新 更多