logo

额外区块类型 (EBT) - 全新的布局构建器体验❗

额外区块类型 (EBT) - 样式化、可定制的区块类型:幻灯片、标签页、卡片、手风琴等更多类型。内置背景、DOM Box、JavaScript 插件的设置。立即体验布局构建的未来。

演示 EBT 模块 下载 EBT 模块

❗额外段落类型 (EPT) - 全新的 Paragraphs 体验

额外段落类型 (EPT) - 类似的基于 Paragraph 的模块集合。

演示 EPT 模块 滚动

滚动

9.6. 带参数的路由

17/10/2025, by Ivan

我们可以在URL中使用参数来定义路由。它们的工作方式与视图中的上下文过滤器相同。例如,我们可以在URL中传递各种实体的ID、文本字符串或由逗号或加号分隔的顺序ID。在本课程中,我们将传递节点的ID,并在内容中显示该节点的标题和正文。

代码示例可以在GitHub上查看:
https://github.com/levmyshkin/drupalbook8

让我们将路由添加到我们的drupalbook.routing.yml模块文件中:

drupalbook.display_node:
  path: '/display-node/{node}'
  defaults:
    _controller: '\Drupal\drupalbook\Controller\DisplayNode::content'
    _title_callback: '\Drupal\drupalbook\Controller\DisplayNode::getTitle'
  requirements:
    _custom_access: '\Drupal\drupalbook\Controller\DisplayNode::access'
  options:
    parameters:
      node:
        type: entity:node

在路径中,我们传递第二个参数{node},在URL中我们将写入常规ID:/display-node/101,但是准备好的节点对象将传递到我们的控制器中。为此,我们在选项中指定参数,指明应该传递什么以及输出是什么。

options:
    parameters:
      node: # 参数的名称,{}之间的内容,可以是node1、node2,如果传递两个不同的参数。
        type: entity: node # 输出的内容,我们可以在控制器内使用该实体的对象。

我还确定了使用_title_callback参数在哪个方法中显示标题。我们将限制匿名用户的文章输出,为此我们使用_custom_access参数,在其中指明在哪个方法中施加各种限制。

现在当我们弄清楚路由的描述后,接下来编写该路由的类。

modules/custom/drupalbook/src/Controller/DisplayNode.php:

<?php
/**
 * @file
 * Contains \Drupal\drupalbook\Controller\DisplayNode.
 */
 
namespace Drupal\drupalbook\Controller;
 
use Drupal\Core\Access\AccessResult;
use Drupal\node\NodeInterface;
 
/**
 * Provides route responses for the DrupalBook module.
 */
class DisplayNode {
 
  /**
   * Returns a simple page.
   *
   * @return array
   *   A simple renderable array.
   */
  public function content(NodeInterface $node) {
    $element = array(
      '#markup' => $node->body->value,
    );
    return $element;
  }
 
  /**
   * Checks access for this controller.
   */
  public function access(NodeInterface $node) {
    $user = \Drupal::currentUser();
    if ($node->getType() == 'article' && !in_array('authenticated', $user->getRoles())) {
      return AccessResult::forbidden();
    }
    return AccessResult::allowed();
  }
 
  /**
   * Returns a page title.
   */
  public function getTitle(NodeInterface $node) {
    return $node->getTitle();
  }
 
}

我为我的路由创建了一个单独的类,以免将所有内容都放在一个控制器类中。让我们来看一下每一行是什么意思。

\drupalbook\Controller;

我们指明了控制器文件所在的位置。

\Core\Access\AccessResult;
use Drupal\node\NodeInterface;

我们包含了AccessResult类文件——我们将使用它来输出403错误,以及NodeInterface——我们将在控制器的参数方法中使用它来获取节点对象。

function content(NodeInterface $node) {
  $element = array(
    '#markup' => $node->body->value,
  );
  return $element;
}

这里,请注意参数,我们获取节点对象,Drupal会自动从URL转换ID并传递给我们,以便我们不需要再次加载节点对象,而是直接使用它。$node->body->value,这是我们从节点中获取字段值的方式,但我们将在下一课中详细处理如何操作对象。最后,我们返回一个带有#markup的数组来输出我们的节点到文本页面。

function access(NodeInterface $node) {
  $user = \Drupal::currentUser();
  if ($node->getType() == 'article' && !in_array('authenticated', $user->getRoles())) {
    return AccessResult::forbidden();
  }
  return AccessResult::allowed();
}

首先,我们使用Drupal的currentUser()方法获取当前用户对象,然后使用该对象获取当前用户的角色。在if检查中,我们检查节点的内容类型和用户角色,匿名用户将收到403错误,如果一切正常,我们继续执行并返回allowed(),也就是简单地批准我们的检查。让我们打开AccessResult类,看看该类还有哪些方法。为此,在PhpStorm中需要按两次shift并输入类名:

Access Result

在这里,你可以找到用于检查权限的以下方法:

neutral
allowed
forbidden
allowedIf
forbiddenIf
allowedIfHasPermission
allowedIfHasPermissions
isAllowed
isForbidden
isNeutral
orIf
andIf

你可以尝试使用allowedIfHasPermission(),例如,为不同角色的路由设置不同的权限。例如,在你的模块中创建一个新的权限,并在控制器中使用它。虽然在yml文件中使用权限会更简单一些。但通过AccessResult类,你可以灵活地描述内容访问的逻辑,例如,“允许12到16点间的授权用户访问内容,拥有高级账户角色的用户可以全天访问。”你可以尝试并实现这种访问权限差异化。

如你所见,Drupal提供了多种方法来实现内容访问控制,这非常方便,因为99%的情况只需使用一种权限就足够了,这对于区分访问权限来说已经足够了。

function getTitle(NodeInterface $node) {
  return $node->getTitle();
}

这里我们只是简单地返回节点的标题,但我们可以扩展回调的功能。例如,像这样:

function getTitle(NodeInterface $node) {
    $user = \Drupal::currentUser();
    if ($node->getType() == 'article' && !in_array('authenticated', $user->getRoles())) {
     return 'Premium content:  ' . $node->getTitle();
   }
   else {
     return 'Free access content:  ' . $node->getTitle();
   }
 
}

或者在标题中显示发布日期:

如你所见,Drupal提供了灵活配置路由和控制器的能力。因此,当客户有关于如何展示材料到网站的想法时,你可以通过Drupal API和一些PHP代码轻松实现。

代码示例可以在GitHub上查看:
https://github.com/levmyshkin/drupalbook8