Zend framework2 如何在Zend Framework 2中创建catchall路由

Zend framework2 如何在Zend Framework 2中创建catchall路由,zend-framework2,Zend Framework2,我正在为ZF2创建一个CMS模块,我希望它不必在url中包含“/page”之类的内容。例如,印记页面的url是 你建议怎么做?我已经考虑过以下方法,但我无法让它们中的任何一种按我所希望的方式工作: 具有连接到我的PageController并将url路径作为参数传递的catchall路由。这里的问题是让catchall路线与现有路线配合得很好。这也意味着所有应该是404错误的页面现在都将通过PageController进行路由,如果在数据库中找不到该页面,则PageController必须处理4

我正在为ZF2创建一个CMS模块,我希望它不必在url中包含“/page”之类的内容。例如,印记页面的url是

你建议怎么做?我已经考虑过以下方法,但我无法让它们中的任何一种按我所希望的方式工作:

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

  • 观察事件\u DISPATCH\u ERROR,如果该页存在于数据库中,则从中恢复。我可以捕获事件,但我不知道如何从中恢复并触发PageController

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


  • 如果有任何关于如何做到这一点的想法,我将不胜感激。理想情况下,该解决方案将能够处理CMS支持的主页(/)。

    我个人会采取不同的方法

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

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


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

    我个人会采取不同的方法

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

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


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

    我最终将选项1和选项3组合在一起。我在模块配置文件中设置了一个catchall路由:

    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代替。看起来线段布线约束使用了正则表达式。这可能会对性能造成一些影响。

    我最终将选项1和选项3结合起来。我在模块配置文件中设置了一个catchall路由:

    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代替。看起来线段布线约束使用了正则表达式。这可能有点影响性能。

    我使用主机名路由器创建了一个catchall:

    '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,所以您可以访问服务管理器,以便执行几乎所有操作,包括数据库调用,以检查路由是否有效。

    我使用主机名路由器创建了一个catchall:

    'wildcard' => array(
        'type' => 'Hostname',
        'may_terminate' => true,
        'options' => array(
            'route' => ':subdomain.:domain.:tld',
            'defaults' => array(
                '__NAMESPACE__' => 'ModName\Controller',
                'controller'    => 'ModName',
                'action'        => 'index'
            ),
        ),
    ),
    
    您可能希望将其与能够更改操作的分派事件相结合。解决