Voilà, voilà... Fin de l'aventure...

 

Fermeture de kolossaldrupal.org dans...


Bonjour tout le monde,

Drupal évolue, les versions changent et Kolossaldrupal.org était essentiellement consacré à la version 6 de Drupal.

Autant dire que les infos présentées ici commencent à dater...

Faute de temps, je ne peux plus garder le site Kolossaldrupal à jour...

Je vous aurais bien proposé de reprendre le flambeau mais... c'est tellement simple de nos jours de se faire son propre site à soi...Pourquoi s'embêter alors ? :-)

Ce site restera donc en l'état, tel qu'il était en 2011...

Ah la la ! Cela ne nous rajeunit pas !

Manuel Vila - Avril 2016

Créer un nouveau type de contenu

Référence en anglais sur drupal.org : 17 Avril 2010 - 21h49
http://drupal.org/node/231019


Puisque que vous avez lu le tutoriel sur la création de Modules Drupal 6.0x, vous connaissez les éléments de base concernant les hooks, les blocs et, éventuellement, les formulaires. Vous voudrez peut-être maintenant utiliser différentes API de Drupal et créer un nouveau type de node.

Avant cela, demandez-vous si vous avez vraiment besoin de créer un nouveau type de node : si vous pouvez utiliser CCK et Views pour collecter et manipuler vos données, vous n'avez pas besoin de ce tutoriel. Cependant, si vous devez manipuler vos données différemment, ou s'il existe entre elles des relations multiples qui ne peuvent être satisfaites avec CCK, ou si vous voulez juste en apprendre davantage sur le fonctionnement interne de Drupal, ce tutoriel devrait vous convenir.

Notez que vous pouvez toujours utiliser CCK et Views si les éléments personnalisés de votre node concernent des changements du système de commentaires, des chemins, informations de publications et autres bonus intégrés à Drupal.

Un type de node simple comme page ou article est le contenu le plus élémentaire d'un site Drupal. Dans leurs formes les plus simples, ce ne sont rien d'autre qu'un Titre, un Corps et, éventuellement, un Teaser. Vous pouvez construire votre propre type de node aisément en suivant les étapes qui suivent. Apprenez-les et vous commencerez à saisir la souplesse de Drupal vis-à-vis de ses contenus.

Pourquoi avez-vous besoin de savoir tout ça ?

Via l'interface d'administration, Drupal 6.0 vous permet de créer facilement ces types de nodes « simples », n'est-ce pas ? La réponse est un OUI sonore, et tout le monde en soupire d'aise. Merci aux développeurs Drupal !!! CCK est alors arrivé et nous a encore plus facilité la vie ! Il ne vous a cependant pas enseigné les bases pour la programmation de modules et c'est pourquoi ce tutoriel a été écrit.(désolé, parfois je colle vraiment au texte original. NdT)

Création de modules : un tutoriel Drupal 6.x est un super tutoriel. node_example est également un remarquable exemple de création de type de node avec l'API. Nous nous en servirons comme référence (vous devriez vraiment le lire).

Dans ce tutoriel, il n'y aura pas de modification de la base de données ou des hacks sur le code, le résultat sera un nouveau module qui sera installé dans son propre dossier.

Ce dont vous avez besoin

  • savoir installer des fichiers dans votre dossier modules
  • un éditeur de texte (puis-je respectueusement suggérer emacs ? NdT)
  • des connaissances sur le PHP seront les bienvenues mais ne sont pas indispensables
  • quelques données sur votre type de node
    • un TECHNICAL-NAME pour votre type de node. N'utilisez pas le nom d'un module existant. Pas d'espaces, de chiffres ou de ponctuation, à moins que vous ne sachiez exactement ce que vous faites
    • un USER-FRIENDLY-NAME pour votre type de node (et une version de ce nom au pluriel) (c'est ainsi qu'apparaîtra votre type de node à plusieurs endroits du site). Les espaces et les chiffres sont acceptés mais pas de ponctuation, à moins que vous ne sachiez exactement ce que vous faites.
      Remarque : vous pouvez utiliser le TECHNICAL-NAME.
    • une MODULE-DESCRIPTION, une courte description de votre type de node qui apparaîtra dans les pages d'administration des modules. N'utilisez pas de guillemets ou d'apostrophes, à moins que vous ne sachiez exactement ce que vous faites
    • une CREATE-CONTENT-DESCRIPTION, une brève description de votre type de node qui apparaîtra dans la page de création de contenu. N'utilisez pas de guillemets ou d'apostrophes, à moins que vous ne sachiez exactement ce que vous faites
    • un HELP-DESCRIPTION, une brève description de votre type de node qui apparaîtra dans la page d'aide. N'utilisez pas de guillemets ou d'apostrophes, à moins que vous ne sachiez exactement ce que vous faites

