Créer un module pour Drupal
Une des grandes forces de Drupal réside en son architecture à base de modules. Que ce soit pour la gestion des blogs ou celle d’un forum, chaque fonction fondamentale est en réalité un simple module interagissant avec le cœur de Drupal. Et si les modules fournis en standard ne suffisent pas, des centaines d’autres sont disponibles couvrant à peu prés tous les usages.
Mais malgré cette richesse, il arrive parfois que l’on ne trouve pas LE module « qui va bien ». Alors pourquoi ne pas le fabriquer soi-même et ainsi découvrir à quel point Drupal s'adapte facilement à des besoins spécifiques.
Pré-requis
Les seuls pré-requis pour développer un module sont une bonne connaissance des concepts clés de Drupal (blocks, node, type de contenu, taxinomie, etc.) ainsi qu'une relative maîtrise de PHP et des bases de données.
Armé de tout cela, nous allons commencer en douceur avec la création d'un module dont le seul but est de modifier à l'affichage tous nos nodes pour y ajouter un petit message.
Les sources
L'ensemble des sources de ce tutoriel est disponible ici.
Pourquoi faire son module ?
Ainsi la grande majorité des fonctions CMS de Drupal sont à la charge des modules, y compris les fondamentaux comme la gestion des nodes, des commentaires, des flux rss, etc. Et comme un système d'exploitation standard, le noyau et les modules disposent d'un ensemble de fonctions spécialisées et groupées par famille (cache, courriels, transactions HTTP, images, etc.), permettant tant d'accélérer le développement en évitant la duplication de code que de réduire le nombre de failles.
Une fois le travail achevé, généralement lorsque la page HTML est produite, le noyau Drupal va éteindre puis décharger les modules, pour finalement s'arrêter. A ce stade, la différence avec un système d'exploitation classique est que Drupal effectue ce cycle démarrage/chargement/traitements/déchargement/arrêt à chaque requête d'un navigateur WEB.
Dans ce type d'architecture, la nature distribuée des traitement entraîne un fort volume d'échange entre entre modules. Ce point constitue généralement le goulot de performance des micro-noyaux. Avec Drupal le problème est réglé assez brutalement par l'utilisation de simples appels de fonctions. Il n'y a donc pas de pénalités particulières à cette approche et Drupal n'est pas pour rien un des CMS les plus véloce de sa catégorie.
Toujours est-il que cette approche "modulaire" depuis l'origine a eu pour résultat une extrême richesse des fonctions que les modules peuvent exploiter. Contrairement aux CMS qui utilisent une vision "greffons" et qui prévoient les points d'attache possibles, Drupal n'est au fond que points d'attache. Il est ainsi très rare de ne pas pouvoir modifier son comportement par un module correctement développé.
Tout cela pour dire que les modules étant un des grands atouts de ce CMS, il serait dommage de se limiter à ceux fabriqués par les autres tant il est si facile de fabriquer les siens, totalement adaptés à ses besoins. Et plus loin encore, tous les modules de Drupal étant sous licence GPL, savoir en fabriquer c'est aussi savoir en modifier pour récupérer par exemple une fonction voulue plutôt que d'embarquer l'usine à gaz au grand complet...
Des modules et des hooks
Un module Drupal n'est rien d'autre qu'un bout de code PHP que l'on peut activer ou désactiver à volonté et dont le seul rôle est d'interagir avec les autres modules de Drupal.
Les interactions entre modules se font sur un mode participatif. En effet l'idée fondatrice est qu'au cours d'un de ses traitements, un module peut demander leur contribution à d'autres modules.
Pour réussir à mettre en oeuvre cette collaboration, Drupal a introduit le concept de "hooks" ou "crochets". Chaque module peut ainsi déclarer un nombre arbitraire de hooks disponibles pour les autres modules qui sont généralement décrits dans sa documentation. Dans notre exemple, le hook proposé par le module node s'appelle "link" et tous les modules qui veulent répondre à ce hook vont déclarer une fonction dont le nom sera composé du nom du module suivi du nom du hook, link, et séparés par un caractère souligné. Ainsi le module comments et le module print vont tout deux implémenter une fonction PHP de ce type avec comments_links d'un côté, et print_links de l'autre. Une telle implémentation ressemblera à ceci :
function comment_link($type, $node = NULL, $teaser = FALSE) {
$links = array();
...
}
Lorsque le module node va avoir besoin de la participation des modules pour ajouter ses liens, il va simplement demander à Drupal de prendre chaque nom de module activé pour regarder s'il existe une fonction composée de ce nom suivi de "_link". Ensuite Drupal va simplement appeler ces fonctions les unes après les autres. Du côté du module node, cet appel va ressembler à ceci :
$node->links = invoke_all('link', $node, $teaser);
invoke_all est la fonction drupal qui va chercher les fonctions hooks de type 'link' dans tous les modules activés et appeler cette fonction si elle existe avec les paramètres qui sont donné. Chaque module va ainsi fournir son tableau de liens que drupal va agréger pour fournir au module appelant, node, un seul tableau contenant tous les liens qui ont été ajoutés par tous ces modules.
Maintenant qui dit appel de fonction, dit paramètres. Il ne suffit donc pas de connaître le nom du hook pour pouvoir l'implémenter, encore faut-il savoir quels paramètres le module appelant va nous transmettre. Pour cela, il faut potasser la documentation de drupal. Ou alors, de manière beaucoup plus direct, il suffit de taper dans google hook_ suivi du nom du hook, par exemple hook_block. Çà marche à tout les coups. Faites cependant attention à bien sélectionner l'onglet correspondant à votre version de Drupal, car d'une version à l'autres les paramètres et les hooks eux-mêmes changent.
Structure d'un module
Organisation générale
Un module est donc un fournisseur de hooks. En conséquence, la majeure partie de son code va s'insérer dans les traitements de Drupal et étendre son comportement. Maintenant de manière plus prosaïque, un module est simplement un dossier qui contient au minimum deux fichiers.
Ce dossier doit porter le nom du module et doit être placé dans l'arborescence de Drupal, à un endroit qui soit approprié pour que ce dernier puisse le voir. Techniquement il est possible de les mettre dans modules/ mais vous seriez vite embêtés lorsque viendra le temps de mettre à jour votre Drupal. Il est donc préconisé de mettre cela dans un dossier sites/all/modules/mes_modules que vous créerez si nécessaire. Ainsi lorsque vous changez de version, il suffit de déplacer le dossier sites à sa place dans la nouvelle arborescence.
Dans ce dossier mes_modules, vous allez donc créer le sous-dossier du module lui-même, dans notre cas tutoriel-modules. A l'intérieur de celui-ci, vous devez avoir au minimum deux fichiers, portant le même nom de base que le dossier parent : tutoriel-modules.info et tutoriel-modules.module. Comme nous allons le voir plus loin, le premier fichier contient des informations sur le module, le second son code PHP. Tout ceci nous donne l'arborescence suivante :
modules
... etc ...
site
all
modules
contributions
...etc...
mes_modules
tutoriel-modules
tutoriel-modules.info
tutoriel-modules.module
...etc...
themes
...etc...
Fichier .info
Le fichier tutoriel-modules.info est un simple fichier texte contenant des informations sur le module comme son nom, sa description, la version de Drupal avec lequel il est compatible, etc. Ce qui nous donne pour notre exemple, le contenu suivant :
name = "Modules"
description = "Code des tutoriels - les modules."
project = "tutoriel_modules"
version = "6.x-1.0"
core = 6.x
package indique dans quelle catégorie le module doit être affiché. name, description sont des informations textuelles qui seront affichées dans le panneau d'administration des modules. name reprend le nom du module (qui est aussi le nom du dossier). version indique quant à lui la version du module. C'est d'ailleurs plus une norme qu'autre chose qui se lit "Module version 0.1 pour Drupal 6.x". Enfin core prévient Drupal que le module est seulement compatible avec sa version 6.x. Tout autre version de Drupal empêchera le module de s'activer.
Si nous avions eu besoin de définir une dépendance avec un autre module, nous aurions ajouté une clause de la forme dependencies[] = autre_module. Enfin, si vous désirez ajouter des commentaires, il suffit d'utiliser le symbole ; suivi du texte du commentaire.
Fichier .module
Le second fichier est le code PHP du module. C'est lui qui va héberger les hooks que nous souhaitons implémenter. Pour l'instant, nous allons faire simple et n'en mettre aucun. Notre fichier va donc contenir une simple balise de démarrage de code PHP :
<?phptutoriel_modules.module
Nous avons maintenant un module complet et inutile mais que Drupal est cependant capable de voir et d'activer. Pour s'en convaincre, il suffit d'aller faire un tour en /admin/build/modules pour le voir apparaître dans la liste. Vous constatez que les informations affichées sont les champs name et description de notre fichier tutoriel_modules.info.
A ce stade nous pourrions donc activer notre module, mais ne le faites pas tout de suite, nous avons encore quelque chose à rajouter.
Implémentation d'un hook
Ce module n'a pas d'autre but que de nous permettre de comprendre comment tout cela fonctionne, aussi ne vous attendez pas à un comportement extraordinaire. Nous allons simplement utiliser le hook link du module node.modules dont nous parlions plus haut pour ajouter à chaque node un nouveau lien "modifier" qui permettra d'éditer le contenu du node courrant.
Comme nous l'avons vu, le hook link est défini de la manière suivante dans la documentation drupal :
hook_link($type, $object, $teaser = FALSE)hook 'link'
Ce qui veut dire que nous allons devoir ajouter à notre fichier tutoriel_modules.module une fonction définie comme ceci :
function tutoriel_modules_link($type, $object, $teaser = FALSE) {
...
}fonction hook_link
Notre implémentation du hook est bien nommée {nom_du_module}_{nom_du_hook}, Drupal le reconnaîtra donc lorsque le module node aura besoin de l'appeler.
Même si ce n'est pas directement le sujet de cet article, ce hook est trés pratique pour ajouter de nouveaux liens sous les nodes, mais aussi sous les commentaires. En effet, le paramètre $type permet de faire la distinction entre le type de lien demandé par $type=="comment" ou $type=="node". Le second paramètre $object sera donc soit un node, soit un commentaire selon la valeur de $type, mais ici c'est le type "node" qui nous intéresse.
Le dernier paramètre permet quant à lui de savoir si le lien est désiré sous le node dans la forme contractée (teaser), comme par exemple sur la page de garde du site, ou sous sa forme complète. Nous avons maintenant tout ce qu'il nous faut pour ajouter un lien à tous les nodes en mode "teaser" comme "complet".
function tutoriel_modules_link($type, $object, $teaser = FALSE) {
// Seulement si l'utilisateur a les droits d'administration
if (!user_access("administer site configuration")) {
return;
}
$links = array ();
// Si l'objet est un node
if ($type == 'node') {
// On ajoute un nouveau lien
$links['editer-node'] = array (
'title' => t('Edit'),
'href' => "node/" . $object->nid . "/edit"
);
}
// On renvoie les liens au module "node"
return $links;
}
La première chose que nous faisons ici est de vérifier que l'utilisateur a bien le droit de modifier le contenu. Si nous ne le faisons pas le lien serait visible y compris pour les visiteurs anonymes. Même si ces derniers aboutiraient sur une erreur 403 ce ne serait pas très élégant.
Ensuite, une fois que nous nous somme assuré que la demande vise bien un node, il suffit de créer un tableau associatif contenant une série de tableaux représentant chacun un lien. Ici nous n'en avons qu'un mais rien n'empêche d'en mettre plusieurs. Dans tous les cas c'est Drupal qui se charge de transformer ce tableau en la balise <A href="..." qui va bien. Ce tableau reprend peu ou prou les arguments de la fonction Drupal l(...) que vous pouvez étudier ici.
Notez que l'on ne met pas de slash au début de l'attribut href. Ceci permet à la fonction Drupal l(...) de choisir toute seule la meilleur représentation pour l'URL. Du coup si vous utilisez le module Alias ou l'internationalisation, l'URL sera modifiée pour correspondre à vos réglages.
Pour finir, un dernier regard sur la fonction t(...) qui est la formule magique permettant à Drupal de traduire le mot anglais edit dans la langue courante de l'interface. Une bonne habitude à prendre dés le début.
Conclusion
Voilà, nous avons terminé notre premier module fonctionnel en espérant que vous avoir montré à quel point, une fois quelques notions de base assimilées Drupal, construire ce genre de brique est rapide et facile.
Simple et efficace comme d'hab!!
C'est exactement ce que je cherchais, et tu viens nous le servir sur un plateau! Je m'en vais l'essayer illico!
Un GRAND merci !
Merci :) J'ai fait une petite mise à jour aidée par un ami et le tuto devrait être un peu plus cohérent maintenant (changement de l'exemple)
Excellent article, je m'en servirai la prochaine fois que je devrai expliquer ce qu'est Drupal (un ensemble de point d'attache) ou ce qu'est un module (un fournisseur de hook).
A quand la rédaction d'un Pro Drupal Dev à la française ?
Merci Alex :) Là je suis parti pour au moins une dizaine de tuto sur le sujet (les sources sont déjà dans le dépôt). On va déjà commencer cela. Un bouquin c'est une autre paire de manches :-)
Bonjour et merci pour ces explications, ma vision des modules s'éclaircit !
Par contre, en suivant le tutoriel, je ne parviens pas à créer le module ...
Déjà, il ne s'affiche pas dans la liste des modules, (j'ai essayé en le mettant dans le rep modules et dans le sous-rep mes_modules, sans résultat).
Par contre, dans le code du node.module, la fonction module_invoke_all('link' ....) n'a pas 3 mais 4 paramètres. Qu'est ce que cela change ?
$node->links = module_invoke_all('link', 'node', $node, $teaser);
Merci
Leula
L'invocation a pour premier paramètre le nom du hook, donc le hook a bien trois paramètres, ceux qui suivent 'link'.
Dans tous les cas, si ton module ne s'affiche pas dans la liste, il y a 9 chances sur 10 pour que ce soit un problème de nommage. Vérifie que tu as bien les fichiers modules (.info et .module) qui ont exactement la même orthographe que leur dossier conteneur. Et que dans le fichier .info le champ "project" a lui aussi cette même orthographe.
merci pour ces eclairecissement
Bravo pour ce tutoriel !
Je suis en train de faire connaissance avec DRUPAL et ça m'a permis de comprendre un peu comment il fonctionnait. Je vais suivre la suite avec intérêt.
merci :)
A ce propos, il ne faut pas s'étonner si l'article a disparu, j'ai fait une grande vague de transfert de contenu de tout ce qui touche à Drupal sur un site à par. Artisan va donc reprendre une orientation plus linuxesque :-)
Le lien pour le retrouver est donné en haut de page.
Bizarre, j'ai fait du copier coller de ton tutoriel et ça ne fonctionne pas, lorsque j'active le module j'ai une page blanche qui s'affiche, lorsque je recharge la page le module est activé mais lorsque je consulte un noeud le lien n'apparait nulle part.
(Pourtant j'ai tout copié collé !)
Une idée ?
Hum, étrange en effet, je viens de l'activer chez moi pour vérifier et cela fonctionne correctement. Peut-être une erreur dans le copier-coller à partir d'un navigateur ? Tu peux aller à cette adresse http://www.arnumeral.fr/subversion/public/tutoriels_drupal/tutoriel_modules qui contient très exactement le module que j'active chez moi.
Si cela ne marche toujours pas, désactive le module, ré-active le et essaye de regarder les erreurs dans tes logs apache, si cela se trouve ça va te donner une explication sur ce qui a planté pendant l'enregistrement du module.
Je pense en fait que cela vient plus du fait qu'il y ait un sous-dossier, j'ai remonté d'un niveau et ça fonctionne...
Du veux dire un sous-dossier "tutoriels/module_tutoriel" ? Si c'est le cas, j'aurais plus tendance à penser à un problème de droit de lecture sur tes dossiers pour apache, non ?
bonjour ce tuto peut il marcher pour un drupal en version 5.7 ?
Sans trop de problème, en enlevant "core" du .info et en adaptant le hook_link comme indiqué ici : http://api.drupal.org/api/function/hook_link/5
bonjour,
j'ai un petit souci, le module apparait dans la liste /admin/build/modules , je l'ai activé, mais je n'ai pas de résultats dans le node... comme si le module n'était pas prit en contre.
J'ai fais de copier coller du code source, j'ai vérifié ma syntaxe, j'ai vérifié les droits d'accès au fichiers, tout mes chemins son correct.
qui aurait une solution pour moi :) ????
probleme résolu ... probleme de drupal fichier corrompu
Merci pour tous ces tutoriels.
Pour le moment j'en ai lu deux et c'est très clair. J'ai juste qq dificultés à les remettre dans l'ordre. Je poste donc ce commentaire ici dans le premier de la série.
Pour le moment j'ai :
Ensuite j'ai un trou. Je pense qu'il y a un tuto au sujet d'un module courses, mais je ne le trouve pas. Il y a un lien vers http://arnumeral.fr/node/1561 qui ne marche pas dans "Créer un module Drupal : AHAH et formulaires dynamiques"
Ensuite je ne sais plus très bien, mais je pense que c'est :
Pouriez-vous faire un récapitulatif de tous les tuto dans l'ordre ?
C'est justement ce que je suis en train de faire. Je vais réorganiser cela au fur et à mesure dans ce "livre" :
http://arnumeral.fr/fabriquer-ses-propres-modules-pour-drupal
Bonjour,
J'ai un petit soucis comme la personne deux commentaires plus haut je m'explique :
J'ai créé le module comme indiqué en copiant collant le code source, vérifiant la syntaxe, activé le module dans la liste des module, pas de soucis de ce côté là.
En revanche quand je créé un contenu aucun lien "modifié" n'apparait. Est-il possible d'avoir plus de précisions concernant "probleme de drupal fichier corrompu".
Je suis ouvert à toute autre idée qui pourrait m'aider.
bravo ! tuto clair, bien illustré !
Excellent tutoriel : simple, clair et précis ! Merci de partager ces précieuses infos, ça donne envie de créer des modules !
Sympa ce ptit tutorial, ca me fait penser qu'il faudrait que jm'y mette...
Feras tu des tutoriaux sur Drupal7?
Et Porteras tu les anciens sur D7 aussi?
Merci pour toutes tes connaissances et ton livre est un véritable bonheur.
merci :)
Sinon oui pour le tutoriaux, mais sûrement dans l'ordre inverse. J'ai pas mal d'inquiétudes sur drupal 7, et porter ces tutoriaux va me permettre de les dissiper, ou de les confirmer.
Bonjour,
merci pour ce tuto très bien expliqué et pourtant j'ai tout de même un problème... :(
J'ai bien créé mon dossier mes_modules et bien créé mes fichier .info et .module (Je fait du copier coller).
Dans l'admin Drupal quand je vais dans le menu Constrcution du site/modules, et bien mon module ne s'affiche pas...Je ne peux pas l'activer.
Une idée? est-ce un problème de droit?
Merci d'avance!
Re bonjour,
J'ai trouvé mon problème très idiot de ma part... j'avais créé mon dossier mes_modules au même niveau que le dossier modules.
:) Merci quand même !
Merci pour ce tuto. Cependant j'ai rencontré qlqs petits problèmes car le hook 'hook_link' est deprecated sur drupal 7 et devient hook_node_view. Voir ci-dessous les petites modifications à apporter pour drupal 7.
helloword.module
<?php
function helloworld_node_view($node, $view_mode) {
Seulement si l'utilisateur a les droits d'administration
if (!user_access("administer site configuration")) {
return;
}
$links = array ();
// Si l'objet est un node
// On ajoute un nouveau lien
$links['editer-node'] = array (
'title' => t('Edit'),
'href' => "node/" . $node->nid . "/edit"
);
if (!empty($links)) {
$node->content['links']['helloworld'] = array(
'#theme' => 'links',
'#links' => $links,
'#attributes' => array('class' => array('links', 'inline')),
);
}
}
j'ai un souci ,j'ai creé le module mais il s'affiche pas dans la listes des module ,j'utilise drupal 7.8 (j'ai change la version dans le fichier .info) aidé moi
mecri a l'avance
T'as résolu ton probleme Fafa ? Je suis confronté à la même chose ça gonfle :-)
Bonjour ,
oui j'ai resolu mon probléme voici le code de mom fichier .info
; $Id$
name = exemple de module
description = Ceci est un module d’exemple
package = Web à part
version = VERSION
core = 7.x
version = "7.8"
et j'ai met le module dans les repertoire ./sites/all/modules/custom
bon courage
Bonjour,
merci, cela m'a un peu éclairé. Je suis actuellement sur un projet . Mias voilà je suis blocké. Je voudrais insérer un champ datepicker dans un type de contenu, mais avec une option supplémentaire pour ce champ, il faudrait que je puisse saisir une valeur pour chaque date pour ma partie admin et que dans la partie frontoffice j'ai un tableau avec mes dates sur une semaine et que sous chaque date je vois le nombre que j'ai saisi dans l'admin.
Comment dois-je m'y prendre, est-ce que je dois recréer un module spécifique ou plusieurs modules pourraient faire cela?
D'avance merci pour votre réponse.
Cordialement
Publier un nouveau commentaire