Модуль Zend Framework 2 по умолчанию

В ZF1 вам не нужно было включать модуль в URL-адрес; если бы он не был предоставлен, по умолчанию использовался бы... модуль по умолчанию. Как это можно сделать в ZF2? Я использовал скелетное приложение для запуска и работы, но кажется, что мне всегда нужно включать имя модуля, например. /application/controller/action.

Я подумал, что могу обойти это, создав маршрут с двумя «заполнителями»; контроллер и действие, а затем установите модуль по умолчанию на «приложение». Затем я бы поместил это в /config/autoload/global.php (или, возможно, /config/application.config.php), чтобы маршрут применялся ко всему моему приложению. Однако я получаю сообщение об ошибке, что URL-адрес не может быть сопоставлен с маршрутизацией, даже если я жестко запрограммирую маршрут на что-то вроде /user/index.

Я попробовал код ниже.

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

Как я писал в качестве комментария, я не уверен, связана ли моя проблема с синтаксисом по умолчанию, но я бы так не думал, поскольку то же самое произойдет, если я жестко запрограммирую маршрут и удалю все значения по умолчанию. Я также пытался поэкспериментировать с ним на основе примеров в скелетном приложении, но безуспешно. Я иду об этом неправильно? Есть ли лучший подход? Или я просто ошибся?

Заранее спасибо.

Изменить. Код, который заставит его работать, см. в ответе. Чтобы узнать, как это работает, прочитайте этой статьи.


person ba0708    schedule 15.09.2012    source источник


Ответы (3)


Примечание. Настоятельно рекомендуется использовать явные маршруты, а не подстановочные знаки.

Вы использовали тип маршрута Zend\Mvc\Router\Http\Literal в своей попытке, так как вы можете догадаться, что это буквальное, т.е. точное совпадение. Чтобы это работало, вам нужен тип маршрута сегмента.

Проверьте application маршрут в конфигурации приложения Zend Skeleton< /a> и это дочерний маршрут default. Он делает именно то, что вы пытаетесь сделать.

Что касается модулей - с точки зрения вашего кода не существует такого понятия, как "модуль". Модуль регистрирует ресурсы при запуске, и после этого он больше не актуален. В zf2 вы указываете точный контроллер по классу или псевдониму, под которым контроллер зарегистрирован в 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'
        ),
    )
);
person Xerkus    schedule 16.09.2012
comment
Я бы добавил подсказку, что каждый контроллер должен быть указан в вызываемых объектах, чтобы их можно было проанализировать из URL-адреса, символ, используемый в вызываемых объектах, должен соответствовать символу, используемому в URL-адресе. - person Samuel Herzog; 16.09.2012
comment
@SamuelHerzog не обязательно быть в invokables, его тоже можно настроить как заводской. Но да, это должно быть в ControllerManager. - person Xerkus; 16.09.2012
comment
конечно, но поскольку вы использовали вызываемые объекты, я подумал, что будет разумнее указать это, чем добавлять дополнительную информацию, это ваша задача :) - person Samuel Herzog; 16.09.2012
comment
Спасибо за ответ. Мне пришлось внести небольшие коррективы, чтобы код заработал, но вы указали мне правильное направление. Я отредактировал код в вашем ответе, чтобы отразить мои правки. Я удалил косую черту из маршрута сегментов (поскольку это дочерний маршрут маршрута /) и установил __NAMESPACE__ в каталог моего контроллера. Делая это, я могу написать localhost/user в URL-адресе и сопоставить его с Application\Controller\User вместо того, чтобы менять ключи моего контроллера, чтобы они совпадали с ключами в URL-адресе (и тем самым открываться для коллизий контроллера модуля). - person ba0708; 16.09.2012
comment
Я ожидал, что этот код будет работать со следующим набором URL-адресов: /application/index/index; /application/index (действие по умолчанию); /application (контроллер и действие по умолчанию); /index/index (модуль по умолчанию); /index (модуль и действие по умолчанию); Но это не так... Так что, на мой взгляд, это неправильный ответ... Я, конечно, понимаю, что нет такой вещи, как модуль, но допустим, что они существуют в пути. - person Karol; 19.02.2013
comment
Привет @ Andy0708 - проверь мой ответ, так как он работает со всеми указанными мной URL-адресами. Я не буду отрицать ответ Xerkus, так как он работает и для некоторых URL-адресов. Также его теоретическое объяснение привело меня к моему решению. - person Karol; 20.02.2013
comment
Пример @Carlos здесь для маршрута сегмента, а не для приведения старого поведения в zf2 - person Xerkus; 20.02.2013
comment
скопируйте свою конфигурацию, измените имя контроллера и получите следующее: Запрошенный контроллер не может быть сопоставлен с существующим классом контроллера. Контроллер: валюта (разрешает неверный класс контроллера или псевдоним: валюта) - person Crusader; 12.03.2015

