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 - Définir l'item de menu actif en fonction du type de noeud

    Posté le Mercredi 20 septembre 2017 - 17:48
    Dernière mise à jour le Vendredi 26 janvier 2018 - 18:35

    Sur ce site, j'ai trois types de contenu :

    • Article
    • Snippet
    • Réalisation

    Pour chacun de ces trois types de contenu, j'ai une vue (View) de listing qui correspond (cf le menu ci-dessus).

    Par défaut quand on est sur la vue de listing des snippets par exemple, on a bien l'élément de menu "Snippets" qui est marqué comme actif, par contre quand on va sur le détail d'un snippet, on perd cette information. Nous allons voir comment sélectionner le menu item qui doit être actif en fonction du type de contenu sur lequel on se trouve.

    1ère étape : surcharger le service MenuActiveTrail

    dans mon module « kgaut » je créé le fichier KgautMenuActiveTrail.php dans le dossier src/Menu avec le contenu suivant :

    1. <?php
    2.  
    3. namespace Drupal\kgaut\Menu;
    4.  
    5. use Drupal\Core\Menu\MenuActiveTrail;
    6. use Drupal\node\NodeInterface;
    7.  
    8. /**
    9.  * Extend the MenuActiveTrail class.
    10.  */
    11. class KgautMenuActiveTrail extends MenuActiveTrail {
    12.  
    13. /**
    14.   * {@inheritdoc}
    15.   */
    16. public function getActiveLink($menu_name = NULL) {
    17. // Call the parent method to implement the default behavior.
    18. $found = parent::getActiveLink($menu_name);
    19.  
    20. // If a node is displayed, load the default parent menu item
    21. // from the node type's menu settings and return it instead
    22. // of the default one.
    23. $node = $this->routeMatch->getParameter('node');
    24.  
    25. if ($node instanceof NodeInterface) {
    26. $bundle = $node->bundle();
    27. switch ($bundle) {
    28. case 'article':
    29. //Ici je demande à recherche le menu item qui utilise la route correspondant à mon type de contenu
    30. $links = $this->menuLinkManager->loadLinksByRoute('view.front_articles.page', [], $menu_name);
    31. break;
    32.  
    33. case 'snippet':
    34. $links = $this->menuLinkManager->loadLinksByRoute('view.front_snippets.page', [], $menu_name);
    35. break;
    36.  
    37. case 'realisation':
    38. $links = $this->menuLinkManager->loadLinksByRoute('view.front_realisations.page', [], $menu_name);
    39. break;
    40. }
    41.  
    42. if (isset($links) && $links) {
    43. $found = reset($links);
    44. }
    45. }
    46. return $found;
    47. }
    48. }

    C'est bien beau, mais maintenant il faut signaler à Drupal que l'on a surchargé un de ses services. Pour cela il faut créer le fichier src/MonModuleServiceProvider.php (attention c'est normé !) Dans mon cas j'ai donc créé le fichier KgautServiceProvider.php dans le dossier src de mon module kgaut (oui je suis très égocentrique).
    En voici le contenu :

    1. <?php
    2. /**
    3.  * @file
    4.  * Contains Drupal\kgaut\KgautServiceProvider.
    5.  */
    6.  
    7. namespace Drupal\kgaut;
    8.  
    9. use Drupal\Core\DependencyInjection\ContainerBuilder;
    10. use Drupal\Core\DependencyInjection\ServiceProviderBase;
    11.  
    12. class KgautServiceProvider extends ServiceProviderBase {
    13.  
    14. /**
    15.   * {@inheritdoc}
    16.   */
    17. public function alter(ContainerBuilder $container) {
    18. $container->getDefinition('menu.active_trail')->setClass('Drupal\kgaut\Menu\KgautMenuActiveTrail');
    19. }
    20.  
    21. }

    Un petit vidage de cache plus tard, et on est bon !

  • Drupal 8 - Rediriger un utilisateur lors de sa connexion

    Posté le Jeudi 14 septembre 2017 - 17:45
    Dernière mise à jour le Vendredi 26 janvier 2018 - 18:35

    Pour rediriger un utilisateur lorsqu'il se connecte on peut utiliser le hook HOOK_user_login().

    Le code qui suit ne redirige que si une redirection n'est pas déjà présente dans l'url :

    1. function MONMODULE_user_login($account) {
    2. if (!isset($_GET['destination'])) {
    3. $response = new \Symfony\Component\HttpFoundation\RedirectResponse(\Drupal::url('popote.user.commandes'));
    4. $response->send();
    5. }
    6. }

     

  • Drupal 8 - Ajouter des suggestions de template pour les Noeuds

    Posté le Jeudi 14 septembre 2017 - 16:18
    Dernière mise à jour le Vendredi 26 janvier 2018 - 18:35

    Dans drupal 8, parfois le thème ajoute des suggestions de template qui vont bien, en fonction du type de noeud et du view_mode, mais ça n'est pas toujours le cas, voici comment faire pour ajouter des suggestions de template via le hook HOOK_theme_suggestions_HOOK() :

    function MONMODULE_theme_suggestions_node(array $variables) {
      $suggestions = [];
      /** @var \Drupal\node\Entity\Node $node */
      $node = $variables['elements']['#node'];
      $sanitized_view_mode = strtr($variables['elements']['#view_mode'], '.', '_');
      $suggestions[] = $variables['theme_hook_original'] . '__' . $sanitized_view_mode;
      $bundle = $node->bundle();
      $sanitized_bundle = strtr($bundle, '.', '_');
      $suggestions[] = $variables['theme_hook_original'] . '__' . $sanitized_bundle;
      $suggestions[] = $variables['theme_hook_original'] . '__' . $sanitized_bundle . '__' . $sanitized_view_mode;
      return $suggestions;
    }

    Pour un type de contenu article en mode de vue teaser on aura ainsi les possibilités de templates suivantes :

    • node.html.twig
    • node--article.html.twig
    • node--teaser.html.twig
    • node--article--teaser.html.twig
  • Drupal 8 - Entité - Champ de base « Date »

    Posté le Vendredi 18 août 2017 - 07:53
    Dernière mise à jour le Vendredi 26 janvier 2018 - 18:35
    1. $fields['date_naissance'] = BaseFieldDefinition::create('datetime')
    2. ->setLabel(t('Date de naissance'))
    3. ->setRequired(TRUE)
    4. ->setDefaultValue(NULL)
    5. ->setSetting('datetime_type', 'date')
    6. ->setDisplayOptions('form', array(
    7. 'type' => 'date',
    8. ))
    9. ->setDisplayConfigurable('form', TRUE)
    10. ->setDisplayConfigurable('view', TRUE);

    Pour un champ DateTime : Drupal 8 - Entité - Champ de base datetime

  • Drupal 8 - Ajouter des propriétés à un type d'entité existant

    Posté le Vendredi 4 août 2017 - 14:43
    Dernière mise à jour le Jeudi 26 avril 2018 - 07:47

    Drupal vient avec des types d'entité prédéfinis (Node, ou User par exemple). À ces type d'entité il est possible d'ajouter des fields, mais il est aussi possible d'ajouter des propriétés.

    Voici comment ajouter des propriétés (prénom et nom) aux utilisateurs.

    Dans le fichier monmodule.module :

    1. function monmodule_entity_base_field_info(\Drupal\Core\Entity\EntityTypeInterface $entity_type) {
    2. if ($entity_type->id() === 'user') {
    3. $fields = [];
    4.  
    5. $fields['firstname'] = \Drupal\Core\Field\BaseFieldDefinition::create('string')
    6. ->setLabel(t('Firstname'))
    7. ->setSettings(array(
    8. 'max_length' => 100,
    9. 'text_processing' => 0,
    10. ))
    11. ->setDisplayConfigurable('form', TRUE)
    12. ->setDisplayConfigurable('view', TRUE);
    13.  
    14. $fields['lastname'] = \Drupal\Core\Field\BaseFieldDefinition::create('string')
    15. ->setLabel(t('Lastname'))
    16. ->setSettings(array(
    17. 'max_length' => 100,
    18. 'text_processing' => 0,
    19. ))
    20. ->setDisplayConfigurable('form', TRUE)
    21. ->setDisplayConfigurable('view', TRUE);
    22.  
    23. return $fields;
    24. }
    25. }

    Dans le fichier monmodule.install :

    1. /**
    2.  * Create user additional properties
    3.  */
    4. function monmodule_update_8001() {
    5. $entity_manager = \Drupal::entityManager();
    6. $definition = $entity_manager->getFieldStorageDefinitions('user')['firstname'];
    7. $entity_manager->onFieldStorageDefinitionCreate($definition);
    8. $definition = $entity_manager->getFieldStorageDefinitions('user')['lastname'];
    9. $entity_manager->onFieldStorageDefinitionCreate($definition);
    10. }
    11.  
    12. function monmodule_uninstall() {
    13. $entity_manager = \Drupal::entityManager();
    14. $definition = $entity_manager->getLastInstalledFieldStorageDefinitions('user')['firstname'];
    15. $entity_manager->onFieldStorageDefinitionDelete($definition);
    16. $definition = $entity_manager->getLastInstalledFieldStorageDefinitions('user')['lastname'];
    17. $entity_manager->onFieldStorageDefinitionDelete($definition);
    18. }

     

  • Drupal 8 - Créer un élément de menu vers une vue

    Posté le Dimanche 30 juillet 2017 - 18:40
    Dernière mise à jour le Vendredi 26 janvier 2018 - 18:35

    Dans le fichier monmodule.links.menu.yml :

    monmodule.menu.cle:
      title: 'Titre de ma mage'
      description: 'Liste des options'
      route_name: view.admin_options.page
      parent: system.admin_content
      weight: 90

    Quelques explications :

    • monmodule.menu.cle est la clée du menu item, cette clée doit être unique
    • title : Le label affiché pour le menu
    • description : Sera affichée au rollover
    • route_name : le nom de la route, sous la forme view.NOM_VUE.NOM_AFFICHAGE
    • parent : Le parent (niveau supérieur) de notre élément de menu, ici notre menu item sera présent sous "Contenu" dans le menu d'administration
    • weight : le poids de l'élément de menu, pour gérer l'odre.

    Petite astuce pour le nom de la route, rendez-vous sur la page d'édition de votre vue vous retrouverez les élement dans l'url (voici un exemple pour mon cas : http://monsite.dev/admin/structure/views/view/admin_options/edit/page

    Si vous souhaitez ajouter le menu item au premier "niveau" d'un menu (donc sans parent), au lieu de "parent", il faut utiliser la clé "menu_name" qui doit référencer le nom machine du menu, voici la structure à adopter :

    monmodule.menu.cle:
      title: 'Titre de ma mage'
      description: 'Liste des options'
      route_name: view.admin_options.page
      menu_name: "main"
      weight: 90
  • Drupal 8 - Entité - Champ de base « image »

    Posté le Vendredi 28 juillet 2017 - 17:18
    Dernière mise à jour le Mercredi 7 mars 2018 - 14:48
    1. $fields['photo'] = BaseFieldDefinition::create('image')
    2. ->setLabel(t('Photo'))
    3. ->setSetting('file_directory', 'formateurs/photos')
    4. ->setSetting('file_extensions', 'png jpg jpeg')
    5. ->setSetting('title_field', FALSE)
    6. ->setSetting('title_field_required', FALSE)
    7. ->setSetting('alt_field', FALSE)
    8. ->setSetting('alt_field_required', FALSE)
    9. ->setDisplayOptions('form', [
    10. 'label' => 'hidden',
    11. 'type' => 'image_image',
    12. 'weight' => 5,
    13. ])
    14. ->setDisplayConfigurable('form', TRUE)
    15. ->setDisplayConfigurable('view', TRUE);
  • Drupal 8 - Views - Ajouter une relation vers une entité de type custom

    Posté le Vendredi 28 juillet 2017 - 16:38
    Dernière mise à jour le Vendredi 26 janvier 2018 - 18:35

    Contexte :

    Un type d'entité custom "Carte" qui utilise come table de stockage "cards". Cette entité possède une propriété "owner" qui permet de la relier à l'utilisateur qui possède la carte. (propriété du type "entity_reference").

    Dans une vue listant les cartes, on peut facilement créer une relation vers le "owner" pour accèder à ses informations.

    Par contre sur une vue listant les utilisateurs, on ne peut pas avoir la relation inverse, liant les utilisateurs à leur carte. Pour cela il faut utiliser le hook_views_data_alter :

    /**
     * Implements hook_views_data_alter().
     */
    function MONMODULE_views_data_alter(array &$data) {
      $data['users_field_data']['cards'] = [
        'title' => t("Les cartes de l'utilisateur"),
        'help' => t("Permet de relier l'utilisateur courant à ses cartes"),
        'relationship' => [
          'group' => t('Cartes'),
          'label' => t("Cartes de l'utilisateur"),
          'base' => 'cards', // nom de la table stockant nos entités custom
          'base field' => 'owner', // nom du champ sur lequel faire la jointure
          'relationship field' => 'uid', // nom du champ cible sur lequel faire la jointure (de la table users_field_data)
          'id' => 'standard',
        ],
      ];
    }

    Merci à flocondetoile sur IRC pour m'avoir mis sur la bonne piste !

  • Drupal 8 - Entité - Champ de base « Référence à un terme de taxonomie »

    Posté le Vendredi 28 juillet 2017 - 12:01
    Dernière mise à jour le Jeudi 11 avril 2019 - 09:26

    Pour faire un champ de base référence à un terme de taxonomie, on va utiliser le type "entity_reference", en lui passant évidement le nom du vocabulaire, (ici "option_types") :

    1. $fields['type'] = BaseFieldDefinition::create('entity_reference')
    2. ->setLabel(t('Catégorie'))
    3. ->setSetting('target_type', 'taxonomy_term')
    4. ->setSetting('handler', 'default:taxonomy_term')
    5. ->setSetting('handler_settings', [
    6. // ici définir l'id du vocabulaire
    7. 'target_bundles' => [ 'option_types' => 'option_types']
    8. ])
    9. //on utilisera l'affichage en mode "radio / checkbox" en fonction de la cardinalité
    10. ->setDisplayOptions('form', array(
    11. 'type' => 'options_buttons',
    12. 'weight' => 3,
    13. ))
    14. ->setDisplayConfigurable('form', TRUE)
    15. ->setDisplayConfigurable('view', TRUE);

    Pour utiliser le formulaire type "tag" :

    1. $fields['type'] = BaseFieldDefinition::create('entity_reference')
    2. ->setLabel(t('Catégorie'))
    3. ->setSetting('target_type', 'taxonomy_term')
    4. ->setSetting('handler', 'default:taxonomy_term')
    5. ->setSetting('handler_settings', [
    6. 'target_bundles' => [ 'option_types' => 'option_types']
    7. ])
    8. ->setDisplayOptions('form', array(
    9. 'type' => 'entity_reference_autocomplete',
    10. 'weight' => 3,
    11. 'settings' => array(
    12. 'match_operator' => 'CONTAINS',
    13. 'size' => '10',
    14. 'autocomplete_type' => 'tags',
    15. 'placeholder' => '',
    16. ),
    17. ))
    18. ->setDisplayConfigurable('form', TRUE)
    19. ->setDisplayConfigurable('view', TRUE);

    Cardinalité

    Pour avoir une cardinalité illimitée (autant de valeurs possibles que l'utilisateur le désir) ajouter l'appel suivant à la déclaration de votre propriété :

    1. ->setCardinality(FieldStorageDefinitionInterface::CARDINALITY_UNLIMITED)

    Création automatiques des termes

    Pour permettre la création automatique des terme de taxonomy dans le vocabulaire, les lignes :

    1. ->setSetting('handler_settings', [
    2. 'target_bundles' => [ 'option_types' => 'option_types']
    3. ])

    Deviennent :

    1. ->setSetting('handler_settings', [
    2. 'target_bundles' => [ 'option_types' => 'option_types'],
    3. 'auto_create' => TRUE,
    4. ])

     

     

  • Drupal 8 - Changer le libellé d'un élément de menu

    Posté le Mercredi 26 juillet 2017 - 11:20
    Dernière mise à jour le Vendredi 26 janvier 2018 - 18:35

    Dans Drupal 8 la gestion des menus et des route à été complètement revue, le hook_menu_alter n'existe plus.

    Si vous souhaitez modifier le label d'un élément de menu (dans la barre d'administration par exemple) il faut utiliser le hook_menu_links_discovered_alter.

    Par exemple si l'on souhaite modifier le menu item « Personnes » (ou « People ») en « Gestion des utilisateurs » :

    /**
     * Implements hook_menu_links_discovered_alter().
     */
    function monmodule_menu_links_discovered_alter(&$links) {
      $links['entity.user.collection']['title'] = t('Gestion des utilisateurs');
    }

    entity.user.collection correspond à la clé de l'élément de menu défini dans le fichier user.links.menu.yml.

    Merci à Julien de m'avoir indiqué ce hook sur IRC ;)