l_r
l_r

Reputation: 1060

ZF3 zend-mvc generic route for many controllers in one module not working

I'm in ZF3, using the zend-mvc-skeleton and trying to configure a generic route that will match as many URLs as possible as I want to be able to create new controllers (including action methods of course), and have them immediately available.

The common approach described in the documentation is to write a route that matches the controller and action (same with ZF2).

Here is my module.config.php

namespace Application;

use Zend\Router\Http\Literal;
use Zend\Router\Http\Segment;
use Zend\ServiceManager\Factory\InvokableFactory;

return [
    'router' => [
        'routes' => [
            'home' => [
                'type'    => Literal::class,
                'options' => [
                    'route'    => '/',
                    'defaults' => [
                        'controller' => Controller\IndexController::class,
                        'action'     => 'index',
                    ],
                ],
            ],
            'default' => [
                'type' => Segment::class,
                'options' => [
                    'route'    => '/application[/:controller[/:action]]',
                    'defaults' => [
                        'controller' => Controller\IndexController::class,
                        'action'     => 'index',
                    ],
                    'constraints' => [
                        'controller' => '[a-zA-Z][a-zA-Z0-9_-]*',
                        'action'     => '[a-zA-Z][a-zA-Z0-9_-]*',
                    ],
                ],
            ],
        ],
    ],
    'controllers' => [/* ... */],
    'view_manager' => [/* ... */],
],

It works like a charm for http://localhost/ and http://localhost/application calling the indexAction() function of the IndexController class inside the /module/Application/src/IndexController.php file.

However, it's not working when I try to get the fooAction() function in the same Controller (i.e. IndexController). It's not resolving correctly http://localhost/application/foo. and I get the following error:

A 404 error occurred

Page not found.

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

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

No Exception available

Same error if I try http://localhost/bar/foo to get the fooAction() in the barController.

Do you have any idea of what's wrong with this? Any help will be appreciated. Many thanks.

Upvotes: 2

Views: 4331

Answers (2)

Julian Danchev
Julian Danchev

Reputation: 31

I came here with similar problem. I have created two controllers in "Application" module, and two in new module "Account" with the same name.

Application/Controller/IndexController
Application/Controller/OverviewController
Account/Controller/IndexController
Account/Controller/OverviewController

here are my modules.config.php

module/Account/config/module.config.php

 return [
'router' => [
    'routes' => [
        'Account-account' => [
         'type'  =>  Segment::class,
         'options' =>  [
          'route' =>  '/account[/][:controller[/][:action][/]]',
           'defaults'  =>  [
             '__NAMESPACE__' =>  'Account\Controller',
             'controller'  =>  Account\Controller\IndexController::class,
             'action'      =>  'index',
             'locale'  =>  'en_us'
           ],
         ],
         'may_terminate' =>  true,
         'child_routes'  => [
           'wildcard'  =>  [
             'type'  =>  'Wildcard'
           ],
         ],
       ],
    ],
],
'controllers' => [
    'factories' => [
        Controller\IndexController::class     => AccountControllerFactory::class,
        Controller\OverviewController::class  => AccountControllerFactory::class,
    ],
    'aliases' => [
      'index'   =>  IndexController::class,
      'overview'  =>  OverviewController::class
    ]

],

and my module/Application/config/module.config.php

return [
    'router' => [
        'routes' => [
            'home' => [
                'type' => Literal::class,
                'options' => [
                    'route'    => '/',
                    'defaults' => [
                        'controller' => Controller\IndexController::class,
                        'action'     => 'index',
                    ],
                ],
            ],
            'Application-application' => [
             'type'  =>  Segment::class,
             'options' =>  [
              'route' =>  '/application[/][:controller[/][:action][/]]',
               'defaults'  =>  [
                 '__NAMESPACE__' =>  'Application\Controller',
                 'controller'  =>  Application\Controller\IndexController::class,
                 'action'      =>  'index',
                 'locale'  =>  'en_US'
               ],
             ],
             'may_terminate' =>  true,
             'child_routes'  => [
               'wildcard'  =>  [
                 'type'  =>  'Wildcard'
               ],
             ],
           ],
        ],
    ],
    'controllers' => [
        'factories' => [
            Controller\IndexController::class => IndexControllerFactory::class,
            Controller\OverviewController::class => IndexControllerFactory::class,
        ],
        'aliases' =>  [
          'index'     =>  IndexController::class,
         'overview'  =>  OverviewController::class,
        ]

    ],

With this configuration if aliases sections are commented there is a error message which says that there is invalid controller or alias (index/overview). If there are aliases route: "application/overview/index" goes into Account module.

Upvotes: 0

complex-space
complex-space

Reputation: 744

The route http://localhost/application/foo won't resolve to fooAction() in the index controller, since /foo in the URL will match the controller not the action. With that route setup you would need to visit http://localhost/application/index/foo.

To get it working you'll also need to make sure you have aliased your controller in the config, e.g. assuming you have:

'controllers' => [
    'invokables' => [
        'Application\Controller\Index' => \Application\Controller\IndexController::class
    ]
],

Then alias the controller so it matches the route parameter:

'controllers' => [
    'invokables' => [
        'Application\Controller\Index' => \Application\Controller\IndexController::class
    ],
    'aliases' => [
        'index' => 'Application\Controller\Index'
    ]
],

You'll need to add aliases that match the route parameter for each controller that isn't registered using the string you want for the route, e.g. a controller Namespace\Controller\BarController should be aliased to bar, etc.

Upvotes: 2

Related Questions