You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.19 13:22:17