Snippets

Les snippets sont des bout de code.

Présenté ici de manière volontairement « brute », ces snippets ont vocation à servir d'aide mémoire.

N'hésitez-pas à poser un commentaire si vous rencontrez un problème avec un des éléments.

Vous pouvez utiliser la navigation via les tags présents sur la droite

  • Drupal 8 - Créer une page d'administration « overview » avec tous les sous-menus

    Posté le Mercredi 18 septembre 2019 - 12:22

    Sur un site drupal 8, j'ai pour habitude de créer un élément de menu spécifique dans la barre d'administration qui comprend toutes les parties un peu métier du site.

    La plupart du temps cette route renvoie vers une méthode « dashboard » d'un AdminController qui au mieux affiche quelques informations.

    Voici comment transformer cette route, en listes des sous-menus, à la manière de la page « Configuration ».

    Dans mon_module.routing.yml :

    1. mon_module.admin.dashboard:
    2.   path: '/admin/mon_module/dashboard'
    3.   defaults:
    4.   _controller: '\Drupal\system\Controller\SystemController::overview'
    5.   link_id: 'mon_module.admin.dashboard'
    6.   _title: 'dashboard'
    7.   requirements:
    8.   _permission: 'access mon_module dashboard'

    et voila le résultat :

    Dashboard Overview

    Pour information, voici comment ajouter cette route à la barre d'administration (dans mon cas en première place) :

    dans le fichier mon_module.links.menu.yml :

    1. mon_module.admin.dashboard:
    2.   title: 'Mon Module'
    3.   route_name: mon_module.admin.dashboard
    4.   description: 'Mon Module dashboard'
    5.   parent: system.admin
    6.   weight: -20

     

  • Drupal 8 et composer, résoudre le problème « Package type "drupal-console-library" is not supported »

    Posté le Mercredi 4 septembre 2019 - 10:22
    Dernière mise à jour le Jeudi 5 septembre 2019 - 18:16

    Sur des projets j'ai depuis quelques jours, lors d'un composer install, l'erreur suivante arrive :

    Package type "drupal-console-library" is not supported

    Pas encore eu le temps de creuser la cause, mais une solution que j'ai trouvé est d'ajouter la gestion des « drupal-console-library » dans la section installer-paths de mon fichier composer.json en ajoutant la ligne suivante :

    1. "vendor/drupal/{$name}": ["type:drupal-console-library"],

    Voici la section en entier :

    1. "installer-paths": {
    2. "web/core": ["type:drupal-core"],
    3. "vendor/drupal/{$name}": ["type:drupal-console-library"],
    4. "web/libraries/{$name}": ["type:drupal-library"],
    5. "web/modules/_contrib/{$name}": ["type:drupal-module"],
    6. "web/profiles/_contrib/{$name}": ["type:drupal-profile"],
    7. "web/themes/_contrib/{$name}": ["type:drupal-theme"],
    8. "drush/_contrib/{$name}": ["type:drupal-drush"]
    9. }

    Si quelqu'un a une idée de la raison, je suis preneur !

    Quelques compléments sur le dossier console : https://drupal.stackexchange.com/questions/228781/using-drupal-console-…

  • Drupal 8 - Rediriger sur le listing des noeuds après la création d'un contenu

    Posté le Lundi 29 juillet 2019 - 18:26

    Sur une commande expresse de Vincent, voici comment modifier les formulaires de création / modification de nœud pour être redirigé sur la page de listing des nœuds plutôt que sur le nœud en lui même lors de la création ou de la modification d'un contenu.

    1 - Altération du type d'entité

    1. # mon_module.module
    2. function mon_module_entity_type_alter(array &$entity_types) {
    3. $entity_types['node']->setFormClass('default', Drupal\mon_module\Entity\Form\CustomNodeForm::class);
    4. $entity_types['node']->setFormClass('edit', Drupal\mon_module\Entity\Form\CustomNodeForm::class);
    5. }

    2 - Classe du formulaire

    1. # web/modules/mon_module/src/Entity/Form/CustomNodeForm.php
    2. <?php
    3.  
    4. namespace Drupal\mon_module\Entity\Form;
    5.  
    6. use Drupal\Core\Form\FormStateInterface;
    7. use Drupal\node\NodeForm;
    8.  
    9. class CustomNodeForm extends NodeForm {
    10.  
    11. public function save(array $form, FormStateInterface $form_state) {
    12. parent::save($form, $form_state);
    13. $form_state->setRedirect('view.content.page_1');
    14. }
    15.  
    16. }

     

  • Drupal 8 - ajouter du css ou du javascript à un module

    Posté le Lundi 15 juillet 2019 - 12:21
    Dernière mise à jour le Lundi 29 juillet 2019 - 15:11

    Voici comment attacher une librairie javascript ou un fichier css à un module custom dans drupal 8.

    Dans les extraits de code ci-dessous, le nom machine du module sera « shoutbox ».

    Déclaration de la librairie

    1. #shoutbox.libraries.yml
    2.  
    3. # nom de la librairie
    4. shoutbox :
    5.   js:
    6. # chemin vers le fichier relatif au module
    7.   js/shoutbox.js: {}
    8.   css:
    9.   theme :
    10. # chemin vers le fichier relatif au module
    11.   css/administration.css : {}

    Voici comment attacher cette librairies dans un bloc, un preprocess de template ou un controller

    1. // suivant l'endroit ooù l'on attache la librairie, cela peut être $build, $variables...
    2. // la partie avant le slash définie le nom du module qui défini la librairie
    3. // la partie après le slash est le nom de la librairie choisie dans le fichier shoutbox.libraries.yml
    4.  
    5. $variables['#attached']['library'][] = 'shoutbox/shoutbox';

     

  • Drupal 8 - Surcharger la classe de contrôle d'accès d'un type d'entité

    Posté le Jeudi 11 juillet 2019 - 16:04
    Dernière mise à jour le Lundi 29 juillet 2019 - 15:23

    Sous drupal 8, les types d'entités, comme les noeuds, viennent avec leur classe pour gérer le contrôle d'accès (création / modification / visualisation / suppression).

    Il est possible de surcharger ces classes pour personnaliser plus finement ce contrôle.

    Nous allons ici surcharger le contrôle d'accès pour un type d'entité « shoutbox », mais c'est le même principe pour les nodes.

    1. # mon_module.module
    2. function mon_module_entity_type_alter(array &$entity_types) {
    3. $entity_types['shoutbox']->setHandlerClass('access', \Drupal\mon_module\Entity\AccessControlHandler\CustomShoutboxAccessControlHandler::class);
    4. // Note : si on avait voulu surcharger le controle d'accès aux noeuds :
    5. // $entity_types['node']->setHandlerClass('access', \Drupal\mon_module\Entity\AccessControlHandler\CustomNodeAccessControlHandler::class);
    6. }

    La classe en elle même, qui étant la classe de contrôle d'accès de base (définie dans l'annotation de notre type d'entité)

    1. # mon_module/src/Entity/AccessControlHandler/CustomShoutboxAccessControlHandler.php
    2. <?php
    3.  
    4. namespace Drupal\mon_module\Entity\AccessControlHandler;
    5.  
    6. use Drupal\Core\Access\AccessResult;
    7. use Drupal\Core\Entity\EntityInterface;
    8. use Drupal\Core\Session\AccountInterface;
    9. use Drupal\shoutbox\Entity\AccessControlHandler\ShoutboxAccessControlHandler;
    10. use Drupal\shoutbox\Entity\Shoutbox;
    11. use Drupal\user\Entity\User;
    12.  
    13. class CustomShoutboxAccessControlHandler extends ShoutboxAccessControlHandler {
    14.  
    15. protected function checkAccess(EntityInterface $entity, $operation, AccountInterface $account) {
    16. /** @var Shoutbox $entity */
    17. if($operation === 'view' && $this->testPerso()) {
    18. if (!$entity->isPublished()) {
    19. return AccessResult::allowedIfHasPermission($account, 'administer shoutbox');
    20. }
    21. if ($this->autreTest()) {
    22. return AccessResult::allowed();
    23. }
    24. return AccessResult::forbidden('Shoutbox privée');
    25. }
    26. return parent::checkAccess($entity, $operation, $account);
    27. }
    28.  
    29. }

    Ici je ne fais un contrôle d'accès que sur l'opération « view » pour la visualisation, je délègue tout le reste à la classe mère.

  • Github - transformer une pull request en patch

    Posté le Lundi 8 juillet 2019 - 12:00

    Petite astuce que beaucoup doivent déjà connaître mais que j'ai (re)découverte, il est très facile de transformer une pull request de github en patch.

    Il suffit de prendre l'url de la PR et d'ajouter .patch à la fin.

    Exemple, pour avoir le patch de https://github.com/hechoendrupal/drupal-console/pull/4013 : https://github.com/hechoendrupal/drupal-console/pull/4013.patch

    Et ce patch peut ensuite être utilisé manuellement ou dans notre fichier composer.json.

  • Drupal 8 - Utiliser les redirections de Redirect sur une page dépubliée

    Posté le Lundi 8 juillet 2019 - 08:52
    Dernière mise à jour le Lundi 29 juillet 2019 - 15:43

    Dans le cas d'une page dé-publiée, si en tant qu'anonyme on tombe sur une erreur 403. On peut vouloir rediriger cette page temporairement vers une autre via le module redirect, mais nativement ça n'est pas pris en compte.

    Voici un petit EventSubscriber qui répond sur les erreurs 403, qui teste si une redirection existe pour le nœud courant, et dans ce cas redirige l'utilisateur.

    Note : Un administrateur ayant la permission pour voir le contenu dé-publié ne sera pas redirigé, car aucune erreur 403 ne sera lancée et donc l'event subscriber ne sera pas appelé.

    Note 2 : C'est un bout de code qui semble fonctionnel, fonctionne avec le multilingue mais qui est certainement perfectible. N'hésitez-pas à me faire vos remarques.

    1 - Déclaration de l'event subscriber :

    1. #mon_module.services.yml
    2.  
    3.   mon_module.redirector:
    4.   class: Drupal\mon_module\EventSubscriber\Redirector
    5.   tags:
    6.   - { name: event_subscriber }

    2 - Définition de l'event subscriber 

    1. # web/modules/custom/mon_module/src/EventSubscriber/Redirector.php
    2. <?php
    3.  
    4. namespace Drupal\mon_module\EventSubscriber;
    5.  
    6. use Drupal\Core\EventSubscriber\HttpExceptionSubscriberBase;
    7. use Drupal\redirect\RedirectRepository;
    8. use Drupal\node\Entity\Node;
    9. use Symfony\Component\HttpKernel\Event\GetResponseForExceptionEvent;
    10. use Symfony\Component\HttpFoundation\RedirectResponse;
    11.  
    12. class Redirector extends HttpExceptionSubscriberBase {
    13.  
    14. /**
    15.   * {@inheritdoc}
    16.   */
    17. protected function getHandledFormats() {
    18. return ['html'];
    19. }
    20.  
    21. public function on403(GetResponseForExceptionEvent $event) {
    22. if ($event->getRequest()->attributes->get('node') !== NULL) {
    23. $nid = \Drupal::routeMatch()->getRawParameter('node');
    24. $langcode = \Drupal::languageManager()->getCurrentLanguage()->getId();
    25. /** @var RedirectRepository $redirectRepository */
    26. $redirectRepository = \Drupal::service('redirect.repository');
    27. $node = Node::load($nid);
    28. if ($node !== NULL && $node->hasTranslation($langcode) && $translation = $node->getTranslation($langcode)) {
    29. if (!$translation->isPublished()) {
    30. $alias = \Drupal::service('path.alias_manager')->getAliasByPath('/node/' . $nid);
    31. $redirection = $redirectRepository->findMatchingRedirect($alias, [], $langcode);
    32. if($redirection) {
    33. $event->setResponse(new RedirectResponse($redirection->getRedirectUrl()->toString(), $redirection->getStatusCode()));
    34. }
    35. }
    36. }
    37. }
    38. }
    39.  
    40. }

     

  • Drupal 8 - Surcharger la classe de formulaire d'un terme de taxonomie

    Posté le Vendredi 5 juillet 2019 - 10:22

    Hier, nous avons vu comment surcharger le formulaire de création / modification d'un nœud, voici aujourd'hui comment faire la même chose mais pour un terme de taxonomie.

    Cela se passe encore en deux étapes.

    1 - Altération du type d'entité

    1. # mon_module.module
    2. function mon_module_entity_type_alter(array &$entity_types) {
    3. $entity_types['taxonomy_term']->setFormClass('default', Drupal\mon_module\Entity\Form\CustomTermForm::class);
    4. }

    2 - Classe du formulaire

    1. # web/modules/mon_module/src/Entity/Form/CustomTermForm.php
    2. <?php
    3.  
    4. namespace Drupal\mon_module\Entity\Form;
    5.  
    6. use Drupal\Core\Form\FormStateInterface;
    7. use Drupal\taxonomy\TermForm;
    8.  
    9. class CustomTermForm extends TermForm {
    10. public function form(array $form, FormStateInterface $form_state) {
    11. $form = parent::form($form, $form_state);
    12. /** @var \Drupal\taxonomy\Entity\Term $term */
    13. $term = $this->entity;
    14. if($term->getVocabularyId() === 'mon_vocabulaire') {
    15. // À vous de jouer
    16. }
    17. return $form;
    18. }
    19.  
    20. }

     

  • Drupal 8 - Surcharger la classe de formulaire d'un nœud

    Posté le Jeudi 4 juillet 2019 - 10:17
    Dernière mise à jour le Jeudi 4 juillet 2019 - 11:36

    Pour modifier le formulaire de création d'un nœud sous drupal 8, on peut utiliser le bon vieux HOOK_form_alter(), mais on peut aussi faire quelque chose de plus « propre » en altérant le type d'entité pour redéfinir son formulaire.

    Cela se passe en deux étapes.

    1 - Altération du type d'entité

    1. # mon_module.module
    2. function mon_module_entity_type_alter(array &$entity_types) {
    3. $entity_types['node']->setFormClass('default', \Drupal\mon_module\Entity\Form\NodeCustomForm::class);
    4. $entity_types['node']->setFormClass('edit', \Drupal\mon_module\Entity\Form\NodeCustomForm::class);
    5. }

    2 - Classe du formulaire

    1. # web/modules/mon_module/src/Entity/Form/NodeCustomForm.php
    2. <?php
    3.  
    4. namespace Drupal\mon_module\Entity\Form;
    5.  
    6. use Drupal\Core\Form\FormStateInterface;
    7. use Drupal\node\NodeForm;
    8.  
    9. class NodeCustomForm extends NodeForm {
    10.  
    11. public function form(array $form, FormStateInterface $form_state) {
    12. $form = parent::form($form, $form_state);
    13. // Faite votre magie ici
    14. /** @var \Drupal\node\Entity\Node $node */
    15. $node = $this->entity;
    16. return $form;
    17. }
    18.  
    19. }

    Cette classe étant la classe normale, nous avons donc juste à appliquer nos modifications à l'intérieur.

    Le problème de cette solution : on ne peut pas avoir deux modules qui surchargent la classe, à moins d'étendre la première dans la seconde.

  • Drupal 8 - rendre un formulaire dans un template

    Posté le Mercredi 5 juin 2019 - 09:36
    Dernière mise à jour le Mercredi 5 juin 2019 - 10:48

    La form api de drupal est très puissante, mais pour jouer avec le markup html avec les #prefix et #suffix peut s'avérer rapidement complexe en plus d'être un peu sale au niveau du code.

    Dans drupal 8 il est possible de facilement utiliser un template pour un formulaire. Pour cela il faut se baser sur le nom machine du formulaire.

    Cela fonctionne pour nos formulaires custom, mais aussi pour les formulaires des modules tiers ou du core. Je vais ici utiliser un template pour le formulaire user_form qui correspond au formulaire de modification du compte utilisateur. Le nom machine de ce formulaire est user_form.

    Définition du template :

    Fichier : mon_module.module

    1. function mon_module_theme() {
    2. $theme = [];
    3. $theme['user_form'] = [
    4. 'render element' => 'form',
    5. 'template' => 'user-form',
    6. ];
    7. return $theme;
    8. }

    J'utilise comme clé de thème le nom machine du formulaire.

    Je peux ensuite créer dans le dossier templates de mon thème le fichier user-form.html.twig : (attention au _ remplacé par un -)

    1. <div>
    2. <p>Test</p>
    3. {{ form }}
    4. <div>

    On peut rendre des champs « manuellement », mais il ne faut pas oublier de rendre le formulaire form à la fin : 

    1. <div>
    2. <p>Test</p>
    3. <div class="col-sm-6">
    4. {{ form.mon_champ_1 }}
    5. </div>
    6. <div class="col-sm-6">
    7. {{ form.mon_champ_2 }}
    8. </div>
    9. {{ form | without('mon_champ_1', 'mon_champ_2') }}
    10. <div>