【问题标题】:How do I make a catchall route in Zend Framework 2如何在 Zend Framework 2 中创建一个包罗万象的路线
【发布时间】:2015-01-18 07:09:46
【问题描述】:

我正在为 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 提供支持的主页 (/)。

【问题讨论】:

    标签: zend-framework2


    【解决方案1】:

    我最终将选项 #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。看起来分段路由约束使用正则表达式。这可能会影响性能。

    【讨论】:

      【解决方案2】:

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

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

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

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

      【讨论】:

      • 安德鲁,感谢您的建议。我同意选项 #2 是个坏主意,所以我取消了那个选项。我会接受你的回答,然后添加一个关于我如何结合选项 #1 和 #3 以使其工作得很好的描述。
      • 顺便说一下,我的 ZF2 开源 CMS 模块在这里:github.com/nhebi/Cms
      【解决方案3】:

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

      '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,您可以访问服务管理器,因此您几乎可以做任何事情,包括调用数据库来检查路由是否有效。

      【讨论】:

        猜你喜欢
        • 2016-04-22
        • 1970-01-01
        • 2013-10-22
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多