web-dev-qa-db-fra.com

Comment obtenir le nœud de contexte dans un bloc personnalisé à l'intérieur d'une liste de vues?

J'ai une vue qui affiche toutes les images du type de contenu photo. J'ai défini certains champs dans cette vue pour l'affichage.

Voici comment iIrender la liste des images:

vues-vues-champs - 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') }}

J'utilise le module Twig Tweak pour rendre un bloc personnalisé dans ce modèle. Ce bloc devrait charger tous les commentaires de l'image. Pour cela, je dois passer le nid du nœud à mon bloc.

Voici le code du bloc:

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;
  }

}

Ce que j'essaie, c'est de placer le contexte de la ligne des vues dans mon bloc. Mais je reçois cette erreur:

Drupal\Component\Plugin\Exception\ContextException : Required contexts without a value: node

Qu'est-ce que je fais mal?

Je peux charger mon bloc depuis template_preprocess_views_view_fields() pour créer un lien avec nid mais j'essaie de comprendre l'annotation du contexte.


Mise à jour

Voici une image de la vue, mon bloc personnalisé ne renvoie qu'un nom de lien "Commentaire".

enter image description here

Je charge maintenant le bloc par programmation au lieu d'utiliser drupal_block Dans le pré-processus.

$block             = \Drupal\block\Entity\Block::load('commentblock');
$variables['test'] = \Drupal::entityTypeManager()
  ->getViewBuilder('block')
  ->view($block);

Ensuite, j'imprime ce bloc dans views-view-fields.html.twig :

{{ fields['title'].content }}
{{ test }}

Si je kint le contexte dans mon bloc, j'obtiens toujours une erreur, sauf si j'ai défini l'annotation required = FALSE.

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

Mais le contexte est toujours vide.

4
Kevin

Lorsque vous placez le bloc, vous devez choisir d'où le bloc obtiendra la valeur du nœud.

Sélectionnez une valeur de nœud

enter image description here

Noeud de l'URL

enter image description here


Ah! J'ai trouvé mon propre problème sur DO . Vous devrez peut-être également supprimer le contexte comme suit:

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

Donc, après de nombreux essais, je n'ai pas trouvé de solution autonome pour mon bloc avec le plugin de contexte. Mais j'ai trouvé un moyen avec une fonction de prétraitement.

Voici comment j'obtiens le nid de ma ligne de vues:

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();
}

Dans cette fonction de prétraitement, j'obtiens la ligne nid et je l'utilise dans la configuration de bloc.

Et dans mon bloc personnalisé:

public function build() {

  $build = [];

  $blockConfig     = $this->getConfiguration();
  $build['#theme'] = 'comment_ajax';
  $build['#nid']   = $blockConfig['nid'];

  return $build;
}

Je récupère le nid de la configuration du bloc.

Cela fonctionne mais je cherchais un moyen sans prétraitement, juste avec le contexte.

Je cherche toujours un meilleur moyen :)

2
Kevin

Les plugins de blocs qui héritent de BlockBase peuvent avoir leurs valeurs de contexte directement définies via ContextAwarePluginBase::setContextValue($key, $value) . Cette méthode peut être utilisée par une fonction de prétraitement pour injecter un contexte qui n'est pas autrement disponible à partir de la route ou de l'environnement.

Dans mon cas, j'ai un bloc qui a besoin d'une entité group dans son contexte:

<?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;
  }

}

Je voulais afficher ce bloc pour chaque entité de groupe qui était une ligne d'un résultat de vue. En ajoutant une fonction de prétraitement à mon module, j'ai pu injecter le contexte 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;
    }
  }
}

Cette même technique devrait également fonctionner pour les nœuds en utilisant $block->setContextValue('node', $node); dans votre fonction hook_preprocess_node.

0
Adam Franco