【问题标题】:Symfony2 - Root slugs for different content typesSymfony2 - 不同内容类型的根 slug
【发布时间】:2015-04-15 16:21:21
【问题描述】:

我希望有多个路由,在 URI 中只有一个路径“部分”,但加载不同类型的内容。

例如,我希望通过 /page-slug-here 加载使用 CMS 创建的页面。但是我也希望通过/product-slug-here 加载产品,通过/category-slug-here 加载类别,通过/brand-slug-here 加载品牌等。

什么是使用 Symfony2 实现这一目标的最佳/最动态的方法,而不需要复杂(且低效)的控制器链转发到下一个动作,当它们各自的内容无法找到时?

我还想避免使用单个操作来检查每种类型的内容。

【问题讨论】:

    标签: php symfony routing


    【解决方案1】:

    您可以拦截请求并使用您自己的路由器侦听器发挥作用。

    我自己没有测试它,但我只是想为您指出正确的方向。

    在您的 service.xml 文件中,您可以添加类似的内容:

        <parameters>
            <parameter key="my.router_listener.class">MyBundle\Listener\RouterListener</parameter>
        </parameters>
    
        <services>
            <service id="my.router_listener" class="%my.router_listener.class%">
                <argument type="service" id="doctrine.orm.entity_manager" />
                <tag name="kernel.event_subscriber" priority="33" />
            </service>
        </services>
    

    这里的优先级很重要。 32是默认路由器。你只想在它之前。 http://symfony.com/doc/current/reference/dic_tags.html

    然后像这样创建服务:

    class DynamicRouterListener extends RouterListener
    {
        private $entityManager;
    
        public function __construct(EntityManager $entityManager)
        {
            //...
        }
    
        public function onKernelRequest(GetResponseEvent $event)
        {
            $request = $event->getRequest();
            $path = $request->getPathinfo();
    
            // Some magic here
            if(// magic is true) {
                $request->attributes->set('_controller', 'MyBundle:MyController:myAction');
            }
        }
    }
    

    接下来出现的默认路由器将看到 _controller 参数已经存在,并将跳过与 dafult 规则的匹配。

    【讨论】:

    • 谢谢,这是一种比使用控制器操作来决定将请求转发到何处更好的方法,并且不需要对 404 进行任何额外处理。我想以此为基础,最好的方法拥有全球路线而不会有冲突风险或需要一系列数据库查询,是否拥有与每种类型的内容相关的Route 实体?可以为我的路由器事件侦听器使用的服务批量获取它们(并在生产中缓存),该服务将处理检查请求的 URI 是否存在?
    • @Adam 我认为这是一个设计问题。当然,您可以根据想要拥有的对象类型创建尽可能多的侦听器,但问题是您将拥有多少类型以及将来更改的可能性有多大?如果,正如您在帖子中提到的那样,您有 3 种类型,那么我建议在一个类中处理它。只要保持小。
    【解决方案2】:

    我认为你不能,不能完全或没有碰撞的风险。

    您需要一些东西来告诉路由器您指的是哪个东西,或者它无法以任何方式知道它是产品、页面还是品牌。至少,您需要手动避免名称冲突。

    您可以使用该匹配模式设置 3 条路由,如下所示:

    /**
     * @Route("/{page-slug}")
     *
     *
     * @Method("GET")
     */
    public function pageAction(PageClass $page)
    {
         ...
    }
    

    但您无法决定在路由器中首先尝试匹配的内容;所以,万一发生碰撞,你基本上就完蛋了。

    【讨论】:

    • 这正是作者不想做的。
    • 嗯,我想多了,你说得对。我会编辑答案
    • 谢谢,但如前所述,我试图避免使用控制器操作转发到其他操作。
    猜你喜欢
    • 2017-04-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-06-27
    • 1970-01-01
    • 1970-01-01
    • 2013-02-04
    • 1970-01-01
    相关资源
    最近更新 更多