Zend Framework 2 default module

2019-04-01 01:20发布

问题:

In ZF1 you did not have to include the module in the URL; if it was not provided, it would default to... the default module. How can this be accomplished in ZF2? I have used the skeleton application to get up and running, but it seems as if I always need to include the module name, e.g. /application/controller/action.

I figured I could work around this by creating a route with two "placeholders"; controller and action, and then set the default module to "application". I would then put this in /config/autoload/global.php (or perhaps /config/application.config.php) so that the route applies for all of my application. However, I am getting the error message that the URL could not be matched by routing, even if I hard code the route to something like /user/index.

I tried the code below.

return array(
    'router' => array(
        'routes' => array(
            'nomodule' => array(
                'type' => 'Zend\Mvc\Router\Http\Literal',
                'options' => array(
                    'route' => '/:controller/:action',
                    'constraints' => array(
                        'controller' => '[a-zA-Z][a-zA-Z0-9_-]*',
                        'action' => '[a-zA-Z][a-zA-Z0-9_-]*'
                    ),
                    'defaults' => array(
                        'module' => 'Application' // Not sure of the syntax here
                    )
                )
            ),
        )
    )
);

As I wrote as a comment, I am not sure if my problem is with the defaults syntax, but I wouldn't think so as the same happens if I hard code the route and remove all defaults. I also tried to experiment with it based on examples in the skeleton application, but without luck. Am I going about it the wrong way? Is there a better approach? Or did I just make a mistake?

Thanks in advance.

Edit: For the code to make it work, see the answer. For an explanation of how it works, read this article.

回答1:

Note: Explicit routes are strongly recommended over wildcard.

You used Zend\Mvc\Router\Http\Literal route type in your attempt, as you might guess it is literal, ie exact match. To make it work you need segment route type.

Check application route in Zend Skeleton Application config and it's child route default. It does exactly what you are trying to do.

As for modules - there is no such thing as 'module' from your code perspective. Module registers resources on startup and it is no longer relevant after that point. In zf2 you specify exact controller by class or alias name under which controller registered with controllerManager

// module\Application\config\module.config.php
return array(
    'router' => array(
        'routes' => array(
            'home' => array(
                'type' => 'Zend\Mvc\Router\Http\Literal',
                'options' => array(
                    'route'    => '/',
                    'defaults' => array(
                        'controller' => 'Application\Controller\Index',
                        'action'     => 'index',
                    ),
                ),
                'may_terminate' => true,
                'child_routes' => array(
                    'default' => array(
                        'type' => 'Segment',
                        'options' => array(
                            'route' => '[:controller[/:action]]',
                            'constraints' => array(
                                'controller' => '[a-zA-Z][a-zA-Z0-9_-]*',
                                'action' => '[a-zA-Z][a-zA-Z0-9_-]*'
                            ),
                            'defaults' => array(
                                'action' => 'index',
                                '__NAMESPACE__' => 'Application\Controller'
                            )
                        )
                    )
                )
            )
        )
    ),
    'controllers' => array(
        'invokables' => array(
            'Application\Controller\Index' => 'Application\Controller\IndexController',
            'Application\Controller\User' => 'Application\Controller\UserController'
        ),
    )
);


回答2:

As I stated in comment under @Xerkus answer, it doesn't work for all URLs:

/application/index/index
/application/index
/application
/index/index
/index
/

I have added also testAction() to IndexController and TestController with same actions as IndexController, so I could test my solution on following routes as well:

/index/test
/test/index
/test/test
/test

So after some research (here and here mainly) I prepared solution working for all of them. I will paste my whole module.config.php array:

