コンテンツタイプphoto
のすべての画像を表示するビューがあります。このビューのいくつかのフィールドを表示用に設定しました。
これは、画像のリストをiIrenderする方法です。
views-view-fields--photo.html
_<figure class="element-item {{ fields['name'].content|lower }}">
<a href="{{ fields['field_photo_1'].content|lower }}">
<img src="{{ fields['field_photo'].content }}"/>
</a>
<figcaption>
<div class="date">{{ fields['field_date'].content }}</div>
<div class="lieu">{{ fields['field_lieu'].content }}</div>
</figcaption>
</figure>
{{ drupal_block('comment_block') }}
_
Twig Tweak モジュールを使用して、このテンプレートでカスタムブロックをレンダリングします。このブロックは、画像のすべてのコメントをロードする必要があります。そのためには、ノードのnid
をブロックに渡す必要があります。
これがブロックのコードです:
CommentBlock.php
_/**
* Provides a 'CommentBlock' block.
*
* @Block(
* id = "comment_block",
* admin_label = @Translation("Comment block"),
* context = {
* "node" = @ContextDefinition("entity:node", label = @Translation("Node"))
* }
* )
*/
class CommentBlock extends BlockBase implements ContainerFactoryPluginInterface {
/**
* Drupal\Core\Entity\EntityTypeManagerInterface definition.
*
* @var \Drupal\Core\Entity\EntityTypeManagerInterface
*/
protected $entityTypeManager;
/**
* Constructs a new CommentBlock object.
*
* @param array $configuration
* A configuration array containing information about the plugin instance.
* @param string $plugin_id
* The plugin_id for the plugin instance.
* @param string $plugin_definition
* The plugin implementation definition.
*/
public function __construct(array $configuration, $plugin_id, $plugin_definition, EntityTypeManagerInterface $entity_type_manager) {
parent::__construct($configuration, $plugin_id, $plugin_definition);
$this->entityTypeManager = $entity_type_manager;
}
/**
* {@inheritdoc}
*/
public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) {
return new static(
$configuration,
$plugin_id,
$plugin_definition,
$container->get('entity_type.manager')
);
}
/**
* {@inheritdoc}
*/
public function build() {
$build = [];
$node = $this->getContextValue('node');
kint($node->id());
$build['#theme'] = 'comment_ajax';
return $build;
}
}
_
私が試みているのは、ビューの行のコンテキストをブロックに取り込むことです。しかし、私はこのエラーを受け取ります:
_Drupal\Component\Plugin\Exception\ContextException : Required contexts without a value: node
_
何が悪いのですか?
template_preprocess_views_view_fields()
からブロックをロードしてnid
にリンクできますが、コンテキストアノテーションを理解しようとします。
これがビューの写真です。私のカスタムブロックはリンク名「コメント」だけを返します。
前処理で_drupal_block
_を使用する代わりに、プログラムでブロックをロードします。
_$block = \Drupal\block\Entity\Block::load('commentblock');
$variables['test'] = \Drupal::entityTypeManager()
->getViewBuilder('block')
->view($block);
_
次に、このブロックをviews-view-fields.html.twigに出力します。
_{{ fields['title'].content }}
{{ test }}
_
ブロック内のコンテキストをkint
した場合でも、注釈_required = FALSE
_を設定しない限り、エラーが発生します。
_ * context = {
* "node" = @ContextDefinition(
* "entity:node",
* label = @Translation("Current Node"),
* required = FALSE,
* )
* }
_
しかし、コンテキストはまだ空です。
ブロックを配置するとき、ブロックがノード値を取得する場所から選択する必要があります。
ああ!自分の DOの問題 を見つけました。次のように、コンテキストを不要にする必要がある場合もあります。
* context = {
* "node" = @ContextDefinition(
* "entity:node",
* label = @Translation("Current Node"),
* required = FALSE,
* )
* }
そのため、何度も試しても、コンテキストプラグインを使用したブロックのスタンドアロンソリューションが見つかりませんでした。しかし、私は前処理機能を持つ方法を見つけました。
ビューの行からnid
を取得する方法は次のとおりです。
function comment_ajax_preprocess_views_view_fields(&$variables) {
$block_manager = \Drupal::service('plugin.manager.block');
$config = ['nid' => $variables['row']->nid];
$plugin_block = $block_manager->createInstance('comment_block', $config);
$variables['blockComment'] = $plugin_block->build();
}
この前処理関数では、行nid
を取得し、それをブロック構成で使用します。
そして私のカスタムブロックで:
public function build() {
$build = [];
$blockConfig = $this->getConfiguration();
$build['#theme'] = 'comment_ajax';
$build['#nid'] = $blockConfig['nid'];
return $build;
}
ブロック構成からnid
を返します。
それは機能しますが、前処理なしで、コンテキストだけで方法を探していました。
私はまだより良い方法を探しています:)
BlockBase
から継承するブロックプラグインは、コンテキスト値を ContextAwarePluginBase::setContextValue($key, $value)
で直接設定できます。このメソッドをプリプロセス関数で使用して、ルートまたは環境からは利用できないコンテキストを挿入できます。
私の場合、そのコンテキストにgroup
エンティティを必要とするブロックがあります。
_<?php
namespace Drupal\middlebury_course_hub\Plugin\Block;
use Drupal\Core\Access\AccessResult;
use Drupal\Core\Block\BlockBase;
use Drupal\Core\Session\AccountInterface;
/**
* Provides a block with a link to the section's roster.
*
* @Block(
* id = "course_hub_roster_link",
* admin_label = @Translation("Roster Link"),
* category = @Translation("Course Hub"),
* context = {
* "group" = @ContextDefinition(
* "entity:group",
* label = @Translation("Current Group"),
* required = FALSE
* )
* }
* )
*/
class RosterLinkBlock extends BlockBase {
/**
* {@inheritdoc}
*/
protected function blockAccess(AccountInterface $account) {
/** @var \Drupal\group\Entity\GroupInterface $group */
if (($group = $this->getContextValue('group')) && $group->id()) {
if ($group->hasPermission('view group_membership content', $account)) {
return AccessResult::allowed();
}
}
return AccessResult::forbidden();
}
/**
* {@inheritdoc}
*/
public function build() {
// This block varies per group.
$build['#cache']['contexts'] = ['group'];
$build['#theme'] = 'course_hub_roster_link';
/** @var \Drupal\group\Entity\GroupInterface $group */
if (($group = $this->getContextValue('group')) && $group->id()) {
$build['#group'] = $group;
}
// If no group was found, cache the empty result on the route.
return $build;
}
}
_
ビュー結果の行であるグループエンティティごとにこのブロックを表示したいと思いました。モジュールに前処理関数を追加することで、group
コンテキストを挿入できます。
_/**
* Implements hook_preprocess_hook().
*/
function middlebury_course_hub_preprocess_group(&$variables) {
if ($variables['view_mode'] == 'dashboard_item') {
// Add the roster-link block to the build-array.
$block = \Drupal::service('plugin.manager.block')
->createInstance('course_hub_roster_link');
$block->setContextValue('group', $variables['group']);
if ($block->access(\Drupal::currentUser())) {
$variables['content']['roster_link'] = $block->build();
$variables['content']['roster_link']['#weight'] = 2;
}
}
}
_
これと同じ手法は、_hook_preprocess_node
_関数で$block->setContextValue('node', $node);
を使用してノードでも機能するはずです。