跳到内容

动态路由

编辑此页

Symfony 默认路由器被开发用于处理静态路由定义,因为它们通常在执行之前在配置文件中声明。完整的路由配置被注入到构造函数中。然后,它使用此配置创建一个 UrlMatcher,而不是注入匹配器作为服务。这使得默认路由器不适合处理动态定义的路由。为了处理大量用户创建的路由,此组件包含了 DynamicRouter,它配置了一个 RequestMatcherInterfaceUrlMatcherInterface 服务。实际的匹配逻辑取决于您选择的底层匹配器实现。您可以通过将其传递给 DynamicRouter 构造函数来轻松使用您自己的匹配策略。作为此组件的一部分,已经提供了 NestedMatcher

DynamicRouter 进一步允许使用一组可以轻松配置的 RouteEnhancerInterface 来修改路由匹配的结果参数。

DynamicRouter 也能够从 Route 对象生成 URL。ProviderBasedGenerator 可以生成从 RouteProviderInterface 实例加载的 URL。ContentAwareGenerator 可以从任何实现了 RouteReferrersInterface 的内容对象确定要生成 URL 的 Route,这意味着您可以直接从内容对象生成 URL。

事件

可选地,您可以为动态路由器提供一个 事件调度器。如果您这样做,它将在匹配过程中触发预匹配事件之一,具体取决于使用的方法,并在生成 URL 之前触发另一个事件。

  • cmf_routing.pre_dynamic_match (在 match 方法开始时分发)
  • cmf_routing.pre_dynamic_match_request (在 matchRequest 方法开始时分发。在 Symfony 完整堆栈框架的上下文中,只会触发此事件。)
  • cmf_routing.pre_dynamic_generate (在 generate 方法开始时分发)

预匹配事件的类是 Symfony\Cmf\Component\Routing\Event\RouterMatchEvent,生成事件的类是 Symfony\Cmf\Component\Routing\Event\RouterGenerateEvent。生成事件还允许您通过更新事件中的值来操作事件中的路由名称、参数和引用类型。

Symfony\Cmf\Component\Routing\Event\Events 类包含事件常量。要了解如何注册事件,请参阅核心文档中的 “`How to create an Event Listener`_”。

匹配器

动态路由器需要注入一个 RequestMatcherInterface 或一个 UrlMatcherInterface。此组件使用 NestedMatcher 提供了一个合适的实现。

路由增强器

可选地,并且在匹配过程之后,DynamicRouter 可以应用一组 RouteEnhancerInterface 实例。路由增强器是一种在框架继续之前操作匹配路由中的参数的方法。它们可以用于,例如,动态分配控制器或通过确定参数或将请求参数“向上转型”为它们对应的对象来将逻辑从控制器中分离出来。

该组件已经提供了一些通用增强器。它们都遵循不更改现有字段,而仅在字段尚不存在时才添加字段的原则。

RouteContentEnhancer
如果路由是 RouteObjectInterface 的实例,则此增强器将目标字段设置为 getContent() 的返回值。
FieldMapEnhancer
配置了键值映射。如果匹配的指定字段包含键,则目标字段设置为值。
FieldByClassEnhancer
配置了类名到值的映射。如果指定的字段包含一个对象,该对象是映射中某个类的实例,则将目标字段设置为相应的值。请注意,如果对象是多个类的实例,则采用第一个匹配项。例如,此增强器用于根据 Content 文档的类确定控制器和模板。此增强器类似于 FieldMapEnhancer,但对映射键执行 instanceof 检查而不是字符串比较。
FieldPresenceEnhancer
如果路由匹配中存在某个字段,则在另一个字段尚未设置的情况下,将该字段设置为指定的值。
ContentRepositoryEnhancer
如果源字段存在于路由匹配中,则在目标字段尚未设置的情况下,将目标字段设置为 ContentRepositoryInterface 返回的内容,其值为源字段的值。

您还可以通过创建一个实现 Symfony\Cmf\Component\Routing\Enhancer\RouteEnhancerInterface 的类来创建自己的路由增强器。

路由增强器使用 addRouteEnhancer 方法注册,该方法具有可选的第二个参数来提供优先级。

路由增强器编译器 Pass

此组件提供了一个 RegisterRouteEnhancersPass。如果您使用 Symfony 依赖注入组件,则可以使用此编译器 pass 将所有具有特定标签的增强器注册到动态路由器。

