<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
  <title>Artisan Numérique</title>
  <link rel="alternate" type="text/html" href="http://artisan.karma-lab.net/node/1561"/>
  <link rel="self" type="application/atom+xml" href="http://artisan.karma-lab.net/node/1561/atom/feed"/>
  <id>http://artisan.karma-lab.net/node/1561/atom/feed</id>
  <updated>2008-10-08T14:54:22+02:00</updated>
  <entry>
    <title>Créer un module Drupal : le type de contenu</title>
    <link rel="alternate" type="text/html" href="http://artisan.karma-lab.net/node/1561" />
    <id>http://artisan.karma-lab.net/node/1561</id>
    <published>2008-05-24T20:52:48+02:00</published>
    <updated>2008-10-08T14:54:22+02:00</updated>
    <author>
      <name>Ulhume</name>
    </author>
    <category term="Drupal" />
    <category term="drupalfr.org" />
    <category term="OK" />
    <category term="Planet Libre" />
    <category term="Tutoriel" />
    <summary type="html"><![CDATA[<p>
Dans le <a class='external' target='_blank' href='/node/1535' >précédent tutoriel</a> 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é. 
</p>
    ]]></summary>
    <content type="html"><![CDATA[<p>
Dans le <a class='external' target='_blank' href='/node/1535' >précédent tutoriel</a> 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é. 
</p>
<!--break-->
<div class='inline-box note'> 
  L'ensemble des sources de ce tutoriel est disponible <a class='external' target='_blank' href='/node/1552' >ici</a>. 
</div> 

	<a name='chapter_1'></a>
  <h2>Où allons nous ?</h2>
	 
<p> 
   Dans le tutoriel précédent, nous avons crée notre premier module de gestion d'un liste de courses, pour l'instant capable d'afficher des informations statiques dans un bloc. Ce que nous allons voir maintenant c'est :
<ul> 
<li>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.</li> 
<li>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é.</li> 
<li>Mettre les véritables informations dans le bloc du précédent tutoriel.</li>
</ul> 
</p> 

<p>
  Avant de commencer, nous allons donc reprendre les sources du précédent tutoriel à fin d'en étendre les fonctionnalités. 
</p>
<div class='inline-box attention'>
  Si vous avez suivi le précédent tutoriel et installé le module qui va avec, commencez par le desinstaller. En effet, nous allons ajouter une partie base de données qui ne sera pas créée le module est déjà installé. 
</div>



	<a name='chapter_2'></a>
  <h2>Installation</h2>
	 
<p> 
  Notre module <kbd>courses</kbd> 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 <kbd>story</kbd> 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, <kbd>produit</kbd>, en cherchant à étendre le type de node simple. 
 </p> 
<p> 
   Drupal stocke les données de base d'un node (titre, corps, etc.) dans la table <kbd>node</kbd> dont la clef primaire est le champ <kbd>nid</kbd>. Ce sont les valeurs de ce champ que vous retrouvez dans l'URL d'un node, sous la forme <kbd>http://mon_site_drupal?q=/node/1234</kbd>. Elle dispose aussi d'un champ <kbd>type</kbd> de type texte identifie le type du contenu. Dans notre cas ce type prendra la valeur <kbd>produit</kbd>. 
</p> 
<p> 
  Mais pour stocker nos informations supplémentaires, nous allons devoir créer une nouvelle table, traditionnellement nommée <kbd>node_produit</kbd>, contenant un champ <kbd>quantité</kbd> pour la quantité restante du produit et un champ <kbd>seuil</kbd> pour la valeur minimum à conserver en réserve. En outre elle disposera, elle aussi, d'un champ <kbd>nid</kbd>. Les informations sur un produit donné seront donc réparties sur les champs des deux tables à la fois (<kbd>node</kbd> et <kbd>node_produit</kbd>)reliées entre-elles par le même <kbd>nid</kbd>. 
</p> 
<p> 
 Du coup, pour obtenir toutes les informations disponibles sur un node de type <kbd>produit</kbd>, nous pouvons formuler la requête suivante : 

  <div class='code-block code-block-fragment'>
  <div class='container'>
  <span class="kw1">SELECT</span> n<span class="sy0">.*,</span>i<span class="sy0">.*</span> <span class="kw1">FROM</span> node n<span class="sy0">,</span> node_produit i <span class="kw1">WHERE</span> n<span class="sy0">.</span>nid<span class="sy0">=</span>i<span class="sy0">.</span>nid <span class="kw1">AND</span> n<span class="sy0">.</span>type<span class="sy0">=</span><span class="st0">'produit'</span>;
  </div>
  
  </div> 
</p> 
<p> 
   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é <b>puis</b> désinstallé. 
</p> 
<p> 
   Pour ce faire, il nous faut rajouter un troisième fichier à notre dossier module : <kbd>courses.install</kbd> qui va contenir deux hooks. Le premier, <kbd><a class='external' target='_blank' href='http://api.drupal.org/api/function/hook_install/6' >hook_install</a></kbd>, est invoqué lors de la première activation du module (installation). Le second, <kbd><a class='external' target='_blank' href='http://api.drupal.org/api/function/hook_uninstall/6' >hook_uninstall</a></kbd>, est quant à lui invoqué lors de la désinstallation du module. 

  <div class='code-block code-block-fragment'>
  <div class='container'>
  <a target="blank" href="http://www.php.net/?php"><span class="kw2">&lt;?php</span></a><br />
<br />
<span class="coMULTI">/**<br />
&nbsp;* Implementation of hook_install().<br />
&nbsp;*/</span><br />
<a target="blank" href="http://www.php.net/function"><span class="kw2">function</span></a> courses_install<span class="br0">&#40;</span><span class="br0">&#41;</span> <span class="br0">&#123;</span><br />
&nbsp; <span class="re0">$result</span><span class="sy0">=</span> <a target="blank" href="http://www.php.net/array"><span class="kw3">array</span></a> <span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">;</span><br />
&nbsp; <a target="blank" href="http://www.php.net/switch"><span class="kw1">switch</span></a> <span class="br0">&#40;</span><span class="re0">$GLOBALS</span><span class="br0">&#91;</span><span class="st0">'db_type'</span><span class="br0">&#93;</span><span class="br0">&#41;</span> <span class="br0">&#123;</span><br />
&nbsp; &nbsp; <span class="co1">// Installation de la table pour MySQL</span><br />
&nbsp; &nbsp; <a target="blank" href="http://www.php.net/case"><span class="kw1">case</span></a> <span class="st0">'mysql'</span> <span class="sy0">:</span><br />
&nbsp; &nbsp; <a target="blank" href="http://www.php.net/case"><span class="kw1">case</span></a> <span class="st0">'mysqli'</span> <span class="sy0">:</span><br />
&nbsp; &nbsp; &nbsp; <span class="re0">$result</span><span class="br0">&#91;</span><span class="br0">&#93;</span><span class="sy0">=</span> db_query<span class="br0">&#40;</span><span class="st0">&quot;<br />
&nbsp; &nbsp; &nbsp; CREATE TABLE {node_produit} (<br />
&nbsp; nid int(10),<br />
&nbsp; &nbsp; &nbsp; &nbsp; quantite int(10),<br />
&nbsp; &nbsp; &nbsp; &nbsp; seuil int(10),<br />
&nbsp; &nbsp; &nbsp; &nbsp; PRIMARY KEY (nid)<br />
&nbsp; &nbsp; &nbsp; &nbsp; )&quot;</span><span class="br0">&#41;</span><span class="sy0">;</span><br />
&nbsp; &nbsp; &nbsp; <a target="blank" href="http://www.php.net/break"><span class="kw1">break</span></a><span class="sy0">;</span><br />
<br />
&nbsp; &nbsp; <span class="co1">// Installation de la table pour PostgreSQL</span><br />
&nbsp; &nbsp; <a target="blank" href="http://www.php.net/case"><span class="kw1">case</span></a> <span class="st0">'pgsql'</span> <span class="sy0">:</span><br />
&nbsp; &nbsp; &nbsp; <a target="blank" href="http://www.php.net/error_log"><span class="kw3">error_log</span></a><span class="br0">&#40;</span><span class="st0">&quot;install on Psql&quot;</span><span class="br0">&#41;</span><span class="sy0">;</span><br />
&nbsp; &nbsp; &nbsp; <span class="re0">$result</span><span class="br0">&#91;</span><span class="br0">&#93;</span><span class="sy0">=</span>db_query<span class="br0">&#40;</span><span class="st0">&quot;<br />
&nbsp; &nbsp; CREATE TABLE {node_produit} (<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; nid INTEGER,<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; quantite INTEGER,<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; seuil INTEGER,<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; PRIMARY KEY (nid)<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;);&quot;</span><span class="br0">&#41;</span><span class="sy0">;</span><br />
&nbsp; &nbsp; &nbsp; <a target="blank" href="http://www.php.net/break"><span class="kw1">break</span></a><span class="sy0">;</span><br />
&nbsp; <span class="br0">&#125;</span><br />
&nbsp; <a target="blank" href="http://www.php.net/return"><span class="kw1">return</span></a> <span class="re0">$result</span><span class="sy0">;</span><br />
<span class="br0">&#125;</span><br />
<br />
<span class="coMULTI">/**<br />
&nbsp;* Implementation of hook_uninstall().<br />
&nbsp;*/</span><br />
<a target="blank" href="http://www.php.net/function"><span class="kw2">function</span></a> courses_uninstall<span class="br0">&#40;</span><span class="br0">&#41;</span> <span class="br0">&#123;</span><br />
&nbsp; <span class="re0">$result</span><span class="sy0">=</span><a target="blank" href="http://www.php.net/array"><span class="kw3">array</span></a><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">;</span><br />
&nbsp; <span class="re0">$result</span><span class="br0">&#91;</span><span class="br0">&#93;</span><span class="sy0">=</span>db_query<span class="br0">&#40;</span><span class="st0">'DROP TABLE {node_produit}'</span><span class="br0">&#41;</span><span class="sy0">;</span><br />
&nbsp; <a target="blank" href="http://www.php.net/return"><span class="kw1">return</span></a> <span class="re0">$result</span><span class="sy0">;</span><br />
<span class="br0">&#125;</span>
  </div>
  <div class='caption'>courses/courses.install</div>
  </div> 
</p> 
<p>
	Le code n'a rien de compliqué mais quelques points cependant méritent éclaircissement.  
</p>
<p> 
  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. 
</p> 
<p> 
  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.
</p>
<p>
 Dans le cas spécifique de l'installation et de la désinstallation, nous utilisons <kbd>update_sql</kbd> mais pour le reste du code elle sera remplacée par <kbd>db_query</kbd>. Ces deux fonctions sont pratiquement identiques à la différence près qu'<kbd>update_sql</kbD> 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. 
</p> 
<p> 
  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. 
</p> 
<p> 
  Maintenant que notre installation est finalisée, il ne nous reste plus qu'à activer notre module dans le panneau d'administration de Drupal : <kbd>http://mon_site_drupal?q=/admin/build/modules</kbd>. 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 <kbd>node_produit</kbd> 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 <kbd>courses_uninstall</kbd> soit appelé et détruise la table. Ensuite, si vous réactivez à nouveau le module, la table sera recréée. 
</p> 


	<a name='chapter_3'></a>
  <h2>Type de contenu</h2>
	 
<p> 
  Notre base est prête, notre module activé et pourtant si nous allons sur l'URL <kbd>http://mon_site_drupal/?q=node/add</kbd>, notre <kbd>produit</kbd> n'apparaît pas. En effet, il faut implémenter deux hooks supplémentaires dans <kbd>courses.module</kbd> pour indiquer à Drupal qu'un nouveau type de node est à prendre en charge. Le premier hook, <kbd><a class='external' target='_blank' href='http://api.drupal.org/api/function/hook_node_info/6' >hook_node_info</a></kbd>, va décrire le nouveau type de node : 

  <div class='code-block code-block-fragment'>
  <div class='container'>
  <a target="blank" href="http://www.php.net/function"><span class="kw2">function</span></a> courses_node_info<span class="br0">&#40;</span><span class="br0">&#41;</span> <span class="br0">&#123;</span><br />
&nbsp; <a target="blank" href="http://www.php.net/return"><span class="kw1">return</span></a> <a target="blank" href="http://www.php.net/array"><span class="kw3">array</span></a><span class="br0">&#40;</span><br />
&nbsp; &nbsp; <span class="st0">'produit'</span> <span class="sy0">=&gt;</span> <a target="blank" href="http://www.php.net/array"><span class="kw3">array</span></a><span class="br0">&#40;</span><br />
&nbsp; &nbsp; &nbsp; <span class="st0">'name'</span> <span class="sy0">=&gt;</span> t<span class="br0">&#40;</span><span class="st0">'Un produit'</span><span class="br0">&#41;</span><span class="sy0">,</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="st0">'description'</span> <span class="sy0">=&gt;</span> t<span class="br0">&#40;</span><span class="st0">&quot;Un produit dans la liste des courses.&quot;</span><span class="br0">&#41;</span><span class="sy0">,</span><br />
&nbsp; &nbsp; &nbsp; <span class="st0">'module'</span> <span class="sy0">=&gt;</span> <span class="st0">'courses'</span><span class="br0">&#41;</span><span class="br0">&#41;</span><span class="sy0">;</span><br />
<span class="br0">&#125;</span>
  </div>
  <div class='caption'>à ajouter au fichier courses.module</div>
  </div> 
</p> 
<p> 
  Ce hook permet de renvoyer à Drupal une liste de nouveaux types de contenu. Ici nous n'en indiquons qu'un seul, <kbd>produit</kbd>, avec sa description et son nom usuel. L'identifiant <kbd>produit</kbd> sera utilisé dans la colonne <kbd>type</kbd> de la table <kbd>node</kbd> comme vu au chapitre précédent.
</p>
<p>
   Le dernier paramètre correspond au nom du module qui va gérer ce type de contenu, en l'occurrence notre module <kbd>courses<.kbd>. 
</p> 


	<a name='chapter_4'></a>
  <h2>Formulaire de saisie</h2>
	 
<p> 
   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.
</p> 
<p> 
  Un node est représenté dans le code de Drupal par l'objet <kbd>$node</kbd>. 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 <kbd>node.tpl.php</kbd>, l'affichage du titre passe par une référence à <kbd>$node->title</kbd>. 
</p> 
<p> 
  Il existe une relation étroite entre l'objet <kbd>$node</kbd> et sa représentation en base de donnée. Si le node existe déjà, Drupal transfère les valeurs correspondantes de la table <kbd>node</kbd> vers les champs de l'objet <kbd>$node</kbd>. 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, <kbd><a class='external' target='_blank' href='http://api.drupal.org/api/function/hook_form/6' >hook_form</a></kbd>.
</p> 
<p> 
   Ce hook est chargé de créer le formulaire mais aussi de l'initialiser avec les valeurs de l'objet <kbd>$node</kbd>. Ce formulaire sera soit utilisé sur un objet vide ou soit sur contenant les données d'un contenu existant. 

  <div class='code-block code-block-fragment'>
  <div class='container'>
  <a target="blank" href="http://www.php.net/function"><span class="kw2">function</span></a> courses_form<span class="br0">&#40;</span><span class="sy0">&amp;</span> <span class="re0">$node</span><span class="br0">&#41;</span><br />
<span class="br0">&#123;</span><br />
&nbsp; <span class="re0">$form</span><span class="br0">&#91;</span><span class="st0">'title'</span><span class="br0">&#93;</span><span class="sy0">=</span> <a target="blank" href="http://www.php.net/array"><span class="kw3">array</span></a> <span class="br0">&#40;</span><br />
&nbsp; &nbsp; <span class="st0">'#type'</span> <span class="sy0">=&gt;</span> <span class="st0">'textfield'</span><span class="sy0">,</span><br />
&nbsp; &nbsp; <span class="st0">'#title'</span> <span class="sy0">=&gt;</span> t<span class="br0">&#40;</span><span class="st0">&quot;Nom du produit&quot;</span><span class="br0">&#41;</span><span class="sy0">,</span><br />
&nbsp; &nbsp; <span class="st0">'#default_value'</span> <span class="sy0">=&gt;</span> <span class="re0">$node</span><span class="sy0">-&gt;</span><span class="me1">title</span><span class="sy0">,</span> <br />
&nbsp; &nbsp; <span class="st0">'#required'</span> <span class="sy0">=&gt;</span> <a target="blank" href="http://www.php.net/true"><span class="kw2">TRUE</span></a> <br />
&nbsp; <span class="br0">&#41;</span><span class="sy0">;</span><br />
&nbsp; <span class="re0">$form</span><span class="br0">&#91;</span><span class="st0">'body_filter'</span><span class="br0">&#93;</span><span class="br0">&#91;</span><span class="st0">'body'</span><span class="br0">&#93;</span><span class="sy0">=</span> <a target="blank" href="http://www.php.net/array"><span class="kw3">array</span></a> <span class="br0">&#40;</span><br />
&nbsp; &nbsp; <span class="st0">'#type'</span> <span class="sy0">=&gt;</span> <span class="st0">'textarea'</span><span class="sy0">,</span><br />
&nbsp; &nbsp; <span class="st0">'#title'</span> <span class="sy0">=&gt;</span> t<span class="br0">&#40;</span><span class="st0">'Notes'</span><span class="br0">&#41;</span><span class="sy0">,</span> <br />
&nbsp; &nbsp; <span class="st0">'#description'</span><span class="sy0">=&gt;</span>t<span class="br0">&#40;</span><span class="st0">&quot;Notes sur le produit&quot;</span><span class="br0">&#41;</span><span class="sy0">,</span> <br />
&nbsp; &nbsp; <span class="st0">'#default_value'</span> <span class="sy0">=&gt;</span> <span class="re0">$node</span><span class="sy0">-&gt;</span><span class="me1">body</span><span class="sy0">,</span> <br />
&nbsp; &nbsp; <span class="st0">'#rows'</span> <span class="sy0">=&gt;</span> <span class="nu0">10</span><span class="sy0">,</span> <br />
&nbsp; &nbsp; <span class="st0">'#required'</span> <span class="sy0">=&gt;</span> <a target="blank" href="http://www.php.net/false"><span class="kw2">FALSE</span></a><span class="br0">&#41;</span><span class="sy0">;</span><br />
&nbsp; <span class="re0">$form</span><span class="br0">&#91;</span><span class="st0">'body_filter'</span><span class="br0">&#93;</span><span class="br0">&#91;</span><span class="st0">'format'</span><span class="br0">&#93;</span><span class="sy0">=</span> filter_form<span class="br0">&#40;</span><span class="re0">$node</span><span class="sy0">-&gt;</span><span class="me1">format</span><span class="br0">&#41;</span><span class="sy0">;</span><br />
<br />
&nbsp; <span class="re0">$form</span><span class="br0">&#91;</span><span class="st0">'seuil'</span><span class="br0">&#93;</span> <span class="sy0">=</span> <a target="blank" href="http://www.php.net/array"><span class="kw3">array</span></a><span class="br0">&#40;</span><br />
&nbsp; &nbsp; <span class="st0">'#type'</span> <span class="sy0">=&gt;</span> <span class="st0">'textfield'</span><span class="sy0">,</span><br />
&nbsp; &nbsp; <span class="st0">'#title'</span> <span class="sy0">=&gt;</span> t<span class="br0">&#40;</span><span class="st0">&quot;Seuil d'achat&quot;</span><span class="br0">&#41;</span><span class="sy0">,</span> <br />
&nbsp; &nbsp; <span class="st0">'#description'</span><span class="sy0">=&gt;</span>t<span class="br0">&#40;</span><span class="st0">&quot;Quantité minimum en dessous de laquelle il faut racheter le produit&quot;</span><span class="br0">&#41;</span><span class="sy0">,</span> <br />
&nbsp; &nbsp; <span class="st0">'#size'</span> <span class="sy0">=&gt;</span> <span class="nu0">4</span><span class="sy0">,</span><br />
&nbsp; &nbsp; <span class="st0">'#required'</span> <span class="sy0">=&gt;</span> <a target="blank" href="http://www.php.net/true"><span class="kw2">TRUE</span></a><span class="sy0">,</span><br />
&nbsp; &nbsp; <span class="st0">'#default_value'</span> <span class="sy0">=&gt;</span> <span class="re0">$node</span><span class="sy0">-&gt;</span><span class="me1">seuil</span><br />
&nbsp; <span class="br0">&#41;</span><span class="sy0">;</span><br />
<br />
<br />
&nbsp; <span class="re0">$form</span><span class="br0">&#91;</span><span class="st0">'quantite'</span><span class="br0">&#93;</span> <span class="sy0">=</span> <a target="blank" href="http://www.php.net/array"><span class="kw3">array</span></a><span class="br0">&#40;</span><br />
&nbsp; &nbsp; <span class="st0">'#title'</span> <span class="sy0">=&gt;</span> t<span class="br0">&#40;</span><span class="st0">&quot;Quantité&quot;</span><span class="br0">&#41;</span><span class="sy0">,</span> <br />
&nbsp; &nbsp; <span class="st0">'#description'</span><span class="sy0">=&gt;</span>t<span class="br0">&#40;</span><span class="st0">&quot;Quantité de produit restant en réserve&quot;</span><span class="br0">&#41;</span><span class="sy0">,</span> <br />
&nbsp; &nbsp; <span class="st0">'#type'</span> <span class="sy0">=&gt;</span> <span class="st0">'textfield'</span><span class="sy0">,</span><br />
&nbsp; &nbsp; <span class="st0">'#size'</span> <span class="sy0">=&gt;</span> <span class="nu0">4</span><span class="sy0">,</span><br />
&nbsp; &nbsp; <span class="st0">'#required'</span> <span class="sy0">=&gt;</span> <a target="blank" href="http://www.php.net/true"><span class="kw2">TRUE</span></a><span class="sy0">,</span><br />
&nbsp; &nbsp; <span class="st0">'#default_value'</span> <span class="sy0">=&gt;</span> <span class="re0">$node</span><span class="sy0">-&gt;</span><span class="me1">quantite</span><br />
&nbsp; <span class="br0">&#41;</span><span class="sy0">;</span><br />
<br />
&nbsp; <a target="blank" href="http://www.php.net/return"><span class="kw1">return</span></a> <span class="re0">$form</span><span class="sy0">;</span><br />
<span class="br0">&#125;</span>
  </div>
  <div class='caption'>Corps de la fonction courses_form</div>
  </div> 
</p> 
<p> 
	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. 
</p> 
<p>
   Comme nous l'avons vu plus haut, l'objet <kbd>$node</kbd> est vide à sa création. Si nous l'utilisons tel quel, les champs <kbd>quantité</kbd> et <kbd>seuil</kbd> seront vides (et non égal à 0). Il est donc nécessaire d'implémenter un nouveau hook, <kbd><a class='external' target='_blank' href='http://api.drupal.org/api/function/hook_prepare/6' >hook_prepare</a></kbd>,  qui a pour rôle de préparer l'objet <kbd>$node</kbd> avant utilisation dans le formulaire. 

  <div class='code-block code-block-fragment'>
  <div class='container'>
  <a target="blank" href="http://www.php.net/function"><span class="kw2">function</span></a> courses_prepare<span class="br0">&#40;</span><span class="sy0">&amp;</span> <span class="re0">$node</span><span class="br0">&#41;</span> <span class="br0">&#123;</span><br />
&nbsp; <span class="re0">$node</span><span class="sy0">-&gt;</span><span class="me1">quantite</span><span class="sy0">=</span><span class="re0">$node</span><span class="sy0">-&gt;</span><span class="me1">quantite</span>?<span class="re0">$node</span><span class="sy0">-&gt;</span><span class="me1">quantite</span><span class="sy0">:</span><span class="nu0">0</span><span class="sy0">;</span><br />
&nbsp; <span class="re0">$node</span><span class="sy0">-&gt;</span><span class="me1">seuil</span><span class="sy0">=</span><span class="re0">$node</span><span class="sy0">-&gt;</span><span class="me1">seuil</span>?<span class="re0">$node</span><span class="sy0">-&gt;</span><span class="me1">seuil</span><span class="sy0">:</span><span class="nu0">0</span><span class="sy0">;</span><br />
<span class="br0">&#125;</span>
  </div>
  <div class='caption'>à ajouter au fichier courses.module</div>
  </div>
</p>
<p>
     Grâce à cette fonction, nous initialisons notre objet <kbd>$node</kbd> 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 <kbd><a class='external' target='_blank' href='http://api.drupal.org/api/function/hook_validate/6' >hook_validate</a></kbd>

  <div class='code-block code-block-fragment'>
  <div class='container'>
  <a target="blank" href="http://www.php.net/function"><span class="kw2">function</span></a> courses_validate<span class="br0">&#40;</span><span class="re0">$form_id</span><span class="sy0">,</span> <span class="re0">$form_values</span><span class="br0">&#41;</span> <span class="br0">&#123;</span><br />
&nbsp; <a target="blank" href="http://www.php.net/if"><span class="kw1">if</span></a> <span class="br0">&#40;</span><span class="sy0">!</span><a target="blank" href="http://www.php.net/is_numeric"><span class="kw3">is_numeric</span></a><span class="br0">&#40;</span><span class="re0">$form_values</span><span class="br0">&#91;</span><span class="st0">'quantite'</span><span class="br0">&#93;</span><span class="br0">&#41;</span> <span class="sy0">||</span> <span class="re0">$form_values</span><span class="br0">&#91;</span><span class="st0">'quantite'</span><span class="br0">&#93;</span> <span class="sy0">&lt;</span> <span class="nu0">0</span><span class="br0">&#41;</span> <span class="br0">&#123;</span><br />
&nbsp; &nbsp; form_set_error<span class="br0">&#40;</span><span class="st0">'quantite'</span><span class="sy0">,</span> t<span class="br0">&#40;</span><span class="st0">'Le champ quantité doit être une valeur numérique et positive'</span><span class="br0">&#41;</span><span class="br0">&#41;</span><span class="sy0">;</span><br />
&nbsp; <span class="br0">&#125;</span><br />
&nbsp; <a target="blank" href="http://www.php.net/if"><span class="kw1">if</span></a> <span class="br0">&#40;</span><span class="sy0">!</span><a target="blank" href="http://www.php.net/is_numeric"><span class="kw3">is_numeric</span></a><span class="br0">&#40;</span><span class="re0">$form_values</span><span class="br0">&#91;</span><span class="st0">'seuil'</span><span class="br0">&#93;</span><span class="br0">&#41;</span> <span class="sy0">||</span> <span class="re0">$form_values</span><span class="br0">&#91;</span><span class="st0">'seuil'</span><span class="br0">&#93;</span> <span class="sy0">&lt;</span> <span class="nu0">0</span><span class="br0">&#41;</span> <span class="br0">&#123;</span><br />
&nbsp; &nbsp; form_set_error<span class="br0">&#40;</span><span class="st0">'seuil'</span><span class="sy0">,</span> t<span class="br0">&#40;</span><span class="st0">'Le champ seuil doit être une valeur numérique et positive'</span><span class="br0">&#41;</span><span class="br0">&#41;</span><span class="sy0">;</span><br />
&nbsp; <span class="br0">&#125;</span><br />
<span class="br0">&#125;</span>
  </div>
  <div class='caption'>à ajouter au fichier courses.module</div>
  </div>
</p>
<p> 
  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 <kbD>http://mon_site_drupal?q=/node/add/produit</kbd>. 
</p> 


	<a name='chapter_5'></a>
  <h2>Base de données</h2>
	 
<p> 
Nous avons maintenant un objet <kbd>$node</kbd> 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.
</p>
<p>
 Commençons par le plus simple : la lecture. Elle est prise en charge par le hook <kbd><a class='external' target='_blank' href='http://api.drupal.org/api/function/hook_load/6' >hook_load</a><kbd> : 

  <div class='code-block code-block-fragment'>
  <div class='container'>
  <a target="blank" href="http://www.php.net/function"><span class="kw2">function</span></a> courses_load<span class="br0">&#40;</span><span class="re0">$node</span><span class="br0">&#41;</span> <span class="br0">&#123;</span><br />
&nbsp; <a target="blank" href="http://www.php.net/return"><span class="kw1">return</span></a> db_fetch_object<span class="br0">&#40;</span>db_query<span class="br0">&#40;</span><span class="st0">'SELECT * FROM {node_produit} WHERE nid = %d'</span><span class="sy0">,</span> <span class="re0">$node</span><span class="sy0">-&gt;</span><span class="me1">nid</span><span class="br0">&#41;</span><span class="br0">&#41;</span><span class="sy0">;</span><br />
<span class="br0">&#125;</span>
  </div>
  <div class='caption'>à ajouter à courses.module</div>
  </div> 
</p> 
<p> 
   <kbd>hook_load</kbd> reçoit en paramètre un objet <kbd>$node</kbd> contenant déjà des informations extraites de la table <kbd>node</kbd>. Cela inclut le <kbd>nid</kbd> 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 <kbd>$node</kbd>. Les fonctions de base de donnée utilisées ici sont les mêmes que celles abordées dans le précédent tutoriel. 
</p> 
<p>
Voyons maintenant comment insérer, mettre à jour ou encore détruire nos données supplémentaires en implémentant respectivement <kbd><a class='external' target='_blank' href='http://api.drupal.org/api/function/hook_insert/6' >hook_insert</a></kbd>, <kbd><a class='external' target='_blank' href='http://api.drupal.org/api/function/hook_update/6' >hook_update</a></kbd> et <kbd><a class='external' target='_blank' href='http://api.drupal.org/api/function/hook_delete/6' >hook_delete</a></kbd> : 

  <div class='code-block code-block-fragment'>
  <div class='container'>
  <a target="blank" href="http://www.php.net/function"><span class="kw2">function</span></a> courses_insert<span class="br0">&#40;</span><span class="re0">$node</span><span class="br0">&#41;</span> <span class="br0">&#123;</span><br />
&nbsp; db_query<span class="br0">&#40;</span><span class="st0">&quot;INSERT INTO {node_produit} (nid, quantite, seuil) VALUES (%d, %d, %d)&quot;</span><span class="sy0">,</span> <span class="re0">$node</span><span class="sy0">-&gt;</span><span class="me1">nid</span><span class="sy0">,</span> <span class="re0">$node</span><span class="sy0">-&gt;</span><span class="me1">quantite</span><span class="sy0">,</span> <span class="re0">$node</span><span class="sy0">-&gt;</span><span class="me1">seuil</span><span class="br0">&#41;</span><span class="sy0">;</span><br />
<span class="br0">&#125;</span><br />
<br />
<a target="blank" href="http://www.php.net/function"><span class="kw2">function</span></a> courses_update<span class="br0">&#40;</span><span class="re0">$node</span><span class="br0">&#41;</span> <span class="br0">&#123;</span><br />
&nbsp; db_query<span class="br0">&#40;</span><span class="st0">&quot;UPDATE {node_produit} set quantite=%d, seuil=%d WHERE nid=%d&quot;</span><span class="sy0">,</span> <span class="re0">$node</span><span class="sy0">-&gt;</span><span class="me1">quantite</span><span class="sy0">,</span> <span class="re0">$node</span><span class="sy0">-&gt;</span><span class="me1">seuil</span><span class="sy0">,</span> <span class="re0">$node</span><span class="sy0">-&gt;</span><span class="me1">nid</span><span class="br0">&#41;</span><span class="sy0">;</span><br />
<span class="br0">&#125;</span><br />
<br />
<br />
<a target="blank" href="http://www.php.net/function"><span class="kw2">function</span></a> courses_delete<span class="br0">&#40;</span><span class="sy0">&amp;</span><span class="re0">$node</span><span class="br0">&#41;</span> <span class="br0">&#123;</span><br />
&nbsp; db_query<span class="br0">&#40;</span><span class="st0">'DELETE FROM {node_produit} WHERE nid = %d'</span><span class="sy0">,</span> <span class="re0">$node</span><span class="sy0">-&gt;</span><span class="me1">nid</span><span class="br0">&#41;</span><span class="sy0">;</span><br />
<span class="br0">&#125;</span>
  </div>
  <div class='caption'>à ajouter à courses.module</div>
  </div> 
</p> 
<p> 
   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 <kbd>produit</kbd>, saisir ses valeurs, le sauvegarder, le modifier, et le détruire. 
</p> 

<p>
   Un des gros avantage de Drupal est l'abstraction de la couche base de données qu'il propose. Elle est certes simple mais très efficace. Et du point de vue du module, peu importe que l'on utilise PostrgeSQL ou MySQL, Drupal lui fournit un jeu de fonctions permettant d'oublier ce "détail". 
</p>
<p>La fonction <kbd>db_query</kbd> a pour rôle de lancer la requête et de renvoyer un curseur sur le résultat. Elle permet l'utilisation des motifs <kbd>%d</kbd> et <kbd>%s</kbd> comme la fonction PHP <a class='external' target='_blank' href='http://fr.php.net/sprintf' >sprintf</a></kbd>.</p>
<p>
 Notez que <kbd>db_query</kbd> ne va pas automatiquement insérer de guillemets autour des chaînes. C'est donc à vous de mettre des <kbd>'%s'</kbd>. En revanche, elle se charge de l'échappement des caractères spéciaux vous protégeant des injections de code SQL malicieux, ce qui n'est déjà pas si mal.  
</p> 
<p> 
La fonction <kbd>db_fetch_object</kbd> va lire en base un enregistrement à la position courante du curseur (celui renvoyé par <kbd>db_query</kbd>) et transformer le résultat en un objet PHP. L'objet reçoit ainsi deux champs <kbd>type</kbd> et <kbd>count</kbd> contenant les résultats de la requête. 
</p>
<p>
La fonction <kbd>db_result</kbd> est une version simplifiée de <kbd>db_fetch_object</kbd> qui est utile lorsque la requête ne renvoie qu'une seule valeur.
</p>



	<a name='chapter_6'></a>
  <h2>Affichage</h2>
	
<p>
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, <kbd><a class='external' target='_blank' href='http://api.drupal.org/api/function/hook_view/6' >hook_view</a></kbd>, et une fonction de thème.  

  <div class='code-block code-block-fragment'>
  <div class='container'>
  <a target="blank" href="http://www.php.net/function"><span class="kw2">function</span></a> courses_view<span class="br0">&#40;</span><span class="re0">$node</span><span class="sy0">,</span> <span class="re0">$teaser</span> <span class="sy0">=</span> <a target="blank" href="http://www.php.net/false"><span class="kw2">FALSE</span></a><span class="sy0">,</span> <span class="re0">$page</span> <span class="sy0">=</span> <a target="blank" href="http://www.php.net/false"><span class="kw2">FALSE</span></a><span class="br0">&#41;</span> <span class="br0">&#123;</span><br />
&nbsp; <span class="re0">$node</span><span class="sy0">=</span> node_prepare<span class="br0">&#40;</span><span class="re0">$node</span><span class="sy0">,</span> <span class="re0">$teaser</span><span class="br0">&#41;</span><span class="sy0">;</span><br />
&nbsp; <a target="blank" href="http://www.php.net/if"><span class="kw1">if</span></a> <span class="br0">&#40;</span><span class="re0">$page</span><span class="br0">&#41;</span> <span class="br0">&#123;</span><br />
&nbsp; &nbsp; <span class="re0">$node</span><span class="sy0">-&gt;</span><span class="me1">content</span><span class="br0">&#91;</span><span class="st0">'Informations'</span><span class="br0">&#93;</span> <span class="sy0">=</span> <a target="blank" href="http://www.php.net/array"><span class="kw3">array</span></a><span class="br0">&#40;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="st0">'#value'</span> <span class="sy0">=&gt;</span> theme<span class="br0">&#40;</span><span class="st0">'produit_view'</span><span class="sy0">,</span> <span class="re0">$node</span><span class="br0">&#41;</span><span class="sy0">,</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="st0">'#weight'</span> <span class="sy0">=&gt;</span> <span class="nu0">1</span><span class="sy0">,</span><br />
&nbsp; &nbsp; <span class="br0">&#41;</span><span class="sy0">;</span><br />
&nbsp; <span class="br0">&#125;</span><br />
&nbsp; <a target="blank" href="http://www.php.net/return"><span class="kw1">return</span></a> <span class="re0">$node</span><span class="sy0">;</span><br />
<span class="br0">&#125;</span>
  </div>
  <div class='caption'>à ajouter à courses.module</div>
  </div>
</p>
<p>
Notre première tâche est de préparer le node à l'affichage. C'est le rôle de la fonction <kbd>node_prepare</kbd> qui va  appliquer les filtres d'entrée au corps et fabriquer le résumé (<kbd>teaser</kbd>).</p>
<p>
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). 
</p>
<p>
 Si nous sommes bien en mode <kbd>page</kbd>, nous pouvons ajouter à l'objet <kbd>$node</kbd> des sections <kbd>$node->content[]</kbd>. 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é <kbd>#value</kbd>) et d'un ordre d'apparition (propriété <kbd>#weight</kbd>). 
</p>
<p>
Pour renseigner <kbd>#value</kbd> nous avons rajouté une petite finesse : l'utilisation d'une fonction de thème <kbd>theme('courses_view', $node)</kbd>. Cela consiste à demander à Drupal d'habiller l'objet <kbd>$node</kbd> avec le thème <kbd>courses_view</kbd>. La fonction en interne va procéder de la manière suivante :
<ul>
<li>Si votre site a un thème, par exemple <kbd>mon_theme</kbd>, Drupal vérifie s'il existe une fonction qui s'appelle <kbd>mon_theme_courses_view</kbd>. Si tel est le cas, c'est elle qui sera utilisée.</li>
<li>Si votre site utilise un <kbd><a class='external' target='_blank' href='http://drupal.org/project/Theme+engines' >theme engine</a></kbd>, par exemple <kbd>phptemplate</kbd>, Drupal cherche une fonction nommée <kbd>phptemplate_courses_view</kbd>.</li>
<li>Le cas échéant, Drupal cherche une fonction nommée <kbd>theme_courses_view</kbd>. Si elle existe, c'est elle qui sera utilisée.</li>
</ul>
</p>
<p>
   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.  

  <div class='code-block code-block-fragment'>
  <div class='container'>
  <a target="blank" href="http://www.php.net/function"><span class="kw2">function</span></a> theme_produit_view<span class="br0">&#40;</span><span class="re0">$node</span><span class="br0">&#41;</span><br />
<span class="br0">&#123;</span><br />
&nbsp; <span class="re0">$result</span> <span class="sy0">=</span> <span class="st0">&quot;&lt;h2&gt;Détail du produit&lt;/h2&gt;&quot;</span><span class="sy0">;</span><br />
&nbsp; <span class="re0">$result</span><span class="sy0">.=</span> <span class="st0">&quot;&lt;div class='quantite'&gt;Quantité restante :&quot;</span><span class="sy0">.</span><span class="re0">$node</span><span class="sy0">-&gt;</span><span class="me1">quantite</span><span class="sy0">.</span><span class="st0">&quot;&lt;/div&gt;&quot;</span><span class="sy0">;</span><br />
&nbsp; <span class="re0">$result</span><span class="sy0">.=</span> <span class="st0">&quot;&lt;div class='seuil'&gt;Seuil avant rachat : &quot;</span><span class="sy0">.</span><span class="re0">$node</span><span class="sy0">-&gt;</span><span class="me1">seuil</span><span class="sy0">.</span><span class="st0">&quot;&lt;/div&gt;&quot;</span><span class="sy0">;</span><br />
&nbsp; <a target="blank" href="http://www.php.net/return"><span class="kw1">return</span></a> <span class="re0">$result</span><span class="sy0">;</span><br />
<span class="br0">&#125;</span>
  </div>
  <div class='caption'>à ajouter à courses.module</div>
  </div>
</p>
<p>
  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, <kbd><a class='external' target='_blank' href='http://api.drupal.org/api/function/hook_theme/6' >hook_theme</a></kbd>, pour enregistrer notre fonction <kbd>theme_produit_view</kbd> dans les tablettes de Drupal. 

  <div class='code-block code-block-fragment'>
  <div class='container'>
  <a target="blank" href="http://www.php.net/function"><span class="kw2">function</span></a> courses_theme<span class="br0">&#40;</span><span class="br0">&#41;</span> <span class="br0">&#123;</span><br />
&nbsp; <a target="blank" href="http://www.php.net/return"><span class="kw1">return</span></a> <a target="blank" href="http://www.php.net/array"><span class="kw3">array</span></a><span class="br0">&#40;</span><br />
&nbsp; &nbsp; <span class="st0">'produit_view'</span> <span class="sy0">=&gt;</span> <a target="blank" href="http://www.php.net/array"><span class="kw3">array</span></a><span class="br0">&#40;</span><br />
&nbsp; &nbsp; &nbsp; <span class="st0">'arguments'</span> <span class="sy0">=&gt;</span> <a target="blank" href="http://www.php.net/array"><span class="kw3">array</span></a><span class="br0">&#40;</span><span class="st0">'node'</span> <span class="sy0">=&gt;</span> <a target="blank" href="http://www.php.net/null"><span class="kw2">NULL</span></a><span class="br0">&#41;</span><br />
&nbsp; &nbsp; <span class="br0">&#41;</span><br />
&nbsp; <span class="br0">&#41;</span><span class="sy0">;</span><br />
<span class="br0">&#125;</span>
  </div>
  <div class='caption'>A ajouter à la suite du module pour Drupal 6</div>
  </div>
</p>
<p>
Attention cependant, ce hook n'est lu qu'à <strong>l'activation du node</strong>. 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 à <kbd>drupal_rebuild_theme_registry();</kbd>. Mais pensez à enlever cette ligne lorsque vous avez fini de tester sous peine de plomber les performances. 
</p>


	<a name='chapter_7'></a>
  <h2>Actions du node</h2>
	
<p>
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 <kbd><a class='external' target='_blank' href='http://api.drupal.org/api/function/hook_view/6' >hook_view</a></kbd>. Nous allons donc utiliser cette fonctionnalité pour ajouter à chaque node un lien vers notre future liste de courses. 

  <div class='code-block code-block-fragment'>
  <div class='container'>
  <span class="sy0">.</span> <br />
<a target="blank" href="http://www.php.net/function"><span class="kw2">function</span></a> courses_link<span class="br0">&#40;</span><span class="re0">$type</span><span class="sy0">,</span> <span class="re0">$node</span> <span class="sy0">=</span> <a target="blank" href="http://www.php.net/null"><span class="kw2">NULL</span></a><span class="sy0">,</span> <span class="re0">$teaser</span> <span class="sy0">=</span> <a target="blank" href="http://www.php.net/false"><span class="kw2">FALSE</span></a><span class="br0">&#41;</span> <span class="br0">&#123;</span><br />
&nbsp; <span class="re0">$links</span> <span class="sy0">=</span> <a target="blank" href="http://www.php.net/array"><span class="kw3">array</span></a><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">;</span><br />
&nbsp; <a target="blank" href="http://www.php.net/if"><span class="kw1">if</span></a> <span class="br0">&#40;</span><span class="re0">$type</span> <span class="sy0">==</span> <span class="st0">'node'</span> <span class="sy0">&amp;&amp;</span> <span class="re0">$node</span><span class="sy0">-&gt;</span><span class="me1">type</span><span class="sy0">=</span><span class="st0">'produit'</span><span class="br0">&#41;</span> <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; <span class="re0">$links</span><span class="br0">&#91;</span><span class="st0">'liste_des_courses'</span><span class="br0">&#93;</span> <span class="sy0">=</span> <a target="blank" href="http://www.php.net/array"><span class="kw3">array</span></a><span class="br0">&#40;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="st0">'title'</span><span class="sy0">=&gt;</span>t<span class="br0">&#40;</span><span class="st0">'Liste des courses'</span><span class="br0">&#41;</span><span class="sy0">,</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="st0">'href'</span><span class="sy0">=&gt;</span> <span class="st0">&quot;courses/liste&quot;</span><span class="sy0">,</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="st0">'attributes'</span><span class="sy0">=&gt;</span>array<span class="br0">&#40;</span><span class="st0">'title'</span> <span class="sy0">=&gt;</span> t<span class="br0">&#40;</span><span class="st0">'Afficher la liste complète des courses.'</span><span class="br0">&#41;</span><span class="br0">&#41;</span><span class="br0">&#41;</span><span class="sy0">;</span><br />
&nbsp; <span class="br0">&#125;</span><br />
&nbsp; <a target="blank" href="http://www.php.net/return"><span class="kw1">return</span></a> <span class="re0">$links</span><span class="sy0">;</span><br />
<span class="br0">&#125;</span>
  </div>
  <div class='caption'>à ajouter à courses.module</div>
  </div>
</p>
<p>
   Attention cependant, contrairement à tous les hooks que nous avons étudié jusqu'à maintenant, ce hook n'est pas spécifique au type <kbd>produit</kbd>. 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 <kbd>produit</kbd>. 
</p>
<p>
   Maintenant que nous avons notre lien vers la liste des courses, il ne nous reste plus qu'à la mettre en oeuvre. 
</p>


	<a name='chapter_8'></a>
  <h2>Liste de courses</h2>
	 
<p> 
   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 <kbd>http://mon_site_drupal?q=chemin1/chemin2</kbd> ou  <kbd>http://mon_site_drupal/chemin1/chemin2</kbd> selon que le mode "URL Simplifié" est actif ou non. La chaîne <kbd>chemin1/chemin2</kbd>, appelée <kbd>path</kbd>, est associée par Drupal à une fonction, appelée <kbd>callback</kbd>. 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 <kbd>path</kbd> et une fonction <kbd>callback</kbd> est appelée un <kbd>menu</kbd>. 
</p> 
<p> 
  Chaque module a la possibilité de définir ses propres menus en implémentant <kbd><a class='external' target='_blank' href='http://api.drupal.org/api/function/hook_menu/6' >hook_menu</a></kbd>. C'est ce que nous allons utiliser pour afficher notre liste de courses : 

  <div class='code-block code-block-fragment'>
  <div class='container'>
  <a target="blank" href="http://www.php.net/function"><span class="kw2">function</span></a> courses_menu<span class="br0">&#40;</span><span class="br0">&#41;</span> <span class="br0">&#123;</span><br />
&nbsp;<span class="re0">$items</span><span class="sy0">=</span> <a target="blank" href="http://www.php.net/array"><span class="kw3">array</span></a> <span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">;</span><br />
&nbsp; <span class="re0">$items</span><span class="br0">&#91;</span><span class="st0">'courses/liste'</span><span class="br0">&#93;</span><span class="sy0">=</span> <a target="blank" href="http://www.php.net/array"><span class="kw3">array</span></a> <span class="br0">&#40;</span><br />
&nbsp; &nbsp; <span class="st0">'title'</span> <span class="sy0">=&gt;</span> t<span class="br0">&#40;</span><span class="st0">&quot;Liste de courses&quot;</span><span class="br0">&#41;</span><span class="sy0">,</span><br />
&nbsp; &nbsp; <span class="st0">'page callback'</span> <span class="sy0">=&gt;</span> <span class="st0">'courses_callback_liste'</span><span class="sy0">,</span><br />
&nbsp; &nbsp; <span class="st0">'type'</span> <span class="sy0">=&gt;</span> MENU_NORMAL_ITEM<span class="sy0">,</span><br />
&nbsp; &nbsp; <span class="st0">'access callback'</span> <span class="sy0">=&gt;</span> <span class="st0">'node_access'</span><br />
&nbsp; <span class="br0">&#41;</span><span class="sy0">;</span><br />
<br />
&nbsp; <a target="blank" href="http://www.php.net/return"><span class="kw1">return</span></a> <span class="re0">$items</span><span class="sy0">;</span><br />
<span class="br0">&#125;</span><br />
<br />
<a target="blank" href="http://www.php.net/function"><span class="kw2">function</span></a> courses_callback_liste<span class="br0">&#40;</span><span class="br0">&#41;</span> <span class="br0">&#123;</span> <br />
drupal_set_title<span class="br0">&#40;</span>t<span class="br0">&#40;</span><span class="st0">'Liste des courses'</span><span class="br0">&#41;</span><span class="br0">&#41;</span><span class="sy0">;</span> <br />
&nbsp; <a target="blank" href="http://www.php.net/return"><span class="kw1">return</span></a> <span class="st0">&quot;Je suis une &lt;b&gt;liste&lt;/b&gt;&quot;</span><span class="sy0">;</span> <br />
<span class="br0">&#125;</span>
  </div>
  <div class='caption'>à ajouter à courses.module</div>
  </div> 
</p> 
<p>
  Comme pour le <kbd>hook_theme</kbd>, <kbd>hook_menu</kbd> n'est appelé qu'à l'activation du module. En conséquence, comme avec <kbd>hook_theme</kbd>, pour tester, vous devrez placer avant l'implémentation un appel à <kbd>menu_rebuild()</kbd>, 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. 
</p>
<p> 
   Une fois le code ajouté allez à l'URL <kbd>http://mon_site_drupal/?q=courses/liste_items</kbd> 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 <kbd>Liste des courses</kbd>. </p> 
<p> 
	<kbd>courses_menu</kbd> renvoie à Drupal un tableau prenant le path comme id et lui associe un tableau de définition du menu. Mettre le nom du module, <kbd>courses</kbd> comme premier élément du <kbd>path</kbd> est une convention permettant d'avoir des URL de la forme <kbd>mon_module/mon_action</kbd>. </p>
<p> A ce menu nous avons donné un titre (paramètre <kbd>title</kbd>) 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 <kbd>type</kbd> qui renseigné à <kbd>MENU_NORMAL_ITEM</kbd> indique à Drupal de rendre le menu visible.
</p>
<p>
Enfin les paramètre <kbd>access callback</kbd> permet à n'importe quel utilisateur étant capable de voir un node, d'accéder à ce menu. 
</p> 
<p> 
  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. 
<p> 
<p> 
  Il ne nous reste maintenant plus qu'à mettre un véritable corps à notre callback pour obtenir enfin notre liste de courses 

  <div class='code-block code-block-fragment'>
  <div class='container'>
  &nbsp;<span class="re0">$path</span><span class="sy0">=</span> drupal_get_path<span class="br0">&#40;</span><span class="st0">'module'</span><span class="sy0">,</span> <span class="st0">'courses'</span><span class="br0">&#41;</span><span class="sy0">;</span><br />
&nbsp; drupal_add_css<span class="br0">&#40;</span><span class="re0">$path</span> <span class="sy0">.</span> <span class="st0">'/default.css'</span><span class="br0">&#41;</span><span class="sy0">;</span><br />
&nbsp; drupal_set_title<span class="br0">&#40;</span>t<span class="br0">&#40;</span><span class="st0">'Liste des Courses'</span><span class="br0">&#41;</span><span class="br0">&#41;</span><span class="sy0">;</span><br />
&nbsp; <span class="re0">$cursor</span> <span class="sy0">=</span> db_query<span class="br0">&#40;</span><span class="st0">&quot;<br />
&nbsp; &nbsp; select n.*,i.* from node n <br />
&nbsp; &nbsp; &nbsp; inner join node_produit i on n.nid=i.nid<br />
&nbsp; &nbsp; where n.type='produit'<br />
&nbsp; &nbsp; order by n.title&quot;</span><span class="br0">&#41;</span><span class="sy0">;</span><br />
<br />
&nbsp; <span class="re0">$output</span><span class="sy0">=</span> <span class="st0">&quot;&lt;table class='liste_produits'&gt;<br />
&nbsp; &lt;tr&gt;&lt;th&gt;Produit&lt;/th&gt;&lt;th&gt;Seuil&lt;/th&gt;&lt;th&gt;Quantité&lt;/th&gt;&lt;th&gt;Action&lt;/th&gt;&lt;/tr&gt;<br />
&nbsp; &quot;</span><span class="sy0">;</span><br />
&nbsp; <a target="blank" href="http://www.php.net/while"><span class="kw1">while</span></a> <span class="br0">&#40;</span><span class="re0">$node</span><span class="sy0">=</span>db_fetch_object<span class="br0">&#40;</span><span class="re0">$cursor</span><span class="br0">&#41;</span><span class="br0">&#41;</span> <span class="br0">&#123;</span><br />
&nbsp; &nbsp; <span class="re0">$output</span> <span class="sy0">.=</span> <span class="st0">&quot;&lt;tr&quot;</span><span class="sy0">;</span><br />
&nbsp; &nbsp; <a target="blank" href="http://www.php.net/if"><span class="kw1">if</span></a> <span class="br0">&#40;</span><span class="re0">$node</span><span class="sy0">-&gt;</span><span class="me1">quantit</span>é <span class="sy0">&lt;</span> <span class="re0">$node</span><span class="sy0">-&gt;</span><span class="me1">seuil</span><span class="br0">&#41;</span> <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; <span class="re0">$output</span> <span class="sy0">.=</span> <span class="st0">&quot; class='manquant'&quot;</span><span class="sy0">;</span><br />
&nbsp; &nbsp; <span class="br0">&#125;</span><br />
&nbsp; &nbsp; <span class="re0">$output</span> <span class="sy0">.=</span> <span class="st0">&quot;&gt;&lt;td&gt;&quot;</span><span class="sy0">.</span><span class="re0">$node</span><span class="sy0">-&gt;</span><span class="me1">title</span><span class="sy0">.</span><span class="st0">&quot;&lt;/td&gt;&lt;td&gt;&quot;</span><span class="sy0">.</span><span class="re0">$node</span><span class="sy0">-&gt;</span><span class="me1">seuil</span><span class="sy0">.</span><span class="st0">&quot;&lt;/td&gt;&lt;td&gt;$node-&gt;quantite&lt;/td&gt;&quot;</span><span class="sy0">;</span><br />
&nbsp; &nbsp; <span class="re0">$output</span> <span class="sy0">.=</span> <span class="st0">&quot;&lt;td&gt;&quot;</span><span class="sy0">;</span><br />
&nbsp; &nbsp; <a target="blank" href="http://www.php.net/if"><span class="kw1">if</span></a> <span class="br0">&#40;</span><span class="re0">$node</span><span class="sy0">-&gt;</span><span class="me1">quantite</span><span class="sy0">&gt;</span><span class="nu0">0</span><span class="br0">&#41;</span> <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; <span class="re0">$output</span> <span class="sy0">.=</span> l<span class="br0">&#40;</span><span class="st0">&quot;Diminuer&quot;</span><span class="sy0">,</span><span class="st0">&quot;courses/diminuer/&quot;</span><span class="sy0">.</span><span class="re0">$node</span><span class="sy0">-&gt;</span><span class="me1">nid</span><span class="br0">&#41;</span><span class="sy0">;</span><br />
&nbsp; &nbsp; &nbsp; <span class="re0">$output</span> <span class="sy0">.=</span> <span class="st0">&quot; | &quot;</span><span class="sy0">;</span><br />
&nbsp; &nbsp; <span class="br0">&#125;</span><br />
&nbsp; &nbsp; <span class="re0">$output</span> <span class="sy0">.=</span> l<span class="br0">&#40;</span><span class="st0">&quot;Modifier&quot;</span><span class="sy0">,</span><span class="st0">&quot;node/&quot;</span><span class="sy0">.</span><span class="re0">$node</span><span class="sy0">-&gt;</span><span class="me1">nid</span><span class="sy0">.</span><span class="st0">&quot;/edit&quot;</span><span class="br0">&#41;</span><span class="sy0">;</span><br />
&nbsp; &nbsp; <span class="re0">$output</span> <span class="sy0">.=</span> <span class="st0">&quot;&lt;/td&gt;&quot;</span><span class="sy0">;</span><br />
&nbsp; &nbsp; <span class="re0">$output</span> <span class="sy0">.=</span> <span class="st0">&quot;&lt;/tr&gt;&quot;</span><span class="sy0">;</span><br />
&nbsp; <span class="br0">&#125;</span><br />
&nbsp; <span class="re0">$output</span><span class="sy0">.=</span><span class="st0">&quot;&lt;/table&gt;&quot;</span><span class="sy0">;</span><br />
&nbsp; <a target="blank" href="http://www.php.net/return"><span class="kw1">return</span></a> <span class="re0">$output</span><span class="sy0">;</span><br />
<span class="br0">&#125;</span>
  </div>
  <div class='caption'>corps de la fonction de callback</div>
  </div> 
</p> 


<p> 
   La fonction commence par deux lignes dont l'objectif est de demander à Drupal de prendre la feuille de style <kbd>default.css</kbd> 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 <a class='external' target='_blank' href='/node/1277%2523module' >tutoriel</a>. Cette feuille de style va juste nous servir à mettre en évidence les lignes de produits qui doivent être rachetés. 

  <div class='code-block code-block-fragment'>
  <div class='container'>
  TR<span class="re1">.manquant</span> TD <span class="br0">&#123;</span> <br />
&nbsp; <span class="kw1">color</span><span class="sy0">:</span> <span class="kw2">red</span><span class="sy0">;</span> <br />
<span class="br0">&#125;</span>
  </div>
  <div class='caption'>Fichier default.css à mettre dans le dossier du module</div>
  </div> 
</p> 
<p> 
  La requête SQL qui suit nous permet d'itérer sur la liste des nodes de type <kbd>produit</kbd> en y ajoutant les informations de la table <kbd>node_produit</kbd>. Nous aurions pu seulement récupérer ici le <kbD>nid</kbd> et utiliser la fonction <kbd>node_load</kbd> 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 <kbd>$node</kbd> en ligne d'un tableau, qui sert de retour à la fonction de call-back. 
</p> 
<p>
  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).
