Drupal, Module, PHP – Concevoir et réaliser un module sous Drupal



Comme un plugin sous WordPress, un module Drupal a pour fonction d’étendre les fonctionnalités de votre CMS et de l’étendre dans le sens qui vous convient c’est à dire ne fonction des besoins de gestion de de contenu de votre site sous Drupal. Voici la définition simple et officielle de ce qu’est un module Drupal.

Une définition simple d’un module Drupal

A module is a collection of functions that link into Drupal, providing additional functionality to your Drupal installation. After reading this tutorial, you will be able to create a basic block module and use it as a template for more advanced modules and node modules.

Avant de se lancer dans la lecture de cet article et de se livrer à une expérience d’extreme coding :):). Un juste rappel de l’environnement de développement. Notre développement se fait sur une version de Drupal 5.14 et en local sur un MAMP. Pour installer MAMP sur Mac, reportez aux nombreux articles de ce blog. Vous pouvez réaliser la même opération sur un PC à l’aide de Easyphp.

Leveraging Drupal: Getting Your Site Done Right

Leveraging Drupal: Getting Your Site Done Right

Un excellent livre sur le CMS Drupal, qui prend vraiment le partie d'une approche pragmatique et efficace. Rien n'est laissé de côté sur la compréhension de Drupal (thème, module...etc) mais il n'y a rien de superflu non plus. Par ailleurs, une chose rare qui mérite d'être signalée c'est une application concrète de la méthode Agile avec "User storie", "Acceptance Test" pour mener à bien le développement d'un site sous Drupal. Un livre très complet.

Genre(s) : , , , , , , , , , , , , , , , , , ,
Auteur(s) :
Edition(s) :

Pour bien commencer

Il vous faudra créer un répertoire dans sites/all/modules/onthisdate. Il est possible que vous ayez à créer préalablement le répertoire sites/all/modules

Le chemin absolu de notre repertoire sera donc /Applications/MAMP/htdocs/DRUPAL_5_14/sites/all/modules/

Créer et placer un fichier PHP nommé onthisdate.module dans le répertoire nouvellement créé /Applications/MAMP/htdocs/DRUPAL_5_14/sites/all/modules/onthisdate/

Pourquoi dans ce répertoire comme il ne s’agit pas d’un core module mais d’un module de votre composition, il vous sera plus facile de faire les mises à jour des core modules sans écraser vos modules sur-mesure.

Selon les standards de coding de Drupal, vous devez commencer par la balise d’ouverture PHP complète au début de votre fichier <?php mais de ne pas faire de balise de fermeture type ?>

le code source de onthisdate.module est le suivant.

<?php
/* $Id$ */

La string $Id$ n’est utile que si vous souhaitez comptabiliser la date et la version de votre module via un outil de gestion de version (CVS).

La définition officielle du _hook

All functions in your module that will be used by Drupal are named {modulename}_{hook}, where “hook” is a pre-defined function name suffix. Drupal will call these functions to get specific data, so having these well-defined names means Drupal knows where to look. We will come to hooks in a while.

On retrouve la même terminologie que dans le CMS WordPress.

Le code du fichier onthisdate.info

 
; $Id: blog.info,v 1.5 2007/06/08 05:50:53 dries Exp $
name = On this date
description = A block module that lists links to content such as blog entries or forum discussions that were created one week ago.
package = Non-Core - optional
version = VERSION
core = 5.x
 
; Test of module creation made by hecube.net

Drupal, Module, PHP - Concevoir et réaliser un module sous Drupal

On peut rajouter du commentaire et/ou donner plus d’information dans des champs optionnels. Cela est toujours utile quand un autre développeur doit passer derrière, ne soyez jamais avare d’informations, c’est un fichier d’informations !

dependencies = module1 module2 module3
package = "Your arbitrary grouping string"
version = "$Name$"

Un complément d’informations sur les autres champs du .info

  • Ne pas compléter package fera que votre module sera classé une non catégorie ou la catégorie par défaut (Uncategorized).
  • Si vous complétez le champs dependencies, le module ne pourra être activé que si les “dependencies” requises sont installées par exemple CCK, Views
    …etc.

