Недавно на работе у меня было требование обслуживать часть веб-сайта с поддержкой 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-маршрута.