ZF2:子路由永远不匹配——为什么?

ZF2: Child route is never matched – why?

我的模块在 Zend Framework 2 中的 module.config.php 看起来像这样:

return array(
    'controllers' => array(
        'invokables' => array(
            'Test\Controller\A' => 'Test\Controller\AController',
            'Test\Controller\B' => 'Test\Controller\BController',
            'Test\Controller\C' => 'Test\Controller\CController',
        ),
    ),

    'router' => array(
        'routes' => array(
            'some-test' => array(
                'type' => 'literal',
                'options' => array(
                    'route' => '/a',
                    'defaults' => array(
                        'controller' =>  'Test\Controller\A',
                        'action' => 'index',
                    ),
                ),
                'may_terminate' => true,
                'child_routes' => array(
                    'some-other-test' => array(
                        'type' => 'segment',
                        'options' => array(
                            'route' => '[/:controller[/:action]]',
                            'defaults' => array(
                                'action' => 'index',
                            ),
                        ),
                    ),
                ),
            ),
        ),
    ),

    'view_manager' => array(
        'template_path_stack' => array(
            __DIR__ . '/../view',
        ),
    ),
);

文字路由有效,/a 正确匹配,而 /a/ 导致 404,这很好且合乎逻辑。

对于分段路线,情况看起来有点不同。不管我输入什么,路由 从未 匹配。所以路线 /a/b 失败了,我不明白。

根据上面的子路由设置,尾部斜杠是可选的,但是当它存在时,还需要指定控制器名称。如果是这种情况,则应调用指定控制器的索引操作——在本例中来自 BController。
如果在控制器名称后添加尾部斜杠,则需要指定操作。

即使我输入 /a/b/index,我也会收到 404 错误:

The requested controller could not be mapped to an existing controller class.

Controller:
b(resolves to invalid controller class or alias: b)

由此我得出结论,整个子路由都不起作用,不仅是 default/fallback 选项。为什么子路由一直不匹配?

您收到的错误表明 Zend 路由器无法将控制器 b 映射到现有的 class。它需要知道您的控制器 class 在应用程序中的位置。

一个可能的解决方案是在 module.config 文件的 invokables 中将控制器的名称作为 aliases。例如:'a' => 'Test\Controller\AController'AController。路由 /a 匹配并且不会抛出错误,因为您在路由配置中设置了默认控制器。

因此您只需要更改这部分代码。这样,控制器将通过 invokables 数组中的 key value 被调用:

'controllers' => array(
        'invokables' => array(
            'a' => 'Test\Controller\AController',
            'b' => 'Test\Controller\BController',
            'c' => 'Test\Controller\CController',
        ),
 ),

另一种解决方案是在路由配置中添加控制器的 __NAMESPACE__,这样您就可以保留与现在相同的别名。

只需像这样修改您的代码:

'router' => array(
    'routes' => array(
        'some-test' => array(
            'type' => 'literal',
            'options' => array(
                'route' => '/a',
                'defaults' => array(
                    '__NAMESPACE__' => 'Test\Controller',//<---add it here
                    'controller' =>  'Test\Controller\A',
                    'action' => 'index',
                ),
            ),
            'may_terminate' => true,
            'child_routes' => array(
                'default' => array(
                    'type' => 'segment',
                    'options' => array(
                        'route' => '[/:controller[/:action]]',
                        'defaults' => array(
                            'action' => 'index',
                        ),
                    ),
                ),
            ),
        ),
    ),
),