9.6. パラメーター付きルート。
ルートには URL 内のパラメーターを使えます。それらは Views のコンテキストフィルターとまったく同じように機能します。例えば、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
ここでは path の 2 番目の引数に {node} を渡します。url には通常の ID を書きます:/display-node/101。しかし、私たちのコントローラーには既成のノードオブジェクトが来ます。そのために、options の parameters で、これらのパラメーターに何を渡すべきか、そして出力が何になるかを示します
options:
parameters:
node: # 引数の名前。{} の間にあるもの。2 つの異なる引数を渡す場合は 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();
}
}
すべてを 1 つのコントローラークラスに詰め込まないように、私のルート用に別のクラスを作成しました。これらの各行が何を意味するか見てみましょう。
\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、これがノードからフィールド値を取得する方法ですが、オブジェクトの操作については次のレッスンで Entity API を分析する際に詳しく扱います。そして最後に、ノードをテキストページに出力するために #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 を 2 回押してクラス名を入力します:

ここでは、権限をチェックするための次のメソッドが見つかります:
neutral allowed forbidden allowedIf forbiddenIf allowedIfHasPermission allowedIfHasPermissions isAllowed isForbidden isNeutral orIf andIf
例えば allowedIfHasPermission() で実験して、ルートに異なるロールに異なる権限を設定できます。例えば、モジュールに新しい権限を作成し、それをコントローラーで使います。もちろん、ルートの yml ファイルで権限を使うほうが簡単です。しかし、AccessResult クラスを通じて、コンテンツへのアクセスのロジックを柔軟に記述できます。例えば「コンテンツへのアクセスは 12 時から 16 時までの認証済みユーザーに許可され、premium アカウントロールを持つユーザーには 24 時間許可される」など。実験して、記事ノードへのアクセス権のこの区別を実装してみてください。
ご覧のとおり、Drupal はコンテンツへのアクセスを実装するいくつかの方法を提供します。これは便利です。というのも、99% のケースでは 1 つの権限を使い、これでアクセス権を区別するのに十分だからです。
function getTitle(NodeInterface $node) {
return $node->getTitle();
}
ここでは単にノードの名前を title として返しますが、私たちのコールバックの機能を拡張できます。例えば、次のように:
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();
}
}
あるいは、title に公開日を表示します:
ご覧のとおり、Drupal はルートとコントローラーを柔軟に構成する機能を提供します。ですから、クライアントがサイトへの素材の出力についてアイデアを持っているとき、Drupal API と少しの PHP コードを使っていつでも実現できます。
コード例は github で見られます:
https://github.com/levmyshkin/drupalbook8