</p>
<p> 
   Notez l'utilisation de la fonction Drupal, <kbd>l(…)</kbd>. 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. 
</p> 
<p>
   Voyons maintenant comment câbler notre action <kbd>diminuer</kbd>. 
</p>


	<a name='chapter_9'></a>
  <h2>Interactivité</h2>
	 
<p> 
    L'action <kbd>diminuer</kbd> codée en lien dans la colonne <kbd>action</kbd> de notre tableau, s'attend à ce que Drupal sache reconnaître un <kbd>path</kbd> de la forme <kbd>couses/diminuer/1234</kbd>. <kbd>1234</kbd> représentant le <kbd>nid</kbd> 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.  

  <div class='code-block code-block-fragment'>
  <div class='container'>
  <span class="re0">$items</span><span class="br0">&#91;</span><span class="st0">'courses/diminuer/%'</span><span class="br0">&#93;</span><span class="sy0">=</span> <a target="blank" href="http://www.php.net/array"><span class="kw3">array</span></a> <span class="br0">&#40;</span><br />
&nbsp; <span class="st0">'page callback'</span> <span class="sy0">=&gt;</span> <span class="st0">'courses_callback_diminuer_quantite'</span><span class="sy0">,</span><br />
&nbsp; <span class="st0">'page arguments'</span> <span class="sy0">=&gt;</span> <a target="blank" href="http://www.php.net/array"><span class="kw3">array</span></a> <span class="br0">&#40;</span><span class="nu0">2</span><span class="br0">&#41;</span><span class="sy0">,</span><br />
&nbsp; <span class="st0">'type'</span> <span class="sy0">=&gt;</span> MENU_CALLBACK<span class="sy0">,</span><br />
&nbsp; <span class="st0">'access callback'</span> <span class="sy0">=&gt;</span> <span class="st0">'node_access'</span><span class="sy0">,</span><br />
&nbsp; <span class="st0">'access arguments'</span> <span class="sy0">=&gt;</span> <a target="blank" href="http://www.php.net/array"><span class="kw3">array</span></a><span class="br0">&#40;</span><span class="st0">'view'</span><span class="sy0">,</span> <span class="nu0">1</span><span class="br0">&#41;</span><br />
<span class="br0">&#41;</span><span class="sy0">;</span>
  </div>
  <div class='caption'>à insérer après le premier $items[]=..., dans la fonction courses_menu</div>
  </div> 