Une partie du code source de onthisdate.module
La totalité du code est disponible en fin de cet article.

 
	<?php
	/* $Id$ */
 
 
	/**
	* Display help and module information
	* @param section which section of the site we're displaying help
	* @return help text for section
	*/
	function onthisdate_help($section='') {
				$output = '';
				switch ($section) {
					case "admin/help#onthisdate":
					$output = '<p>'. t("Displays links to nodes created on this date"). '</p>';
					break;
					}
				return $output;
			} // function onthisdate_help
 
 
 
	/**
	* Valid permissions for this module
	* @return array An array of valid permissions for the onthisdate module
	*/
		function onthisdate_perm() {
			return array('access onthisdate content');
		} // function onthisdate_perm()
 
 
	/**
	* Generate HTML for the onthisdate block
	* @param op the operation from the URL
	* @param delta offset
	* @returns block HTML
	*/
		function onthisdate_block($op='list', $delta=0) {
		// listing of blocks, such as on the admin/block page
			if ($op == "list") {
				$block[0]["info"] = t("On This Date");
				return $block;
				} else if ($op == 'view') {
			// our block content
			// content variable that will be returned for display
			$block_content = '';
			// Get today's date
			$today = getdate();
			// calculate midnight one week ago
			$start_time = mktime(0, 0, 0,$today['mon'],
			($today['mday'] - 7), $today['year']);
			// we want items that occur only on the day in question, so
			//calculate 1 day
			$end_time = $start_time + 86400;
			// 60 * 60 * 24 = 86400 seconds in a day
		$query = "SELECT nid, title, created FROM "."{node} WHERE created >= '".$start_time."' AND created <= '".$end_time."'";
		// get the links
		$queryResult = db_query($query);
			while ($links = db_fetch_object($queryResult)) {
				$block_content .= l($links->title,'node/'.$links->nid).'<br/>';
				}
		// check to see if there was any content before setting up the block
			if ($block_content == '') {
				// no content from a week ago, return nothing.
				return;
			}
		// set up the block
			$block['subject'] = 'On This Date';
			$block['content'] = $block_content;
			return $block;
			}
		}

Créer une page de configuration du module

Une fois que notre module est activé, il ne nous reste plus qu’à créer une page de configuration pour notre module onthisdate où l’administrateur du site pourra définir les modalités de fonctionnement de son module bref le paramétrer.

On va créer une fonction onthisdate_admin mais il est à noter que _admin n’est pas un hook on aurait pu donc appeler notre fonction onthisdate_adminitration_parametrage par exemple.

Les fonctions à ajouter à onthisdate.module pour autoriser le paramétrage de votre module sont les suivantes. Elles sont isolées ci-dessous.

	/**
	 * @file
	 * Enables to show the principles to build a module for Drupal 5.14.
	 */
 
	function onthisdate_admin() {
			$form['onthisdate_maxdisp'] = array(
				'#type' => 'textfield',
				'#title' => t('Maximum number of links'),
				'#default_value' => variable_get('onthisdate_maxdisp', 3),
				'#size' => 2,
				'#maxlength' => 2,
				'#description' => t("The maximum number of links to display in the block.")
				);
			return system_settings_form($form);
		}
 
 
		function onthisdate_menu() {
			$items = array();
			$items[] = array(
				'path' => 'admin/settings/onthisdate',
				'title' => t('On this date module settings'),
				'description' => t('Description of your on this date settings control'),
				'callback' => 'drupal_get_form',
				'callback arguments' => 'onthisdate_admin',
				'access' => user_access('access administration pages'),
				'type' => MENU_NORMAL_ITEM,
				);
 
			//this is added for this current tutorial.
			$items[] = array(
				'path' => 'onthisdate',
				'title' => t('on this date'),
				'callback' => 'onthisdate_all',
				'access' => user_access('access onthisdate content'),
				'type' => MENU_CALLBACK
				// 'type' => MENU_NORMAL_ITEM
 
 
				);
			return $items;
		}

Changement d’un des paramètres
Si on active 'type' => MENU_NORMAL_ITEM

// 'type' => MENU_CALLBACK
'type' => MENU_NORMAL_ITEM

Vous pouvez voir le résultat de votre paramétrage à la page suivante :
http://127.0.0.1/DRUPAL_5_14/?q=onthisdate

Avec la valeur MENU_CALLBACK activée
Drupal, Module, PHP - Concevoir et réaliser un module sous Drupal

Avec la valeur MENU_NORMAL_ITEM activée
Drupal, Module, PHP - Concevoir et réaliser un module sous Drupal

