Makina Blog

Le blog Makina-corpus

Retour d'expérience sur un premier projet Drupal 8


Ce que vous devez savoir si vous commencez un projet Drupal 8 en 2016.

Après 5 ans de développement et une profonde réécriture, Drupal 8.0 est sorti en octobre 2015. Nous avons déjà écrit que Drupal 8 n'était pas prêt il y a quelques mois, notamment pour les grands projets à livrer vite. Depuis Drupal fait l'objet de versions régulières (8.1 en avril 2016, 8.2 en octobre 2016), pendant que les modules communautaires continuent d'être portés sur cette nouvelle version. Nous avons saisi l'occasion d'un projet de taille plus modeste pour monter en compétence et tester Drupal 8 plus en profondeur, notamment au niveau des APIs de développement.

Le projet a été réalisé entre mai et novembre 2016, sur la version 8.1.x, puis 8.2.x de Drupal. Cet article présente notre retour avec un statut au mois d'août 2016, ainsi que quelques bouts de code ou patchs qui pourront vous être utiles.

Ce qui s'est bien passé

Moins de modules, un site simplifié

Beaucoup de fonctionnalités ont été intégrées au cœur de Drupal 8 (voir notre article sur les nouveautés de Drupal 8), et il n'est plus nécessaire d'intégrer autant de modules issus de la communauté sur le site pour les fonctionnalités de base, permettant pour des sites simples de se contenter quasiment des modules orientés SEO (Pathauto & Metatags notamment).

Dans le cadre de notre projet, nous avons utilisé des modules pour les grandes fonctionnalités (recherche avec SearchAPI, SEO avec Pathauto & Metatags, gestion de la configuration avec Features), plus quelques petits modules additionnels couvrant exactement quelques besoins ponctuels, mais au final le site comporte tout de même beaucoup moins de modules que le moindre site Drupal 7 que nous faisions auparavant.

Utiliser Twig est un plaisir

