Drupal 10:如何从路由向节点及区块传递参数?
解决方案
1. 扩展NodeRouteProvider解决多语言URL管理问题
不用手动维护固定路径的路由,通过扩展核心NodeRouteProvider为节点添加带arg参数的动态路由,自动复用核心的多语言、URL别名解析逻辑,彻底解决多语言环境下的URL管理复杂度问题。
实现步骤:
- 在自定义模块(如
example_module)中创建路由提供者类src/Routing/ExampleNodeRouteProvider.php:
<?php namespace Drupal\example_module\Routing; use Drupal\Core\Entity\EntityTypeInterface; use Drupal\node\Routing\NodeRouteProvider; use Symfony\Component\Routing\Route; class ExampleNodeRouteProvider extends NodeRouteProvider { public function getRoutes(EntityTypeInterface $entity_type) { $collection = parent::getRoutes($entity_type); // 为节点追加带arg参数的路由 if ($route = $this->buildNodeWithArgRoute($entity_type)) { $collection->add('node.view_with_arg', $route); } return $collection; } /** * 构建带arg参数的节点路由 */ protected function buildNodeWithArgRoute(EntityTypeInterface $entity_type) { $route = new Route( '/node/{node}/{arg}', [ '_entity_view' => 'node.full', '_title_callback' => '\Drupal\node\Controller\NodeViewController::title', ], [ '_permission' => 'access content', 'arg' => '[0-9]{2}-[0-9]{2}', ], [ 'parameters' => [ 'node' => ['type' => 'entity:node'], 'arg' => ['type' => 'string'], ], '_node_operation_route' => TRUE, ] ); // 启用核心多语言路径处理 $route->setOption('parameters', [ 'node' => [ 'type' => 'entity:node', 'load_latest_revision' => FALSE, ], ]); return $route; } }
- 在模块的
example_module.module中替换节点的路由提供者:
<?php /** * Implements hook_entity_type_build(). */ function example_module_entity_type_build(array &$entity_types) { if (isset($entity_types['node'])) { $entity_types['node']->setHandlerClass('route_provider', \Drupal\example_module\Routing\ExampleNodeRouteProvider::class); } }
这样配置后,核心会自动处理URL别名映射(比如你的节点别名为example,/example/03-09会被正确解析),多语言环境下的别名也会自动生效,无需手动维护多套路径。
2. 修复节点标题重复问题
你之前的路由中硬写了_title: "Example",同时NodeViewController会自动从节点实体读取标题,导致重复显示。解决方法如下:
- 移除路由中硬写的
_title配置,改用_title_callback关联核心的节点标题回调(如上面自定义路由中使用的\Drupal\node\Controller\NodeViewController::title),让标题直接读取节点实体的标题值。 - 如果需要自定义标题,可编写专属回调函数,例如:
/** * 自定义节点标题回调 */ function example_module_custom_node_title(\Drupal\node\NodeInterface $node) { return $node->getTitle(); }
然后在路由中替换为_title_callback: '\Drupal\example_module\example_module_custom_node_title'。
3. 区块中获取arg参数
在自定义区块的build()方法中,通过路由匹配器直接获取参数:
public function build() { $arg = \Drupal::routeMatch()->getParameter('arg'); // 基于arg生成动态区块内容 return [ '#markup' => '<p>当前参数:' . $arg . '</p>', '#cache' => [ 'contexts' => ['route'], ], ]; }
额外优化:限制路由仅针对特定节点
如果只需要给nid为51079的节点启用该路由,可添加自定义访问控制:
- 创建访问检查类
src/Access/ExampleNodeAccessCheck.php:
<?php namespace Drupal\example_module\Access; use Drupal\Core\Access\AccessResult; use Drupal\Core\Routing\Access\AccessInterface; use Drupal\node\NodeInterface; class ExampleNodeAccessCheck implements AccessInterface { public function access(NodeInterface $node) { // 仅允许nid为51079的节点使用该路由 return AccessResult::allowedIf($node->id() == 51079)->addCacheableDependency($node); } }
- 在
example_module.services.yml中注册服务:
services: example_module.node_access_check: class: Drupal\example_module\Access\ExampleNodeAccessCheck tags: - { name: access_check, applies_to: _custom_access }
- 在路由的
requirements中添加_custom_access: '\Drupal\example_module\Access\ExampleNodeAccessCheck::access'即可。
内容的提问来源于stack exchange,提问作者user15739925
相关产品推荐
相关产品推荐

