現在のノードのIDを表示するだけの非常に基本的なブロックです。
<?php
/**
* @file
* Contains \Drupal\mymodule\Plugin\Block\ExampleEmptyBlock.
*/
namespace Drupal\mymodule\Plugin\Block;
use Drupal\Core\Block\BlockBase;
use Drupal\Core\Cache\Cache;
/**
* @Block(
* id = "example_empty",
* admin_label = @Translation("Example: empty block")
* )
*/
class ExampleEmptyBlock extends BlockBase {
/**
* {@inheritdoc}
*/
public function build() {
$node = \Drupal::routeMatch()->getParameter('node');
$build = array();
if ($node) {
$config = \Drupal::config('system.site');
$build = array(
'#type' => 'markup',
'#markup' => '<p>' . $node->id() . '<p>',
'#cache' => array(
'tags' => $this->getCacheTags(),
'contexts' => $this->getCacheContexts(),
),
);
}
return $build;
}
/**
* {@inheritdoc}
*/
public function getCacheTags() {
$node = \Drupal::routeMatch()->getParameter('node');
return Cache::mergeTags(parent::getCacheTags(), ["node:{$node->id()}"]);
}
/**
* {@inheritdoc}
*/
public function getCacheContexts() {
return Cache::mergeContexts(parent::getCacheContexts(), ['user.node_grants:view']);
}
}
しかし、一度キャッシュされると、どのノードにアクセスしてもブロックは同じままです。ノードIDごとに結果を正しくキャッシュするにはどうすればよいでしょうか?
これはコメント付きの完全な動作コードである。
namespace Drupal\module_name\Plugin\Block;
use Drupal\Core\Block\BlockBase;
use Drupal\Core\Cache\Cache;
/**
* Provides a Node cached block that display node's ID.
*
* @Block(
* id = "node_cached_block",
* admin_label = @Translation("Node Cached")
* )
*/
class NodeCachedBlock extends BlockBase {
public function build() {
$build = array();
//if node is found from routeMatch create a markup with node ID's.
if ($node = \Drupal::routeMatch()->getParameter('node')) {
$build['node_id'] = array(
'#markup' => '<p>' . $node->id() . '<p>',
);
}
return $build;
}
public function getCacheTags() {
//With this when your node change your block will rebuild
if ($node = \Drupal::routeMatch()->getParameter('node')) {
//if there is node add its cachetag
return Cache::mergeTags(parent::getCacheTags(), array('node:' . $node->id()));
} else {
//Return default tags instead.
return parent::getCacheTags();
}
}
public function getCacheContexts() {
//if you depends on \Drupal::routeMatch()
//you must set context of this block with 'route' context tag.
//Every new route this block will rebuild
return Cache::mergeContexts(parent::getCacheContexts(), array('route'));
}
}
テストしました。
コードをモジュールフォルダ内のNodeCachedBlock.phpという名前のファイルに置き、名前空間{module_name}を変更し、キャッシュをクリアして使用するだけです。
ブロックプラグインのクラスをDrupalCoreBlockBlockBase
から派生させると、キャッシュタグとコンテキストを設定する2つのメソッドができる。
例えば、Bookモジュールブロックはこれらのメソッドを以下のように実装する。
/**
* {@inheritdoc}
*/
public function getCacheContexts() {
return Cache::mergeContexts(parent::getCacheContexts(), ['route.book_navigation']);
}
Forumモジュール・ブロックは以下のコードを使います。
/**
* {@inheritdoc}
*/
public function getCacheContexts() {
return Cache::mergeContexts(parent::getCacheContexts(), ['user.node_grants:view']);
}
/**
* {@inheritdoc}
*/
public function getCacheTags() {
return Cache::mergeTags(parent::getCacheTags(), ['node_list']);
}
あなたの場合、次のコードを使います。
/**
* {@inheritdoc}
*/
public function getCacheTags() {
$node = \Drupal::routeMatch()->getParameter('node');
return Cache::mergeTags(parent::getCacheTags(), ["node:{$node->id()}"]);
}
また、ブロックを全くキャッシュ不可能にするために、次の方法を使うこともできます(私はそれを避けるとしても)。他のケースでも役に立つかもしれません。
/**
* {@inheritdoc}
*/
public function getCacheMaxAge() {
return 0;
}
Cacheクラスを使う場合は、
use DrupalCoreCache;`をファイルの先頭に追加することを忘れないでください。
ノードから自動的に#cache
を追加したい場合:
use Drupal\Core\Cache\Cache;
$build = array(
...
'#cache' => array(
'tags' => Cache::mergeTags($this->getCacheTags(), $node->getCacheTags()),
'contexts' => $node->getCacheContexts(),
'max-age' => $node->getCacheMaxAge(),
),
);
ここではコンテキストが重要です。
コンテキストを手動で設定するには
$build = array(
...
'#cache' => array(
'contexts' => array('url.path'),
),
);