Pour voir l’aide concernant le module
http://127.0.0.1/DRUPAL_5_14/?q=admin/help/onthisdate
Drupal, Module, PHP - Concevoir et réaliser un module sous Drupal

Pour paramètrer l’accès à votre module pour des utilisateurs loggués ou non…
http://127.0.0.1/DRUPAL_5_14/?q=admin/user/access#module-onthisdate
Drupal, Module, PHP - Concevoir et réaliser un module sous Drupal

Un conseil, si la page de configuration ou la page de resulat de votre module http://127.0.0.1/DRUPAL_5_14/?q=admin/settings/onthisdate n’existe pas, le mieux de désactiver puis de réactiver le module, vous devriez voir ensuite apparaitre la page de configuration.

Dans nos exemples d’URL données ci-dessus, nous n’avons pas activé l’option Clean URLs

Les informations sur l’environnement de test

On a fait une installation de test sur MAMP de Drupal 5.14

URL : http://127.0.0.1/DRUPAL_5_14/

Le couple admin:motdepasse

  • user: bruno
  • pwd: demo

Les information essentielles sur la base de données adossée au Drupal 5.14

Database Name = drupal5_14
Database User name = drupal5_14
Database Password = drupal5_14
Database Host = localhost
Table prefix: d_

	/Applications/MAMP/Library/bin/mysql -u root -p
# Création simultanée de la base drupal5_14 
# et de l'utilisateur drupal5_14 
 
CREATE USER 'drupal5_14'@'localhost' IDENTIFIED BY 'drupal5_14'; GRANT USAGE ON *.* TO 'drupal5_14'@'localhost' IDENTIFIED BY 'drupal5_14'WITH MAX_QUERIES_PER_HOUR 0 MAX_CONNECTIONS_PER_HOUR 0 MAX_UPDATES_PER_HOUR 0 MAX_USER_CONNECTIONS 0; CREATE DATABASE IF NOT EXISTS drupal5_14;GRANT ALL PRIVILEGES ON drupal5_14.* TO 'drupal5_14'@'localhost';

Le code du fichier onthisdate.module