Comme exemple, disons que vous voulez un type de node press release.

  • TECHNICAL-NAME = "press_release" (notez le signe souligné)
  • USER-FRIENDLY-NAME = "Press Release"
  • USER-FRIENDLY-PLURAL = "Press Releases"
  • MODULE-DESCRIPTION = "Permet la création de communiqué de presse"
  • CREATE-CONTENT-DESCRIPTION = "Crée un communiqué de presse"
  • ADMIN-HELP-TEXT = "Ce module a été créé par [indiquez votre nom ici]."

J'ai utilisé à dessein un exemple ayant deux mots : « Press release », qui donne un TECHNICAL-NAME et un USER-FRIENDLY-NAME différents, l'un avec un signe souligné, l'autre pas. Cela permettra de s'y retrouver dans les modifications du code-source où ils apparaissent tous les deux, mais dans la plupart de types de nodes existants (ou ceux que vous créerez) on utilise la même valeur.

Dans les exemples de code qui suivent, le texte en gras indique les modifications de code-source (le formatage PHP ne sera pas utilisé). Les guillemets et les apostrophes dans le code sont importants, faites-y attention. Lorsque vous verrez ----- cela indique où démarre le code et où il se termine, n'utilisez pas cette notation dans votre propre code.

Il y a deux fichiers obligatoires pour la création de modules. Le premier est le fichier .info. Vous en apprendrez plus sur ce fichier sa création à la page Écrire des fichiers .info (Drupal 6.x ou à la page Communiquer votre module à Drupal.

Ce n'est pas un fichier PHP, il ne doit donc pas débuter par <?php.

Le format est :

; $Id$
name = USER-FRIENDLY-NAME
description = "MODULE-DESCRIPTION"
core = 6.x

Dans notre exemple :

; $Id$
name = Press Release
description = "Enables the creation of press releases."
core = 6.x

Oui, vous n'avez besoin que de ces quatre lignes (au minimum).

Sauvegardez ce fichier sous le nom TECHNICAL-NAME.info (pour notre exemple : press_release.info).

Le second fichier obligatoire est le fichier .module. C'est dans ce fichier que se fait tout le boulot.

Dans node_example de nombreux hooks sont cités et expliqués. node_example est un exemple de type de nodes avec des champs supplémentaires. Ce how-to ne répond pas à ce besoin mais nous met le pied à l'étrier. Si vous avez besoin de champs supplémentaires, vous voudrez en savoir davantage sur ces hooks et node-example constitue un bon début.

Le fichier .module contient tous les hooks mis en œuvre. La notion de hook est facile à comprendre. Toutes les fonctions de votre module utilisées par Drupal sont nommées ainsi : {nomdumodule}_{suffixe}. Suffixe est le nom d'une fonction pré-déclarée pour le hook. Donc, quand nous lisons que nous devons implémenter hook_foo() pour notre module exemple, nous devrions écrire une fonction appelée press_release_foo(). Drupal appellera ces fonctions pour obtenir certaines données, ainsi, en ayant correctement nommé ces fonctions Drupal saura où chercher.

Chacun de hooks suivant sont décrits dans node-example et dans l'API.

Ces hooks devraient être implémentés dans chaque module de type node. Notre exemple implémentera les quatre hooks suivants :

  • hook_node()
  • hook_perm()
  • hook_access()
  • hook_form()

Les hooks suivants sont requis si vous avez des champs supplémentaires créés par votre type de node (notez que vous pouvez utiliser CCK avec votre node-type pour ajouter des champs). Notre exemple n'implémentera pas ces hooks.

  • hook_insert()
  • hook_update()
  • hook_delete()
  • hook_validate()
  • hook_nodeapi()
  • hook_view()
  • hook_load()

Le hook suivant n'apparaît pas dans node_example mais l'utiliser est une bonne idée. Notre exemple implémentera ce hook.

  • hook_help

Remarque : placer le commentaire suivant avant chaque hook est une pratique recommandée :

/**
* Implementation of hook_{hook name here}().
*/

mais nous ne le ferons pas dans ce qui suit.

Commençons ! Voici un fichier PHP, sa toute première ligne sera donc <?php

Implémentation de hook_node_info()

C'est un hook indispensable, il déclare un tas de choses sur le node-type, ce qui suit est le minimum requis :

D'après node-example :

<?php
function node_example_node_info() {
  return array(
    
'node_example' => array(
      
'name' => t('example node'),
      
'module' => 'node_example',
      
'description' => "This is an example node type with a few fields.",
    )
  );

?>

Ce que nous analyserons en :

-----
function TECHNICAL-NAME_node_info() {
return array(
'TECHNICAL-NAME' => array(
'name' => t('USER-FRIENDLY-NAME'),
'module' => 'TECHNICAL-NAME',
'description' => "CREATE-CONTENT-DESCRIPTION",
)
);
}
-----

Dans notre exemple :

-----
function press_release_node_info() {
return array(
'press_release' => array(
'name' => t('Press Release'),
'module' => 'press_release',
'description' => "Create a press release.",
)
);
}
-----

 

Implémentation de hook_perm()

Puisque nous ne réservons la possibilité de créer de nouveaux nodes qu'à certains utilisateurs, nous devrons déclarer la nature des droits ici. Nous déclarerons aussi un droit qui permet aux utilisateurs de modifier les nodes qu'ils ont créés.

Dans notre exemple, les droits que vous définissez seront référencés par le prochain hook (hook_access).

D'après node-example :

<?php
function node_example_perm() {
  return array(
'create example node''edit own example nodes');

?>

node-example utilise USER-FRIENDLY-PLURAL pour déclarer ses droits, mais il est recommandé que les chaînes de caractères qui indiquent vos droits soient uniques dans votre module. Sinon, la page des droits d'accès affichera les mêmes droits à plusieurs endroits. Vos chaînes de caractères devraient également contenir le nom de votre module, pour éviter des conflits name space avec les autres modules. La convention de nom actuelle est verbe + nom de module. Cet exemple suivra cette recommandation (bien qu'utiliser USER-FRIENDLY-PLURAL soit bien aussi.

Le hook s'analyse alors comme suit :

-----
function TECHNICAL-NAME_perm() {
return array('create TECHNICAL-NAME', 'edit own TECHNICAL-NAME');
}
-----

Dans notre exemple cela donne :


-----
function press_release_perm() {
return array('create press_release', 'edit own press_release');
}
-----

Implémentation de hook_access()

les modules nodes peuvent implémenter node_access() pour définir les opérations que les utilisateurs peuvent effectuer sur les nodes. Cet exemple utilise un modèle d'accès très répandu. Il est important de noter que vous devez utiliser les mêmes droits que ceux déclarés dans le hook précédent.

D'après node_example :

<?php
function node_example_access($op$node$account) {

  if (
$op == 'create') {
    
// Only users with permission to do so may create this node type.
    
return user_access('create nameofnodetype'$account);
  }

  
// Users who create a node may edit or delete it later, assuming they have the
  // necessary permissions.
  
if ($op == 'update' || $op == 'delete') {
    if (
user_access('edit own nameofnodetype'$account) && ($account->uid == $node->uid)) {
      return 
TRUE;
    }
  }

?>

A nouveau, nous suivons le conseil d'utiliser TECHNICAL-NAME et non USER-FRIENDLY-PLURAL.

Ce qui nous donne :

-----
function TECHNICAL-NAME_access($op, $node, $account) {

if ($op == 'create') {
// Only users with permission to do so may create this node type.
return user_access('create TECHNICAL-NAME', $account);
}

// Users who create a node may edit or delete it later, assuming they have the
// necessary permissions.
if ($op == 'update' || $op == 'delete') {
if (user_access('edit own TECHNICAL-NAME',$account) && ($account->uid == $node->uid)) {
return TRUE;
}
}
}
-----

Dans notre exemple :

-----
function press_release_access($op, $node, $account) {

if ($op == 'create') {
// Only users with permission to do so may create this node type.
return user_access('create press_release', $account);
}

// Users who create a node may edit or delete it later, assuming they have the
// necessary permissions.
if ($op == 'update' || $op == 'delete') {
if (user_access('edit own press_release',$account) && ($account->uid == $node->uid)) {
return TRUE;
}
}
}
-----

implémentation de hook_form()

Nous allons maintenant décrire le formulaire utilisé pour collecter les données propres à ce type de node.

Ce hook nous demandera de renvoyer un tableau avec un sous-tableau contenant des infos sur chaque élément du formulaire. Les formulaires sont, d'après moi, l'aspect de Drupal le plus difficile à apprendre. Mais, étant donné la spectaculaire façon dont Drupal implémente les formulaires, nous n'avons que peu de code à modifier dans cet exemple.

D'après node_example :

<?php
function node_example_form(&$node) {
  
$type node_get_types('type'$node);

  
// Nous devons définir les éléments du formulaire pour le titre et le corps du node.
  
$form['title'] = array(
    
'#type' => 'textfield',
    
'#title' => check_plain($type->title_label),
    
'#required' => TRUE,
    
'#default_value' => $node->title,
    
'#weight' => -5
  
);
  
// Nous voulons que les éléments body et filtre soient contigus . Nous pourrions l'obtenir 
  // en paramétrant leurs poids, mais un autre module pourrait ajouter des éléments de même poids 
  // au formulaire qui se retrouverait parmi les nôtres. En les mettant ensemble dans un sous-tableau
  // nous les forçons à apparaître côte à côte.
  
$form['body_filter']['body'] = array(
    
'#type' => 'textarea',
    
'#title' => check_plain($type->body_label),
    
'#default_value' => $node->body,
    
'#required' => FALSE
  
);
  
$form['body_filter']['filter'] = filter_form($node->format);

  
// NOTE dans node_example il y a du code supplémentaire dont nous n'avons pas besoins pour notre exemple

  
return $form;
}
?>

La seule modification requise ici est le modification du nom de la fonction, le reste du code ne change pas.

Ce qui nous donne :

-----
function TECHNICAL-NAME_form(&$node) {
(tout le code est identique)
}
-----

Dans notre exemple cela devient :

-----
function press_release_form(&$node) {
(tout le code est identique)
}
-----

 

Implémentation de hook_help()

Ce hook n'est pas présent dans node_example,

<?php
function hook_help($path$arg) {
  switch (
$path) {
    case 
'admin/help#block':
      return 
'<p>'t('Blocks are boxes of content that may be rendered into certain regions of your web pages, for example, into sidebars. Blocks are usually generated automatically by modules (e.g., Recent Forum Topics), but administrators can also define custom blocks.') .'</p>';

    case 
'admin/build/block':
      return 
t('<p>Blocks are boxes of content that may be rendered into certain regions of your web pages, for example, into sidebars. They are usually generated automatically by modules, but administrators can create blocks manually.</p>
<p>If you want certain blocks to disable themselves temporarily during high server loads, check the "Throttle" box. You can configure the auto-throttle on the <a href="@throttle">throttle configuration page</a> after having enabled the throttle module.</p>
<p>You can configure the behaviour of each block (for example, specifying on which pages and for what users it will appear) by clicking the "configure" link for each block.</p>'
, array('@throttle' => url('admin/settings/throttle')));
  }
}
?>

Ce qui nous donne :


-----
function TECHNICAL-NAME_help($path, $arg) {
switch ($path) {
case 'admin/help#TECHNICAL-NAME':
return '

' . t('ADMIN-HELP-TEXT') . '

';
break;
}
}
-----

Et dans notre code :

-----
function press_release_help($path, $arg) {
switch ($path) {
case 'admin/help#press_release':
return '

' . t('This module was created by [your name here].') . '

';
break;
}
}
-----

C'est tout concernant le code. Heureusement, rien de bien compliqué.

Sauvegardez le fichier sous le nom TECHNICAL-NAME.module (dans notre exemple : press_release.module), vous êtes maintenant prêts à le télécharger sur le site.

Tester votre module

Dans le dossier modules de votre site, créez un dossier nommé TECHNICAL-NAME (dans notre exemple ce sera : press_release). Téléchargez-y les deux fichiers .info et .module.

Allez dans la page Administrer » Construction du site » Modules, vous devriez voir votre nouveau module dans la liste, activez-le comme vous le feriez pour n'importe quel autre module.

Remarque : si vous obtenez un écran vierge après l'activation, cela signifie qu'il y a une erreur dans le code PHP de votre nouveau module, reportez-vous à cette page pour résoudre le problème, sinon, effacez vos fichiers et reprenez tout depuis le début.

Votre nouveau type de node devrait fonctionner de la même façon avec les nodes de type page et article. Vous devrez leur accorder des droits (Administrer » Gestion des utilisateurs » Droits d'accès), les configurer (Administrer » Gestion du contenu » Types de contenus), permettre la catégorisation (Administrer » Gestion du contenu » Taxinomie), etc.

Code que vous pouvez copier-coller, puis adapter :

Fichier .info :

; $Id$
name = USER-FRIENDLY-NAME
description = "MODULE-DESCRIPTION"
core = 6.x

Fichier .module :

<?php
/**
* Implementation of hook_node_info().
*/
function TECHNICAL-NAME_node_info() {
  return array(
    
'TECHNICAL-NAME' => array(
      
'name' => t('USER-FRIENDLY-NAME'),
      
'module' => 'TECHNICAL-NAME',
      
'description' => "CREATE-CONTENT-DESCRIPTION",
    )
  );
}

/**
* Implementation of hook_perm().
*/
function TECHNICAL-NAME_perm() {
  return array(
'create TECHNICAL-NAME''edit own TECHNICAL-NAME');
}

/**
* Implementation of hook_access().
*/
function TECHNICAL-NAME_access($op$node) {
  global 
$user;

  if (
$op == 'create') {
    
// Seuls les utilisateurs avec les bons droits d'accès peuvent créer ce type de node.
    
return user_access('create TECHNICAL-NAME');
  }

  
// Les utilisateurs peuvent modifier ou effacer leur propre node, 
  // à condition d'avoir les droits requis.
  
if ($op == 'update' || $op == 'delete') {
    if (
user_access('edit own TECHNICAL-NAME') && ($user->uid == $node->uid)) {
      return 
TRUE;
    }
  }
}

/**
* Implementation of hook_form().
*/
function TECHNICAL-NAME_form(&$node) {
  
$type node_get_types('type'$node);

  
// Nous devons définir les éléments du formulaire pour le titre et le corps du node.
  
$form['title'] = array(
    
'#type' => 'textfield',
    
'#title' => check_plain($type->title_label),
    
'#required' => TRUE,
    
'#default_value' => $node->title,
    
'#weight' => -5
  
);
  
// Nous voulons que les éléments body et filtre soient contigus . Nous pourrions l'obtenir 
  // en paramétrant leurs poids, mais un autre module pourrait ajouter des éléments de même poids 
  // au formulaire qui se retrouverait parmi les nôtres. En les mettant ensemble dans un sous-tableau
  // nous les forçons à apparaître côte à côte.
  
$form['body_filter']['body'] = array(
    
'#type' => 'textarea',
    
'#title' => check_plain($type->body_label),
    
'#default_value' => $node->body,
    
'#required' => FALSE
  
);
  
$form['body_filter']['filter'] = filter_form($node->format);

  
// NOTE dans node_example il y a du code supplémentaire dont nous n'avons pas besoins pour notre exemple

  
return $form;
}

/**
* Implementation of hook_help().
*/
function TECHNICAL-NAME_help($path$arg) {
  switch (
$path) {
    case 
'admin/help#TECHNICAL-NAME':
      return 
'<p>' t('ADMIN-HELP-TEXT') . '</p>';
      break;
  }

?>