</p> 
<p> 
   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 <kbd>%</kbd>. 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. 
</p>
<p>
   Ce motif représente un paramètre qu'il est possible de transmettre à la fonction callback par la propriété <kbd>#page arguments</kbd>. Il s'agit d'un simple tableau contenant les indexes (débutant à 0) des parties variables du path (ici le morceau de rang 2). 
</p>

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

  <div class='code-block code-block-fragment'>
  <div class='container'>
  <a target="blank" href="http://www.php.net/function"><span class="kw2">function</span></a> courses_callback_diminuer_quantite<span class="br0">&#40;</span><span class="re0">$nid</span><span class="br0">&#41;</span> <span class="br0">&#123;</span><br />
&nbsp; <span class="re0">$node</span><span class="sy0">=</span>node_load<span class="br0">&#40;</span><span class="re0">$nid</span><span class="br0">&#41;</span><span class="sy0">;</span><br />
&nbsp; <a target="blank" href="http://www.php.net/if"><span class="kw1">if</span></a> <span class="br0">&#40;</span><span class="re0">$node</span><span class="sy0">-&gt;</span><span class="me1">quantite</span><span class="sy0">&gt;</span><span class="nu0">0</span><span class="br0">&#41;</span> <span class="br0">&#123;</span><br />
&nbsp; &nbsp; <span class="re0">$node</span><span class="sy0">-&gt;</span><span class="me1">quantite</span><span class="sy0">--;</span><br />
&nbsp; <span class="br0">&#125;</span><br />
&nbsp; node_save<span class="br0">&#40;</span><span class="re0">$node</span><span class="br0">&#41;</span><span class="sy0">;</span><br />
&nbsp; <a target="blank" href="http://www.php.net/return"><span class="kw1">return</span></a> courses_callback_liste<span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">;</span><br />
<span class="br0">&#125;</span>
  </div>
  
  </div> 
