背景:
我正在尝试根据请求主机有条件地加载路由。我有一个数据库设置,其中有映射到模板的主机。如果用户来自主机A
并且使用模板TA
我想加载该模板的路由。如果它们来自主机B
则加载该模板的路由(TB
(。
我必须这样做的原因是每个模板将共享许多路由。但是,给定模板有一些独特的路由。
将每个模板路由限制为给定主机是可以的,除了实际上有 1000 个主机。
我尝试过的:
我已经尝试了自定义路由加载程序,如此处文档中所述:
http://symfony.com/doc/current/cookbook/routing/custom_route_loader.html
但是,当我配置服务并尝试注入"@request"
时,构造函数失败$request因为 null
services:
acme_demo.routing_loader:
class: AcmeDemoBundleRoutingExtraLoader
arguments: ["@request"]
tags:
- { name: routing.loader }
类:
<?php
namespace: AcmeDemoBundleRouting;
use SymfonyComponentHttpFoundationRequest;
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
,但我似乎无法让SymfonyComponentRoutingLoaderAnnotationFileLoader
工作。
好的,我终于找到了一个可行的解决方案,它是上述几个指南的混合体。
我使用内核请求侦听器:
services:
website_listener:
class: NameSpaceBundleEventListenerWebsiteListener
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 NameSpaceWebsiteBundleEventListener;
use NameSpaceTemplateBundleServiceTemplateService;
use NameSpaceWebsiteBundleServiceWebsiteService;
use SymfonyComponentHttpKernelEventGetResponseEvent;
use SymfonyComponentHttpKernelExceptionNotFoundHttpException;
use SymfonyComponentRoutingLoaderAnnotationDirectoryLoader;
use SymfonyComponentHttpKernelEventListenerRouterListener;
use SymfonyComponentRoutingMatcherUrlMatcher;
use SymfonyComponentRoutingRequestContext;
use SymfonyComponentRoutingRouteCollection;
use SymfonyBundleFrameworkBundleRoutingRouter;
use SymfonyComponentPropertyAccessPropertyAccess;
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']
只是一个命名空间控制器引用,就像您在 routeting.yml 中添加路由一样。像这样:"@NamespaceBundle/Controller"