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 - Ajouter une propriété à un type d'entité config

    Posté le Vendredi 9 novembre 2018 - 11:08

    Voici comment altérer un type d'entité config pour lui ajouter une propriété.

    Dans le cas présent, nous allons modifier le type d'entité ConfigurableLanguage afin de lui ajouter un champ google_analytics, pour avoir par exemple un code de tracking différent pour chaque langue.

    Commençons par définir les nouveaux formulaire concernant pour l'édition et la création de langue :

    modules/custom/mon_module/mon_module.module

    1. function mon_module_entity_type_alter(array &$entity_types) {
    2. $entity_types['configurable_language']->setFormClass('add', \Drupal\mon_module\Entity\Form\LanguageCustomAddForm::class);
    3. $entity_types['configurable_language']->setFormClass('edit', \Drupal\mon_module\Entity\Form\LanguageCustomEditForm::class);
    4. }

     

    Ci dessous, le contenu des formulaires qui héritent directement des formulaires de base qu'ils supplantent.

    modules/custom/mon_module/src/Entity/Form/LanguageCustomAddForm.php

    1. <?php
    2.  
    3. namespace Drupal\mon_module\Entity\Form;
    4.  
    5. use Drupal\Core\Form\FormStateInterface;
    6. use Drupal\language\Form\LanguageAddForm;
    7.  
    8. class LanguageCustomAddForm extends LanguageAddForm {
    9. use LanguageCustomTrait;
    10.  
    11. public function form(array $form, FormStateInterface $form_state) {
    12. $form = parent::form($form, $form_state);
    13. $this->getFormCustomFields($form);
    14. return $form;
    15. }
    16.  
    17. }

     

    modules/custom/mon_module/src/Entity/Form/LanguageCustomEditForm.php

    1. <?php
    2.  
    3. namespace Drupal\mon_module\Entity\Form;
    4.  
    5. use Drupal\Core\Form\FormStateInterface;
    6. use Drupal\language\Form\LanguageEditForm;
    7.  
    8. class LanguageCustomEditForm extends LanguageEditForm {
    9. use LanguageCustomTrait;
    10.  
    11. public function form(array $form, FormStateInterface $form_state) {
    12. $form = parent::form($form, $form_state);
    13. $this->getFormCustomFields($form);
    14. return $form;
    15. }
    16.  
    17. }

     

    Enfin, afin d'éviter la répétition de code, je passe par un trait qui contient mes customisations.

    Ce trait est appelé dans les classes ci-dessous via l'appel : $this->getFormCustomFields($form);

    Ce trait, fait deux choses, dans la méthode getFormCustomFields() il altère le formulaire pour ajouter le champs qui nous intéresse, et via l'appel à la méthode customEntityBuilder(), l'enregistrement de ce champ est effectué.

    modules/custom/mon_module/src/Entity/Form/LanguageCustomTrait.php

    1. <?php
    2.  
    3. namespace Drupal\mon_module\Entity\Form;
    4.  
    5. use Drupal\Core\Form\FormStateInterface;
    6. use Drupal\language\ConfigurableLanguageInterface;
    7.  
    8. trait LanguageCustomTrait {
    9.  
    10. public function getFormCustomFields(&$form) {
    11. /* @var $language \Drupal\language\ConfigurableLanguageInterface */
    12. $language = $this->entity;
    13.  
    14. $form['google_analytics'] = [
    15. '#title' => t('ID Google Analytics'),
    16. '#type' => 'textfield',
    17. '#default_value' => $language->getThirdPartySetting('mon_module', 'google_analytics')
    18. ];
    19. $form['#entity_builders'][] = '::customEntityBuilder';
    20. }
    21.  
    22. function customEntityBuilder($entity_type, ConfigurableLanguageInterface $language, &$form, FormStateInterface $form_state) {
    23. if ($form_state->getValue('google_analytics')) {
    24. $language->setThirdPartySetting('mon_module', 'google_analytics', $form_state->getValue('google_analytics'));
    25. return;
    26. }
    27. $language->unsetThirdPartySetting('mon_module', 'google_analytics');
    28. }
    29.  
    30. }

    évidement, pensez à modifier toutes les occurrences de mon_module par le nom machine de votre module.

    Merci à Alexandre Mallet aka @woprrr pour la piste

  • Drupal 8 - Afficher un noeud via le code

    Posté le Jeudi 25 octobre 2018 - 09:41

    Pour afficher avoir le renderable array d'un noeud dans le code, rien de plus simple via le service entity_type.manager :

    1. $node = Node::load(1);
    2. $node_rederable = \Drupal::service('entity_type.manager')->getViewBuilder('node')->view($node);

    Pour utiliser un autre view_mode :

    1. $node = Node::load(1);
    2. $node_rederable = \Drupal::service('entity_type.manager')->getViewBuilder('node')->view($node, 'embed');

    Évidement le plus propre et de passer par l'injection de dépendance, voici une version simplifiée de mon contrôleur :

    1. <?php
    2.  
    3. namespace Drupal\mon_module\Controller;
    4.  
    5. use Drupal\Core\Controller\ControllerBase;
    6. use Drupal\Core\Entity\EntityTypeManager;
    7. use Drupal\node\Entity\Node;
    8. use Symfony\Component\DependencyInjection\ContainerInterface;
    9.  
    10. /**
    11.  * Class PageController.
    12.  */
    13. class PageController extends ControllerBase {
    14.  
    15. /**
    16.   * @var \Drupal\Core\Entity\EntityTypeManager
    17.   */
    18. protected $entityTypeManager;
    19.  
    20. public function __construct(EntityTypeManager $entityTypeManager) {
    21. $this->entityTypeManager = $entityTypeManager;
    22. }
    23.  
    24. public static function create(ContainerInterface $container) {
    25. return new static($container->get('entity_type.manager'));
    26. }
    27.  
    28. public function frontpage() {
    29. $node = Node::load(1);
    30. $page = $this->entityTypeManager->getViewBuilder('node')->view($node, 'embed');
    31.  
    32. return [
    33. 'page' => $page,
    34. ];
    35. }
    36. }

     

  • Redirection Apache - Rediriger si présence d'un paramètre GET

    Posté le Jeudi 25 octobre 2018 - 09:33

    L'ensemble de règles suivante ne lancera une redirection 301 que sur l'URI /documentation et que si est présent un paramètre GET body_value.

    1. RewriteCond %{REQUEST_URI} ^/documentation$ [NC]
    2. RewriteCond %{QUERY_STRING} body_value
    3. RewriteRule ^(.*)$ http%{ENV:protossl}://%{HTTP_HOST}/recherche-documentation [R=301,L]

    Les urls suivantes seront redirigées :

    Les urls suivantes ne seront pas redirigées :

  • Drupal 8 - Afficher un menu dans le code

    Posté le Jeudi 20 septembre 2018 - 19:10

    Dans le contrôleur / Bloc...

    1. /** @var \Drupal\Core\Menu\MenuLinkTree $menu_tree_service */
    2. $menu_tree_service = \Drupal::service('menu.link_tree');
    3. $menu_parameters = new \Drupal\Core\Menu\MenuTreeParameters();
    4. $menu_parameters->setMaxDepth(1); // Profondeur du menu à afficher
    5. $menu_name = 'footer' // Nom machine du menu à afficher
    6. $menus = [
    7. 'footer' => $menu_tree_service->build($menu_tree_service->load($menu_name, $menu_parameters)),
    8. ];
    9. return [
    10. '#theme' => 'page-404',
    11. '#menus' => $menus,
    12. ];

    et tout simplement dans notre template :

    {{ menus.footer }}

     

  • Apache 2.4 - Vhost - Restreindre l'accès à un site sauf pour certaines IP

    Posté le Mardi 28 août 2018 - 11:42

    Il est facile sous apache de restreindre l'accès à un site dans un virtual host via l'instruction Require valid-user.

    Exemple :

    1. <Directory "/home/monsite/web">
    2. AuthType Basic
    3. AuthName "Restricted Content"
    4. AuthUserFile /home/monsite/htpasswd-preprod
    5. Require valid-user
    6. AllowOverride All
    7. Options -Indexes +FollowSymLinks +MultiViews
    8. </Directory>

    Mais dans certains cas, on veut autoriser certaines ip à accéder au site sans authentification "htpasswd", dans le cas de retour de brique de paiement, ou de webservice, dans ce cas on peut utiliser la forme suivante :

    1. <Directory "/home/monsite/web">
    2. AuthType Basic
    3. AuthName "Restricted Content"
    4. AuthUserFile /home/monsite/htpasswd-preprod
    5. <RequireAny>
    6. Require valid-user
    7. Require ip 194.01.01.0/24 #autorisation d'une range d'ip
    8. Require ip 134.0.0.1 #autorisation d'une ip unique
    9. </RequireAny>
    10. AllowOverride All
    11. Options -Indexes +FollowSymLinks +MultiViews
    12. </Directory>

    Ainsi les accès provenant d'autres parties que l'ip définie ou le range d'ip se verront présenter l'authentification via le htpasswd défini.

  • Drupal 8 - Créer la traduction d'une chaine de caractère dans le code

    Posté le Lundi 6 août 2018 - 18:18

    Dans un processus de déploiement, il est utile de gérer les traductions de chaînes de caractères dans le code, afin de pouvoir les déployer plus facilement.

    Exemple avec cette fonction d'update à adapter en fonction de vos besoins :

    1. /**
    2.  * Création d'une traduction
    3.  */
    4. function mespronos_tweaks_update_8005() {
    5. $chaine = 'Forgotten password';
    6. $traduction = 'Mot de passe oublié';
    7. $storage = \Drupal::service('locale.storage');
    8. $string = $storage->findString(['source' => $chaine]);
    9. if ($string === NULL) {
    10. $string = new \Drupal\locale\SourceString();
    11. $string->setString($chaine);
    12. $string->setStorage($storage);
    13. $string->save();
    14. }
    15.  
    16. $translation = $storage->createTranslation(array(
    17. 'lid' => $string->lid,
    18. 'language' => 'fr',
    19. 'translation' => $traduction,
    20. ))->save();
    21. }

    Pour un exemple réel, il sera plus pratique de passer par un tableau associatif (à deux dimensions si l'on veut importer plusieurs langues) qui sera parcouru par un ou deux foreach.

  • Drupal 8 - Ajouter une restriction par ip sur une route

    Posté le Mercredi 1 août 2018 - 07:48

    Dans le fichier MODULE.routing.yml on va utiliser le requirement « _custom_access »

    1. module.ma_methode:
    2.   path: 'mon-module/mon-chemin'
    3.   defaults:
    4.   _controller: '\Drupal\module\Controller\monController::maMethode'
    5.   requirements:
    6.   _custom_access: '\Drupal\module\Controller\monController::maMethodeAccess'

    Que l'on va implémenter dans notre contrôleur, ici monController.php :

    1. public function maMethodeAccess() {
    2. /** @var Request $request */
    3. $request = \Drupal::request();
    4. $ipAutorisees = \Drupal::config('iamyourstory.checkcard_api')->get('allowed_ips')
    5. $ipAutorisees = explode(',', $ipAutorisees);
    6. $ipAutorisees = array_map('trim', $ipAutorisees);
    7. return AccessResult::allowedIf(\in_array($request->server->get('REMOTE_ADDR'), $ipAutorisees));
    8. }

    à noter :

    • Les ip autorisées sont stockées en configuration via un formulaire de config, les ip sont séparées par une virgule, d'où le explode.
    • J'utilise ensuite la fonction array_map('trim', $ipAutorisees) pour supprimer les éventuels espaces. Si la personne avait saisi « 127.0.0.1, 192.168.0.2 », mon tableau sans le trim sera ['127.0.0.1', ' 192.168.0.2'] (espace au départ de la seconde ip.)
  • Drupal 8 - Entité - Champ de base Fichier (File)

    Posté le Mardi 27 mars 2018 - 08:51

    Voici comment créer un champ « fichier » au sein d'un type d'entité custom dans drupal 8 :

    1. $fields['programme_pdf'] = BaseFieldDefinition::create('file')
    2. ->setLabel(t('Programme PDF'))
    3. ->setSetting('file_directory', 'formations/programme') // dossier d'upload
    4. ->setSetting('max_filesize', '10MB') // taille max du fichier
    5. ->setSetting('file_extensions', 'pdf') // extensions autorisées, à séparer par un espace
    6. ->setSetting('description_field', FALSE) // si on veut activer un champ « description »
    7. ->setDisplayOptions('form', [
    8. 'label' => 'hidden',
    9. 'type' => 'file_generic',
    10. 'weight' => 4,
    11. ])
    12. ->setDisplayConfigurable('form', TRUE)
    13. ->setDisplayConfigurable('view', TRUE);

     

  • Drupal 8 - Entitée & Views - Créer une relations inverse

    Posté le Jeudi 22 mars 2018 - 17:35
    Dernière mise à jour le Vendredi 23 mars 2018 - 07:49

    Prenons deux types d'entités custom : « Bière » et « Brasserie » avec une relation 1-n entre les deux dans le sens :

    • Une bière provient d'une et d'une seule brasserie
    • Une brasserie peut proposer N bières

     Ainsi :

    drupal-views-relations.png

    En drupalisme, on aurait une propriété « entity_reference » au niveau de notre bière qui fera référence à la brasserie.

    Dans views, si on fait un listing des bières, pas de soucis pour accéder au contenu de la brasserie depuis la bière, par contre l'inverse n'est pas possible.

    Depuis un listing de brasserie, il n'est pas possible d’accéder aux bières de la brasserie.

    Pour cela il faut utiliser la classe en charge de views_data, définie dans l'annotation de notre type d'entité brasserie :

    drupal-entitee-annotation.png

    Et voila le contenu de ce fichier

    1. <?php
    2.  
    3. namespace Drupal\mon_module\Entity\ViewsData;
    4.  
    5. use Drupal\views\EntityViewsData;
    6.  
    7. class BrasserieViewsData extends EntityViewsData {
    8.  
    9. /**
    10.   * {@inheritdoc}
    11.   */
    12. public function getViewsData() {
    13. $data = parent::getViewsData();
    14. $data['brasserie']['bieres'] = [
    15. 'title' => t('Bieres'),
    16. 'help' => t('Lie la brasserie aux bières produites'),
    17. 'relationship' => [
    18. 'group' => t('bieres'), // Affiché en information dans la partie « relationship » de views
    19. 'label' => t('Actions de formation'), // Affiché en information dans la partie « relationship » de views
    20. 'base' => 'biere', // Table de base de l'entitée cible
    21. 'field table' => 'biere', // Table contenant le champ de l'entitée cible sur lequel on fera la jointure
    22. 'base field' => 'brasserie',// Champ de l'entité cible Champ sur lequel on fera la jointure
    23. 'relationship field' => 'brasserie_id', // Champ de l'entité source sur lequel on fera la jointure
    24. 'id' => 'standard',
    25. ],
    26. ];
    27. return $data;
    28. }
    29. }

    Et voila le travail !

    views-relationship.png

  • Drupal 8 - Menu - Ajouter un élément de menu avec des paramètres GET

    Posté le Lundi 12 mars 2018 - 07:14

    Voici comment créer un Menu item (élément de menu) avec des paramètres GET.

    Pour cela on utilise le fichier MON_MODULE.links.menu.yml (à noter que cela marchera aussi dans les fichiers MON_MODULE.links.action.yml et MON_MODULE.links.task.yml)

    1. formations.element:
    2.   title: 'Mon titre de menu'
    3.   weight : 2
    4.   route_name: view.front_formations.page
    5.   menu_name: menu-formation
    6.   options:
    7.   query:
    8.   label: 'prise-de-vue'
    9.   cat: 2

    Ici l'url aura comme « query string » : ?label=prise-de-vue&cat=2

    Pour rappel la clé menu_name attend le nom du menu dans lequel on veut placer l'élément de menu que l'on vient de définir.