Quickie 02 : Ajouter une règle d'affichage personnalisée pour les blocs

05 Avril 2021 · 5 Min · 0
Feu tricolore

Dans Drupal, les blocs sont les pierres angulaires de l'affichage des éléments du site. Bien-sûr en fonction des pages on n'affiche pas tous les blocs possible en même temps.
On peut paramétrer certaines règles d'affichage que le core certains modules proposent. Aujourd’hui je vais présenter comment créer des règles personnalisées.

1) Présentation des blocs

Dans un premier temps je vais expliquer le sujet du jour pour ceux ne comprenant pas trop de quoi je parle à cet instant.
Depuis la page "Mise en page des blocs" (/admin/structure/block) d'un site Drupal on peut en fonction des régions déclarées dans le thème ajouter ou supprimer des blocs. Un bloc est une entité Drupal qui a pour but d'afficher une portion du site. Ça peut être des menus, le logo, le contenu principal...

Tous les blocs possèdent une configuration minimale (titre, nom machine,  région d'assignation, un booléen permettant d'afficher le titre ou non) ainsi que la fameuse configuration de visibilité.

2) Configurer la visibilité d'un bloc

Par défaut un bloc est affiché sur toutes les pages du site. On peut spécifier les urls, les types de contenus, les rôles de l'utilisateur courant sur lesquelles ce bloc doit (ou non) s'afficher afin d'avoir une construction de page dynamique. Pour cela on a à disposition des cases à cocher pour paramétrer ces conditions.
 

Capture d'écran de la configuration d'un bloc

Une fois cette configuration sauvegardée, on peut voir le bloc s'afficher ou non grâce aux conditions sélectionnées.
 

3) Créer des conditions de visibilité personnalisées

Les possibilités de configurations de Drupal Core sont assez limitées même si elles couvrent un grand champ de possibilités. Des modules contrib peuvent ajouter de nouveaux éléments, donc si ils peuvent le faire pourquoi pas nous ?

Pour cela il faut déclarer un Plugin de type Condition soit via la commande :

drupal generate:plugin:condition


ou en adaptant le code ci-dessous à votre cas d'utilisation.

<?php

namespace Drupal\mixalis_common\Plugin\Condition;

use Drupal\Core\Condition\ConditionPluginBase;
use Drupal\Core\Datetime\DateFormatter;
use Drupal\Core\Entity\EntityTypeBundleInfoInterface;
use Drupal\Core\Entity\EntityTypeManagerInterface;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;

/**
 * Provides a 'Even day condition' condition to enable a condition based in
 * module selected status.
 *
 * @Condition(
 *   id = "even_day_condition",
 *   label = @Translation("Even day condition"),
 *   context = {
 *     "block" = @ContextDefinition("entity:block", required = TRUE , label =
 *   @Translation("block"))
 *   }
 * )
 *
 */
class EvenDayCondition extends ConditionPluginBase implements ContainerFactoryPluginInterface {

  /**
   * The date formatter service.
   *
   * @var \Drupal\Core\Datetime\DateFormatterInterface
   */
  protected $dateFormatter;


  public function __construct(DateFormatter $dateFormatter, array $configuration, $plugin_id, $plugin_definition) {
    parent::__construct($configuration, $plugin_id, $plugin_definition);
    $this->dateFormatter = $dateFormatter;
  }

  /**
   * {@inheritdoc}
   */
  public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) {
    return new static(
      $container->get('date.formatter'),
      $configuration,
      $plugin_id,
      $plugin_definition
    );
  }

  /**
   * {@inheritdoc}
   */
  public function buildConfigurationForm(array $form, FormStateInterface $form_state) {
    $form['even_day'] = [
      '#type' => 'checkbox',
      '#title' => $this->t('Display when the day number is even.'),
      '#default_value' => $this->configuration['even_day'],
    ];
    return parent::buildConfigurationForm($form, $form_state);
  }

  /**
   * {@inheritdoc}
   */
  public function submitConfigurationForm(array &$form, FormStateInterface $form_state) {
    $this->configuration['even_day'] = $form_state->getValue('even_day');
    parent::submitConfigurationForm($form, $form_state);
  }

  /**
   * {@inheritdoc}
   */
  public function defaultConfiguration() {
    return ['even_day' => 0] + parent::defaultConfiguration();
  }

  /**
   * Evaluates the condition and returns TRUE or FALSE accordingly.
   *
   * @return bool
   *   TRUE if the day number is even.
   */
  public function evaluate() {
    if (empty($this->configuration['even_day']) && !$this->isNegated()) {
      return TRUE;
    }

    $dDay = (int) $this->dateFormatter->format(time(), 'custom', 'j');

    return $this->isNegated() ? $dDay % 2 : !($dDay % 2);
  }

  /**
   * Provides a human readable summary of the condition's configuration.
   */
  public function summary() {
    $status = $this->getContextValue('even_day') ? t('enabled') : t('disabled');

    return t(
      'The block is  @status.',
      ['@status' => $status]);
  }

}

Dans ce cas d'exemple, j'ajoute juste une case à cocher pour afficher ou non le bloc en fonction des jours paires ou impaires. Très peu de chance que ce code vous soit utile dans son intégralité hormis pour des easters eggs à des moments précis de l'année.

Vu que cet article est un quickie je ne vais pas entrer dans les détails mais pour résumer il y a 4 méthodes principales :

  • defaultConfiguration() --> Définit les configurations avec leur valeur par défaut
  • buildConfigurationForm()--> Construction du formulaire de la configuration du plugin.
  • submitConfigurationForm() --> Enregistrement des valeurs de la configuration
  • evaluate() --> Méthode qui portera le code métier du Plugin.

Petite information importante : En étendant la classe ConditionPluginBase on hérite de la configuration 'negate' permettant de faire l'inverse de ce qui est coché. Si on en veut pas on peut toujours supprimer l'entrée $form['negate'] ou construire le formulaire sans appeler le parent::.
 

4) Conclusion

Vous pouvez maintenant créer vos propres conditions d'affichage d'un bloc sous Drupal 8 et Drupal 9. Essayer de prendre le temps de passer par ces conditions plutôt que d'avoir cette logique directement dans les méthodes build() de vos blocs, ou pire, dans les preprocess et templates. Une fois vos plugins de conditions créés, tous vos blocs pourront en bénéficier sans une ligne de code supplémentaire.



0 commentaire

Ajouter un commentaire

Texte brut

  • Aucune balise HTML autorisée.
  • Les lignes et les paragraphes vont à la ligne automatiquement.
  • Les adresses de pages web et les adresses courriel se transforment en liens automatiquement.
CAPTCHA
Cette question sert à vérifier si vous êtes un visiteur humain ou non afin d'éviter les soumissions de pourriel (spam) automatisées.