Статьи

Связывание поддоменов в веб-приложении Zend Framework 2

Недавно на работе у меня было требование обслуживать часть веб-сайта с поддержкой ZF2 из другого субдомена без www. На самом деле проблема заключалась в том, что такое требование влечет за собой необходимость сделать все остальные маршруты абсолютными, потому что когда какая-то ссылка на страницу в поддомене по умолчанию появляется на странице поддомена, она должна быть направлена ​​на поддомен по умолчанию (www), а не текущий. Итак, вот обзор решения, которое я придумал, чтобы разрешить эту ситуацию.

Zend Framework 2 представляет мощный механизм маршрутизации, предоставляющий различные стратегии для определения конечных точек приложения. Среди прочего, есть тип маршрута Hostname , который позволяет сопоставить имя хоста запроса.

Чтобы настроить привязку поддоменов для этой отдельной области / модуля сайта, будь то блог, его верхний маршрут должен быть определен как маршрут типа имени хоста :

'router' => array(
    'routes' => array(
        'blog' => array(
            'type' => 'hostname',
            'options' => array(
                'route' => 'blog.example.com',
                'defaults' => array(
                    'controller' => 'Application\Controller\BlogController',
                    'action' => 'index',
                ),
            ),
            'may_terminate' => true,
            'child_routes' => array(
                'post' => array(
                    'type' => 'segment',
                    'options' => array(
                        'route' => '/[:slug]',
                        'constraints' => array(
                            'slug' => '[a-zA-Z0-9_-]+'
                        ),
                        'defaults' => array(
                            'action' => 'view'
                        )
                    )
                )
            )
        )
    )
)

В результате блог и его сообщения будут доступны по базовому URL-адресу blog.example.com . Но некоторые другие ссылки, такие как, например, ссылки для входа в систему / регистрации, должны по-прежнему указывать на домен по умолчанию, например www.example.com/login , при отображении на какой-либо странице блога. Чтобы достичь этого, моя идея состояла в том, чтобы динамически переопределить все маршруты, не являющиеся именами хостов в системе, таким образом, чтобы они имели префикс по умолчанию для маршрута имени хоста. Для этого сначала я определил абстрактный маршрут и назвал его «defaultDomain»:

//...
'defaultDomain' => array(
    'type' => 'hostname',
    'options' => array(
        'route' => 'www.example.com',
    ),
),
//...

Затем для самой переопределенной части я создал делегатор, обертку вокруг фабрики для создания службы маршрутизатора, которая перехватывает конфигурацию маршрутов и объединяет каждый маршрут, не связанный с именем хоста, в цепной маршрут , состоящий из маршрута домена по умолчанию и фактического маршрута:

public function getServiceConfig()
{
    return array(
        //...
        'delegators' => array(
            'Router' => array(
                function(ServiceLocatorInterface $sm, $name, $requestedName, $callback) {
                    if (!Console::isConsole()) {
                        $config = $sm->get('Config');
                        $routes = $config['router']['routes'];

                        $defaultDomain = $routes['defaultDomain'];
                        foreach ($routes as $name => $route) {
                            if ($route['type'] != 'hostname') {
                                $routes[$name] = array(
                                    'type' => 'chain',
                                    'options' => array(
                                        'routes' => array($defaultDomain, $route),
                                        'route_plugins' => $sm->get('RoutePluginManager')
                                    )
                                );
                            }
                        }
                        unset($routes['defaultDomain']);

                        //Save changes
                        $config['router']['routes'] = $routes;
                        $sm->setAllowOverride(true);
                        $sm->setService('Config', $config);
                        $sm->setAllowOverride(false);
                    }

                    return $callback();
                }
            ),
        ),
        //...
    );
}

На практике я закодировал это немного по-другому, в отдельном классе фабрики делегаторов, но суть должна быть ясна. При этом, когда, например, запрашивается маршрут пользователя / входа в систему , он всегда будет собираться в виде абсолютного URL-адреса: www.example.org/user/login на каждой странице, где он запрашивается, поскольку теперь он определяется как цепочка маршрута домена по умолчанию и исходного маршрута.

Что мне понравилось в этом подходе, так это то, что он ненавязчив , что означает, что если по какой-либо причине модуль Blog должен быть возвращен в поддомен по умолчанию, не будет необходимости изменять любой другой маршрут, кроме одного для страниц блога, потому что имя / определение этот маршрут пользователя / входа в систему остался прежним, и на него не повлияло введение этого корневого базового URL-маршрута.