dongpaocuan7498 2014-09-17 02:35
浏览 34
已采纳

Symfony 2如何动态添加具有对请求对象的访问权限的路由

Background:

I am trying to conditionally load routes based on the request host. I have a database setup that has hosts in it that map to templates. If a user comes in from the host A and that uses template TA I want to load the routes for that template. If they come in from host B then load the routes for that template (TB).

The reason I have to do this is because each template will share many routes. There are however some unique routes for a given template.

It would be fine to restrict each template routes to a given host, except that there are literally 1000's of hosts.

What I Have Tried:

I have tried a custom route loader as described in the documentation here:

http://symfony.com/doc/current/cookbook/routing/custom_route_loader.html

However when i configure the service and try and inject the "@request" the constructor fails because $request is null

services:
    acme_demo.routing_loader:
        class: Acme\DemoBundle\Routing\ExtraLoader
        arguments: ["@request"]
        tags:
            - { name: routing.loader }

Class:

<?php
namespace: Acme\DemoBundle\Routing;
use Symfony\Component\HttpFoundation\Request;
class ExtraLoader
{
    protected $request;

    public function __construct(Request $request)
    {
        $this->request = $request;
    }
    // ...
}

This also doesnt work if I try and switch "@request" for "@service_container" then call

$this->container->get('request');

The closest I got to getting this working was following a guide found here:

http://marcjschmidt.de/blog/2013/11/30/symfony-custom-dynamic-router.html

The problem i have with this on is im trying to use annotation on a controller and i cant seem to get the Symfony\Component\Routing\Loader\AnnotationFileLoader working.

  • 写回答

1条回答 默认 最新

  • dongnu4254 2014-09-17 05:35
    关注

    Ok I have finally figured out a working solution, Its a mix of several of the above mentioned guides.

    Im using a kernel request listener:

    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 }
    

    The Listener:

    <?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;
                }
            }
    
        }
    }
    

    The Key parts of this are:

    • The Loader - I found "@sensio_framework_extra.routing.loader.annot_dir" in the source code. That the annotation directory loader that symfony uses by default so thats the one that I want to use too. But if you want to use a different loader there are others available.
    • The Router - This is what i use to get all of the current routes. NOTE that the $allRoutes->addCollection($routes) call is on a seperate line. Im not sure why it makes a difference but calling it all in 1 like was not working.
    • $template['routes'] is just a namespaces controller reference like you would use to add routing in your routing.yml. Something like: "@NamespaceBundle/Controller"
    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论

报告相同问题?

悬赏问题

  • ¥100 Jenkins自动化部署—悬赏100元
  • ¥15 关于#python#的问题:求帮写python代码
  • ¥20 MATLAB画图图形出现上下震荡的线条
  • ¥15 关于#windows#的问题:怎么用WIN 11系统的电脑 克隆WIN NT3.51-4.0系统的硬盘
  • ¥15 perl MISA分析p3_in脚本出错
  • ¥15 k8s部署jupyterlab,jupyterlab保存不了文件
  • ¥15 ubuntu虚拟机打包apk错误
  • ¥199 rust编程架构设计的方案 有偿
  • ¥15 回答4f系统的像差计算
  • ¥15 java如何提取出pdf里的文字?