Drupal 8 - InternalLinkListBuilder

EntityListBuilder, ou l'art d'afficher sa liste d'entité

Pour cet article de la série sur la Création d'un module avec Drupal 8, nous allons nous pencher sur la classe InternalLinkListBuilder.

Annotation

La classe InternalLinkListBuilder hérite de la classe EntityListBuilder, elle même héritant de EntityHandlerBase. L'association entre notre classe et l'entité InternalLink se situe au niveau de l'annotation d'entité:

/**
 * Defines the Internal link entity.
 *
 * @ingroup internal_link
 *
 * @ContentEntityType(
 *   id = "internal_link",
 *   label = @Translation("Internal link"),
 *   handlers = {
 *     "view_builder" = "Drupal\Core\Entity\EntityViewBuilder",
 *     "list_builder" = "Drupal\internal_link\InternalLinkListBuilder",
 *     "views_data" = "Drupal\internal_link\Entity\InternalLinkViewsData",
 *   ...
 */

Comme nous le voyons dans la liste des gestionnaires, il en y en a un nommé "list_builder" qui référence notre classe InternalLinkListBuilder.

But de la classe InternalLinkListBuilder

Cette classe nous permet de personnaliser la page de listing des entités, qu'on retrouve à l'url /admin/structure/internal_link. Par défaut, cette liste n'affiche que le strict minimum: l'identifiant et le nom de l'entité. Mais dès lors que notre entité possède de multiples champs, nous voudrions peut-être lister certains champs utiles à la compréhension de l'entité. Dans les cas des entités internal_link, une idée intéressante serait de lister les éléments suivants:

  • Le mot
  • Le mode
  • La sensibilité à la casse
  • Le type d'url
  • Le lien final
  • L'auteur
  • Le statut
  • Le poids

Notre implémentation

Pour afficher ces éléments, nous allons modifier la classe InternalLinkListBuilder pour que le code corresponde au suivant:

/**
 * @file
 * Contains \Drupal\internal_link\InternalLinkListBuilder.
 */
 
namespace Drupal\internal_link;
 
use Drupal\Core\Entity\EntityInterface;
use Drupal\Core\Entity\EntityListBuilder;
use Drupal\Core\Language\LanguageInterface;
use Drupal\Core\Routing\LinkGeneratorTrait;
use Drupal\Core\Url;
 
/**
 * Defines a class to build a listing of Internal link entities.
 *
 * @ingroup internal_link
 */
class InternalLinkListBuilder extends EntityListBuilder {
  use LinkGeneratorTrait;
 
  /**
   * Loads entity IDs using a pager sorted by the entity id.
   *
   * @return array
   *   An array of entity IDs.
   */
  protected function getEntityIds() {
    $query = $this->getStorage()->getQuery()
    //->sort($this->entityType->getKey('id'));
    ->sort('weight', 'ASC');
 
    // Only add the pager if a limit is specified.
    if ($this->limit) {
      $query->pager($this->limit);
    }
    return $query->execute();
  }
 
 
  /**
   * {@inheritdoc}
   */
  public function buildHeader() {
    $header['id'] = $this->t('ID');
    $header['word'] = $this->t('Word');
    $header['mode'] = [
      'data' => $this->t('Mode'),
      'class' => [RESPONSIVE_PRIORITY_MEDIUM],
    ];
    $header['case_sensitive'] = [
      'data' => $this->t('Case sensitive'),
      'class' => [RESPONSIVE_PRIORITY_LOW],
    ];
    $header['url_type'] = [
      'data' => $this->t('Url type'),
      'class' => [RESPONSIVE_PRIORITY_LOW],
    ];
    $header['url'] = $this->t('Url');
    $header['author'] = [
      'data' => $this->t('Author'),
      'class' => [RESPONSIVE_PRIORITY_LOW],
    ];
    $header['status'] = $this->t('Status');
    $header['weight'] = [
      'data' => $this->t('Weight'),
      'class' => [RESPONSIVE_PRIORITY_MEDIUM],
    ];
 
    return $header + parent::buildHeader();
  }
 
  /**
   * 
   * {@inheritDoc}
   * @see \Drupal\Core\Entity\EntityListBuilder::buildRow()
   */
  public function buildRow(EntityInterface $entity) {
    /* @var $entity \Drupal\internal_link\Entity\InternalLink */
 
    $translation = $entity;
    if ($entity->isTranslatable()) {
      $current_language_type = LanguageInterface::TYPE_INTERFACE;
      $langcode = \Drupal::service('language_manager')->getCurrentLanguage($current_language_type)->getId();
      if ($entity->hasTranslation($langcode)) {
        $translation = $entity->getTranslation($langcode);
      }
    }
 
    $uri = $entity->toUrl();
 
    $row['id'] = $translation->id();
    $row['word']['data'] = [
      '#type' => 'link',
      '#title' => $translation->label(),
      '#url' => $uri,
    ];
    $row['mode'] = $translation->getModeLabel($entity->getMode());
    $row['case_sensitive'] = $translation->getCaseSensitive() ? $this->t('Yes') : $this->t('No');
    $row['url_type'] = $translation->getUrlTypeLabel($translation->getUrlType());
    $row['url'] = $translation->getUrlData($translation->label(), TRUE);
    $row['author']['data'] = [
      '#theme' => 'username',
      '#account' => $translation->getOwner(),
    ];
    $row['status'] = $translation->isPublished() ? $this->t('published') : $this->t('not published');
    $row['weight'] = $translation->getWeight();
    return $row + parent::buildRow($translation);
  }
}

Nous avons surdéfini la méthode getEntityIds afin de proposer un tri par poids plutôt que par identifiant, comme l'exécutait la classe parent EntityListBuilder.

Nous avons ensuite rajouté les en-têtes nécessaires dans la fonction buildHeader, puis les valeurs correspondantes dans la fonction buildRow.

Conclusion

Rien de sorcier. Notez simplement les éléments suivants concernant les en-têtes:

  1. chaque élément d'en-tête doit posséder un élément de donnée;
  2. certains éléments sont sous une forme plus complexe que d'autres. Cette forme permet d'intégrer l'attribut "class" ou d'autres attributs qui pourraient être utiles;
  3. les classes passées aux en-têtes complexes commencent par RESPONSIVE_PRIORITY_. Ces classes indiquent que les colonnes correspondantes ont une priorité moyenne (MEDIUM) ou faible (LOW) lors de l'affichage du tableau. A plus la fenêtre navigateur est petite, à plus le système masquera de colonnes dont la priorité est spécifiée de cette manière;

et les éléments suivants concernant les données:

  1. word est affiché sous forme de lien;
  2. url fait appel à la méthode getUrlData de l'entité, en lui passant l'argument $list_builder à TRUE, afin de récupérer des informations supplémentaires dans le titre de lien;
  3. author utilise la fonction de #theme "username" pour associer le nom de l'auteur à un lien direct vers son profil;

Nous avons maintenant un nouveau type d'entité internal_link qui est pleinement fonctionnel. Nous pouvons créer, éditer et supprimer des liens internes via la partie administrative. Nous pouvons également gérer les affichages (formulaire et visuels) de nos entités en passant par l'url /admin/config/search/internal_link/settings. Cette page permet la gestion du type d'entité, et c'est à ce niveau que nous continuerons dans notre prochain article.

Ajouter un commentaire

CAPTCHA
Cette question permet de savoir si vous êtes un visiteur ou un robot de soumission de spams