Фон:
Я пытаюсь условно загрузить маршруты на основе запроса узла. У меня есть настройка базы данных, в которой есть хосты, которые сопоставляются с шаблонами. Если пользователь заходит с хоста A
и который использует шаблон TA
Я хочу загрузить маршруты для этого шаблона. Если они приходят от хозяина B
затем загрузите маршруты для этого шаблона (TB
).
Я должен сделать это потому, что каждый шаблон будет использовать много маршрутов. Однако есть несколько уникальных маршрутов для данного шаблона.
Было бы хорошо ограничить каждый шаблон маршрутов для данного хоста, за исключением того, что существует буквально 1000 хостов.
Что я попробовал:
Я пробовал собственный загрузчик маршрутов, как описано в документации здесь:
http://symfony.com/doc/current/cookbook/routing/custom_route_loader.html
Однако, когда я настраиваю службу и пытаюсь внедрить "@request"
конструктор терпит неудачу, потому что $ request является нулем
services:
acme_demo.routing_loader:
class: Acme\DemoBundle\Routing\ExtraLoader
arguments: ["@request"]
tags:
- { name: routing.loader }
Учебный класс:
<?php
namespace: Acme\DemoBundle\Routing;
use Symfony\Component\HttpFoundation\Request;
class ExtraLoader
{
protected $request;
public function __construct(Request $request)
{
$this->request = $request;
}
// ...
}
Это также не работает, если я пытаюсь переключиться "@request"
за "@service_container"
затем позвоните
$this->container->get('request');
Самое близкое, что я получил к этой работе, было следующее руководство, найденное здесь:
http://marcjschmidt.de/blog/2013/11/30/symfony-custom-dynamic-router.html
Проблема, которую я имею с этим, я пытаюсь использовать annotation
на контроллере, и я не могу получить Symfony\Component\Routing\Loader\AnnotationFileLoader
за работой.
Хорошо, я наконец-то разобрался с рабочим решением, это смесь нескольких из упомянутых выше руководств.
Я использую слушатель запроса ядра:
services:
website_listener:
class: NameSpace\Bundle\EventListener\WebsiteListener
arguments:
- "@website_service"- "@template_service"- "@sensio_framework_extra.routing.loader.annot_dir"- "@router"- "%admin_domain%"tags:
- { name: kernel.event_listener, event: kernel.request, method: onKernelRequest, priority: 33 }
Слушатель:
<?php
namespace NameSpace\WebsiteBundle\EventListener;
use NameSpace\TemplateBundle\Service\TemplateService;
use NameSpace\WebsiteBundle\Service\WebsiteService;
use Symfony\Component\HttpKernel\Event\GetResponseEvent;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
use Symfony\Component\Routing\Loader\AnnotationDirectoryLoader;
use Symfony\Component\HttpKernel\EventListener\RouterListener;
use Symfony\Component\Routing\Matcher\UrlMatcher;
use Symfony\Component\Routing\RequestContext;
use Symfony\Component\Routing\RouteCollection;
use Symfony\Bundle\FrameworkBundle\Routing\Router;
use Symfony\Component\PropertyAccess\PropertyAccess;
class WebsiteListener
{
/**
* @var WebsiteService
*/
protected $websiteService;
/**
* @var TemplateService
*/
protected $templateService;
/**
* @var AnnotationDirectoryLoader
*/
protected $loader;
/**
* @var Router
*/
protected $router;
/**
* @var string
*/
protected $adminDomain;
public function __construct(WebsiteService $websiteService, TemplateService $templateService, AnnotationDirectoryLoader $loader, Router $router, $adminDomain)
{
$this->websiteService = $websiteService;
$this->templateService = $templateService;
$this->loader = $loader;
$this->router = $router;
$this->adminDomain = $adminDomain;
}
public function loadRoutes()
{
$template = $this->templateService->getTemplateByAlias($this->websiteService->getWebsite()->getTemplate());
$routes = $this->loader->load($template['routes'],'annotation');
$allRoutes = $this->router->getRouteCollection();
$allRoutes->addCollection($routes);
}
public function onKernelRequest(GetResponseEvent $event)
{
try {
$this->websiteService->handleRequest($event->getRequest());
$this->loadRoutes();
} catch(NotFoundHttpException $e) {
if($event->getRequest()->getHost() !== $this->adminDomain){
throw $e;
}
}
}
}
Ключевые части этого:
Loader
— Я нашел "@sensio_framework_extra.routing.loader.annot_dir"
в исходном коде. То, что загрузчик каталогов аннотаций, который Symfony использует по умолчанию, это тот, который я тоже хочу использовать. Но если вы хотите использовать другой загрузчик, есть другие доступные.Router
— Это то, что я использую, чтобы получить все текущие маршруты. НОТА что $allRoutes->addCollection($routes)
звонок на отдельной линии. Я не уверен, почему это имеет значение, но назвать все это в 1 как не работало.$template['routes']
это просто ссылка на контроллер пространства имен, которую вы использовали бы для добавления маршрутизации в вашем routing.yml. Что-то вроде: "@NamespaceBundle/Controller"
Других решений пока нет …