0

我正在为 ZF2 创建一个 CMS 模块,我希望它不必在 url 中包含“/page”或类似内容。因此,例如,印记页面的 url 将是http://www.yourdomain.com/imprint

你会如何建议这样做?我考虑了以下方法,但我无法让它们中的任何一个按我想要的方式工作:

  1. 有一个连接到我的 PageController 并将 url 路径作为参数传递的包罗万象的路由。这里的问题是让包罗万象的路线与现有路线配合得很好。这也意味着所有应该是 404 错误的页面现在都将通过 PageController 路由,如果在数据库中找不到该页面,则它必须处理 404 页面。

    或者

  2. 观察事件 EVENT_DISPATCH_ERROR 并在页面存在于数据库中时从中恢复。我可以捕捉到该事件,但我不知道如何从中恢复并触发 PageController。

    或者

  3. 每当创建、更新或删除 cms 页面标题时,都要重建所有 cms 路由的缓存。这似乎是一个干净的解决方案,但除了将缓存构建为 config/autoload 目录中的 php 配置文件之外,我不确定如何继续。

对于如何实现这一点的任何想法,我将不胜感激。理想情况下,该解决方案也将能够处理由 CMS 提供支持的主页 (/)。

4

3 回答 3

2

我最终结合了选项#1 和#3。我在模块配置文件中设置了一条包罗万象的路线:

return array(
    // Relative to app root
    'routeCacheFile' => 'data/cache/cmsRoutes',
    'router' => array(
        'routes' => array(
            'cmsPage' => array(
                'type' => 'segment',
                'priority' => 100,
                'options' => array(
                    'route' => '/:pageRoute',
                    'constraints' => array(
                        'pageRoute' => 'dynamically-populated-by-bootstrap'
                    ),
                    'defaults' => array(
                        'controller' => 'pages',
                        'action' => 'view'
                    )
                )
            )
        ),
        // ...
    );

第一个配置选项是缓存文件。稍后再谈。请注意,该路线是只有一个元素的分段路线:pageRoute。然后有一个约束,我们将像这样填写 Module.php:

public function getConfig()
{
    $config = include __DIR__ . '/config/module.config.php';

    // Get the cms page routes from a cache file
    if (!empty($config['routeCacheFile'])) {
        $cachedRoutes = file_get_contents($config['routeCacheFile']);

        $config['router']['routes']['cmsPage']['options']
            ['constraints']['pageRoute'] = $cachedRoutes;
    }

    return $config;
}

我不只是包含并返回配置数组,而是获取 routeCacheFile 设置,获取文件的内容,然后使用它们来替换“动态填充由引导程序”约束。缓存文件包含所有已发布路由的简单管道分隔列表(更多内容见下文),如下所示:about|staff|some/longer/route|terms-of-service关于此的一个好处是我们不需要连接到数据库来路由请求。

我不会对最后一点的代码感到厌烦,但是每次我的 PageController 保存页面时,它都会触发一个服务类,该类会查找所有已发布的路由并将它们写入配置中的缓存文件。

您如何看待这种方法?它不会破坏任何现有路由(我使用优先级设置来设置路由匹配的顺序),它不需要数据库查找来路由请求,也不需要任何错误条件的滥用。缺点:对文件系统有依赖性,这使得单元测试变得更加困难。也许我可以改用 Zend\Cache。看起来分段路由约束使用正则表达式。这可能会对性能造成一些影响。

于 2013-04-24T20:23:39.850 回答
1

我个人会采取不同的方法。

选项 1 肯定会起作用,但我会创建一种新型路由器 (CmsRouter),然后我们可以创建一个优先于其他静态路由的路由。

该路由可以检查数据库中已知页面/ slug 的列表,甚至更好地使用一些智能缓存来加快查找速度。

我当然不会使用方法 2),因为您在完全没有错误的情况下使用错误条件,我会避免这样做。

于 2013-04-23T22:01:14.763 回答
0

我使用主机名路由器创建了一个包罗万象:

'wildcard' => array(
    'type' => 'Hostname',
    'may_terminate' => true,
    'options' => array(
        'route' => ':subdomain.:domain.:tld',
        'defaults' => array(
            '__NAMESPACE__' => 'ModName\Controller',
            'controller'    => 'ModName',
            'action'        => 'index'
        ),
    ),
),

您可能希望将此与能够更改操作的调度事件结合起来。为了解决类似的问题,我附上了SharedListenerAggregateInterface以下内容:

public function attachShared(SharedEventManagerInterface $sharedManager)
{
    $this->listeners[] = $sharedManager->attach('ModName\Controller\ModNameController', MvcEvent::EVENT_DISPATCH, array($this, 'changeAction'), 10);
}

public function changeAction(\Zend\Mvc\MvcEvent $event)
{
    if (/* criteria for action foo */) {
        $event->getRouteMatch()->setParam('action','foo');
    } else if (/* criteria for action bar */) {
        $event->getRouteMatch()->setParam('action','bar');
    }
}

因为这是一个 MvcEvent,您可以访问服务管理器,因此您几乎可以做任何事情,包括调用数据库来检查路由是否有效。

于 2015-01-17T23:09:46.093 回答