Atelier Drupal 7

Créer un site internet avec un CMS pas comme les autres


précédentsommairesuivant

Chapitre VI Introduction à la création de modules

Développer un module Drupal peut parfois vous sauver si une fonctionnalité n'existe pas ou si vous souhaitez modifier certains comportements de Drupal. S'attaquer à cette tâche peut d'abord paraître insurmontable, mais finalement elle s'avère assez simple.

Le but de ce chapitre est de vous permettre de commencer en douceur la programmation avec Drupal. Il vous présentera toute une palette d'outils qui vous faciliteront votre vie de développeur Drupal.

VI-A. Environnement de développement

Pour développer des modules Drupal, un éditeur de texte suffit - Notepad++ pour Windows ou Gedit pour Linux -, mais un environnement de développement tel qu'Eclipse, vous simplifiera la vie grâce à la complétion automatique et à des options de débogage que vous découvrirez par la suite (chap. Déboguer avec EclipseDéboguer avec Eclipse ).

Cette section est donc facultative si vous êtes uniquement intéressé par la programmation Drupal. Le cas échéant, vous pouvez passer directement au chap. Architecture d'un moduleArchitecture d'un module .

VI-A-1. Installation et configuration d'Eclipse

Pour développer un module Drupal avec Eclipse, le plus simple est de choisir la distribution PDT (PHP Developement Tools - Outils de développement PHP). Vous pourrez la trouver à l'adresse suivante : http://www.eclipse.org/pdt/downloads. Cependant, si Eclipse est déjà installé sur votre configuration, il est possible d'installer PDT sous forme de plugins. Ce type d'installation ne sera pas détaillé ici.

VI-A-1-a. Installation sous Windows

-> Rendez-vous à l'adresse http://www.eclipse.org/pdt/downloads.

-> Téléchargez le package All-In-One Windows 32-bit (version PDT 2.2.0 utilisée pour ce livre).

-> Extrayez le contenu de l'archive dans un répertoire (c:\Programmes\eclipse pour ce livre).