1
2
3
4
5
6
7
8
use Symfony\Cmf\Component\Routing\DependencyInjection\Compiler\RegisterRouterEnhancersPass;
use Symfony\Component\DependencyInjection\ContainerBuilder;

// a ContainerBuilder
$container = ...;

$pass = new RegisterRouterEnhancersPass('cmf_routing.dynamic_router', 'dynamic_router_route_enhancer');
$container->addCompilerPass($pass);

在添加 pass 并配置容器构建器之后,您可以继续按照 Symfony DI 组件编译部分 中所述编译容器。

您可以选择配置动态路由器服务名称。当从容器加载动态路由器时,编译器 pass 将修改此服务定义以注册增强器。如果您未指定任何内容,则默认服务名称为 cmf_routing.dynamic_router

您还可以使用编译器 pass 构造函数的第二个参数配置要使用的标签名称。如果您不这样做,则默认标签是 dynamic_router_route_enhancer。如果您正在使用 Symfony CMF RoutingBundle,则此标签已使用默认名称激活。

将路由与内容链接

根据您的应用程序逻辑,请求的 URL 可能具有关联的内容对象。此类 URL 的路由可以实现 RouteObjectInterface 以在存在时返回内容对象。如果您配置了 RouteContentEnhancer,它会将内容对象插入到 _content 键的匹配数组中。请注意,Route 可能实现 RouteObjectInterface,但在某些情况下仍然不返回任何模型实例。在这种情况下,将不会设置 _content 字段。

此外,实现此接口的路由还可以提供自定义路由名称。getRouteKey 返回的键将用作路由名称,而不是 Symfony 核心兼容的路由名称,并且可以包含任何字符。例如,这允许您将路径设置为路由名称。与 NestedMatcher 一起提供的 UrlMatcher 都将 _route 键替换为路由实例,并将提供的名称放入 _route_name 中。

所有路由仍然需要扩展 Symfony 组件中的基类 Symfony\\Component\\Routing\\Route

重定向

您可以通过实现 RedirectRouteInterface 来创建重定向。它可以重定向到绝对 URI、可以由链中的任何 Router 生成的路由名称或另一个 Route 对象。

请注意,实际的重定向逻辑不是由 bundle 处理的。您应该实现自己的逻辑来处理重定向。有关在完整的 Symfony 堆栈下实现该重定向的示例,请参阅 RoutingBundle

生成 URL

除了将传入的请求匹配到一组参数之外,Router 还负责从路由及其参数生成 URL。ChainRouter 迭代其已知的路由器,直到其中一个能够生成匹配的 URL。

除了 RequestMatcherInterfaceUrlMatcherInterface 将 Request/URL 匹配到其对应的参数之外,DynamicRouter 还使用 UrlGeneratorInterface 实例,这使其可以从路由生成 URL。

生成器方法如下所示:

1
public function generate(string $name, array $parameters = [], int $referenceType = self::ABSOLUTE_PATH);

在 Symfony 核心中,所有路由都通过名称标识。CMF 路由也可以从路由对象生成 URL。由于 $name 必须是字符串,因此必须使用特殊的 cmf_routing_object 名称,并且路由实例在参数中传递,键为 _route_object

ProviderBasedGenerator 扩展了 Symfony 的默认 UrlGenerator (它反过来又实现了 UrlGeneratorInterface),并要求路由提供程序根据名称和参数查找路由。然后,它让核心逻辑从该 Route 生成 URL。

CMF 组件还包括 ContentAwareGenerator,它扩展了 ProviderBasedGenerator,用于检查 _route_object 参数是否是实现 RouteReferrersReadInterface 的对象。如果是,则从该对象获取 Route。使用 ContentAwareGenerator,您可以通过三种方式为内容生成 URL:

  • 或者将 Route 对象作为 _route_object 参数传递
  • 或者将作为内容的 RouteReferrersInterface 对象作为 _route_object 参数传递
  • 或者提供 ContentRepositoryInterface 的实现,并将内容对象的 id 作为参数 content_idcmf_routing_object 作为 $name 传递。

如果您想实现自己的生成器,请实现 VersatileGeneratorInterface,以便在无法生成路由时获得更好的调试消息。

这项工作,包括代码示例,根据 Creative Commons BY-SA 3.0 许可获得许可。
目录
    版本