</p> 
<p>
Le traitement effectué par cette fonction de callback consiste simplement à charger dans l'objet <kbd>$node</kbd> le node dont le <kbd>nid</kbd> est passé en paramètre. Ensuite nous décrémentons la quantité. Enfin nous sauvegardons l'objet en base de données.
</p>


	<a name='chapter_10'></a>
  <h2>Et notre bloc alors ?</h2>
	
<p>
  Pour l'instant, notre bloc est resté avec ses valeurs statiques, il est grand temps de remplacer cela par des valeurs réelles. Pour se faire, rien de nouveau, nous allons utiliser ce que nous avons déjà fait avec la fonction qui liste les items et remplacer la fonction <kbd>courses_contenu_block</kbd> du précédent tutoriel avec ceci :
  
  <div class='code-block code-block-fragment'>
  <div class='container'>
  <span class="re0">$cursor</span> <span class="sy0">=</span> db_query<span class="br0">&#40;</span><span class="st0">&quot;<br />
&nbsp; select n.*,i.* from node n <br />
&nbsp; &nbsp; inner join node_produit i on n.nid=i.nid<br />
&nbsp; where n.type='produit'<br />
&nbsp; order by n.title <br />
&nbsp; limit %d&quot;</span><span class="sy0">,</span> courses_nombre_item_max<span class="br0">&#40;</span><span class="br0">&#41;</span><span class="br0">&#41;</span><span class="sy0">;</span><br />
<a target="blank" href="http://www.php.net/while"><span class="kw1">while</span></a> <span class="br0">&#40;</span><span class="re0">$item</span><span class="sy0">=</span>db_fetch_array<span class="br0">&#40;</span><span class="re0">$cursor</span><span class="br0">&#41;</span><span class="br0">&#41;</span> <span class="br0">&#123;</span><br />
&nbsp; <span class="re0">$q</span><span class="sy0">=</span><span class="re0">$item</span><span class="br0">&#91;</span><span class="st0">'quantite'</span><span class="br0">&#93;</span><span class="sy0">;</span><br />
&nbsp; <span class="re0">$s</span><span class="sy0">=</span><span class="re0">$item</span><span class="br0">&#91;</span><span class="st0">'seuil'</span><span class="br0">&#93;</span><span class="sy0">;</span><br />
&nbsp; <a target="blank" href="http://www.php.net/if"><span class="kw1">if</span></a> <span class="br0">&#40;</span><span class="re0">$q</span> <span class="sy0">&lt;</span> <span class="re0">$s</span><span class="br0">&#41;</span> <span class="br0">&#123;</span><br />
&nbsp; &nbsp; <span class="re0">$result</span><span class="sy0">.=</span><span class="st0">&quot;&lt;li class='leaf'&gt;&quot;</span><span class="sy0">.</span>t<span class="br0">&#40;</span><span class="re0">$item</span><span class="br0">&#91;</span><span class="st0">'title'</span><span class="br0">&#93;</span><span class="br0">&#41;</span><span class="sy0">.</span><span class="st0">' ('</span><span class="sy0">.</span><span class="br0">&#40;</span><span class="re0">$s</span><span class="sy0">-</span><span class="re0">$q</span><span class="br0">&#41;</span><span class="sy0">.</span><span class="st0">&quot;)&lt;/li&gt;&quot;</span><span class="sy0">;</span><br />
&nbsp; <span class="br0">&#125;</span><br />
&nbsp; <span class="re0">$nombre</span><span class="sy0">++;</span><br />
<span class="br0">&#125;</span><br />
<a target="blank" href="http://www.php.net/if"><span class="kw1">if</span></a> <span class="br0">&#40;</span><a target="blank" href="http://www.php.net/strlen"><span class="kw3">strlen</span></a><span class="br0">&#40;</span><span class="re0">$result</span><span class="br0">&#41;</span><span class="sy0">==</span><span class="nu0">0</span><span class="br0">&#41;</span> <span class="br0">&#123;</span><br />
&nbsp; <a target="blank" href="http://www.php.net/return"><span class="kw1">return</span></a> <a target="blank" href="http://www.php.net/null"><span class="kw2">NULL</span></a><span class="sy0">;</span><br />
<span class="br0">&#125;</span> <a target="blank" href="http://www.php.net/else"><span class="kw1">else</span></a> <span class="br0">&#123;</span><br />
&nbsp; <span class="re0">$result</span><span class="sy0">=</span><span class="st0">&quot;&lt;ul class='menu'&gt;&quot;</span><span class="sy0">.</span><span class="re0">$result</span><span class="sy0">.</span><span class="st0">&quot;&lt;/ul&gt;&quot;</span><span class="sy0">;</span><br />
<span class="br0">&#125;</span><br />
<a target="blank" href="http://www.php.net/return"><span class="kw1">return</span></a> <span class="re0">$result</span><span class="sy0">;</span>
  </div>
  
  </div>
</p>
<p>
  La seule chose intéressante dans ce code est le <kbd>return NULL</kbd> à la fin. L'idée est que si nous n'avons aucun produit en manque, nous tombons dans ce cas. Et si Drupal constate que le contenu d'un block est NULL, il n'affiche plus le bloc, titre compris. Cette approche nous permet de ne faire apparaître le bloc QUE lorsqu'il est nécessaire. 
</p>


	<a name='chapter_11'></a>
  <h2>Conclusion</h2>
	 
<p> 
    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 <external href="">CCK</external> et <external href="">Views</kbd>. 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. 
</p>
    ]]></content>
  </entry>
</feed>
