Drupal : règles personnalisées pour écrire vos propres conditions d'événements, actions et objets personnalisés (+ jetons personnalisés)

Le module de règles est un module très puissant qui vous permet de faire les choses réagir dans votre site lorsque certains événements se produisent (comme un commentaire a été fait), sous certaines conditions (par exemple lorsque l'utilisateur a le rôle x).

Un grand nombre d'événements, les conditions et les actions sont deja sortis de la boîte ou fournies par des modules contrib qui intègrent des règles.

Mais que faire lorsque vous avez un module et que vous voulez ajouter le support des règles? Tout d'abord, pourquoi devriez-vous ajouter le support des règles? Pourquoi ne pas tout faire dans le code?

Exemple
Laissez-moi vous expliquer cela par un exemple. On a un module personnalisé qui permet aux administrateurs de définir des paquets dont les utilisateurs peuvent commander (les paquets ne sont pas des nœuds, pourquoi ils ne sont pas n'est notre sujet). Alors, quand un paquet est acheté un événement est déclenché. Nous avons aussi une condition personnalisée qui permet de vérifier le type de l'emballage. Enfin, nous avons une action personnalisée qui modifie le statut de l'ordonnance rendue. (On a une table de base avec des forfaits et une autre avec les commandes de colis)

Maintenant, un administrateur du site peut définir un ensemble de mails en utilisant ces règles. Par exemple, un courrier pourrait être envoyé à l'utilisateur quand il achète un forfait d'abonnement ou d'un message système pourrait être réglé lorsque l'utilisateur achète un paquet qui augmente sa quantité de crédits. Pour chaque type de forfait acheté, un e-mail différent pourrait être envoyé. Vous avez l'idée, imaginez avoir à changer dans le code de l'e-mail sur cette action, ou les messages du système chaque fois que le propriétaire du site veut avoir "Cher client" au lieu de "client Tout Puissant" en haut de ses mails / messages.

Regardons maintenant le code, vous devez avoir vos règles personnalisées.
Il y a 3 hooks que vous aurez besoin pour mettre en œuvre, afin de créer un module personnalisé et créer un fichier supplémentaire appelé your_module.rules.inc, toutes les règles de notre code lié ira là-dedans.

Evènements
Le premier hook est hook_rules_event_info () et définit notre évènement sur mesure.

<?php
/ **
Implémentation de hook_rules_event_info ().
* @
ingroup rules
*/
function 
your_module_rules_event_info() {
  return array(
    
'your_module_package_bought' => array(
      
'label' => t('A package was bought'),
      
'module' => 'your_module',
      
'arguments' => array(
        
'acting_user' => array('type' => 'user''label' => t('The user who bought the package.')),
        
'package' => array('type' => 'package''label' => t('The purchased package.')),
      ),
    ),
  );
}
?>

Ce qu'on a fait est définir une action qui les utilisateurs agissants et l'objet du package. Allons déclencher cette action en achetant un paquet. (Cette fonction sera située dans your_module.module)

<?php
function your_module_buy_package() {
  
//le code pour l'achat d'un paquet
  //l'achat du paquet déclenche la règle
  
$order order_load($oid);//$oid sera l'id de la commande
  
$package package_load($pid);//pid sera l'id du paquet acheté
  
global $user;
  
rules_invoke_event('your_module_package_bought'$user$package$order);
  
watchdog('your_module',t('A Member !uid has ordered (order:!oid) package !pid', array('!uid' => $user->uid'pid' => $package->pid'oid' => $order->oid)));
}
?>

Dans l'interface des règles sur le site, vous allez définir votre règle qui sera déclenchée en sélectionnant cet évènement.
Notez comment on connecte l'événement au watchdog. Cette pratique est utile quand vous voulez suivre ce qui se passe sur votre site. Vous pourriez également avoir le watchdog de configuré dans l'interface déclenchée lors de la définition des actions pour votre événement, mais je pense que la connectivité du watchdog est plus quelque chose qui relève du code et c'est quelque chose que l'administrateur du site ne doit pas être en mesure de configurer (contrairement aux mails et aux messages utilisateur).

Conditions
Maintenant, on va définir la condition afin que vous puissiez baser votre réaction sur le type du paquet acheté. Pour celle-ci, vous aurez besoin d'implémenter la fonction hook_condition_info ()

<?php
/ **
 * 
Implémentation des hook_rules_condition_info ()
function 
your_module_rules_condition_info() {
  return array(
    
'your_module_condition_package_type' => array(
      
'label' => t('Type du paquet'),
      
'arguments' => array(
        
'package_id' => array('type' => 'value''label' => t('le type du paquet acheté..')),
        
'package_type' => array('type' => 'string''label' => t('Le type du paquet acheté est')),
      ),
      
'module' => 'your_module',
    ),
  );
}

/**
 * Condition packages_condition_packagetype
 */
function your_module_condition_package_type($pid$type) {
  
$package package_load($pid);
  return (
$package->type == $type) ? true false;
}
?>

Lorsque la condition évalue que la fonction your_module_condition_package_type fonction est exécutée en utilisant les arguments pid (ID de package) fournies par l'événement et le type d'argument définie dans l'interface.

La fonction retourne vrai si le type de forfait acheté est le même que le type du paquet définie dans l'interface.

Actions
Beaucoup d'autres actions sont définies deja. Pour nos actions on a déjà les messages e-mail et message de disponibles. On configure le "envoyer un mail à un utilisateur" et pour ce faire on a besoin de quelques jetons.

Jetons de remplacement
Comme vous l'avez remarqué, il y a quelques jetons de remplacement à portée de main que nous pourrions utiliser hors de la boîte, comme l'utilisateur agissant par exemple. On pourrait alors ajouter un jeton pour remplacer le nom d'utilisateur ([acting_user: l'utilisateur]). Dans le courrier de ce jeton sera remplacé par le nom de l'utilisateur agissant.
Dans notre exemple, nous pourrions construire un jeton de remplacement sur mesure pour le nom du package. En utilisant l'ID du package, on peut retrouver le nom du package.

