web-dev-qa-db-ja.com

ビューリスト内のカスタムブロックのコンテキストノードを取得する方法

コンテンツタイプ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にリンクできますが、コンテキストアノテーションを理解しようとします。


更新

これがビューの写真です。私のカスタムブロックはリンク名「コメント」だけを返します。

enter image description here

前処理で_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,
 *     )
 *   }
_

しかし、コンテキストはまだ空です。

4
Kevin

ブロックを配置するとき、ブロックがノード値を取得する場所から選択する必要があります。

ノード値を選択

enter image description here

URLからのノード

enter image description here


ああ!自分の DOの問題 を見つけました。次のように、コンテキストを不要にする必要がある場合もあります。

 *   context = {
 *     "node" = @ContextDefinition(
 *       "entity:node",
 *       label = @Translation("Current Node"),
 *       required = FALSE,
 *     )
 *   }
4
leymannx

そのため、何度も試しても、コンテキストプラグインを使用したブロックのスタンドアロンソリューションが見つかりませんでした。しかし、私は前処理機能を持つ方法を見つけました。

ビューの行から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を返します。

それは機能しますが、前処理なしで、コンテキストだけで方法を探していました。

私はまだより良い方法を探しています:)

2
Kevin

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);を使用してノードでも機能するはずです。

0
Adam Franco