Voici le code complet du fichier du module onthisdate

	<?php
	/* $Id: onthisdate.module,v 1.0 28/12/2010 08:30:45 $ */
 
	/**
	 * @file
	 * Enables to show the principles to build a module for Drupal 5.14.
	 */
 
	function onthisdate_admin() {
			$form['onthisdate_maxdisp'] = array(
				'#type' => 'textfield',
				'#title' => t('Maximum number of links'),
				'#default_value' => variable_get('onthisdate_maxdisp', 3),
				'#size' => 2,
				'#maxlength' => 2,
				'#description' => t("The maximum number of links to display in the block.")
				);
			return system_settings_form($form);
		}
 
 
		function onthisdate_menu() {
			$items = array();
			$items[] = array(
				'path' => 'admin/settings/onthisdate',
				'title' => t('On this date module settings'),
				'description' => t('Description of your on this date settings control'),
				'callback' => 'drupal_get_form',
				'callback arguments' => 'onthisdate_admin',
				'access' => user_access('access administration pages'),
				'type' => MENU_NORMAL_ITEM,
				);
 
			//this is added for this current tutorial.
			$items[] = array(
				'path' => 'onthisdate',
				'title' => t('on this date'),
				'callback' => 'onthisdate_all',
				'access' => user_access('access onthisdate content'),
				'type' => MENU_CALLBACK
				// 'type' => MENU_NORMAL_ITEM
 
 
				);
			return $items;
		}
 
	/**
	* Display help and module information
	* @param section which section of the site we're displaying help
	* @return help text for section
	*/
	function onthisdate_help($section='') {
				$output = '';
				switch ($section) {
					case "admin/help#onthisdate":
 
					$output = '<p>'. t('This module displays links to <i>nodes</i> created on this date. <b>The following text has been written by Hecube.net to demonstrate that it is easy to add text, links, explanations in the help section of the module.</b>') .'</p>';
 
 
 
 
				$output .= '<p>'. t('You can find more articles about Drupal on our blog <a href="@hecube" target="_blank">@ social.hecube.net</a>. These <em>articles</em> deal with numerous subjects about Drupal: Drupal 6.x themes web design, Drupal service activation and content type, e-commerce with Drupal 6.x.', array('@hecube' => 'http://social.hecube.net/')) .'</p>';
 
 
				      $output .= '<p>'. t('For this module, it can be called in a block that could be named <em>On this date</em>. This block may be enabled at the <a href="@blocks">blocks administration page</a>.', array('@blocks' => url('admin/build/block'))) .'</p>';
 
 
				      $output .= '<p>'. t('To use this module, be sure to <a href="@modules">enable</a> the module, in the modules page and define a <a href="@blocks">position</a>.', array('@modules' => url('admin/build/modules'), '@blocks' => url('admin/build/block'))) .'</p>';
				      $output .= '<p>'. t('For more information, see the online handbook on <a href="@drupal">Drupal.org</a>.', array('@drupal' => 'http://drupal.org/handbook/')) .'</p>';
 
 
					break;
					}
				return $output;
			} // function onthisdate_help
 
 
 
	/**
	* Valid permissions for this module
	* @return array An array of valid permissions for the onthisdate module
	*/
		function onthisdate_perm() {
			return array('access onthisdate content');
		} // function onthisdate_perm()
 
 
	/**
	* Generate HTML for the onthisdate block
	* @param op the operation from the URL
	* @param delta offset
	* @returns block HTML
	*/
		function onthisdate_block($op='list', $delta=0) {
		// listing of blocks, such as on the admin/block page
			if ($op == "list") {
				$block[0]["info"] = t("On This Date");
				return $block;
				} else if ($op == 'view') {
			// our block content
			// content variable that will be returned for display
			$block_content = '';
			// Get today's date
			$today = getdate();
			// calculate midnight one week ago
			$start_time = mktime(0, 0, 0,$today['mon'],
			($today['mday'] - 7), $today['year']);
			// we want items that occur only on the day in question, so
			//calculate 1 day
			$end_time = $start_time + 86400;
			// 60 * 60 * 24 = 86400 seconds in a day
 
			/* The query changed to enable configuration from admin */
			$limitnum = variable_get('onthisdate_maxdisp', 3);
			/* $query = "SELECT nid, title, created FROM "."{node} WHERE created >= '".$start_time."' AND created <= '".$end_time. "' LIMIT ".$limitnum; */
 
	$query = "SELECT nid, title, created FROM "."{node} WHERE created >= %d "."AND created <= %d";
 
			$queryResult = db_query_range($query, $start_time, $end_time, 0,
			$limitnum);
 
 
 
		// get the links
		$queryResult = db_query($query);
			while ($links = db_fetch_object($queryResult)) {
				$block_content .= l($links->title,'node/'.$links->nid).'<br/>';
				}
		// check to see if there was any content before setting up the block
			if ($block_content == '') {
				// no content from a week ago, return nothing.
				return;
			}
		// set up the block
			$block['subject'] = 'On This Date';
			$block['content'] = $block_content;
 
			return $block;
			}
		}
 
 
		function onthisdate_all() {
		// content variable that will be returned for display
		$page_content = '';
		// Get today's date
		$today = getdate();
		// calculate midnight one week ago
		$start_time = mktime(0, 0, 0, $today['mon'], ($today['mday'] - 7),
		$today['year']);
		// we want items that occur only on the day in question,
		// so calculate 1 day
		$end_time = $start_time + 86400;
		// 60 * 60 * 24 = 86400 seconds in a day
 
		/* $query = "SELECT nid, title, created FROM "."{node} WHERE created >= '".$start_time."' AND created <= '". $end_time . "'"; */
		/* $query = "SELECT nid, title, created FROM "."{node}"; */
		$limitnum = variable_get('onthisdate_maxdisp', 3);
		/* $query = "SELECT nid, title, created FROM "."{node} LIMIT 0, ".$limitnum.""; */
		$query = "SELECT nid, title, created FROM "."{node} LIMIT ".$limitnum."";
 
		// get the links (no range limit here)
		$queryResult = db_query($query);
				while ($links = db_fetch_object($queryResult)) {
					$page_content .= l($links->title, 'node/'.$links->nid).'<br />';
				}
				// add a more link to our page that displays all the links
				$page_content .="<div class="more-link">".l(t("more"),"onthisdate", array("title" => t("More events on this day.")))."</div>";
 
				// check to see if there was any content before
				// setting up the block
				if ($page_content == '') {
				// no content from a week ago, let the user know
				$page_content = "No events occurred on this site on this date in
				history.";
				}
 
			return $page_content;
		} // end function onthisdate_all