Structure de base d'un module Drupal
Partie II du guide pratique pour créer des modules de base Drupal 8
De .info aux tests, uniquement les bases
Structure de base
loremipsum.info.yml
name: Lorem ipsum
type: module
description: 'Générateur Lorem ipsum pour Drupal'
package: Development
core: 8.x
configure: loremipsum.form
Les fichiers info sont désormais formatés en YML, et la différence entre modules et thèmes doit être claire via la déclaration du type. La déclaration config pointe vers une route (plus d'infos plus tard), sinon il n'y a rien d'autre. En fait, c'est le seul fichier dont votre module aura besoin. Après avoir sauvegardé ce fichier (dans le dossier root/modules), vous pouvez activer votre module dans /admin/modules sans casser votre site. Mais comme vous le verrez plus loin, ce n'est pas suffisant.
loremipsum.module
<?php
use Drupal\Core\Routing\RouteMatchInterface;
/**
* Implémente hook_help().
*/
function loremipsum_help($route_name, RouteMatchInterface $route_match) {
switch ($route_name) {
case 'help.page.loremipsum':
return t('
<h2>Générateur Lorem ipsum pour Drupal.</h2>
<h3>Instructions</h3>
<p>Lorem ipsum dolor sit amet... <strong>Je plaisante !</strong></p>
<p>Décompressez dans le dossier <em>modules</em> (actuellement à la racine de votre installation Drupal 8) et activez-le dans <strong>/admin/modules</strong>.</p>
<p>Ensuite, rendez-vous sur <strong>/admin/config/development/loremipsum</strong> et entrez votre propre jeu de phrases pour générer un texte aléatoire (ou utilisez le Lorem ipsum par défaut).</p>
<p>Enfin, visitez <strong>www.example.com/loremipsum/generate/P/S</strong> oĂą :</p>
<ul>
<li><em>P</em> est le nombre de <em>paragraphes</em></li>
<li><em>S</em> est le nombre maximal de <em>phrases</em></li>
</ul>
<p>Il existe aussi un bloc générateur où vous pouvez choisir le nombre de paragraphes et de phrases, et il s'occupe du reste.</p>
<p>Si nécessaire, il existe aussi une permission spécifique <em>generate lorem ipsum</em>.</p>
<h3>Attention</h3>
<p>La plupart des bugs ont été corrigés, les failles bouchées, des fonctionnalités ajoutées. Mais ce module est en cours de développement. Merci de rapporter bugs et suggestions, ok ?</p>
');
}
}
Il est bon de placer ici au moins un appel Ă hook_help(). Notez aussi l'instruction use qui importe la classe RouteMatchInterface. Ceci est principalement dĂ» au fait que hook_menu() n'existe plus.
… Et en avançant, vous verrez que le fichier .module servira aussi à contenir des informations de thème. Gardez cela en tête.
loremipsum.install
<?php
/**
* @file
* Fonctions d'installation pour le module Lorem ipsum.
*/
use Drupal\user\RoleInterface;
/**
* Implémente hook_install().
*/
function loremipsum_install() {
user_role_change_permissions(RoleInterface::ANONYMOUS_ID, array(
'generate lorem ipsum' => TRUE,
));
}
Ici, on utilise une autre classe : RoleInterface. Essentiellement, ce fichier informe Drupal : « Dès que ce module est activé, trouvez la permission 'generate lorem ipsum' et activez-la ».
Mais où cette permission est-elle définie ?
loremipsum.permissions.yml
generate lorem ipsum:
title: 'Générer du Lorem ipsum'
Comme vous le voyez, c'est bien plus simple que d'implémenter hook_permission(). La syntaxe complète est documentée dans la documentation de PermissionHandler.
loremipsum.routing.yml
loremipsum.generate:
path: '/loremipsum/generate/{paragraphs}/{phrases}'
defaults:
_controller: '\Drupal\loremipsum\Controller\LoremIpsumController::generate'
requirements:
_permission: 'generate lorem ipsum'
loremipsum.form:
path: '/admin/config/development/loremipsum'
defaults:
_form: '\Drupal\loremipsum\Form\LoremIpsumForm'
_title: 'Paramètres Lorem ipsum'
requirements:
_permission: 'administer site configuration'
Le fichier de routage remplace l’appel à hook_menu(). Chaque entrée (sans indentation) définit une route avec des lignes indentées détaillant ses paramètres spécifiques.
La route loremipsum.generate définit une page qui accepte deux arguments entre accolades {}; elle correspond à un contrôleur (plus tard expliqué), tandis que loremipsum.form correspond à un formulaire de configuration avec un titre.
Les deux routes requièrent des permissions, mais vous pouvez les remplacer par _access: 'TRUE' pour un accès libre.
loremipsum.services.yml
Permet de déclarer un service personnalisé.
loremipsum.links.menu.yml
loremipsum.form:
title: 'Paramètres Lorem Ipsum'
description: 'Configurer les paramètres du module Lorem Ipsum.'
route_name: loremipsum.form
parent: 'system.admin_config_development'
Alors que le fichier de routage crée la page à /admin/config/development/loremipsum, ces définitions sont nécessaires pour ajouter les pages dans le menu Administration.
loremipsum.links.task.yml
Définitions pour créer des tâches locales (onglets) supplémentaires pour une route donnée.
loremipsum.links.action.yml
Définitions pour créer des actions locales (boutons) supplémentaires pour une route donnée.
loremipsum.links.contextual.yml
Définitions pour créer des actions contextuelles supplémentaires pour un élément de l’interface utilisateur.
loremipsum.libraries.yml
Utilisé pour déclarer les dépendances aux bibliothèques CSS et Javascript. Plus de détails dans la documentation correspondante.
README.md
Décompressez dans le dossier *modules* (actuellement à la racine de votre installation Drupal 8) et activez-le dans `/admin/modules`.
Puis rendez-vous sur `/admin/config/development/loremipsum` et entrez votre propre série de phrases pour générer un texte aléatoire (ou utilisez le Lorem ipsum par défaut).
Enfin, visitez `www.example.com/loremipsum/generate/P/S`, oĂą:
- *P* est le nombre de *paragraphes*
- *S* est le nombre maximal de *phrases*
Il existe aussi un bloc générateur où vous pouvez choisir combien de paragraphes et de phrases, et il fera le reste.
Si besoin, une permission spécifique *generate lorem ipsum* est disponible.
Attention
---------
La plupart des bugs ont été corrigés, les failles comblées, des fonctionnalités ajoutées. Mais ce module est toujours en cours de développement. Merci de signaler bugs et suggestions, ok ?
Oui, les fichiers README sont désormais écrits au format Markdown. Plutôt cool, si vous me demandez.
Passons maintenant aux dossiers pour examiner plus en détail certains aspects.
LICENSE.TXT
N’incluez pas de fichier LICENSE.txt (ou équivalent). Le script de packaging l’ajoutera automatiquement.
/config/install/loremipsum.settings.yml
loremipsum:
page_title: 'Lorem ipsum'
source_text: "Lorem ipsum dolor sit amet, consectetur adipisci elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum."
Ce fichier contient les paramètres par défaut qui sont assignés aux champs correspondants via le fichier suivant :
loremipsum:
page_title: 'Lorem ipsum'
source_text: "Lorem ipsum dolor sit amet, consectetur adipisci elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. \nUt enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. \nDuis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. \nExcepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum."
Ce fichier contient les paramètres par défaut qui sont assignés aux champs correspondants via le fichier suivant :
/config/schema/loremipsum.schema.yml
loremipsum.settings:
type: config_object
label: 'Paramètres Lorem Ipsum'
mapping:
loremipsum:
type: mapping
mapping:
page_title:
type: text
label: 'Titre de la page du générateur Lorem ipsum :'
source_text:
type: text
label: 'Texte source pour la génération de lorem ipsum :'
block.settings.loremipsum_block:
type: block_settings
label: 'Bloc Lorem ipsum'
mapping:
loremipsum_block_settings:
type: text
label: 'Paramètres du bloc Lorem ipsum'
Le fichier de schéma est utilisé même si vous ne définissez pas de table personnalisée pour votre module — ici vous pouvez voir les valeurs par défaut assignées aux champs du formulaire de configuration.
En développant ce code, j’ai découvert que préremplir les champs était l’une des tâches les plus complexes. Heureusement, il existe un module pour cela : Configuration Inspector pour Drupal 8, qui vous aidera à déboguer les paramètres par défaut.
De plus, le fichier de schéma YML est très utile à bien des égards.
/src/Controller/LoremIpsumController.php
<?php
namespace Drupal\loremipsum\Controller;
// Modification suivant https://www.drupal.org/node/2457593
// Voir https://www.drupal.org/node/2549395 pour les méthodes dépréciées
// use Drupal\Component\Utility\SafeMarkup;
use Drupal\Component\Utility\Html;
// Utiliser Html au lieu de SafeMarkup
/**
* Routines du contrĂ´leur pour les pages Lorem ipsum.
*/
class LoremIpsumController {
/**
* Construit le texte Lorem ipsum avec des arguments.
* Ce callback est mappé au chemin
* 'loremipsum/generate/{paragraphs}/{phrases}'.
*
* @param string $paragraphs
* Le nombre de paragraphes à générer.
* @param string $phrases
* Le nombre maximal de phrases pouvant être générées dans un paragraphe.
*/
public function generate($paragraphs, $phrases) {
Nous arrivons au cœur du module, une classe avec une unique méthode générant le texte de remplissage. Comme vous voyez, la méthode dans la classe LoremIpsumController correspond à l'entrée dans le fichier YAML de routage :

Le cadre blanc montre le code du fichier loremipsum.routing.yml et l’arrière-plan montre le fichier avec lequel nous travaillons.
Continuons, le fragment de code suivant récupère les paramètres du module et les sauvegarde pour une utilisation ultérieure :
// Paramètres par défaut.
$config = \Drupal::config('loremipsum.settings');
// Titre de la page et texte source.
$page_title = $config->get('loremipsum.page_title');
$source_text = $config->get('loremipsum.source_text');
Les paramètres mentionnés ci-dessus (loremipsum.page_title et loremipsum.source_text) proviennent du fichier YAML de configuration :

Puis on éclate les phrases de $source_text en un tableau :
$repertory = explode(PHP_EOL, $source_text);
Et on utilise ce tableau pour construire les paragraphes :
$element['#source_text'] = array();
// Générer X paragraphes avec jusqu'à Y phrases chacun.
for ($i = 1; $i <= $paragraphs; $i++) {
$this_paragraph = '';
// Quand on dit "jusqu'Ă Y phrases", on ne veut pas dire "de 1 Ă Y".
// On commence donc à la moitié.
$random_phrases = mt_rand(round($phrases / 2), $phrases);
// Ne pas répéter la dernière phrase.
$last_number = 0;
$next_number = 0;
for ($j = 1; $j <= $random_phrases; $j++) {
do {
$next_number = floor(mt_rand(0, count($repertory) - 1));
} while ($next_number === $last_number && count($repertory) > 1);
$this_paragraph .= $repertory[$next_number] . ' ';
$last_number = $next_number;
}
//$element['#source_text'][] = SafeMarkup::checkPlain($this_paragraph);
$element['#source_text'][] = Html::escape($this_paragraph);
}
Notez que ['#source_text'] est un tableau rendu transmis au template, et que chaque élément passe par Html::escape() pour la sécurité.
Enfin, on donne un titre à notre tableau rendu, on assigne la fonction thème et on le retourne :
//$element['#title'] = SafeMarkup::checkPlain($page_title);
$element['#title'] = Html::escape($page_title);
// Fonction thème.
$element['#theme'] = 'loremipsum';
return $element;
}
}
Mais avant de passer ces variables à notre template, il faut s’en occuper.
Étape suivante ;
Thématiser le module.
Puis ;
Ajouter un formulaire de configuration.
Définir un bloc pour ce module.
Écrire des tests pour ce module.