Un seul regret à ce jour, la difficulté de vérifier qu'un champ est vide. C'est en cours de traitement dans une issue du cœur, mais pour le moment, le code est un peu alourdi par ce genre de directive (il est également possible d'utiliser une fonction preprocess() :

 {% if content.field_myfield['#items'] is not empty %}

La console Drupal est très utile

Si le développement lui-même s'est un peu complexifié (au point que le développement sans IDE / débogueur est vraiment déconseillé, la communauté a rapidement mis au point un outil pour automatiser la génération de code : la Drupal Console.

Autant le dire tout de suite : cet outil est indispensable si vous souhaitez développer en Drupal 8. Le temps gagné par la génération des classes et namespaces permet de compenser un peu la montée en compétence sur Drupal 8.

Attention, à partir de la prochaine version, il faudra désormais l'installer par projet et non plus forcément de façon globale :

composer require --dev drupal/console:dev-master

Ce qui s'est moins bien passé

Une documentation éparse

Disons-le tout net, il existe peu de retours d'expérience de projets Drupal 8 achevés, et il est difficile de trouver de la documentation sur comment "bien" faire les choses. Les équipes de développement n'ont pas encore assez de recul pour avoir correctement pris en main toutes les évolutions, et il est beaucoup plus difficile que sur Drupal 7 de trouver des articles de blog ou même la documentation officielle Drupal sur certaines personnalisations un peu avancées. Il n'est pas rare de ne trouver que StackOverflow ou drupal.org comme seules réponses à des recherches qui semblaient pourtant simples.

Les modules issus de la communauté ne sont pas (tous) prêts

Rules, SearchAPI, Notifications… la liste de modules que nous avions l'habitude d'utiliser en Drupal 7 et qui ne sont pas complètement portés est longue. Certains sont en version alpha, mais la stabilité laisse régulièrement à désirer, et dans un contexte de mise en production rapide, il faut donc chercher ailleurs une solution.

Cela signifie souvent la (re-)développer, quand contribuer au portage du module n'est pas une solution (architecture du portage Drupal 8 pas encore complètement définie), et le travail est parfois complexe.

Prévoyez donc pour vos premiers petits projets une marge supplémentaire dans l'évaluation du coût de développement.

Tout de même une bonne nouvelle

La communauté est là…

La communauté est (toujours) là ! On trouve quand même un certain nombres de courageux qui ont commencé l'aventure Drupal 8 et vous ne serez bien souvent pas complètement seuls à rencontrer certaines problématiques.

Je recommande d'ailleurs comme sources de documentation les blogs français des Happyculteurs et de Flocon de toile.

… mais il faut chercher

D'ailleurs, depuis le début de ce projet, nous avons inclus plusieurs patchs du cœur dans notre installation, et nous suivons un nombre bien plus grand d'issues en attente de résolution.

Un futur prometteur

À force de suivre les issues du cœur, on constate également les nombreuses avancées de chaque version, et certains des problèmes rencontrés durant le projet trouveront leur correction dès la sortie de la version 8.2.0, tandis que d'autres plus récalcitrants sont déjà corrigés dans la branche 8.3.x. Les patchs sont donc souvent disponibles, pour qui sait chercher.

Quelques points d'attention techniques

Les form modes

Les form modes (la possibilité d'avoir plusieurs rendus différents du même formulaire) sont une excellente idée, permettant une richesse fonctionnelle très intéressante. Mais …

Si vous ajoutez un form mode à un formulaire d'entité du cœur (par exemple, un nouveau mode sur le compte utilisateur), vous ne pourrez pas l'utiliser directement dans du code :

\Drupal::service('entity.form_builder')->getForm($user, 'my_form_mode');

En effet, il faut au préalable déclarer une classe associée au formulaire, sous peine de prendre le message d'erreur "The "user" entity type did not specify a "my_form_mode" form class" (voir cette issue du cœur) :

/**
 * Implements hook_entity_type_build().
 */
function my_module_entity_type_build(array &$entity_types) {
  $entity_types['user']->setFormClass('my_form_mode', 'Drupal\user\ProfileForm');
}

L'industrialisation

Cette partie mériterait un article à elle toute seule. Si les possibilités d'export de la configuration apportées par CMI (la configuration management initiative) font beaucoup de bien (plus de configuration "non exportable" via Features, tout est confortablement intégré dans le cœur), les bonnes pratiques et les processus de travail ne sont pas encore complètement aboutis, la communauté continue de se chercher sur le sujet.

Aujourd'hui, nous avons des solutions qui fonctionnent, mais qui sont encore trop adaptées à chaque projet ou chaque écosystème de mise en production, il n'y a pas encore de "standard de fait".

Drush Make ou Composer ?

Pour la récupération des modules, on semble s'orienter vers le modèle Composer drupal-project. Il est d'ailleurs également possible de récupérer des bibliothèques javascript via composer, afin de complètement remplacer l'utilisation de drush make.

Autre avantage de ce drupal-project : il installe drush et la console de façon contextuelle au projet (dans /vendor/bin), permettant des environnements complètements isolés et autonomes.

Config installer vs. config update vs. config devel ? Et Features ?

Pour la gestion de la configuration, plusieurs options s'offrent là encore à vous. Si le profil d'installation Config Installer semble préconisé par certains développeurs de la communauté, nous avons sur ce projet utilisé Config Update et Features (qui ne sert plus aujourd'hui qu'à faciliter le packaging, mais qu'il n'est plus nécessaire d'activer). Cependant, nous sommes pour le moment en phase de création du site, et il faudra suivre le bon fonctionnement des mises à jour de configuration pour valider complètement la procédure d'industrialisation.

Ah, au passage, une petite ligne de commande utile pour mettre à jour votre feature suite à une modification (je pars du principe que vous travaillez dans un profil d'installation et que vous avez créé un bundle correspondant) :

drush features-export my_module --bundle=my_bundle --add-profile=my_profile

Vous constaterez rapidement que sans ces options, Features génèrera correctement votre module… mais avec le mauvais nom (my_module au lieu de my_bundle_my_module) ou au mauvais endroit (dans /modules au lieu de /profiles/my_profile/module).

CMI, c'est le paradis ?

C'est un net progrès ! Par contre, les modules suscités étant encore tous en phase de développement, il arrive que des problèmes surviennent et que vous deviez tout de même réaliser un export manuel de certaines configurations. Les fichiers sont très lisibles, mais il peut vous arriver d'en oublier un, et il faut compter avec ces dépendances manquantes dont seule la prochaine réinstallation vous avertira.

Il est également possible qu'en vous contentant d'exporter votre configuration, l'installation ne se passe pas bien à cause de dépendances manquantes. Là encore, il y a des des issues pour ça ;-)

Bref, vous allez réinstaller souvent pour tester votre configuration.

Mon conseil : vous devez pouvoir (ré-)installer votre projet le plus vite possible. L'intégration continue est donc une solution intéressante pour détecter le plus tôt possible les problèmes.

La gestion du cache

Avec le nouveau système de gestion de cache, chaque élément de votre page comporte la gestion de son propre cache. Vous devez donc gérer le cache pour chaque élément que vous allez produire (notamment vos blocs). Soyons honnête, vous allez oublier de façon régulière.

Heureusement, cela se constate rapidement lors de tests, mais c'est d'autant plus important de tester en profondeur votre site, notamment avec plusieurs utilisateurs.

À noter qu'il est assez facile de rajouter les méta-données du cache, puisque nous ne manipulons plus que des Render Arrays (pour aller plus loin, lisez l'article du blog des Happyculteurs sur le sujet) :

$build['#cache'] = ['contexts' => ['url']];

Les patchs que nous avons utilisés

Une meilleure gestion des dépendances manquantes

Le nouveau système de configuration permet d'exporter l'intégralité de ce que vous paramétrez sur le site (hors contenus). Cependant, si on essaie de répartir la configuration dans des modules, il est possible d'oublier de mentionner une dépendance, ou de ne pas charger les modules dans le bon ordre.

Dans ce cas, Drupal ne chargera pas correctement la configuration, et votre processus d'installation n'ira d'ailleurs pas jusqu'au bout, avec un charmant message d'erreur "dependency missing". Nous avons donc utilisé un patch du cœur permettant de lister les dépendances manquantes, facilitant grandement le déboguage de ces situations.

Une ergonomie des blocs perfectible

Drupal 8 introduit le concept de plugin de Condition, permettant de réutiliser les mêmes conditions dans différents modules (simplifiant ainsi les intégrations de modules génériques tels que Rules). Problème : toutes ces nouvelles conditions apparaissent dans l'interface des blocs, rendant la configuration d'un seul bloc par l'interface difficile à prendre en main pour un non-développeur.

Là encore, un patch du cœur restreignant les conditions par contexte vient améliorer tout ça en retirant notamment les conditions offertes par le module CTools de l'interface des blocs (par contre, pour Rules, vous repasserez, mais vu l'état actuel du module, ce n'est pas si surprenant).

Ce patch est désormais intégré dans le cœur depuis la version 8.2.2.

Un fil d'Ariane multilingue récalcitrant

En utilisant un site multilingue, vous pouvez vous retrouver avec un fil d'Ariane indiquant simplement "Home" sur une langue qui n'est pas la langue par défaut du site. Si il est tout à fait possible de ne pas afficher le bloc "fil d'Ariane" sur la page d'accueil, c'est tout de même plus intéressant de corriger le problème, et c'est en cours de travail dans les issues du cœur.

Quelques bouts de code qui peuvent vous êtres utiles

Afficher une entité

Fini les node_view(), Drupal 8 dispose désormais de service pour afficher des entités :

$entity_type =  'node';
$view_mode = 'teaser';
$view_builder = \Drupal::entityTypeManager()->getViewBuilder($entity_type);
$output = $view_builder->viewMultiple($my_nodes, $view_mode);

Récupérer l'entité de la page courante

Fini les menu_get_object(), vous pouvez désormais utiliser le routage :

$current_node = \Drupal::routeMatch()->getParameter('node');

Récupérer la valeur d'un champ

Attention, petite subtilité dans le cas d'un champ multiple :

$node->get('field_my_field')->getValue(); // Récupère toutes les valeurs dans un tableau.
$node->get('field_my_field')->value; // Récupère la première valeur (delta 0).

Ajouter la page courante au fil d'Ariane

C'est plus ou moins ce que fait le module Current Page Crumb :

/**
 * Implements hook_system_breadcrumb_alter().
 */
function my_module_system_breadcrumb_alter(Breadcrumb &$breadcrumb, RouteMatchInterface $route_match, array $context) {
  // Append the current page title to the breadcrumb for non-admin routes.
  if ($breadcrumb && !\Drupal::service('router.admin_context')->isAdminRoute()) {
    $request = \Drupal::request();
    $title = \Drupal::service('title_resolver')->getTitle($request, $route_match->getRouteObject());
    if (!empty($title)) {
      $breadcrumb->addLink(Link::createFromRoute($title, '<none>'));
      $breadcrumb->addCacheContexts(['url.path']);
    }
  }
}

Vous noterez l'ajout obligatoire de la méta-donnée de cache : le fil d'Ariane issu du cœur de Drupal dépend de la page parente, et contient donc un contexte de cache url.path.parent. Dans la mesure où nous ajoutons le titre de la page courante, il ne faut pas oublier d'ajouter son chemin comme contexte de cache, sous peine d'avoir des fils d'Ariane identiques sur toutes les pages ayant le même parent (je vous ai déjà dit que vous auriez des problèmes de cache ;-)).

Ajouter les views modes comme template suggestion

Très simple, mais raisonnablement utile, notamment sur les utilisateurs, ou ce n'est pas fait dans le cœur :

/**
 * Implement hook_theme_suggestions_HOOK().
 */
function my_module_theme_suggestions_user(array $variables) {
  return array(
    'user__' . $variables['elements']['#view_mode']
  );
}

Faire un #states depuis un <SELECT>

Et non, ça ne fonctionne pas tout seul, allez savoir pourquoi. Cette fois-ci, pas d'issue du cœur, heureusement que StackOverflow existe ;-)

La bonne syntaxe est donc (pas de ":", pas de selecteur "name") :

'select[data-drupal-selector="edit-field-my-field"]' => array('value' => $value)

Utiliser la route associée à une Views

Ce n'est pas forcément très bien documenté, donc si vous avez besoin d'accéder à la route associée à une Views en mode d'affichage "page", il vous suffit d'utiliser :

view.view_name.display_name

En conclusion

Mon avis n'a pas changé, il est tout à fait possible de réaliser aujourd'hui des sites en Drupal 8, mais selon la date de mise en production attendue, prenez des provisions pour risques un peu plus importantes dans vos évaluations… et rapprochez-vous d'experts Drupal qui connaissent le fonctionnement de la communauté, ou suivez notre formation au développement Drupal 8 !

Formations associées

Formations Drupal

Formation Drupal Administrateur

Toulouse Du 22 au 24 mai 2024

Voir la formation

Formations Drupal

Formation Drupal Développeur

À distance (FOAD) Du 2 au 4 avril 2024

Voir la formation

Actualités en lien

Image
Migration Drupal 7 à Drupal 10
04/04/2024

Migration d'un site Drupal 7 en Drupal 10

Trucs, astuces et "bouts" de code pour migrer votre site web de Drupal 7 à Drupal 10. Compte-rendu d'une conférence donnée au Drupalcamp Rennes 2024.

Voir l'article
Image
Drupal 8 logo
27/07/2016

Démarrer un thème Drupal 8 en 10 minutes

Un thème Drupal 8 à télécharger pour être opérationnel immédiatement.

Voir l'article
Image
Drupal 8 logo
29/05/2016

Comment créer un site web avec Drupal ?

Présentation rapide de ma méthode pour construire un site web avec Drupal, quelle que soit la version.

Voir l'article

Inscription à la newsletter

Nous vous avons convaincus