return array(
    'router' => array(
        'routes' => array(
            'home' => array(
                'type' => 'Literal',
                'options' => array(
                    'route'    => '/',
                    'defaults' => array(
                        'controller' => 'Application\Controller\Index',
                        'action'     => 'index',
                    ),
                ),
            ),
            'noModule' => array(
                'type' => 'Segment',
                'options' => array(
                    'route'    => '/[:controller[/:action]]',
                    'constraints' => array(
                        'controller' => '[a-zA-Z][a-zA-Z0-9_-]*',
                        'action'     => '[a-zA-Z][a-zA-Z0-9_-]*',
                    ),
                    'defaults' => array(
                        '__NAMESPACE__' => 'Application\Controller',
                        'controller'    => 'Index',
                        'action'        => 'index',
                    ),
                ),
            ),
            // The following is a route to simplify getting started creating
            // new controllers and actions without needing to create a new
            // module. Simply drop new controllers in, and you can access them
            // using the path /application/:controller/:action
            'application' => array(
                'type'    => 'Literal',
                'options' => array(
                    'route'    => '/application',
                    'defaults' => array(
                        '__NAMESPACE__' => 'Application\Controller',
                        'controller'    => 'Index',
                        'action'        => 'index',
                    ),
                ),
                'may_terminate' => true,
                'child_routes' => array(
                    'default' => array(
                        'type'    => 'Segment',
                        'options' => array(
                            'route'    => '/[:controller[/:action]]',
                            'constraints' => array(
                                'controller' => '[a-zA-Z][a-zA-Z0-9_-]*',
                                'action'     => '[a-zA-Z][a-zA-Z0-9_-]*',
                            ),
                            'defaults' => array(
                            ),
                        ),
                    ),
                ),
            ),
        ),
    ),
    'service_manager' => array(
        'factories' => array(
            'translator' => 'Zend\I18n\Translator\TranslatorServiceFactory',
        ),
    ),
    'translator' => array(
        'locale' => 'en_US',
        'translation_file_patterns' => array(
            array(
                'type'     => 'gettext',
                'base_dir' => __DIR__ . '/../language',
                'pattern'  => '%s.mo',
            ),
        ),
    ),
    'controllers' => array(
        'invokables' => array(
            'Application\Controller\Index' => 'Application\Controller\IndexController',
            'Application\Controller\Test' => 'Application\Controller\TestController'
        ),
    ),
    'view_manager' => array(
        'display_not_found_reason' => true,
        'display_exceptions'       => true,
        'doctype'                  => 'HTML5',
        'not_found_template'       => 'error/404',
        'exception_template'       => 'error/index',
        'template_map' => array(
            'layout/layout'           => __DIR__ . '/../view/layout/layout.phtml',
            'application/index/index' => __DIR__ . '/../view/application/index/index.phtml',
            'error/404'               => __DIR__ . '/../view/error/404.phtml',
            'error/index'             => __DIR__ . '/../view/error/index.phtml',
        ),
        'template_path_stack' => array(
            __DIR__ . '/../view',
        ),
    ),
);

In comparison with Zend 2 Skeleteon Application config I've added noModule route, and new controller invokable - test. Of course noModule route includes Application/Controller namespace, so basing on this fact, you can set whatever default module you need. Now it works as it should.

Of course remember that your noModule route should be defined in first module from application.config.php to ensure that it will always take precedence. Also remember that default module solution should be done carefully, to avoid conflicts between controllers and modules names, e.g. if you name your next module Index, then clearly you will have a naming conflict with IndexController in Application module.



回答3:

I'm new to ZF in general and I just started learning it, so tried this and it worked for me. Just to be sure, u want to change your default module when you go to your domain URL and don't type in a controller name, right?

Go to your module.config.php

 'router' => array(
    'routes' => array(
        'album WITH CONTROLLER IN URL' => array(
            'type'    => 'segment',
            'options' => array(
                'route'    => '/album[/:action]',
                'constraints' => array(
                    'action' => '[a-zA-Z][a-zA-Z0-9_-]*',
                ),
                'defaults' => array(
                    'controller' => 'Album\Controller\Album',
                    'action'     => 'index',
                ),
            ),
        ),
        'album WITHOUT CONTROLLER IN URL' => array(
            'type'    => 'segment',
            'options' => array(
                'route'    => '/[:action]',
                'constraints' => array(
                    'action' => '[a-zA-Z][a-zA-Z0-9_-]*',
                ),
                'defaults' => array(
                    'controller' => 'Album\Controller\Album',
                    'action'     => 'index',
                ),
            ),
        ),
        'SET IT AS YOUR HOMEPAGE' => array(
            'type'    => 'segment',
            'options' => array(
                'route'    => '/',
                'defaults' => array(
                    'controller' => 'Album\Controller\Album',
                    'action'     => 'index',
                ),
            ),
        ),
    ),
),