【问题标题】:Symfony 2 How To Dynamically Add Routes With Access To The Request ObjectSymfony 2 如何动态添加访问请求对象的路由
【发布时间】:2014-09-17 02:35:54
【问题描述】:

背景:

我正在尝试根据请求主机有条件地加载路由。我有一个数据库设置,其中包含映射到模板的主机。如果用户来自主机 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 工作。

【问题讨论】:

    标签: php symfony event-listener symfony-2.5


    【解决方案1】:

    好的,我终于找到了一个可行的解决方案,它结合了上述几个指南。

    我正在使用内核请求侦听器:

    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-&gt;addCollection($routes) 调用在单独的行上。我不知道为什么它会有所作为,但将其全部归为 1 并不起作用。
    • $template['routes'] 只是一个命名空间控制器引用,就像你用来在你的 routing.yml 中添加路由一样。类似:"@NamespaceBundle/Controller"

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2014-03-18
      • 1970-01-01
      • 1970-01-01
      • 2017-02-02
      • 1970-01-01
      • 2014-12-31
      • 2011-08-27
      相关资源
      最近更新 更多