0
votes

My Module's module.config.php in Zend Framework 2 looks like this:

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',
        ),
    ),
);

The literal route works, /a is correctly matched, while /a/ results in a 404, which is fine & logical.

With the segment route, things look a bit differently. Regardless of what I enter, the route is never matched. So the route /a/b fails and I don't understand.

According the the child route setup above, the trailing slash is optional, but when it's there, a controller name also needs to be specified. If this is the case, the index action of the specified controller should be called – in this example from the BController.
If a trailing slash is added after the controller name, an action needs to be specified.

Even when I enter /a/b/index, I get a 404 error:

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

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

From this I conclude that the whole child route it not working, not only the default/fallback option. Why is the child route never matched?

1
i suspect that optional part might throw matching off 'route' => '[/:controller[/:action]]', -> 'route' => '/:controller[/:action]',Xerkus
Are you sure you are not getting invalid controller error on /a/b?Xerkus
@Xerkus I just tried your route, it's also not working. I am not exactly sure what an invalid controller error is, but the error I get is really just the one from my question.Sven
error you get for /a/b/index says that your route works. So if you don't get same error for /a/b then something strange happeningXerkus
You could change aliases for your controllers in the invokables like this : 'a' => 'Test\Controller\AController', 'b' => 'Test\Controller\BController', 'c' => 'Test\Controller\CController',. I think it would workblackbishop

1 Answers

2
votes

The error you get says that Zend router could not map the controller b to an existing class. It needs to know where is situated your controller class in the application.

A possible solution is to give the names of your controllers as aliases within invokables in your module.config file. For example : 'a' => 'Test\Controller\AController' for the AController. The route /a is matched and doesn't throws an error because you set the default controller in the route configuration.

So you need just to change this part of your code. This way the controller will be invoked with its key value in the invokables array:

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

Another solution is to add the __NAMESPACE__ of your controllers in your route configuration, this way you can keep the same aliases you have now.

Just modify your code like this :

'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',
                        ),
                    ),
                ),
            ),
        ),
    ),
),