Créer un module Drupal : le type de contenu
Le 24 mai 2008, à 20:52 par Ulhume...

Dans le précédent tutoriel nous avons vu comment créer un module simple comprenant les notions de hooks et la méthode unifiée d'accès à la base de données. Il est maintenant temps de passer au stade au dessus avec un module prenant cette fois en charge un type de contenu totalement personnalisé.

L'ensemble des sources de ce tutoriel est disponible via subversion.

Où allons nous ?

Le but de ce module est simplement de gérer une liste de courses. Il s'agira en quelque sorte de la version moderne du tableau sur le réfrigérateur, amélioré d'une petite gestion des réserves. Le module permettra :

  • L'enregistrement, la modification et la suppression d'un produit. Un produit étant défini par son nom, sa quantité en réserve et la valeur seuil devant déclencher son rachat.
  • L'affichage de la liste des produits. Chaque produit devant être racheté sera surligné. Sur chaque ligne, seront disposées deux actions, l'une permettant de le modifier, l'autre de décrémenter la quantité de produit restant d'une unité.

Avant de commencer, il nous faut créer un dossier pour notre module et les deux fichiers de bases courses/courses.info et courses/courses.module. Prenez pour exemple ceux que nous avons créé pour le module statistiques en le laissant dans le fichier .module aucun code autre que la balise de démarrage PHP.

Installation

Notre module courses a pour finalité de pouvoir saisir des produits et de les présenter sous la forme d'une liste. Nous pourrions pour cela utiliser un type de contenu simple comme story mais cette structure de stockage serait trop limitée car nous avons des informations plus précises à saisir que les seuls titre et corps. Il nous faut en effet spécifier le nombre de produits restants et le nombre minimum à avoir en réserve pour pouvoir générer notre liste de courses. Nous allons donc créer un nouveau type de node, produit, en cherchant à étendre le type de node simple.

Drupal stocke les données de base d'un node (titre, corps, etc.) dans la table node dont la clef primaire est le champ nid. Ce sont les valeurs de ce champ que vous retrouvez dans l'URL d'un node, sous la forme http://mon_site_drupal?q=/node/1234. Elle dispose aussi d'un champ type de type texte identifie le type du contenu. Dans notre cas ce type prendra la valeur produit.

Mais pour stocker nos informations supplémentaires, nous allons devoir créer une nouvelle table, traditionnellement nommée node_produit, contenant un champ quantité pour la quantité restante du produit et un champ seuil pour la valeur minimum à conserver en réserve. En outre elle disposera, elle aussi, d'un champ nid. Les informations sur un produit donné seront donc réparties sur les champs des deux tables à la fois (node et node_produit)reliées entre-elles par le même nid.

Du coup, pour obtenir toutes les informations disponibles sur un node de type produit, nous pouvons formuler la requête suivante :

SELECT n.*,i.* FROM node n, node_produit i WHERE n.nid=i.nid AND n.type='produit';

Alors nous pourrions évidemment créer cette nouvelle table à la main mais ce serait bien peu pratique lorsque viendra le moment de redistribuer ce module. La bonne pratique est donc de déléguer ce travail à Drupal lors de l'activation du module. De la même manière, nous allons lui indiquer comment la supprimer, lorsque le module est désactivé puis désinstallé.

Pour ce faire, il nous faut rajouter un troisième fichier à notre dossier module : courses.install qui va contenir deux hooks. Le premier, hook_install, est invoqué lors de la première activation du module (installation). Le second, hook_uninstall, est quant à lui invoqué lors de la désinstallation du module.