Как я сказал в комментарии под ответом @Xerkus, он не работает для всех URL-адресов:

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

Я также добавил testAction() к IndexController и TestController с теми же действиями, что и IndexController, чтобы я мог протестировать свое решение и на следующих маршрутах:

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

Итак, после некоторых исследований (здесь и в основном здесь) Я подготовил решение, работающее для всех из них. Я вставлю весь свой массив module.config.php:

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

По сравнению с конфигом Zend 2 Skeleton Application я добавил noModule маршрут, а новый controller invokable - test. Конечно, маршрут noModule включает в себя пространство имен Application/Controller, поэтому, основываясь на этом факте, вы можете установить любой модуль по умолчанию, который вам нужен. Теперь работает как надо.

Конечно, помните, что ваш маршрут noModule должен быть определен в первом модуле из application.config.php, чтобы гарантировать, что он всегда будет иметь приоритет. Также помните, что решение модуля по умолчанию должно быть сделано тщательно, чтобы избежать конфликтов между именами контроллеров и модулей, например. если вы назовете свой следующий модуль Index, то, очевидно, у вас возникнет конфликт имен с IndexController в модуле Application.

person Karol    schedule 20.02.2013
comment
хотя это работает, это концептуально неправильный подход. Вы пытаетесь привнести аспекты zf1 в приложение zf2. В zf2 предпочтение отдается определенным маршрутам, и для этого есть много причин, среди которых разделение ответственности: ваш код в слоях контроллера/представления будет зависеть только от имени маршрута, а не от имени маршрута + контроллер [+ действие], следовательно, контроллер и/или действие можно легко поменять местами в одном месте. Еще одна проблема, с которой вы только что столкнулись, заключается в том, что ваш маршрут будет неправильно соответствовать большому количеству URI, что приведет к неправильному разрешению контроллера и огромному количеству WTF. - person Xerkus; 20.02.2013
comment
@Xerkus - я согласен с вами, что это не так, как должно было быть, и это смешение подхода zf1 с архитектурой zf2. Вот почему я написал, что вам нужно быть осторожным и искать конфликты. Я не говорил, что буду использовать его в каком-либо проекте — я просто задал вопрос. Иногда вы не можете следовать наилучшему подходу или шаблону проектирования, и я знаю, что вы, как разработчик, сталкивались с такими ситуациями и раньше. Вот почему я потратил некоторое время, чтобы заставить этот код работать. И, как я уже писал, я согласен с вашим теоретическим объяснением, которое на самом деле помогло мне понять несколько вещей в маршрутизации ZF2. - person Karol; 20.02.2013

Я новичок в ZF в целом, и я только начал его изучать, поэтому попробовал это, и это сработало для меня. Просто чтобы быть уверенным, вы хотите изменить свой модуль по умолчанию, когда вы переходите к URL-адресу своего домена и не вводите имя контроллера, верно?

Перейдите к вашему 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',
                ),
            ),
        ),
    ),
),
person Lorenz V.    schedule 16.09.2012
comment
ваши ограничения должны соответствовать заполнителю в маршруте (например, /: action), чтобы иметь какой-либо эффект. - person Samuel Herzog; 16.09.2012