Pour obtenir des jetons personnalisés dans Drupal, nous allons utiliser les fonctions API hook_token_values() et hook_token_list() (Mettre ce code dans your_module.module)

La fonction hook_token_list fournira des données à l'interface et le hook_token_values ​​va remplacer le jeton [paquet: nom_du_paquet] que vous allez mettre dans vos mails.

<?php
/**
 * Implémentation of hook_token_list()
 */
function your_module_token_list($type 'all') {
  if (
$type == 'all' || $type == 'package') {
    
$tokens['your_module'] = array(
      
'package_name' => t('The name of the package'),   
    );
  }

  return 
$tokens;
}

/**
 * Implémentation of hook token api
 */
function your_module_token_values($type$object NULL$options = array()) {
  
$tokens = array();
  if (
$object) {
    if (
$type == 'package') {
      
$tokens = array(
        
'package_name' => $object->name,
      );
    }
  }

  return 
$tokens;
}
?>

Dans notre invocation, nous avons passé le paquet comme un argument, en faisant ainsi des règles a donné notre forfait à la fonction your_module_token_values​​() dans l'argument objet $ pour qu'il puisse remplacer le jeton nom_du_paquet avec le nom réel de nos jetons.

Actions personnalisées
Le dernier hook est hook_rules_action_info() qui définit votre action personnalisée.

<?php
/ **
 * 
Implémentation de la fonction hook_rules_action_info ().
 * /
function 
packages_rules_action_info() {
  return array(
    
'your_module_action_change_order_status' => array(
      
'label' => t('Change the order status'),
      
'arguments' => array(
        
'order' => array('type' => 'value''label' => t('The order object.')),
      ),
      
'module' => 'your_module',
    ),
  );
}
?>

La fonction fait l'action utilise la variable paramètres. Vous pouvez configurer la valeur du statut par l'interface de cette façon. Si vous ne voulez pas que tout coder en dur la valeur, cela démontre simplement que vous pouvez avoir un formulaire dans l'interface de capture des valeurs personnalisées.

<?php
function your_module_action_change_order_status($oid) {
  
$q "UPDATE {orders} SET status = '%s' WHERE id = %d";
  
db_query($q$settings['status'], $oid);
  
//better would be to create an order_save function but you get the idea
}

/**
* Action drupal message configuration form.
*/
function your_module_action_change_order_status_form($settings, &$form) {
  
$settings += array('status' => '');

  
$form['settings']['status'] = array(
    
'#type' => 'textfield',
    
'#title' => t('Status'),
    
'#default_value' => $settings['status'],
    
'#description' => t('The order status will change to the one supplied here.'),
  );
}

?>

Le chargement de l'ordre pourrait être comme ceci:

<?php
function order_load($oid) {
  
$order db_fetch_object("SELECT oid, status, uid FROM {orders} WHERE oid = %d"$oid);
    
  return 
$order;
}
?>

Conclusion
Comme démontré, les règles est un module puissant, avec une api aussi puissante capable de définir des événements personnalisés, des conditions et des actions.
Les règles intègrent avec tous les modules principaux (et l'API token), et il est à mon humble avis lors de l'élaboration des modules, si possible, un point d'intégration qui mérite votre attention.

extra
Pour plus d'informations sur l'API voir le fichier rules.api.php dans le paquet des règles. Il montre quelques possibilités de modification et d'exposition des objets personnalisés à des règles.