courses/courses.install
  1. <?php
  2.  
  3. /**
  4.  * Implementation of hook_install().
  5.  */
  6. function courses_install() {
  7.   $result= array ();
  8.   switch ($GLOBALS['db_type']) {
  9.     // Installation de la table pour MySQL
  10.     case 'mysql' :
  11.     case 'mysqli' :
  12.       $result[]= db_query("
  13.      CREATE TABLE {node_produit} (
  14.   nid int(10),
  15.        quantite int(10),
  16.        seuil int(10),
  17.        PRIMARY KEY (nid)
  18.        )");
  19.       break;
  20.  
  21.     // Installation de la table pour PostgreSQL
  22.     case 'pgsql' :
  23.       error_log("install on Psql");
  24.       $result[]=db_query("
  25.     CREATE TABLE {node_produit} (
  26.           nid INTEGER,
  27.           quantite INTEGER,
  28.           seuil INTEGER,
  29.           PRIMARY KEY (nid)
  30.         );");
  31.       break;
  32.   }
  33.   return $result;
  34. }
  35.  
  36. /**
  37.  * Implementation of hook_uninstall().
  38.  */
  39. function courses_uninstall() {
  40.   $result=array();
  41.   $result[]=db_query('DROP TABLE {node_produit}');
  42.   return $result;
  43. }

Le code n'a rien de compliqué mais quelques points cependant méritent éclaircissement.

Tout d'abord, nous distinguons deux cas qui correspondent aux deux bases de données prises en charge par Drupal : mySQL et PostgreSQL. En effet, si les bases de données sont à peu près équivalentes s'agissant des requêtes INSERT,DELETE,UPDATE et SELECT, c'est un peu moins le cas pour les commandes CREATE et ALTER.

Ensuite concernant l'exécution des requêtes SQL, nous devons à tout prix éviter d'utiliser les fonctions base de données de PHP au profit de celles fournies par Drupal. En effet ces dernières présentent l'avantage de faire abstraction de la base de données sous-jacente.

Dans le cas spécifique de l'installation et de la désinstallation, nous utilisons update_sql mais pour le reste du code elle sera remplacée par db_query. Ces deux fonctions sont pratiquement identiques à la différence près qu'update_sql fournit plus d'informations sur le déroulement de la requête. Informations qui seront utilisées par l'assistant d'installation et de mise à jour de Drupal.

Dernier point : les accolades utilisées pour encadrer le nom des tables. Elles ne sont pas nécessaires mais permettent à Drupal certaines opérations de préparation des requêtes. C'est donc juste une bonne habitude à prendre.

Maintenant que notre installation est finalisée, il ne nous reste plus qu'à activer notre module dans le panneau d'administration de Drupal : http://mon_site_drupal?q=/admin/build/modules. Une fois cette opération achevée, vous pouvez vérifier à l'aide de votre explorateur de base de données préféré que la table node_produit a bel et bien été créée. Si vous désactivez et réactivez votre module, notez que le code d'installation n'est pas ré-exécuté. En effet, il vous faut d'abord désinstaller le module, pour que le hook courses_uninstall soit appelé et détruise la table. Ensuite, si vous réactivez à nouveau le module, la table sera recréée.

Type de contenu

Notre base est prête, notre module activé et pourtant si nous allons sur l'URL http://mon_site_drupal/?q=node/add, notre produit n'apparaît pas. En effet, il faut implémenter deux hooks supplémentaires dans courses.module pour indiquer à Drupal qu'un nouveau type de node est à prendre en charge. Le premier hook, hook_node_info, va décrire le nouveau type de node :

à ajouter au fichier courses.module
  1. function courses_node_info() {
  2.   return array(
  3.     'produit' => array(
  4.       'name' => t('Un produit'),
  5.                 'description' => t("Un produit dans la liste des courses."),
  6.       'module' => 'courses'));
  7. }

Ce hook permet de renvoyer à Drupal une liste de nouveaux types de contenu. Ici nous n'en indiquons qu'un seul, produit, avec sa description et son nom usuel. L'identifiant produit sera utilisé dans la colonne type de la table node comme vu au chapitre précédent.

Le dernier paramètre correspond au nom du module qui va gérer ce type de contenu, en l'occurrence notre module courses<.kbd>.

Formulaire de saisie

Une dernière étape est nécessaire à l'apparition dans la liste de notre nouveau type de contenu : mettre en place le formulaire de saisie. Mais avant cela, il est important de bien comprendre comment Drupal fait vivre un node.

Un node est représenté dans le code de Drupal par l'objet $node. A chaque étape du cycle de vie du node, différents hooks viennent enrichir cet objet jusqu'à y ajouter le code HTML qui sera inséré dans la page. C'est ainsi que dans le template node.tpl.php, l'affichage du titre passe par une référence à $node->title.

Il existe une relation étroite entre l'objet $node et sa représentation en base de donnée. Si le node existe déjà, Drupal transfère les valeurs correspondantes de la table node vers les champs de l'objet $node. Les identifiants de chaque colonne deviennent ainsi les noms d'attributs de l'objet. Lorsque le node n'existe pas encore, Drupal crée simplement un objet vide. C'est donc soit l'objet vide, soit l'objet chargé des valeurs en base, que nous allons récupérer dans le hook qui va créer notre formulaire, hook_form.

Ce hook est chargé de créer le formulaire mais aussi de l'initialiser avec les valeurs de l'objet $node. Ce formulaire sera soit utilisé sur un objet vide ou soit sur contenant les données d'un contenu existant.

Corps de la fonction courses_form
  1. function courses_form(& $node)
  2. {
  3.   $form['title']= array (
  4.     '#type' => 'textfield',
  5.     '#title' => t("Nom du produit"),
  6.     '#default_value' => $node->title,
  7.     '#required' => TRUE
  8.   );
  9.   $form['body_filter']['body']= array (
  10.     '#type' => 'textarea',
  11.     '#title' => t('Notes'),
  12.     '#description'=>t("Notes sur le produit"),
  13.     '#default_value' => $node->body,
  14.     '#rows' => 10,
  15.     '#required' => FALSE);
  16.   $form['body_filter']['format']= filter_form($node->format);
  17.  
  18.   $form['seuil'] = array(
  19.     '#type' => 'textfield',
  20.     '#title' => t("Seuil d'achat"),
  21.     '#description'=>t("Quantité minimum en dessous de laquelle il faut racheter le produit"),
  22.     '#size' => 4,
  23.     '#required' => TRUE,
  24.     '#default_value' => $node->seuil
  25.   );
  26.  
  27.  
  28.   $form['quantite'] = array(
  29.     '#title' => t("Quantité"),
  30.     '#description'=>t("Quantité de produit restant en réserve"),
  31.     '#type' => 'textfield',
  32.     '#size' => 4,
  33.     '#required' => TRUE,
  34.     '#default_value' => $node->quantite
  35.   );
  36.  
  37.   return $form;
  38. }

Ici, rien de nouveau par rapport au formulaire que nous avions définit pour le module statistique. Il est juste un peu plus complet mais fonctionne exactement sur le même principe.

Comme nous l'avons vu plus haut, l'objet $node est vide à sa création. Si nous l'utilisons tel quel, les champs quantité et seuil seront vides (et non égal à 0). Il est donc nécessaire d'implémenter un nouveau hook, hook_prepare, qui a pour rôle de préparer l'objet $node avant utilisation dans le formulaire.

à ajouter au fichier courses.module
  1. function courses_prepare(& $node) {
  2.   $node->quantite=$node->quantite?$node->quantite:0;
  3.   $node->seuil=$node->seuil?$node->seuil:0;
  4. }

Grâce à cette fonction, nous initialisons notre objet $node avec les bonnes valeurs par défaut. De la même manière nous pouvons valider ce que renvoie le formulaire en implémentant cette fois hook_validate

à ajouter au fichier courses.module
  1. function courses_validate($form_id, $form_values) {
  2.   if (!is_numeric($form_values['quantite']) || $form_values['quantite'] < 0) {
  3.     form_set_error('quantite', t('Le champ quantité doit être une valeur numérique et positive'));
  4.   }
  5.   if (!is_numeric($form_values['seuil']) || $form_values['seuil'] < 0) {
  6.     form_set_error('seuil', t('Le champ seuil doit être une valeur numérique et positive'));
  7.   }
  8. }

Ici nous cherchons juste à nous assurer que les valeurs saisies sont numériques et positives. Maintenant notre formulaire est complet. Nous pouvons l'essayer en utilisant l'URL http://mon_site_drupal?q=/node/add/produit.

Base de données

Nous avons maintenant un objet $node correctement renseigné par notre formulaire. Il ne nous reste donc plus qu'à coder sa sauvegarde en base de données. Pour ce faire, nous allons devoir implémenter quatre hooks, un par commande SQL.

Commençons par le plus simple : la lecture. Elle est prise en charge par le hook hook_load :

à ajouter à courses.module
  1. function courses_load($node) {
  2.   return db_fetch_object(db_query('SELECT * FROM {node_produit} WHERE nid = %d', $node->nid));
  3. }

hook_load reçoit en paramètre un objet $node contenant déjà des informations extraites de la table node. Cela inclut le nid que nous utilisons dans notre requête pour lire en base nos valeurs supplémentaires. L'objet ainsi formé est renvoyé à Drupal qui l'agrégera à l'objet $node. Les fonctions de base de donnée utilisées ici sont les mêmes que celles abordées dans le précédent tutoriel.

Voyons maintenant comment insérer, mettre à jour ou encore détruire nos données supplémentaires en implémentant respectivement hook_insert, hook_update et hook_delete :

à ajouter à courses.module
  1. function courses_insert($node) {
  2.   db_query("INSERT INTO {node_produit} (nid, quantite, seuil) VALUES (%d, %d, %d)", $node->nid, $node->quantite, $node->seuil);
  3. }
  4.  
  5. function courses_update($node) {
  6.   db_query("UPDATE {node_produit} set quantite=%d, seuil=%d WHERE nid=%d", $node->quantite, $node->seuil, $node->nid);
  7. }
  8.  
  9.  
  10. function courses_delete(&$node) {
  11.   db_query('DELETE FROM {node_produit} WHERE nid = %d', $node->nid);
  12. }

Notre nouveau type de contenu implémente maintenant tous les hooks nécessaires à son stockage en base de données. Nous pouvons maintenant créer un nouveau produit, saisir ses valeurs, le sauvegarder, le modifier, et le détruire.

Affichage

La première chose que l'on constate une fois que l'on a saisi et validé notre premier produit est que les informations affichées n'incluent ni la quantité, ni le seuil de rachat. Ne sont présentes que les données d'un node standard. Pour changer cela, nous allons implémenter un nouveau hook, hook_view, et une fonction de thème.

à ajouter à courses.module
  1. function courses_view($node, $teaser = FALSE, $page = FALSE) {
  2.   $node= node_prepare($node, $teaser);
  3.   if ($page) {
  4.     $node->content['Informations'] = array(
  5.         '#value' => theme('produit_view', $node),
  6.         '#weight' => 1,
  7.     );
  8.   }
  9.   return $node;
  10. }

Notre première tâche est de préparer le node à l'affichage. C'est le rôle de la fonction node_prepare qui va appliquer les filtres d'entrée au corps et fabriquer le résumé (teaser).

Une fois le node préparé, nous vérifions dans quel contexte nous sommes appelé pour n'inclure nos informations supplémentaire que lorsque Drupal a besoin du node en entier (mode page) et pas seulement du résumé (mode teaser).

Si nous sommes bien en mode page, nous pouvons ajouter à l'objet $node des sections $node->content[]. Ces sections seront affichée par Drupal après le titre et le corps du node. Chacune d'entre elles est composée d'un contenu HTML (propriété #value) et d'un ordre d'apparition (propriété #weight).

Pour renseigner #value nous avons rajouté une petite finesse : l'utilisation d'une fonction de thème theme('courses_view', $node). Cela consiste à demander à Drupal d'habiller l'objet $node avec le thème courses_view. La fonction en interne va procéder de la manière suivante :

  • Si votre site a un thème, par exemple mon_theme, Drupal vérifie s'il existe une fonction qui s'appelle mon_theme_courses_view. Si tel est le cas, c'est elle qui sera utilisée.
  • Si votre site utilise un theme engine, par exemple phptemplate, Drupal cherche une fonction nommée phptemplate_courses_view.
  • Le cas échéant, Drupal cherche une fonction nommée theme_courses_view. Si elle existe, c'est elle qui sera utilisée.

Une bonne pratique est donc de toujours fournir un thème par défaut en utilisant ce dernier cas de figure. Ainsi, Drupal pourra toujours trouver de quoi habiller notre node tout en laissant à vos utilisateurs la possibilité d'en changer le style. Là aussi c'est une bonne pratique à garder à l'esprit.

à ajouter à courses.module
  1. function theme_produit_view($node)
  2. {
  3.   $result = "<h2>Détail du produit</h2>";
  4.   $result.= "<div class='quantite'>Quantité restante :".$node->quantite."</div>";
  5.   $result.= "<div class='seuil'>Seuil avant rachat : ".$node->seuil."</div>";
  6.   return $result;
  7. }

Pour des raisons de performances, ce type de fonction thème n'est pas cherché par Drupal de manière automatique. Il est donc nécessaire d'implémenter un hook supplémentaire, hook_theme, pour enregistrer notre fonction theme_produit_view dans les tablettes de Drupal.

A ajouter à la suite du module pour Drupal 6
  1. function courses_theme() {
  2.   return array(
  3.     'produit_view' => array(
  4.       'arguments' => array('node' => NULL)
  5.     )
  6.   );
  7. }

Attention cependant, ce hook n'est lu qu'à l'activation du node. Si l'on veut pour tester avoir une prise en charge dynamique, il est nécessaire d'ajouter, par exemple juste avant l'implémentation ci-dessus, un appel à drupal_rebuild_theme_registry();. Mais pensez à enlever cette ligne lorsque vous avez fini de tester sous peine de plomber les performances.

Actions du node

Vous aurez sans doute remarqué que chaque node disposent, à la fin du résumé ou de la page, d'une série de liens qui offrent des actions qui lui sont propres. Ces liens sont définis grâce à l'implémentation de hook_view. Nous allons donc utiliser cette fonctionnalité pour ajouter à chaque node un lien vers notre future liste de courses.

à ajouter à courses.module
  1. .
  2. function courses_link($type, $node = NULL, $teaser = FALSE) {
  3.   $links = array();
  4.   if ($type == 'node' && $node->type='produit') {
  5.       $links['liste_des_courses'] = array(
  6.         'title'=>t('Liste des courses'),
  7.         'href'=> "courses/liste",
  8.         'attributes'=>array('title' => t('Afficher la liste complète des courses.')));
  9.   }
  10.   return $links;
  11. }

Attention cependant, contrairement à tous les hooks que nous avons étudié jusqu'à maintenant, ce hook n'est pas spécifique au type produit. Il faut donc vérifier avant d'ajouter un lien que l'on est bien dans le contexte d'un node (et pas d'un commentaire), et que le type du node est bien produit.

Maintenant que nous avons notre lien vers la liste des courses, il ne nous reste plus qu'à la mettre en oeuvre.

Liste de courses

Avant de rentrer dans le vif du sujet, arrêtons nous un peu sur la manière dont Drupal gère les URL. Ces dernières sont de la forme http://mon_site_drupal?q=chemin1/chemin2 ou http://mon_site_drupal/chemin1/chemin2 selon que le mode "URL Simplifié" est actif ou non. La chaîne chemin1/chemin2, appelée path, est associée par Drupal à une fonction, appelée callback. Lorsqu'il est exécutée, cette fonction renvoie à Drupal du code HTML qu'il va insérer dans la page. Cette association entre un path et une fonction callback est appelée un menu.

Chaque module a la possibilité de définir ses propres menus en implémentant hook_menu. C'est ce que nous allons utiliser pour afficher notre liste de courses :

à ajouter à courses.module
  1. function courses_menu() {
  2.  $items= array ();
  3.   $items['courses/liste']= array (
  4.     'title' => t("Liste de courses"),
  5.     'page callback' => 'courses_callback_liste',
  6.     'type' => MENU_NORMAL_ITEM,
  7.     'access callback' => 'node_access'
  8.   );
  9.  
  10.   return $items;
  11. }
  12.  
  13. function courses_callback_liste() {
  14. drupal_set_title(t('Liste des courses'));
  15.   return "Je suis une <b>liste</b>";
  16. }

Comme pour le hook_theme, hook_menu n'est appelé qu'à l'activation du module. En conséquence, comme avec hook_theme, pour tester, vous devrez placer avant l'implémentation un appel à menu_rebuild(), cela va vous permettre de reconstruire dynamiquement la table des menus à chaque requête. Mais là aussi, pensez à enlever cet appel lorsque vous avez achevé vos tests car les performances seraient catastrophiques.

Une fois le code ajouté allez à l'URL http://mon_site_drupal/?q=courses/liste_items et voyez le résultat. Notre texte s'affiche tranquillement au milieu de la page et le titre de la fenêtre du navigateur est bien Liste des courses.

courses_menu renvoie à Drupal un tableau prenant le path comme id et lui associe un tableau de définition du menu. Mettre le nom du module, courses comme premier élément du path est une convention permettant d'avoir des URL de la forme mon_module/mon_action.

A ce menu nous avons donné un titre (paramètre title) et si vous mettez à jour votre navigateur, vous devriez voir ce titre et le lien associer apparaître dans le bloc de navigation. C'est grâce au paramètre type qui renseigné à MENU_NORMAL_ITEM indique à Drupal de rendre le menu visible.

Enfin les paramètre access callback permet à n'importe quel utilisateur étant capable de voir un node, d'accéder à ce menu.

La fonction de callback quant à elle, commence par changer le titre de la page et poursuit par la construction du contenu HTML du corps qui sera renvoyé à Drupal.

Il ne nous reste maintenant plus qu'à mettre un véritable corps à notre callback pour obtenir enfin notre liste de courses

corps de la fonction de callback
  1.  $path= drupal_get_path('module', 'courses');
  2.   drupal_add_css($path . '/default.css');
  3.   drupal_set_title(t('Liste des Courses'));
  4.   $cursor = db_query("
  5.     select n.*,i.* from node n
  6.       inner join node_produit i on n.nid=i.nid
  7.     where n.type='produit'
  8.     order by n.title");
  9.  
  10.   $output= "<table class='liste_produits'>
  11.  <tr><th>Produit</th><th>Seuil</th><th>Quantité</th><th>Action</th></tr>
  12.  ";
  13.   while ($node=db_fetch_object($cursor)) {
  14.     $output .= "<tr";
  15.     if ($node->quantité < $node->seuil) {
  16.       $output .= " class='manquant'";
  17.     }
  18.     $output .= "><td>".$node->title."</td><td>".$node->seuil."</td><td>$node->quantite</td>";
  19.     $output .= "<td>";
  20.     if ($node->quantite>0) {
  21.       $output .= l("Diminuer","courses/diminuer/".$node->nid);
  22.       $output .= " | ";
  23.     }
  24.     $output .= l("Modifier","node/".$node->nid."/edit");
  25.     $output .= "</td>";
  26.     $output .= "</tr>";
  27.   }
  28.   $output.="</table>";
  29.   return $output;
  30. }

La fonction commence par deux lignes dont l'objectif est de demander à Drupal de prendre la feuille de style default.css qui se trouve dans le dossier du module, et de la lier à la page. Pour plus d'informations sur cette méthode, reportez vous à ce tutoriel. Cette feuille de style va juste nous servir à mettre en évidence les lignes de produits qui doivent être rachetés.

Fichier default.css à mettre dans le dossier du module
  1. TR.manquant TD {
  2.   color: red;
  3. }

La requête SQL qui suit nous permet d'itérer sur la liste des nodes de type produit en y ajoutant les informations de la table node_produit. Nous aurions pu seulement récupérer ici le nid et utiliser la fonction node_load mais cette méthode est beaucoup plus rapide. Le reste du code n'est plus qu'un travail de mise en forme du contenu de l'objet $node en ligne d'un tableau, qui sert de retour à la fonction de call-back.

La dernière colonne du tableau contient des liens qui représentent les actions par produit : modifier et diminuer. La première est simplement un raccourcis sur l'édition du node, la seconde va nous permettre de diminuer la quantité restant de produit d'un simple click (voir chapitre suivant).

Notez l'utilisation de la fonction Drupal, l(…). Son rôle est de fabriquer un lien HTML à partir d'un texte et d'un chemin. Il est fortement conseillé de toujours utiliser cette fonction pour générer un lien et ainsi laisser Drupal en trouver la meilleur représentation URL.

Voyons maintenant comment câbler notre action diminuer.

Interactivité

L'action diminuer codée en lien dans la colonne action de notre tableau, s'attend à ce que Drupal sache reconnaître un path de la forme couses/diminuer/1234. 1234 représentant le nid de la ligne courante. Pour cela nous allons devoir créer un nouveau menu d'un genre un peu différent du précédent, c'est à dire capable de comprendre un paramètre (le nid) et ne devant pas s'afficher dans le bloc de navigation.

à insérer après le premier $items[]=..., dans la fonction courses_menu
  1. $items['courses/diminuer/%']= array (
  2.   'page callback' => 'courses_callback_diminuer_quantite',
  3.   'page arguments' => array (2),
  4.   'type' => MENU_CALLBACK,
  5.   'access callback' => 'node_access',
  6.   'access arguments' => array('view', 1)
  7. );

Mis à part son type, ce menu diffère dans son approche du path. En effet, vous aurez remarqué que le dernier paramètre est le symble %. Cela indique à drupal que n'importe quel élément peut satisfaire à ce troisième morceau de chemin. Dans notre cas, ce sera un chiffre représentant le nid.

Ce motif représente un paramètre qu'il est possible de transmettre à la fonction callback par la propriété #page arguments. Il s'agit d'un simple tableau contenant les indexes (débutant à 0) des parties variables du path (ici le morceau de rang 2).

Il ne nous reste maintenant plus qu'à écrire cette fonction de callback :

  1. function courses_callback_diminuer_quantite($nid) {
  2.   $node=node_load($nid);
  3.   if ($node->quantite>0) {
  4.     $node->quantite--;
  5.   }
  6.   node_save($node);
  7.   return courses_callback_liste();
  8. }

Le traitement effectué par cette fonction de callback consiste simplement à charger dans l'objet $node le node dont le nid est passé en paramètre. Ensuite nous décrémentons la quantité. Enfin nous sauvegardons l'objet en base de données.

Conclusion

Voilà comment en relativement peu de code, il est possible de fabriquer de toute pièce un module prenant en charge un nouveau type de contenu. Il existe une autre méthodes permettant d'arriver au même résultat avec sûrement encore moins de travail, les module CCK et Views. Mais j'aurais une forte tendance à mettre en garde contre ces outils certes très efficaces mais ne laissant que peu de maîtrise sur la structure de donnée sous-jacente et la finesse des requêtes. Cela permet sans aucun doute d'aller très vite mais cette vitesse risque de se payer cher lorsque vous devrez maintenir et faire évoluer votre type de contenu jusqu'à un point où ces outils ne puisse plus vous suivre.

Commentaires

Jérémy , le 24 May, 2008 - 23:12

Hello,

Je suis en train de développer un CMS (depuis bientôt un an) qui permettrait, comme Drupal (je ne savais pas que Drupal savait le faire mais bon) de gérer différents types de contenus, à la seule différence par rapport à Drupal que la création d'un datatype pourra se faire sans code, directement dans un éditeur Wysiwyg.

Si celà intéresse quelque contributeur, je laisse mon JID:
La page du projet sur codingteam.net: http://zax.codingteam.net (le SVN n'est plus du tout à jour).

Je profite un peu de ton excélent billet pour faire de la pub, tu m'en voudras pas? Wink

Bonne soirée!

Ulhume, le 25 May, 2008 - 00:02

Pas de problème Smiling

Oncle Tom , le 25 May, 2008 - 10:03

Super article merci beaucoup Smiling j'ai légèrement taté Drupal jusqu'à présent et ton article m'a appris beaucoup de choses. J'attends les autres articles avec grand plaisir.
Kudos !

Ulhume, le 25 May, 2008 - 10:33

@Oncle Tom Merci Smiling Je vais pour l'instant essayer de re-organiser les anciens tutos sur les modules Drupal de sorte à les rendre cohérents les uns avec les autres. Pour les nouveaux, je vais attendre un peu car j'ai vaguement l'impression de flooder planet-libre Wink

anti-pixel , le 26 May, 2008 - 21:32

pour la prochaine fois que j'ai rien à faire au taff Glad

Poster un nouveau commentaire

Le contenu de ce champ est gardé secret et ne sera pas montré publiquement.
  • Allowed HTML tags: <a> <em> <strong> <cite> <code> <ul> <ol> <li> <dl> <dt> <dd>
  • To highlight piece of code, just surround them with <code type="language"> Your code &tl;/code>>. Language can be java,c++,bash,etc... Everything Geshi support.
  • Les lignes et les paragraphes vont à la ligne automatiquement.
  • Textual smileys will be replaced with graphical ones.
  • Les adresses de pages web et de messagerie électronique sont transformées en liens automatiquement.

Plus d'informations sur les options de formatage

Connexion utilisateur
Les derniers bavardages...