3

我有一个当前项目,它必须显示具有特定实体的已定义页面,使用 Symfony2 非常容易管理的内容,以及不同布局上的内容页面,我猜这有点不太常见。

我在尝试构建路由系统时遇到了麻烦。

例如,如果我必须显示一个包含一些新闻的页面,我想用一个新路由更新我的包的路由器,例如:

my_bundle_news_page:
    pattern: /news
    defaults:
        _controller: MyBundle:NewsController:indexAction

但是如何管理可以在多个级别上具有完全自定义 URL 的动态路由器呢?

假设我有一个“页面”实体,它是可选的“父子”关系的自引用。我不认为我可以为这个特定的路由使用任何配置 YAML 文件?!

my_bundle_custom_page:
    pattern: /{slug}
    defaults:
        _controller: MyBundle:PageController:showAction

这将绑定所有第一级页面:

/项目

/关于

/接触

/我们的项目

例如,一个页面会显示一个像这样的 slug:

/我们的项目/健康

其实任何网址...

/{slug-level1}/{slug-level2}/{slug-level3} 等。

因为页面应该从网站管理员更改和更新。

我想最好的方法是让路由器将 {slug} 与数据库字段(实体属性)进行比较

我在Symfony-CMF 文档中读到,可以编写基于路由提供者的服务:

namespace MyBundle\Routing;

use Symfony\Component\Routing\RouteCollection;
use Symfony\Component\Routing\Route as SymfonyRoute;

use MyBundle\Entity\PageRepository;

class RouteProvider extends PageRepository {
    public function findPageBySlug($slug)
    {
        // Find a page by slug property
        $page = $this->findOneBySlug($slug);

        if (!$page) {
            // Maybe any custom Exception
            throw $this->createNotFoundException('The page you are looking for does not exists.');
        }

        $pattern = $page->getUrl(); // e.g. "/first-level/second-level/third-level"

        $collection = new RouteCollection();

        // create a new Route and set our page as a default
        // (so that we can retrieve it from the request)
        $route = new SymfonyRoute($pattern, array(
            'page' => $page,
        ));

        // add the route to the RouteCollection using a unique ID as the key.
        $collection->add('page_'.uniqid(), $route);

        return $collection;
    }
}

但是如何将其设置为服务?有什么要求吗?这种事情怎么会起作用,它是否在调用请求时向 RouteCollection 添加了一条路由?

我能以这种方式绑定任何路线吗?

编辑:我的包的 services.yml

parameters:
    cmf_routing.matcher.dummy_collection.class: Symfony\Component\Routing\RouteCollection
    cmf_routing.matcher.dummy_context.class: Symfony\Component\Routing\RequestContext
    cmf_routing.generator.class: Symfony\Cmf\Bundle\RoutingBundle\Routing\ContentAwareGenerator
    cmf_routing.nested_matcher.class:  Symfony\Cmf\Component\Routing\NestedMatcher\NestedMatcher
    cmf_routing.url_matcher.class:  Symfony\Cmf\Component\Routing\NestedMatcher\NestedMatcher
    fsbcms.chain_router.class: Symfony\Cmf\Component\Routing\ChainRouter
    fsbcms.route_provider.class: FSB\CMSBundle\Routing\RouteProvider
    fsbcms.dynamic_router.class: Symfony\Cmf\Component\Routing\DynamicRouter
    fsbcms.route_entity.class: null

services:
    fsbcms.router:
        class: %fsbcms.chain_router.class%
        arguments:
            - "@logger"
        calls:
            - [setContext, ["router.request_context"]]
    fsbcms.route_provider:
        class: "%fsbcms.route_provider.class%"
        arguments:
            - "@doctrine"
    cmf_routing.matcher.dummy_collection:
        class: "%cmf_routing.matcher.dummy_collection.class%"
        public: "false"
    cmf_routing.matcher.dummy_context:
        class: "%cmf_routing.matcher.dummy_context.class%"
        public: false
    cmf_routing.generator:
        class: "%cmf_routing.generator.class%"
        arguments:
            - "@fsbcms.route_provider"
            - "@logger"
        calls:
            - [setContainer, ["service_container"]]
            - [setContentRepository, ["cmf_routing.content_repository"]]
    cmf_routing.url_matcher:
        class: "%cmf_routing.url_matcher.class%"
        arguments: ["@cmf_routing.matcher.dummy_collection", "@cmf_routing.matcher.dummy_context"]
    cmf_routing.nested_matcher:
        class: "%cmf_routing.nested_matcher.class%"
        arguments: ["@fsbcms.route_provider"]
        calls:
            - [setFinalMatcher, ["cmf_routing.url_matcher"]]
    fsbcms.dynamic_router:
        class: "%fsbcms.dynamic_router.class%"
        arguments:
            - "@router.request_context"
            - "@cmf_routing.nested_matcher"
            - "@cmf_routing.generator"
        tags:
            - { name: router, priority: 300 }
4

1 回答 1

3

我建议看一下 Symfony CMF 路由组件和 CmfRoutingBundle(在 symfony 中实现该组件)。

Routing 组件使用链式路由器,这与这个问题无关,但很高兴知道。链路由器链接在路由器队列上。该组件提供了一个使用 NestedMatcher 的 DynamicRouter。这正是你想要的。

NestedMatcher 使用路由提供程序从动态源(例如数据库)获取路由。您在问题中展示了一个 Route 提供程序的示例。

此外,它使用 FinalMatcher 来匹配路由。您可以只传递 的一个实例Symfony\Cmf\Component\Routing\NestedMatcher\UrlMatcher,因为您所做的事情并不太难。

查看RoutingBundle 的文档以了解如何激活链路由器,然后创建一个加载路由的路由提供程序,创建一个服务:

acme_routing.route_provider:
    class: Acme\RoutingBundle\Provider\DoctrineOrmProvider
    arguments: ["@doctrine"]

现在,您可以创建一个 NestedMatcher 服务:

acme_routing.url_matcher:
    class: Symfony\Cmf\Component\Routing\NestedMatcher\UrlMatcher
    arguments: ["@cmf_routing.matcher.dummy_collection", "@cmf_routing.matcher.dummy_context"]

acme_routing.nested_matcher:
    class: Symfony\Cmf\Component\Routing\NestedMatcher
    arguments: ["@acme_routing.route_provider"]
    calls:
        - [setFinalMatcher, ["acme_routing.url_matcher"]]

现在,注册 DynamicRouter 并将其放入链中:

acme_routing.dynamic_router:
    class: Symfony\Cmf\Component\Routing\DynamicRouter
    arguments:
        - "@router.request_context"
        - "@acme_routing.nested_matcher"
        - "@cmf_routing.generator"
    tags:
        - { name: router, priority: 300 }

现在,它应该可以工作并且应该从数据库中加载路由并将它们与请求进行匹配。

于 2013-07-14T15:39:07.853 回答