Eclipse est un programme écrit en Java, il faut donc que l'environnement d'exécution Java soit également installé (JRE - http://www.java.com/fr/download/).

-> Exécutez eclipse.exe (c:\Programmes\eclipse\eclipse.exe pour ce livre).

-> Sélectionnez le répertoire de Workspace par défaut et cochez la case Use this as the default and do not ask again

Image non disponible
Sélection du Workspace au lancement d'Eclipse

Le Workspace est l'espace de travail (un répertoire) ou Eclipse va stocker des données de configuration dans le sous-dossier .metadata. Lorsque vous créez un nouveau projet, c'est également ce répertoire qui sera utilisé.
Veillez donc à ne pas choisir un sous-répertoire de c:\wamp, car vous n'allez pas créer un nouveau projet, mais en créer à partir du répertoire Drupal existant, et il n'est pas possible d'importer un projet inclus dans le répertoire Workspace.

Il est possible de changer de Workspace à partir d'Eclipse dans le menu File - Switch Workspace.

-> Cliquez sur OK.

Vous arrivez alors sur votre espace de travail. Il faut maintenant configurer Eclipse pour Drupal. Rendez-vous au chap. Configuration d'Eclipse pour DrupalConfiguration d'Eclipse pour Drupal .

VI-A-1-b. Installation sous Ubuntu

Installer Java

Eclipse est un programme écrit en Java, il faut donc tout d'abord que votre installation puisse exécuter un programme Java.

Vous pouvez consulter la documentation du site ubuntu-fr pour installer Java d'une autre façon : http://doc.ubuntu-fr.org/java.

Il faut tout d'abord ajouter les dépôts qui contiennent l'environnement Java.

-> Démarre Synaptic.

-> Onglet Autres logiciels.

-> Sélectionner la ligne Partenaires de Canonical.

-> Bouton Fermer.

-> Puis, bouton Recharger de la fenêtre principale de Synaptic.

Il suffit maintenant d'installer les paquets Java :

 
Sélectionnez
sudo apt-get install sun-java6-jre sun-java6-plugin sun-java6-fonts

Installer Eclipse

Vous pouvez consulter la documentation du site ubuntu-fr pour installer Eclipse d'une autre façon : http://doc.ubuntu-fr.org/eclipse.

-> Rendez-vous à l'adresse http://www.eclipse.org/pdt/downloads.

-> Téléchargez le package Linux x86/GTK 2 32-bit ou 64-bit(version PDT 2.2.0 utilisée pour ce livre).

-> Extrayez le contenu de l'archive dans un répertoire (/home/atelier/eclipse)...

-> Exécutez le programme /home/atelier/eclipse/eclipse

Image non disponible
Eclipse sur Ubuntu

VI-A-1-c. Configuration d'Eclipse pour Drupal

Association de fichiers

Un module Drupal comporte des fichiers contenant du code php, et qui ont des extensions différentes de .php. C'est le cas pour les fichiers *.module, *.install, *.theme et *.engine. Il faut donc configurer Eclipse pour qu'il traite ces fichiers comme des fichiers php classiques.

-> Dans Eclipse, cliquez sur Window - Preferences.

-> Dans la liste de gauche sélectionnez la ligne General - Content Types.

-> Dans la zone Content types, sélectionnez la ligne Text - PHP Content Type

Image non disponible
La fenêtre des préférences, section Types de contenus.

-> Bouton Add...

-> Ajoutez *.module dans la zone de texte.

-> Faites de même pour les extensions *.install, *.theme et *.engine.

Les quatre nouvelles extensions devraient maintenant apparaître dans la zone File associations.

-> Validez la fenêtre des préférences en cliquant sur OK.

Indentation

Par convention, tous les fichiers de Drupal doivent être indentés par deux espaces. Eclipse indente par défaut d'une tabulation de quatre blancs, mais il est possible de modifier ce comportement.

-> Dans Eclipse, cliquez Window - Preferences.

-> Dans la liste de gauche, sélectionnez la ligne General - Editors - Text Editors.

-> À la ligne Displayed tab width, indiquez 2.

-> Cochez la case Insert spaces for tabs

Image non disponible
Réglage de l'indentation dans Eclipse.

Les préférences permettent de régler un nombre important de paramètres dans Eclipse. La zone de texte située en haut à gauche de la fenêtre permet de faire une recherche parmi toutes les préférences. Par exemple, sur la copie d'écran précédente, seuls les items contenant le mot tab ont été sélectionnés.

-> Bouton OK.

-> Puis menu File - Restart pour que les préférences modifiées soient prises en compte.

Création d'un projet à partir d'un dossier Drupal

Un projet sous Eclipse PDT comporte l'ensemble des fichiers du site web. Pour une installation Drupal, c'est donc le répertoire racine de votre site qu'il va falloir importer dans le projet.

-> Menu File - New - PHP Project.

-> Donnez un nom à votre projet dans la zone Project name (drupal pour ce livre).

-> Sélectionnez l'option Create project at existing location (from existing source) et pointez vers votre répertoire d'installation Drupal (c:\wamp\www\drupal).

Image non disponible
Création d'un nouveau projet à partir d'un répertoire existant

-> Bouton Finish.

-> Fermez la fenêtre Welcome.

Vous pouvez maintenant vérifier que les fichiers *.module s'ouvrent bien avec l'éditeur PHP et qu'ils sont bien colorisés.

Image non disponible
Le fichier modules/block/block.module édité avec Eclipse.

Eclipse est maintenant prêt à être utilisé pour développer un nouveau module Drupal !

Vous en apprendrez plus sur Eclipse au chap. Déboguer avec EclipseDéboguer avec Eclipse .

VI-A-2. Architecture d'un module

Dans ce chapitre, vous créerez votre premier module qui affichera un bloc contenant le fameux message « Hello World ! » Il est bien sûr possible de créer un bloc de façon plus simple via la page de gestion des blocs, mais cela vous permettra de comprendre quelques éléments essentiels de la programmation Drupal.

VI-A-2-a. Le répertoire du module et le fichier .info

Comme pour les thèmes, chaque module possède son propre répertoire.

-> Le module s'appellera Hello, il faut donc créer le répertoire sites/all/modules/hello.

Il est possible de créer un répertoire ou des fichiers directement depuis l'arborescence d'Eclipse : clic droit à l'endroit où vous voulez créer le répertoire puis New - Folder.

Comme pour les thèmes, les informations générales des modules sont inscrites dans un fichier .info.

-> Créez le fichier hello.info dans votre répertoire hello.

-> Copiez-y le code suivant :

 
Sélectionnez
; $Id:
name = Hello
description = Hello from Atelier Drupal.
core = 7.x
version = 7.x-0.x-dev
package = Atelier Drupal 
files[] = hello.module

-> Créez un fichier hello.module vide dans le répertoire du module.

Ce fichier doit exister pour que Drupal affiche les informations relatives aux modules.

-> Rendez-vous sur la page d'activation : menu Modules

Image non disponible
Le fichier .info interprété par Drupal

Le module hello apparaît dans la liste à une nouvelle section ATELIER DRUPAL.

Voici une description de chaque ligne du fichier .info.

; $Id: Ligne utilisée par le CVS de Drupal pour la gestion des versions du fichier.
name Nom du module, affiché dans la colonne NOM.
description Description du module, affichée dans la colonne DESCRIPTION.
core Indique avec quelle version de Drupal le module est compatible, ici, toutes les versions 7.
version Version du module, affichée dans la colonne VERSION.
package Section dans laquelle le module sera affiché.
files[] Liste des fichiers du module.

VI-A-2-b. Les hooks

Vous êtes maintenant prêt à écrire le code PHP de votre module.

Ce module hello devra afficher un bloc « Hello World ! ».

Image non disponible
L'objectif du module hello

Les blocs sont gérés par le module Block de Drupal, ce module propose entre autres une page de configuration des blocs (menu Structure - lien Blocs) qui permet de choisir la région dans laquelle le bloc sera affiché et se charge ensuite d'afficher les blocs dans chaque région.

Pour le module Hello, il s'agit de dire au module Block : « Je propose un nouveau bloc » qui a pour nom Hello World, pour titre « My first module say » et pour contenu « Hello World !!! ».

Pour que les modules puissent se « parler », Drupal utilise un système de hooks. Les modules peuvent proposer des services (hooks) que les autres peuvent utiliser.

Par exemple, Block propose hook_block_info qui réunira les informations sur les blocs de tous les modules afin de construire sa page (menu Structure - lien Blocs). C'est la première hook que vous allez utiliser :

-> dans le fichier hello.module, insérez le texte suivant :

 
Sélectionnez
<?php
function hello_block_info() {
  $block['hello-block'] = array(
    'info' => 'Hello world !',
  );
  return $block;
}

voyez maintenant le résultat de ce code :

-> activez le module Hello ;

-> menu Structure - lien Blocs

Image non disponible
La hook hook_block_info a pris en compte notre module

Voici maintenant l'explication du code :

<?php Indique que le script contient du code PHP. Remarquez qu'il n'y a pas de balise fermante à la fin du script (?>) c'est une règle de Drupal.
function hello_block_info() Pour implémenter une hook, il faut créer une fonction ayant pour nom <nom_du_module>_<nom_de_la_hook>. Cette fonction du module hello implémente donc hook_block_info.
$block['hello-block'] = array( Cette hook attend en valeur de retour un tableau associatif contenant la liste des blocs du module.
'info' => 'Hello world !' L'élément info du tableau associatif indique la description du bloc telle qu'elle sera affichée sur la page menu Structure - lien Blocs.
return $block; La fonction retourne le tableau $block

En résumé, lorsque la page menu Structure - lien Blocs est affichée, le module Block démarre sa hook hook_block_info. Drupal cherche alors dans les modules activés s'ils comportent une fonction portant le nom <nom_du_module>_block_info. Si c'est le cas, il retourne au module Block les tableaux associatifs qui décrivent les blocs des modules.

VI-A-2-c. Rechercher de la documentation sur http://api.drupal.org

Vous avez appris grâce à ce livre comment hook_block_info fonctionnait : le nom de la hook, le type de valeur à retourner, les éléments du tableau associatif à retourner, etc. Mais comment faire pour savoir quelles autres hooks existent et comment elles s'utilisent ? La réponse est sur http://api.drupal.org.

-> Rendez-vous sur le site http://api.drupal.org.

-> Dans la zone de recherche entrez hook_block

Image non disponible
La liste des hooks du module block

Dans la liste qui apparaît, vous pouvez retrouver hook_block_info, mais également hook_block_view qui permet d'afficher les blocs et hook_block_configure, qui permet de personnaliser la page de configuration d'un bloc, etc.

-> Cliquez maintenant sur la ligne hook_block_info

Image non disponible
La documentation de hook_block_info

Sur cette page vous pouvez retrouver une description de la hook :

  • un lien vers la documentation du module block (block.api.php) est proposé ;
  • une explication du fonctionnement de la hook est proposée.

Plus bas, une section Return Value est importante, elle indique que :

  • la hook attend en retour un tableau associatif (Return value : An associative array) dont chaque élément est un bloc et les clés attendues (key-value pairs) ;
  • une seule clé est obligatoire (required), c'est la clé info ;
  • d'autres sont optionnelles : cache permet de gérer la façon dont le bloc sera mis en cache. weight, statuts, region, visibility, pages permettent de régler les valeurs par défaut de votre bloc.

VI-A-2-d. hook_block_view : afficher des blocs

Il s'agit maintenant de définir le titre du bloc (My first module says), son contenu (Hello World !), et de demander au module block de l'afficher. Pour cela, il faut utiliser hook_block_view.

Image non disponible
La documentation de hook_block_view

La page de documentation indique que :

  • cette hook prend un paramètre $delta qui permet d'identifier le block qui s'affiche. En effet, un module peut proposer d'afficher plusieurs blocs ;
  • la valeur de retour attendue est un tableau associatif ;
  • ce tableau associatif devra comporter deux éléments qui ont pour clés « subject » et « content ».

-> Voici donc le code à ajouter au fichier hello.module pour implémenter hook_block_view

 
Sélectionnez
function hello_block_view($delta = '') {
  $block = array(
    'subject' => 'My First module say :',
    'content' => 'Hello World !!!' 
  );
  return $block;
}

La déclaration de fonction doit être identique à celle trouvée sur api.drupal.org. Ne vous privez donc pas d'un copier/coller depuis ce site et n'oubliez pas ensuite de changer le mot hook_ par le nom de votre module (ici hello_block_view).

-> Allez sur la page menu Structure - lien Blocs et mettez ce bloc en Sidebar First sous Bartik.

Vous devriez maintenant voir apparaître le bloc !

VI-A-2-e. Conventions et finitions

Votre module s'affiche, certes, mais il comporte encore quelques défauts pour devenir un module Drupal accepté par la communauté !

Commentaires

La première raison pour laquelle un module Drupal doit être correctement commenté est qu'il est plus facile à reprendre et à maintenir. La seconde est que Drupal utilise ces commentaires de façon mécanique pour générer sa documentation. Les deux pages que vous avez visitées sur api.drupal.org proviennent directement du code source de Drupal ! Cette prouesse est réalisée grâce au logiciel Doxygen (http://www.doxygen.org).

Voici le fichier hello.module correctement commenté :

 
Sélectionnez
<?php
/**
 * @file
 * Display a Hello World block
 */
 
/**
 * Implementation of hook_block_info()
 */
function hello_block_info() {
  $block['hello-block'] = array(
    'info' => 'Hello world !',
  );
  return $block;
}
 
/**
 * Implementation of hook_block_view()
 */
function hello_block_view($delta = '') {
  $block = array(
    'subject' => 'First module say :',
    'content' => 'Hello World !!!' 
  );
  return $block;
}

Un fichier de code source doit débuter avec un commentaire @file qui décrit la fonction principale du fichier.

Chaque fonction doit être décrite avec ses paramètres. Si cette fonction implémente une hook, indiquez juste son nom.

Pour en savoir plus sur la génération automatique de documentation par Doxygen, rendez-vous à la page http://drupal.org/node/1354.

fonction t()

Comme vous avez pu le voir au chap. Site multilingueSite multilingue , chaque chaîne de l'interface d'un module peut être traduite via différents modules. Cela sera possible pour vos propres modules si vous utilisez la fonction t() (pour Translate) autour de chaque chaîne de caractères de votre module :

 
Sélectionnez
$block['hello-block'] = array(
  'info' => t('Hello world !'),
);
 
$block = array (
  'subject' => t('First module say :'),
  'content' => t('Hello World !!!') 
);

Pour certains champs, il ne faut pas utiliser la fonction t(), car elle est automatiquement appelée.

hook_help

Tout module doit implémenter cette hook qui permet d'utiliser le module Help.

 
Sélectionnez
/**
 * Implementation of hook_help()
 */
function hello_help($path, $arg) {
  switch ($path) {
    case 'admin/help#hello':
      return '<p>' . t('Sample module from Atelier Drupal book. This module just provide a hello world block.') . '</p>';
  }
}

Cette hook prend en argument le chemin d'accès à la page d'aide. Le chemin ici est admin/help (page d'aide de Drupal) section hello :

Image non disponible
Le module hello a été ajouté aux pages d'aide

Si ce lien n'apparaît pas, effacez tous les caches.

Image non disponible
Le lien est également ajouté à la page des modules
Image non disponible
Page d'aide du module Hello

Utilisez le module chap. Le module CoderLe module Coder pour voir si votre module respecte les conventions de codage.

Le module Hello que vous avez développé tout au long de cette section vous a permis de découvrir comment débuter avec la programmation Drupal. Mais il ne faisait rien à proprement parler. C'est pourquoi dans la prochaine section, vous allez développer votre premier vrai module Drupal grâce à l'environnement que vous avez mis en place.

VI-B. Votre premier module Drupal

Tout au long de cette section, vous créerez un module qui permet de produire un résumé de votre installation Drupal.

À la fin de cette section, ce module aura une page à l'URL /summary, qui affichera la liste des modules activés, les vocabulaires de taxonomy, et les types de contenus.

Image non disponible
La page du module Summary

Une page de configuration du module permettra de sélectionner les sections à afficher et de modifier les titres de celles-ci.

Image non disponible
La page de configuration du module

Il y a donc du travail !

VI-B-1. La page Summary

VI-B-1-a. Démarrage

Comme pour le module Hello, il faut créer :

-> un répertoire pour le module sites/default/modules/summary (ou sites/all/modules/summary) ;

-> un fichier summary.info

 
Sélectionnez
; $Id:
name = Summary
description = Display a Summary of your Drupal Installation.
core = 7.x
package = Atelier Drupal
files[] = summary.module

-> et enfin un fichier summary.module avec un commentaire descriptif et une page d'aide :

 
Sélectionnez
<?php
 
/*
 * @file
 * Display a Summary of your Drupal Installation.
 */
 
/**
 * Implementation of hook_help()
 */
function summary_help($path, $arg) {
  switch ($path) {
    case 'admin/help#summary':
      return '<p>' . t('Sample module from Atelier Drupal book. This module provide a summary page of your Drupal Installation.') . '</p>';
  }
}

VI-B-1-b. hook_menu() : créez une page associée à une URL

Il s'agit de créer une nouvelle page dont le chemin sera /summary et le titre Summary of your site. Pour cela il faut utiliser la hook hook_menu().

La longue page de documentation de la hook indique que la valeur de retour doit être un tableau associatif dont chaque élément est un menu, car il est bien sûr possible d'avoir plusieurs pages pour un module. La clé de chaque élément doit décrire son chemin.

La hook_menu() ne définit donc pas un item de menu, mais associe une page avec une URL.

Pour chaque menu, un tableau associatif doit être décrit. Ici, vous utiliserez les clés « title », « access arguments », « type » et « page callback ».

-> Ajoutez ce code au fichier summary.module :

 
Sélectionnez
/*
 * Implementation of hook_menu()
 */
function summary_menu() {
  $items['summary'] = array(
    'title' => 'Summary of your site',
    'access arguments' => array(true),
    'type' => MENU_CALLBACK, 
    'page callback' => 'summary_content',
  );
  return $items; 
}
 
/*
 * Content of the summary page
 */
function summary_content() {
  return 'Hello World !!!';
}

Voici une description des clés utilisées pour cet exemple :

'title' Titre de la page. La fonction t() est automatiquement appelée.
'access arguments' Permet de définir les droits d'accès. Ici, tout le monde a le droit d'accéder à cette page.
'type' Type de page et de menu, permet d'indiquer si le menu doit être affiché dans le bloc d'admin, dans le fil d'Arianne, si c'est une sous-page, etc.
'page callback' Nom de la fonction qui sera appelée pour retourner le contenu.

En PHP, une fonction peut prendre en argument le nom d'une autre fonction et demander son exécution par la suite. Elle est alors appelée fonction callback.

-> Activez le module Summary.

-> Pointez votre navigateur vers l'URL /summary

Image non disponible
La page /summary

Il reste maintenant à générer le contenu de cette page.

VI-B-1-c. Liste des modules activés

La première section du module doit afficher la liste des modules. Après recherche sur http://api.drupal.org, la fonction module_list() semble être créée pour cela. Testez la fonction dans le bloc Execute PHP de Devel.

Chap. Devel : simplifiez votre vie de développeurDevel : simplifiez votre vie de développeur .

Image non disponible
Test de module_list() avec le module Devel
Image non disponible
Résultat de la fonction module_list()

La fonction module_list() retourne donc un tableau (Array) contenant la liste des modules activés. Il suffit donc de modifier la fonction summary_content et de traiter le tableau.

 
Sélectionnez
function summary_content(){
  //List of all activated modules
  $summary_module_list = module_list();
  $summary_module_list = t('<h3>List of all activated modules</h3>') . implode($summary_module_list,', ');
  $output = $summary_module_list; 
  return $output;
}
Image non disponible
Le module en action

VI-B-1-d. Liste des vocabulaires de taxonomy

De la même façon que pour les modules, le site http://api.drupal.org informe que la fonction
taxonomy_get_vocabularies() existe.

Image non disponible
dpm(taxonomy_get_vocabularies());

taxonomy_get_vocabularies retourne donc un tableau d'objets (stdClass). Chacun de ces objets décrit un vocabulaire. Le nom du vocabulaire est dans la propriété name des objets. Il faut donc parcourir chaque élément du tableau et récupérer le nom du vocabulaire :

-> ajoutez ce code à la fonction summary_content :

 
Sélectionnez
// List of vocabularies
$summary_vocabularies = taxonomy_get_vocabularies();
$summary_vocabularies_list='';
foreach ($summary_vocabularies as $vocab){
  $summary_vocabularies_list .= $vocab->name . ',';
}
$summary_vocabularies_list = t('<h3>Vocabularies</h3>') . $summary_vocabularies_list;
$output .= $summary_vocabularies_list;
 
return $output;

VI-B-1-e. Exercice : liste des types de nodes

  • Ajoutez le code nécessaire à la fonction summary_content() pour lister les types de nodes existants.
Image non disponible
La section Node types

Corrigé

Image non disponible
dpm(node_type_get_types());

La fonction node_type_get_types retourne un tableau d'objets (stdClass).

 
Sélectionnez
//List of node types 
$summary_node_types = node_type_get_types();
$summary_node_types_list = array();
foreach ($summary_node_types as $node_type) {
  $summary_node_types_list[] = $node_type->name;
}
$summary_node_types_list = t('<h3>Node types</h3>').implode($summary_node_types_list, ', ');
$output .= $summary_node_types_list;

VI-B-2. La page de configuration du module

VI-B-2-a. hook_menu() : ajout d'une deuxième page pour le module

La page de configuration du module summary sera accessible à partir de l'URL
admin/config/system/summary. Il faut donc ajouter un élément au tableau de la hook_menu.

 
Sélectionnez
function summary_menu(){
  $items['summary'] = array(
    'title' => t('Summary of your site'),
    'page callback' => 'summary_content',
    'access arguments' => array(true),
    'type' => MENU_CALLBACK,
  );
 
  $items['admin/config/system/summary'] = array(
    'title' => t('Summary settings'),
    'description' => t('Summary configuration page'),
    'page callback' => 'drupal_get_form',
    'page arguments' => array('summary_admin_settings'),
    'access arguments' => array('administer site configuration'),
    'type' => MENU_NORMAL_ITEM,
  );
 
  return $items; 
}

L'URL de la page (admin/config/system/summary) permet d'ajouter un lien dans la page de configuration (config) à la section système (system).
Le lien Menu item du bloc Devel permet de connaître les informations des différentes pages.

Cette page de configuration sera en fait un formulaire HTML. Pour composer un formulaire, Drupal propose une API bien particulière qui sera décrite plus tard.

'page_callback' Ici, on appelle une fonction Drupal (drupal_get_form) qui construira le formulaire.
'page arguments' Liste des arguments à passer à la fonction callback.
'access argument' Vérifie que l'utilisateur a les droits d'administration du site avant d'afficher la page.
'type' Nom de la fonction qui sera appelée pour retourner le contenu.

Le but est de créer un formulaire, Drupal propose pour cela la fonction drupal_get_form. Cette fonction prend en argument le nom d'une autre fonction qui décrit les éléments qui composeront le formulaire.

La fonction qui décrira le formulaire s'appellera summary_admin_settings, donc hook_menu appellera drupal_get_form(summary_admin_settings) lorsque la page devra s'afficher.

VI-B-2-b. Form API : créer des formulaires HTML dans Drupal

La page d'administration proposera une case à cocher pour chaque section de summary permettant à l'administrateur de choisir si la section doit s'afficher ou non.

-> Ajoutez le code suivant au fichier summary.module :

 
Sélectionnez
/*
 * Define the adminsitration form
 */
function summary_admin_settings(){
  $form['summary_display'] = array(
    '#type' => 'checkboxes',
    '#title' => t('Sections of the summary'),
    '#description' => t('Check the sections to show in the summary page'),
    '#options' => array('module' => t('Module list'), 'vocabulary' => t('Vocabulary list'), 'content_type' => t('Content types')),
  );
  return $form;
}

Un tableau $form est donc créé, chaque élément de ce tableau est un élément du formulaire et peut se paramétrer grâce à des propriétés. Voici la liste des propriétés utilisées :

'#type' Type de widget à utiliser. Ici des cases à cocher.
'#title' Titre à afficher au-dessus du widget.
'#description' Texte d'aide en dessous du widget.
'#options' Propriété propre aux cases à cocher, tableau listant les cases à cocher à afficher et leurs étiquettes.

Une description de tous les éléments pouvant être insérés dans un formulaire est disponible à la page : http://api.drupal.org/api/drupal/developer-topics--forms_api_reference.html.
Le lien Hook_elements() du bloc Devel affiche la liste des éléments disponibles.

-> Menu Configuration - lien Summary settings

Image non disponible
Les premiers éléments du formulaire

VI-B-2-c. system_settings_form : ajouter le bouton de sauvegarde

Il manque le bouton de sauvegarde à votre formulaire. Il serait possible d'en créer un en ajoutant un nouvel élément de #type submit au tableau $form, mais il est préférable d'utiliser la fonction system_settings_form qui ajoute les boutons nécessaires par défaut des formulaires de configuration.

-> Modifiez la dernière ligne de la fonction summary_admin_settings comme ceci :

 
Sélectionnez
return system_settings_form($form);
Image non disponible
Le bouton ajouté par system_settings_form

Le bouton est bien là, mais les paramètres ne sont pas encore enregistrés.

VI-B-2-d. variable_get : sauvegarder des données dans la table variable

Voici comment modifier le code pour que les valeurs soient sauvegardées :

 
Sélectionnez
function summary_admin_settings(){
  $form['summary_display'] = array(
    '#type' => 'checkboxes',
    '#title' => t('Things to show for the summary'),
    '#description' => t('Check the things to show in the summary page'),
    '#options' => array('module' => t('Module list'), 'vocabulary' => t('Vocabulary list'), 'content_type' => t('Content types')),
    '#default_value' => variable_get('summary_display',array('module', 'vocabulary')),
  );
  return system_settings_form($form);
}

La fonction variable_get permet de récupérer des variables enregistrées dans le tableau de variables globales $conf, lui-même stocké dans la table variables de la base de données de Drupal.

Elle prend deux paramètres, le premier, obligatoire, est le nom de la variable à récupérer, le second, optionnel, est la valeur que retourne variable_get si aucune variable n'est trouvée dans $conf.

Ici, on initialise donc le formulaire avec des valeurs par défaut qui seront, soit prises dans le tableau $conf si elles sont présentes, soit prises dans le second paramètre qui indique que les cases module et vocabulary sont cochées par défaut.

Pour afficher ce que contient $conf, vous pouvez exécuter le code suivant dans le bloc Execute PHP du module Devel :
 
Sélectionnez
global $conf;
dpm($conf);

Dernière question ; comment sont sauvegardées ces valeurs ? Eh bien c'est la fonction system_settings_form qui s'occupe de tout !

Pour que la fonction system_settings_form sauvegarde automatiquement les paramètres, il faut veiller à ce que le nom de l'élément de formulaire - $form['summary_display'] - soit identique à celui du premier paramètre de variable_get - variable_get('summary_display').

VI-B-2-e. Exercice : personnalisation des titres des sections

  • Ajoutez des éléments textfield permettant à l'utilisateur de modifier les titres des sections ;
Image non disponible
Modification des titres de sections
  • Ajoutez des éléments fieldset pour les cases à cocher et un autre pour les labels.
Image non disponible
Ajout de fieldset

Corrigé

Ajoutez des éléments textfield permettant à l'utilisateur de modifier les titres des sections

 
Sélectionnez
$form['summary_module_label'] = array(
  '#type' => 'textfield',
  '#title' => t('Label of the module section'),
  '#description' => t('Change the label of the module section'),
  '#default_value' => variable_get('summary_module_label','Activated modules'), 
);
 
$form['summary_taxonomy_label'] = array(
  '#type' => 'textfield',
  '#title' => t('Label of the taxonomy section'),
  '#description' => t('Change the label of the taxonomy section'),
  '#default_value' => variable_get('summary_taxonomy_label','Taxonomy vocabularies'), 
);
 
$form['summary_content_types'] = array(
  '#type' => 'textfield',
  '#title' => t('Label of the content types section'),
  '#description' => t('Change the label of the content types section'),
  '#default_value' => variable_get('summary_content_types','Content types'), 
);

Ajoutez des éléments fieldset pour les cases à cocher et un auteur pour les labels

 
Sélectionnez
/*
 * Define the adminsitration form
 */
function summary_admin_settings(){
  $form['checkbox_visible'] = array(
    '#type' => 'fieldset',
    '#title' => t('Section visibility'),
    '#description' => t('Things to show for the summary'),
    '#collapsible' => TRUE,
    '#collapsed' => TRUE,
  );
 
  $form['checkbox_visible']['summary_display'] = array(
    '#type' => 'checkboxes',
    '#title' => t('Things to show for the summary'),
    '#description' => t('Check the things to show in the summary page'),
    '#options' => array('module' => t('Module list'), 'vocabulary' => t('Vocabulary list'), 'content_type' => t('Content types')),
   '#default_value' => variable_get('summary_display',array('module', 'vocabulary')),
  );
 
   $form['labels'] = array(
    '#type' => 'fieldset',
    '#title' => t('Labels of sections'),
    '#description' => t('Change the labels of the summary'),
    '#collapsible' => TRUE,
    '#collapsed' => TRUE,
  );
 
  $form['labels']['summary_module_label'] = array(
    '#type' => 'textfield',
    '#title' => t('Label of the module section'),
    '#description' => t('Change the label of the module section'),
    '#default_value' => variable_get('summary_module_label','Activated modules'), 
  );
 
  $form['labels']['summary_taxonomy_label'] = array(
    '#type' => 'textfield',
    '#title' => t('Label of the taxonomy section'),
    '#description' => t('Change the label of the taxonomy section'),
    '#default_value' => variable_get('summary_taxonomy_label','Taxonomy vocabularies'), 
  );
 
  $form['labels']['summary_content_types'] = array(
    '#type' => 'textfield',
    '#title' => t('Label of the content types section'),
    '#description' => t('Change the label of the content types section'),
    '#default_value' => variable_get('summary_content_types','Content types'), 
  );
  return system_settings_form($form);
}

VI-B-3. Utilisation des paramètres pour la page Summary

Il faut maintenant récupérer les paramètres sauvegardés dans la table variables par la page de configuration.

Les valeurs des cases à cocher sont stockées à la ligne summary_display de la table variables. La fonction variable_get() permet de récupérer ces valeurs :

-> à la page de configuration du module Summary, cochez uniquement la section Vocabulary list ;

-> bouton Enregistrer la configuration

Image non disponible
dpm(variable_get('summary_display',array()));

Le lien Variable editor du bloc Devel affiche les valeurs des lignes de la table variables.

summary_display est retournée sous forme de tableau associatif. Si la section n'est pas à afficher, sa valeur est à 0 (false), sinon, sa valeur est le nom de la clé (true).

Il suffit donc de tester cette valeur avant d'ajouter chaque section.

-> Modifiez la fonction summary_content comme cela :

 
Sélectionnez
function summary_content() {
  //List of all activated modules
  $summary_module_list = module_list();
  $summary_module_list = t('<h3>Activated modules</h3>') . implode($summary_module_list,', ');
 
  // List of vocabularies
  $summary_vocabularies = taxonomy_get_vocabularies();
  $summary_vocabularies_list='';
  foreach ($summary_vocabularies as $vocab){
    $summary_vocabularies_list .= $vocab->name . ',';
  }
  $summary_vocabularies_list = t('<h3>Vocabularies</h3>') . $summary_vocabularies_list;
 
  // List of content types
  $summary_node_types = node_type_get_types();
  $summary_node_types_list ='';
  foreach ($summary_node_types as $node_types){
    $summary_node_types_list .= $node_types->name . ',';
  }
  $summary_node_types_list = t('<h3>Node type</h3>') . $summary_node_types_list;
 
  $display = variable_get('summary_display',array());
  $output = '';
  if ($display['module']) { $output .= $summary_module_list; }
  if ($display['vocabulary']) { $output .= $summary_vocabularies_list; }
  if ($display['content_type']) { $output .= $summary_node_types_list; }
  return $output; 
}

VI-B-3-a. Exercice : affichage des labels personnalisés

Modifiez la fonction summary_content pour qu'elle affiche les labels de la page de configuration du module.

Image non disponible
Modification des labels
Image non disponible
Page Summary avec labels personnalisés

Corrigé

Les valeurs des labels sont stockées dans les lignes summary_module_label, summary_taxonomy_label et summary_content_types de la table variables. La fonction variable_get() permet de récupérer ces valeurs.

Image non disponible
dpm(variable_get('summary_taxonomy_label',''));

summary_taxonomy_label est donc retournée sous forme de chaîne de caractères correspondant à la valeur du label. Si rien n'est retourné, il faut préciser une valeur par défaut dans la fonction variable_get.

Voici donc la ligne modifiée pour la section liste des vocabulaires :

 
Sélectionnez
$summary_vocabularies_list = t('<h3>Vocabularies</h3>') . $summary_vocabularies_list;

Modifiée en :

 
Sélectionnez
$summary_vocabularies_list = '<h3>' . variable_get('summary_taxonomy_label' ,t('Vocabularies')) . '</h3>' . $summary_vocabularies_list;

Répétez l'opération pour les autres sections.

VI-B-4. Exécuter des requêtes SQL dans un module en récupérer le résultat

Il existe un grand nombre de fonctions dans l'API Drupal, et qui interrogent la base de données à votre place. Mais il est parfois nécessaire de faire ses propres requêtes.

VI-B-4-a. Requête simple retournant une seule ligne

Vous allez commencer par afficher le nombre de nodes publiées dans Drupal. La requête SQL est :

 
Sélectionnez
SELECT count(*)
FROM node
WHERE status = 1

Chap. La Base de données de DrupalLa base de données de Drupal .

La requête ne retourne qu'une seule valeur : le nombre de nodes.

Vous allez maintenant modifier le fichier summary.module pour qu'il affiche une nouvelle section Number of nodes.

Modifiez la fin de la fonction summary_content() ainsi :

 
Sélectionnez
//Number of nodes
$query = 'SELECT count(*) FROM node WHERE status = 1';
$summary_node_count = db_query($query)->fetchField();
$summary_node_count = t('<h3>Number of nodes</h3>') . $summary_node_count;
 
$display = variable_get('summary_display',array()); 
$output = '';
if ($display['module'])
$output .= $summary_module_list ; 
if ($display['vocabulary']) 
$output .= $summary_vocabularies_list; 
if (array_key_exists('content_type',$display) && $display['content_type'])
$output .= $summary_node_types_list;
$output .= $summary_node_count; 
 
return $output; 
Image non disponible
La nouvelle section de summary

La fonction : db_query prend en paramètre la requête SQL et retourne un objet. Une méthode de cet objet est fetchField qui retourne le résultat de la requête.

Noms de tables

La requête précédente retourne le résultat escompté, et pourtant elle pose un problème. Il est en effet possible de préfixer les tables avec une chaîne de caractères à l'installation de Drupal. Ainsi, la table node n'aura peut-être pas pour nom node mais drupal_node (si les tables sont préfixées drupal_). Pour que Drupal gère cela, il faut entourer le nom des tables par des accolades.

La requête devient donc :

 
Sélectionnez
$query = 'SELECT count(*) FROM {node} WHERE status = 1';

VI-B-4-b. Requête avec résultat sur plusieurs lignes

Pour modifier votre nouveau paragraphe pour qu'il affiche le nombre de nodes par type, la requête SQL devient :

 
Sélectionnez
SELECT type, count(*) AS "Nombre nodes"
FROM node
GROUP BY type

Dans le module summary, la requête devient donc :

 
Sélectionnez
//Number of nodes per type
$query = 'SELECT type, count(*) FROM {node} GROUP BY type';

L'objet retourné par db_query (de type DatabaseStatementBase) permet d'exécuter plusieurs méthodes :

rowCount Retourne le nombre de lignes du résultat de la requêteImage non disponible
fecthAssoc Retourne une ligne du résultat de la requête sous forme de tableau (nom colonne - valeur). Au prochain appel de la fonction, la ligne suivante est retournée :Image non disponible
fetchAllKeyed Retourne l'ensemble des résultats sous forme de tableau. La clé des éléments est la première colonne de la requête.Image non disponible
fetchAllAssoc Retourne l'ensemble des résultats sous forme de tableau. La colonne devant servir de clé est passée en paramètre.Image non disponible
getQueryString Retourne la requête SQL de l'objet.Image non disponible
fetchCol Retourne tous les éléments d'une colonne. Le numéro de la colonne est passé en paramètre.Image non disponible
fetchField Retourne la première colonne de la première ligne.Image non disponible

Il y a donc plusieurs solutions possibles pour arriver au même résultat.

  • Exemple de traitement des résultats en utilisant la méthode fetchAllAssoc() :
 
Sélectionnez
//Number of nodes per type
$query = 'SELECT type, count(*) AS count FROM {node} GROUP BY type';
$result = db_query($query)->fetchAllAssoc('type');
$summary_node_count_type = '';
foreach($result as $row) {
  $summary_node_count_type .= $row->type.' : '.$row->count.'<br/>'; 
}
$summary_node_count = t('<h3>Number of nodes per type</h3>').$summary_node_count_type ;
  • Exemple de traitement des résultats en utilisant la méthode fetchAssoc() :
 
Sélectionnez
$query = 'SELECT type, count(*) AS count FROM {node} GROUP BY type';
//Avec la méthode fetchAssoc
$result = db_query($query);
$summary_node_count_type = '';
while ($row = $result->fetchAssoc()) {
  $summary_node_count_type .= $row['type'].' : '.$row['count'].'<br/>';
}
$summary_node_count = t('<h3>Number of nodes per type</h3>').$summary_node_count_type ;
Image non disponible
La section nombre de nodes par type

VI-B-4-c. Requête avec variables

Vous aurez parfois besoin de positionner des variables dans vos requêtes.

Voici par exemple une requête qui sélectionne le titre des nodes publiées de type article :

 
Sélectionnez
$query = 'SELECT title FROM {node} WHERE type="article" AND status=1';
$result = db_query($query);

Imaginez maintenant que vous avez deux variables $type et $status contenant respectivement le type et le statut des nodes à afficher, la requête devient alors :

 
Sélectionnez
$query = 'SELECT title FROM {node} WHERE type = :type AND status = :status';
$result = db_query($query, array( ':type' => $type, ':status' => $status));

Il faut donc utiliser des jokers (:type, :status), leurs valeurs sont ensuite remplacées lors de l'exécution de la fonction db_query. Celle-ci prend un tableau en deuxième argument qui contient la liste des valeurs et des jokers.

VI-B-4-d. Requête avec le constructeur de requêtes

La requête précédente est une requête simple, mais le système des jokers peut vite devenir confus si votre requête comporte un grand nombre de paramètres. Drupal propose alors tout un système de construction de requêtes via PHP.

Voici par exemple ce que deviendrait la requête précédente :

 
Sélectionnez
$query = db_select(node, n);
$query
  ->fields('n', array('title'))
  ->condition('type', $type)
  ->condition('status', $status);
$result = $query->execute();

L'idée est donc de commencer par créer un objet de type SelectQuery en appelant la fonction db_select et ensuite de le modifier en lui ajoutant des directives SQL. Lorsque celle-ci est construite, il faut lancer la méthode execute() pour récupérer le résultat de la requête.

La fonction db_select prend en premier argument le nom de la table à utiliser (node) et en deuxième argument un alias (n). C'est cet alias qui sera utilisé dans les autres directives SQL (fields('n', array('title')).

Cette méthode permet de construire une requête tout au long d'un script PHP sans avoir à manipuler de longues chaînes de caractères pour former une requête SQL valide.

SelectQuery possède quelques dizaines de méthodes correspondant à des directives SQL. Vous pouvez retrouver la liste de ces méthodes sur la page SelectQuery du site http://api.drupal.org.
Image non disponible
Extrait de la page de documentation de SelectQuery

Vous pouvez utiliser les méthodes DeleteQuery, InsertQuery et UpdateQuery pour des requêtes SQL delete, insert et update.

VI-B-5. Theming du contenu

Dans le module Summary, vous avez inséré quelques balises HTML directement dans le code PHP (balise H3 pour les titres). Dans cette section, vous permettrez aux créateurs de thèmes de modifier l'apparence du contenu de votre module.

Pour bien comprendre cette section, lisez le chap. Les thèmesChapitre V Les thèmes Drupal dans son ensemble.

VI-B-5-a. Affichage du nombre de nodes sous forme de tableau

Il serait plus lisible d'afficher le nombre de nodes par type de contenu sous forme de tableau :

Image non disponible
Affichage d'un tableau avec Bartik

Pour cela, il faut utiliser la fonction de theme Drupal theme_table. Vous pouvez rechercher comment elle s'utilise sur api.drupal.org.

Image non disponible
Les fonctions de thème sur api.drupal.org

Vous pouvez retrouver la liste des fonctions de thème à la page
http://api.drupal.org/api/group/themeable/7.

Lorsqu'elles sont utilisées à l'intérieur de Drupal, il faut appeler les fonctions de thème par la fonction theme() de cette façon :

  • theme_table($variables) devient theme('table', $variables) ;
  • theme_date($variables) devient theme('date', $variables) ;
  • etc.

La fonction theme_table prend en paramètre un tableau qui contient lui-même deux tableaux. Le premier doit contenir les en-têtes (header), le second les lignes (rows).

Voici comment implémenter cette fonction pour le nombre de nodes par type :

 
Sélectionnez
$result = db_query($query);
$header = array (t('Node type'), '#');
while ($row = $result->fetchAssoc()) {
  $rows[] = $row;
}
$table = theme('table', array ('header' => $header, 'rows' => $rows));
$summary_node_count_type = t('<h3>Number of nodes per type</h3>').$table;
Image non disponible
Contenu des deux tableaux $header et $rows passés en paramètre

VI-B-5-b. Implémentation de hook_theme

Vous allez maintenant créer votre propre fonction de thème que d'autres développeurs et créateurs de thèmes pourront utiliser.

Cette fonction permettra de présenter un paragraphe du module summary :

Image non disponible
La fonction de thème theme_summary_paragraph()

Pour cela, votre module doit implémenter la hook hook_theme() qui prend en paramètre la liste des fonctions de thème du module.

Il faut préciser les paramètres qu'aura chaque fonction. Ici, vous avez besoin du titre de la section et de son contenu.

 
Sélectionnez
/**
 * Implementation of hook_theme
 */
function summary_theme () {
  $functions = array(
    'summary_paragraph' => array (
      'variables' => array('title' => NULL, 'content' => NULL)
    )
  );
  return $functions;
}
Vous pouvez consulter la liste de fonctions de thème disponible sur votre installation en utilisant le lien Theme registry du bloc Devel.
-> Videz les caches.
-> Lien Theme registry du bloc devel (devel/theme/registry).
Image non disponible
La fonction de thème de summary est enregistrée

VI-B-5-c. Création d'une fonction par défaut pour le module

Il faut maintenant fournir une fonction par défaut dans le module au cas où le thème actif ne surcharge pas la fonction de thème.

Cette fonction affiche uniquement le titre dans une balise <h4> et le contenu dans une balise <p>

 
Sélectionnez
/**
 * Fonction de thème par défaut
 */
function theme_summary_paragraph($variables) {
  $output = '<h4>'.$variable['title'].'</h4>';
  $output .= '<p>'.$variable['content'].'</p>';
  return $output;
}

VI-B-5-d. Appel de la fonction de thème dans le module

Vous utiliserez votre fonction dans le module pour présenter vos paragraphes. Il suffit de passer en paramètre les deux chaînes composants le titre et le contenu dans un tableau associatif :

 
Sélectionnez
$title = variable_get('summary_content_types',t('Content types'));
$content = implode($summary_node_types_list, ', ');
$summary_node_types_list = theme('summary_paragraph', array('title' => $title, 'content' => $content));
Image non disponible
Le titre de content type est maintenant en <h4>

-> Modifiez le module pour qu'il utilise la fonction pour chacun des paragraphes.

VI-B-5-e. Création d'un template par défaut

Pour un créateur de thèmes, il est plus facile d'utiliser un template de type .tpl.php. Et cela n'est pas beaucoup plus compliqué à fournir qu'une fonction de thème.

Tout d'abord, il faut préciser un nom de template dans la fonction hook_theme :

 
Sélectionnez
/**
 * Implementation of hook_theme
 */
function summary_theme () {
  $functions = array(
    'summary_paragraph' => array (
      'variables' => array('title' => NULL, 'content' => NULL),
      'template' => 'summary_paragraph',
    )
  );
  return $functions;
}

Drupal ajoute automatiquement le suffixe .tpl.php au nom du template.

Il reste à créer le template par défaut summary_paragraph.tpl.php dans le répertoire du module summary :

 
Sélectionnez
<?php 
/**
 * @file
 * Default theme implementation for each paragraph in the summary module.
 *
 * Available variables:
 * - $title: Title of the paragraph.
 * - $content: Content of the paragraph
 */
?>
<li class="summary_item">
  <h3><?php print $title ?></h3>
  <div class="summary_content"><?php print $content ?></div>
</li>

-> Videz les caches.

-> Rechargez votre page

Image non disponible
Summary utilise maintenant un template !

Pour des raisons de performances, évitez de fournir un template lorsque celui-ci sera appelé de nombreuses fois sur une page.

Le but de cette section était de vous ouvrir les portes de la programmation avec Drupal. Si vous désirez aller plus loin, je vous conseille de parcourir le site http://api.drupal.org ou de lire le livre Pro Drupal Developement (http://www.drupalbook.com/).

VI-C. Les outils pour mieux développer avec Drupal

VI-C-1. Devel : simplifiez votre vie de développeur

Le module Devel est une boite à outils pour aider le développeur de modules Drupal.

-> Installez et activez le module Devel (version utilisée dans ce livre : 7.x-1.0).

VI-C-1-a. Le bloc Développement

-> Activez le bloc Développement en barre de gauche de Bartik.

-> Allez sur la page d'accueil de votre site.

S'affiche alors un bloc contenant un menu permettant d'accéder aux fonctionnalités de Devel :

Devel settings Accéder à la page de configuration de Devel.
Empty cache Permet de vider l'ensemble des caches de Drupal.
Execute PHP Code Ouvre une page contenant une zone de texte permettant d'exécuter du code PHP.
Field info Affiche les informations de chaque champ pouvant être attaché à un contenu.
Function reference Affiche la liste de toutes les fonctions utilisées sur le site. Si celles-ci sont dans l'API Drupal 7, un lien vers leur documentation est proposé.
Hook_elements() Liste des éléments pouvant être inclus dans un formulaire.
Lancer le traitement régulier Lance le cron.
Menu item Détaille les paramètres d'un menu (hook_menu). Par exemple : devel/menu/item&path=admin/config/system/site-information, détaillera le menu admin/config/system/site-information.
PHPinfo() Affiche des informations détaillées sur votre configuration PHP.
Rebuild menus Reconfigure l'ensemble des menus. Tous les menus reprennent leur configuration par défaut.
Reinstall modules Désinstalle et réinstalle tous les modules du site.
Session viewer Affiche des informations sur la session en cours.
Theme registry Affiche la liste de toutes les fonctions de thème du site.
Variable editor Affiche la liste de toutes les variables de $conf. Il est également possible de les éditer à partir de cette interface.
Image non disponible
L'éditeur de variables
Image non disponible
Détails d'un menu

VI-C-1-b. Le bloc Execute PHP

-> Activez le bloc Execute PHP en pied de page de Bartik et de Seven.

Il est ensuite possible d'exécuter du code PHP à partir de cette zone de texte.

Image non disponible
Test d'utilisation de la fonction system_region_list()
Image non disponible
Résultat de la fonction

VI-C-1-c. Les fonctions de débogage

Plusieurs fonctions de débogage sont livrées avec Devel. Vous pouvez les insérer n'importe où dans votre code (y compris dans l'interface Drupal).

  S'affiche avec Krumo S'affiche en haut de page S'affiche en zone de notification
dpm() X   X
dvm()     X
kpr() X X  
dpr()   X  

VI-C-1-d. Le générateur de contenu

Ce module permet de créer n'importe quel type de contenu pour tester votre site, il permet également de créer des commentaires, des utilisateurs, des vocabulaires et des termes de taxonomy.

-> Activez le module Devel generate.

-> Menu Configuration - lien Développement.

Vous avez alors accès à différents menus permettant de créer du contenu, des utilisateurs et de la taxonomy.

-> Cliquez sur Generate content.

Image non disponible
Le générateur de contenu
  • Vous pouvez alors régler les différents paramètres avant de générer le contenu en cliquant sur Do it !

VI-C-1-e. Le Profiler SQL

Devel permet de connaître la liste des requêtes qui ont été exécutées pour l'affichage d'une page.

-> Menu Configuration - lien Développement.

-> Cochez la case Afficher la liste des requêtes.

-> Cliquez sur Enregistrer.

VI-C-2. Le module Coder

Le module Coder inspecte le code des modules et indique s'ils ne respectent pas les conventions de codages de Drupal (http://drupal.org/node/318).

-> Installez le module (version utilisée dans ce livre : 7.x-1.0-beta6) - http://drupal.org/project/coder.

-> Activez les modules Coder et Coder Review.

-> Menu Modules

Image non disponible
Coder ajoute un lien Code Review pour chaque module

-> Cliquez sur le lien Code Review de votre module.

-> Constatez le nombre d'erreurs à corriger !

Image non disponible
Un module bien peu respectueux des conventions !

VI-C-3. Drupal for Firebug

Ce module permet de déboguer certaines parties de vos modules à partir de Firebug, module de Firefox.

Installation

Pour que ce module fonctionne, il faut activer le module Drupal et le module Firefox.

-> Installez le module Drupal For Firebug(version utilisée dans ce livre : 7.x-1.2) - http://drupal.org/project/drupalforfirebug.

-> Activez les modules Drupal for Firebug Preprocessor et Drupal for Firebug.

-> Téléchargez et activez le module Drupal For Firebug de Firefox (version utilisée dans ce livre : 0.0.7) - https://addons.mozilla.org/en-US/firefox/addon/drupal-for-firebug/.

Lors de la rédaction de ce livre, le plugin pour Firefox ne fonctionnait pas. C'est pourquoi les copies d'écran ont été prises avec Google chrome avec l'extension Drupal for Chrome.

Utilisation

Chargez une page de Drupal, lancez Firebug, un nouvel onglet Drupal apparaît, il est alors possible d'avoir des informations sur cette page :

Image non disponible
Détail des composants d'un formulaire

Plusieurs sous-onglets sont alors disponibles :

Informations Vous pouvez utiliser la fonction firep() pour afficher des informations dans cet onglet.
Forms Affiche les paramètres des composants des formulaires de la page.
Sql Affiche les requêtes SQL exécutées pour la page si l'option du Profiler SQL est activée (chap. Le Profiler SQLLe Profiler SQL).
User Affiche les informations liées à l'utilisateur.
Node Affiche les informations liées aux nodes chargées sur la page (y compris celles des vues).
View Affiche les informations liées aux vues chargées sur la page.
PHP Fonctionne de la même façon que le bloc Execute PHP du module Devel (chap. Le bloc Execute PHPLe bloc Execute PHP).

VI-C-4. Déboguer avec Eclipse

Lorsque vous développerez des modules complexes, pouvoir déboguer avec une interface graphique peut vous faire gagner du temps : pouvoir mettre des points d'arrêt, exécuter le programme pas à pas et voir directement l'évolution des valeurs des variables peut aider à mieux comprendre ses erreurs.

Dans cette section, vous installerez le débogueur Xdebug sur votre serveur, et vous l'utiliserez avec Eclipse.

VI-C-4-a. Installation de Xdebug sur WampServer

Xdebug est installé par défaut sur Wampserver, mais il n'est pas configuré en mode remote (débogage à distance) :

Pour vérifier l'installation de XDebug sur votre serveur :
-> menu Rapports - lien Tableau de bord d'administration ;
-> lien plus d'informations de la ligne PHP.
Image non disponible
Xdebug est activé !

Pour modifier la configuration de Xdebug :

-> éditez votre fichier php.ini (icône Wampserver - PHP - php.ini) ;

-> modifiez ainsi les lignes de la section ; XDEBUG Extension du fichier :

 
Sélectionnez
[xdebug]
xdebug.remote_enable=on
xdebug.remote_host="127.0.0.1"
xdebug.remote_port=9000
xdebug.remote_handler="dbgp"
xdebug.remote_mode=req

-> enregistrez le fichier et redémarrez WampServer.

VI-C-4-b. Installation de Xdebug sur Ubuntu

Commencez par installer le paquet Xdebug

 
Sélectionnez
sudo apt-get install php5-xdebug

Puis éditez le fichier de configuration de Xdebug :

 
Sélectionnez
sudo gedit /etc/php5/conf.d/xdebug.ini

Ajoutez au fichier les lignes suivantes :

 
Sélectionnez
xdebug.remote_enable=on
xdebug.remote_host="127.0.0.1"
xdebug.remote_port=9000
xdebug.remote_handler="dbgp"
xdebug.remote_mode=req

Sauvegardez le fichier et redémarrez Apache :

 
Sélectionnez
sudo /etc/init.d/apache2 restart

Vous pouvez vérifier si Xdebug s'est bien installé :

-> menu Rapports - lien Tableau de bord d'administration ;

-> lien plus d'informations de la ligne PHP

Image non disponible
Xdebug est bien installé

VI-C-4-c. Module easy Xdebug pour Firefox

Il existe un module pour Firefox qui permet de simplifier le démarrage d'une session xdebug.

-> Dans le menu Modules complémentaires de Firefox, recherchez l'extension easy xdebug (version utilisée pour ce livre easy Xdebug 1.5).

-> Installer le module.

-> Redémarrez Firefox.

Deux icônes s'affichent en bas à droite de Firefox, l'une pour démarrer une session de débogage, l'autre pour la stopper.

Image non disponible
Les icônes de easy xdebug

Vous pouvez afficher ou cacher la barre des modules de Firefox grâce au menu Options - Barre des modules.

VI-C-4-d. Configuration d'Eclipse pour xdebug

Il s'agit maintenant d'indiquer à Eclipse que vous utiliserez Xdebug pour déboguer votre projet Drupal.

-> Menu Window - Preferences.

-> Sélectionnez l'item PHP - Debug.

-> À la ligne PHP Debugger choisissez XDebug.

Image non disponible
Configuration du débogueur

-> Cliquez sur le lien configure... de XDebug.

-> Sélectionnez XDebug dans la liste Installed Debuggers.

-> Bouton Configure.

-> Dans la liste Accept remote session (JIT), choisissez any

Vous pouvez également décocher la case Show super globals in variable views qui vous permettra de limiter le nombre de variables affichées lors du débogage.

-> Bouton OK.

-> Bouton OK.

VI-C-4-e. Utiliser xdebug

Vous allez maintenant déboguer votre fonction summary_content(). Elle est utilisée lors de l'affichage de la page /summary.

-> Ouvrez le fichier sites/all/modules/summary/summary.module.

-> Dans la marge de la première ligne de la fonction, faites un clic droit et choisissez Toggle Breakpoints

Image non disponible
Ajout d'un point d'arrêt dans le script

Un point bleu signifiant le point d'arrêt devrait apparaître dans la marge. Lorsque le programme atteindra cette ligne, il arrêtera de s'exécuter et vous informera sur son état.

Vous pouvez également positionner vos points d'arrêts dans le fichier template de vos thèmes et modules.

-> Dans Firefox, pointez vers l'URL /summary.

-> Démarrez la session xdebug grâce à l'icône Start Xdebug Session de easy Xdebug.

-> Rechargez la page (F5).

Eclipse demande alors le type de perspective qu'il doit utiliser pour la session de débogage

Image non disponible
Eclipse a détecté une session de débogage

-> Bouton Yes.

Une perspective sous Eclipse est un mode de présentation des différentes fenêtres. Vous pouvez passer de l'une à l'autre en cliquant sur les boutons à droite de la barre d'outils.
Image non disponible
Les perspectives de Eclipse

Eclipse s'arrête alors à la première ligne du index.php de Drupal. Utilisez la barre de boutons de la vue Debug d'Eclipse pour naviguer dans le programme.

Image non disponible
Boutons de navigation dans le script

-> Bouton Resume (F8).

Le script se déroule alors jusqu'au prochain point d'arrêt qui est celui que vous avez ajouté dans la fonction summary_content().

-> Continuez à dérouler le script pas à pas (Bouton Step Over (F6)).

-> Remarquez l'évolution des variables dans la vue Variables

Image non disponible
Inspection du fonctionnement du module summary

Si Eclipse ne s'arrête pas sur votre point d'arrêt, il se peut que votre code ne soit pas exécuté par Drupal, car le code HTML généré est en cache. Cela est fréquent pour le contenu des blocs.
Videz alors le cache et rechargez la page.

Bonne route !

J'espère que c'est avec plaisir que vous avez découvert les possibilités de Drupal. Ce livre ne se prétend pas exhaustif, car le sujet est très vaste. J'ai essayé de vous donner les clés pour ouvrir le maximum de portes pour explorer le vaste monde de Drupal. Maintenant, à vous de découvrir LA fonctionnalité que vous recherchez !

À bientôt au détour d'un forum !


précédentsommairesuivant

Vous avez aimé ce tutoriel ? Alors partagez-le en cliquant sur les boutons suivants : Viadeo Twitter Facebook Share on Google+   

  

Licence Creative Commons
Le contenu de cet article est rédigé par Cyprien Roudet et est mis à disposition selon les termes de la Licence Creative Commons Attribution 3.0 non transposé.
Les logos Developpez.com, en-tête, pied de page, css, et look & feel de l'article sont Copyright © 2013 Developpez.com.