Curso de desarrollo de módulos de Drupal 7 (IV): Administración y Formularios

Una de las tareas típicas a la hora de gestionar un módulo es el apartado de la Configuración. Siguiendo con el ejemplo mostrado en la primera y segunda entrega. Añadiremos las funcionalidades necesarias para poder gestionar un apartado en la administración Drupal.

Recordatorios

En las anteriores entregas ya tneíamos creada la carpeta del módulo, y los ficheros ejemplo.info y ejemplo.install. Donde introduciamos las funciones de ejemplo_install() y ejemplo _uninstall(). En el ejemplo.info ya habíamos colocado una ruta a la administración del módulo metiante el parámetro settings con el valor “admin/config/ejemplo/settings”.

Gestionando las entradas en el Menú de Administración

Para incluir las nuevas funciones será necesario añadir un nuevo fichero al módulo. Este fichero deberá llamarse nombredemodulo.module, en nuestro caso se llamará ejemplo.module. Lo creamos y colocamos la cabecera del fichero típica:
<?php
/**
* @file
* Fichero del módulo de ejemplo para drupal
*
* Descripción larga del fichero que entra dentro del módulo de ejemplo de Drupal
*/
Por otra parte será necesario que incluyamos una referencia al fichero ejemplo.module en el fichero ejemplo.module, incorporando una nueva línea al fichero:
files[] = ejemplo.module
De esta manera dentro de la información del módulo se hará referencia a este nuevo fichero.

Incluyendo la implementación del hook_menu()

Entonces tenemos ya todo preparado para poder introducir la gestión de los nuevos elementos de menú. Para ello deberemos relizar una implementación del hook_menu(), en nuestro caso deberá llamarse ejemplo_menu(), por lo que incluiremos el siguiente código en el fichero ejemplo.module:
/**
 * Implementation of hook_menu().
 */
function ejemplo_menu() {
}
A continuación deberemos gestionar las entradas en el menú de administración, mediante la declaración de arrays asociativos con los datos necesarios para generar y gestionar la entrada de cada elemento del menú.
Empezaremos por el elemento que se introduce en el menú de administración, para ello incluimos el siguiente código en la función ejemplo_menu():
$items[‘admin/config/ejemplo’] = array(
    ‘title’ => ‘Node annotation’,
    ‘description’ => ‘Adjust node annotation options.’,
    ‘position’ => ‘right’,
    ‘weight’ => -5,
    ‘page callback’ => ‘system_admin_menu_block_page’,
    ‘access arguments’ => array(‘administer site configuration’),
    ‘file’ => ‘system.admin.inc’,
    ‘file path’ => drupal_get_path(‘module’, ‘system’),
  );
  return $items;

como puede verse en el código rellenamos un array con los datos del enlace y hacemos que la función devuelva dicho array.
El resultado de la inclusión de este código es la generación de un nuevo enlace en el menú de Configuración de Drupal, tras su activación, como puede verse en la siguiente captura…

Si pasamos el ratón por encima del nuevo enlace en el menú veremos que apunta a la ruta “admin/config/ejemplo/settings” tal como hemos indicado en fichero de ejemplo.info. La gestión de la llamada a esa URL es la que incluiremos con el siguiente elemento del array asociativo $items.
Expliquemos cuáles son los elementos que estamos definiendo en el array asociativo $items:

  • el índice que utilizamos en la ruta de inclusión del enlace, a efectos prácticos incluye el enlace en la parte de Configuración de la administración, porque hemos puesto como índice “admin/config/ejemplo”, ya que “admin/config” es la ruta hasta el menú de Configuración, y al incluir la siguiente ruta “/ejemplo” nos crea esa nueva entrada.
  • title: es el ítulo que debe aparecer en el enlace, este texto es automáticamente traducible, no hace falta hacer uso de la función t() para traducirlo.
  • description: es la descripción que aparece justo debajo del enlace.
  • position: indica la zona donde debe presentar el enlace, en este caso nos lo intenta presentar en la parte de la derecha ‘right’.
  • weight: es el peso que queremos darle al enlace, el peso es una variable que cuanto mayor valor tenga más arriba debería aparecer el enlace en el menú y viceversa. en este caso es -5 por lo que debería aparecer debajo de los elementos principales del menú.
  • page callback: es la función que debe manejar dicho enlace. en este caso al ser un enlace de la configuración debe ser una función de drupal la que sea capaz de gestionarlo, por lo que introducimos el valor ‘system_admin_menu_block_page’ que es la función del módulo system que gestiona ese bloque de menú.
  • access arguments: son los permisos necesarios para ver esa entrada de menú, como todo elemento de la configuración requiere del permiso ‘administer site configuration’, que lo introducimos como un elemento de un array, debido a que podemos tener combinaciones de permisos para poder acceder a distintos elementos del menú.
  • file: indicación del fichero que contiene la función de callback, en este caso es el fichero ‘system.admin.inc’, si nos damos cuenta la mayor parte de las funciones de callback de los menús se gestionarán desde ficheros de módulo que se llaman nombredemodulo.admin.inc.
  • file path: indicación de la ruta donde está presente el fichero system.admin.inc, en este caso la coseguiremos a partir de la función drupal_get_path(‘module’, ‘system’), que nos devolverá la ruta del directorio del módulo ‘system’, para su posterior inclusión y ejecución de la llamada a la función ‘system_admin_menu_block_page’.

 Ahora con el enlace ya en su sitio debemos gestionar la URL del formulario de configuración del módulo, por lo que debemos introducir otro elemento en el array $items antes de devolverlo, incluyendo el siguiente código:
$items[‘admin/config/ejemplo/settings’] = array(
    ‘title’ => ‘Annotation settings’,
    ‘description’ => ‘Change how annotations behave.’,
    ‘page callback’ => ‘drupal_get_form’,
    ‘page arguments’ => array(‘ejemplo_admin_settings’),
    ‘access arguments’ => array(‘administer site configuration’),
    ‘type’ => MENU_NORMAL_ITEM,
    ‘file’ => ‘ejemplo.admin.inc’,
  );
Debido a que queremos gestionar un formulario los elemento del array son ligeramente distintos a los que introdujimos anterioremente:

  • el índice es la URL que queremos gestionar, en este caso la que se pulsa desde el menú de Configuración para acceder a los “settings” del módulo ejemplo.
  • title: es el título que colocaremos a la página del formulario
  • description: es la descripción del formulario en sí mismo, podríamos verla desde la gestión de menús.
  • page callback: es la función a la que necesitamos llamar cuando nos llamen desde esa URL, en este caso en la función ‘drupal_get_form’ ya que debemos devolver un formulario.
  • page arguments: son los argumentos a pasar a esa función, en este caso es el nombre de la función del módulo que se invocará para coseguir dicho formulario, que se llamará ‘ejemplo_admin_settings’.
  • access arguments: como en el caso anterior necesitaremos los permisos de admisnitración del sitio para poder entrar a esta parte de la configuración.
  • type: indicamos que la entrada del menú es un MENU_NORMAL_ITEM, significa que será un elemento de un menú que el administrador debe ser capaz de poder mover u ocultar como desee.
  • file: nombre del fichero donde se almacenará la función ‘ejemplo_admin_settings’, en nuestro caso será el nuevo fichero ‘ejemplo.admin.inc’

Como podemos ver necesitaremos un nuevo fichero llamado ‘ejemplo.admin.inc’ en el módulo para que pueda gestionar las funciones del formulario que hemos indicado en la entrada del menú que acabamos de introducir.
Así que creamos dicho fichero ‘ejemplo.admin.inc’, lo colocamos en el mismo directorio del módulo y le incluimos la cabecera típica de los ficheros php del módulo:
<?php
// $Id$

/**
 * @file
 * Administration page callbacks for the ejemplo module.
 */
También será necesario incluir dicho fichero en el ejemplo.info mediante la inclusión de una nueva línea:
files[] = ejemplo.admin.inc
De esta manera el módulo sabrá todos los ficheros incluye.

El formulario  de Administración del módulo

Generando el Formulario de Configuración

Ahora es cuando deberíamos introducir las funciones de generación, validación y envío del formulario.
Antes de empezar será necesario hacernos una idea del formulario que queremos gestionar, para ello veamos una captura del formulario generado…

 como puede verse, en el formulario disponemos fundamentalmente de los siguientes campos:

  • Un listado de checkboxes que representan los distintos tipos de contenido presentes en ese momento en Drupal. Si es la primera vez que ocnfigurarmos el módulo, no deberían aparecer ninguno de los tipos de contenidos como “checked”, y que no los habíamos selccionado previamente. Pero si anteriormente los habíamos seleccionado sí deberían aparecer como “checked”.
  • Un grupo de botones de Radio que indican cuando deberían borrarse el valor del campo “anotaciones” hechos sobre esos tipos de contenido. El valor predefinido será que nunca debe borrar dichas anotaciones. Debería recordar la opción marcada en anteriores configuraciones.
  • Un cuadro de texto que permite la introducción de un número, que representa el número de campos ‘annotation’ que debería añadir a los tipos de contenido marcados.
  • Un botón de Submit para guardar las configuraciones.

Teniendo estos datos presentes, procederemos a incluir el código en el fichero ejemplo.admin.inc de la función ejemplo_admin_settings:
/**
 * Form builder. Configure annotations.
 *
 * @ingroup forms
 * @see system_settings_form().
 */
function ejemplo_admin_settings() {
 
  $types = node_type_get_types();
  foreach($types as $node_type) {
     $options[$node_type->type] = $node_type->name;
  } 
 
  $form[‘ejemplo_node_types’] = array(
    ‘#type’ => ‘checkboxes’,
    ‘#title’ => t(‘Users may ejemplo these content types’),
    ‘#options’ => $options,
    ‘#default_value’ => variable_get(‘ejemplo_node_types’, array(‘page’)),
    ‘#description’ => t(‘A text field will be available on these content types to
       make user-specific notes.’),
  );
 
  $form[‘ejemplo_deletion’] = array(
    ‘#type’ => ‘radios’,
    ‘#title’ => t(‘Annotations will be deleted’),
    ‘#description’ => t(‘Select a method for deleting annotations.’),
    ‘#options’ => array(
      t(‘Never’),
      t(‘Randomly’),
      t(‘After 30 days’)
    ),
    ‘#default_value’ => variable_get(‘ejemplo_deletion’, 0) // Default to Never
  );

  $form[‘ejemplo_limit_per_node’] = array(
    ‘#type’ => ‘textfield’,
    ‘#title’ => t(‘Annotations per node’),
    ‘#description’ => t(‘Enter the maximum number of annotations allowed per
      node (0 for no limit).’),
    ‘#default_value’ => variable_get(‘ejemplo_limit_per_node’, 1),
    ‘#size’ => 3
  );
  return system_settings_form($form, TRUE);

}
Como vemos en el código no es necesario pasarle ningún argumento a la función, todos los datos del formulario que queremos generar los meteremos dentro de la propia función.
los fundamentos de la función es que generaremos un array asociativo que pasaremos a la función ‘system_settings_form’ como parámetro principal y lo que nos devuelva esa función es lo que devolveremos nosotros en la función ‘ejemplo_admin_settings’, que será lo que le pasemos a la función ‘drupal_get_form’, que es la que finalmente calculará el formulario para poder presentarlo en la página de Drupal. Esta secuencia de llamadas será común en todos los formularios de configuración de módulos.
Veamos cómo configuramos el formulario para cada uno de los elementos que debemos presentar.
Empecemos con la configuración del listado de checkboxes:
$types = node_type_get_types();
  foreach($types as $node_type) {
     $options[$node_type->type] = $node_type->name;
  } 
 
  $form[‘ejemplo_node_types’] = array(
    ‘#type’ => ‘checkboxes’,
    ‘#title’ => t(‘Users may ejemplo these content types’),
    ‘#options’ => $options,
    ‘#default_value’ => variable_get(‘ejemplo_node_types’, array(‘page’)),
    ‘#description’ => t(‘A text field will be available on these content types to
       make user-specific notes.’),
  );
la parte del formulario que generaremos es la siguiente…

como debemos presentar los distintos nombre de los tipos de contenido necesitamos generar un array para poder pasar a la generación de las checkboxes, que es lo que hacemos con la obtención del array $types y el foreach que hay justo debajo, donde indicamos como índice el tipo de contenido y en el valor el nombre del tipo de contenido.
Ahora toca configurar los elementos del array asociativo para las checkboxes:

  • el índice es parte del nombre del elemento que generaremos en el formulario, com una identificación de la parte del formulario donde nos encontramos.
  • #type: indica el tipo de elemento del formulario que queremos gestionar, en este caso checkboxes.
  • #title: es la traducción del título que le damos a esa sección del formulario, como pude verse se usa la función traductora t()
  • #options: es el array que hemos generado anteriormente con el array $options, con los nombres de los tipos de contenidos presentes en el sistema.
  • #description: la descripción que aparecerá debajo del título, que debería ayudar a la rellenado de dicha parte del formulario, también se usa una llamada a la función t()
  • #default_value: define las opciones por defecto que deberían aparecer marcadas según se netra al formulario, en este caso se hace una llamada a la función ‘variable_get’, que es la función principal del drupal para coger variables que nos pasan, indicando el nombre de la variable que queremos capturar ‘ejemplo_node_types’ que coincide con el nombre del índice que hemos colocado, que es la que agrupa las opciones de tipos de contenido en el formulario. Y le pasamos también la opción por defecto, como segunda parámetro si no los pasan esa variable ‘ejemplo_node_types’, que como puede verse es un array con un único elemento que es el tipo ‘page’, que es el nombre que tiene el tipo de contenido página, que viene por defecto en Drupal 7 con la instalación Standard, y sin módulos extra activados.

Ahora pasamos a la generación de los radio button…

mediante el código:
$form[‘ejemplo_deletion’] = array(
    ‘#type’ => ‘radios’,
    ‘#title’ => t(‘Annotations will be deleted’),
    ‘#description’ => t(‘Select a method for deleting annotations.’),
    ‘#options’ => array(
      t(‘Never’),
      t(‘Randomly’),
      t(‘After 30 days’)
    ),
    ‘#default_value’ => variable_get(‘ejemplo_deletion’, 0) // Default to Never
  );
Como puede verse la estructra del array es muy similar:

  • el indice marca el nombre del apartado del formulario ‘ejemplo_deletion’
  • #type: en este caso el valor es ‘radios’ porque queremos generar radio buttons.
  • #descripción: con el texto traducido
  • #options: en este caso lo generamos de manera manual, con un array asociativo, donde incluimos los textos traducibles de las distintas opciones a presentar.
  • #default_value: indicamos que si no nos mandan la variable ‘ejemplo_deletion’ debemos marcar por defecto la primera opción (la 0) del listado de opciones, y si nos mandan la variable, cogemos el valor que nos hayan marcado anteriormente.

 A continuación generaremos la parte de la input text para recoger el número de anotaciones por tipo de contenido…

incluyendo el siguiente código:
$form[‘ejemplo_limit_per_node’] = array(
    ‘#type’ => ‘textfield’,
    ‘#title’ => t(‘Annotations per node’),
    ‘#description’ => t(‘Enter the maximum number of annotations allowed per
      node (0 for no limit).’),
    ‘#default_value’ => variable_get(‘ejemplo_limit_per_node’, 1),
    ‘#size’ => 3
  );
En el array asociativo se definen los siguientes elementos:

  • el índice es el nombre de la zona del formulario que queremos gestionar ‘ejemplo_limit_per_node’
  • #type: nos indica que quiere generar un campo de texto ‘textfield’
  • #title y #description: nos dan las cadenas traducibles para el título y la descripción, como es habitual
  • #default_value: captura la variable ‘ejemplo_limit_per_node’ y coloca su valor si nos pasan la variable y sino coloca el valor 1 en el campo de texto.
  • #size: nos define el tamaño del cuadro de texto.

No está de más recordar, que una vez definidos estos elementos del array $form necesitamos devolverlo a través de la llamada a la función ‘system_settings_form’ poniendo:
return system_settings_form($form, TRUE);

Validación del Formulario

Una vez generado el formulario necesitaremos saber cómo validarlo, ésto lo realizaremos a través de una nueva función con un nombre similar a la anterior, en este caso ‘ejemplo_admin_settings_validate’, el nombre dela función depende del nombre que le hayamos dado a la función de callback de generación del formulario, es decir se añade la cadena ‘_validate’ al nombre de la primera función para poner el nombre a dicha función de validación, así que tendremos que incluir un código como el siguiente:
/**
 * ejemplo_admin_settings_validate
 *
 * Update content types to reflect changes to the annotation configuration options selected by the site administrator.
 * If the administrator checked a box for a content type that did not previously have an annotation field then add it to the
 * content type.   If a content type is unchecked by the administrator and that content type had an annotation field, then
 * remove that field from the content type.
 */
function ejemplo_admin_settings_validate($form, $form_state) {
}
Como puede verse a la función de validación se le pasan fundamentalmente dos parámetros, $form que es el formulario que queremos generar y $form_state que es el estado actual del formulario que estamos gestionando, es decir los datos.
Esta función debería gestionar dos cosas:

  • Las validaciones del formulario: es decir todas aquellas cosas que tengamos que comprobar para que el fomulario valide. Si no valida será necesario generar los errores a presentar al usuario para decirle porqué no valida el formulario, mediante la función form_set_error() y realizar un return, para que no continue la validación.
  • Realizar las acciones necesarias cuando el formulario valida, es decir guardar todos aquellos valores del formulario en la configuración o donde sea necesario para que no se pierdan.

Empecemos por la parte de validación:
$limit = $form_state[‘values’][‘ejemplo_limit_per_node’];
  if (!is_numeric($limit)) {
    form_set_error(‘ejemplo_limit_per_node’, t(‘Please enter a number.’));
    return;
  }
 En este caso sólo estamos validando un campo, el ‘ejemplo_limit_per_node’, para verificar que su valor efectivamente es numérico. Para ello utilizamos la variable $form_state, donde através de su índice [‘values’] almacena los valores introducidos en el formulario por parte del usuario, luego indicamos el ‘campo’ que queremos comprobar, en este caso ‘ejemplo_limit_per_node’.
Dependiendo del tipo de campo podemos enocntrarnos con valores simples o arrays de selección, el tratamiento a estos valores dependerá del ‘#type’ de ‘campo’ del formulario.
En este caso simplemente hacemos un if para saber si el campo es numérico mediante la función ‘is_numeric’ y generarmos el error y hacemos el return sin devolver nada.

En el caso de que el formulario valide, continuamos con la función haciendo lo que tengamos que hacer con los valores del formulario.
En primer lugar intentamos añadir el campo ‘annotation’ a los tipos de contenido que nos han seleccionado en las checkboxes:
// loop through each of the content type checkboxes shown on the form
  foreach ($form_state[‘values’][‘ejemplo_node_types’] as $key => $value) {

// if the check box for a content type is unchecked, look to see whether this content type has the
// annotation field attached to it using the field_info_instance function.  If it does then we
// need to remove the annotation field as the administrator has unchecked the box.
     if (!$value) {
        $instance = field_info_instance(‘node’, ‘annotation’, $key);
         if (!empty($instance)) {
           field_delete_instance($instance);    
           watchdog(“Annotation”, “Deleted annotation field from content type: “.$key);
        } // end of annotation existed, need to remove it
     } else {
// if the check box is checked for a content type look to see whether the field is associated with that
// content type.  If not then add the annotation field to the content type
        $instance = field_info_instance(‘node’, ‘annotation’, $key);
        if (empty($instance)) {
            $instance = array(
             ‘field_name’ => ‘annotation’,
               ‘entity_type’ => ‘node’,
               ‘bundle’ => $key,
                ‘label’ => t(‘Annotation’),
                ‘widget_type’ => ‘text_textarea_with_summary’,
                ‘settings’ => array(‘display_summary’ => TRUE),
                ‘display’ => array(
                ‘default’ => array(
                     ‘type’ => ‘text_default’,
                 ),
                ‘teaser’ => array(
                     ‘type’ => ‘text_summary_or_trimmed’,
                 ),
                ),
            );
       
            $instance = field_create_instance($instance);
   
            watchdog(“Annotation”, “Added annotation field to content type: “.$key);
        } // end of annotation field didn’t exist so add it
     } // end of if
 
  } // end of foreach

Por lo que hacemos un foreach sobre el ‘campo’ ‘ejemplo_node_types’ para recorrer el array de las opciones que nos devuelven.
Si no está marcado el tipo de contenido, verfificamos si ese tipo de contenido tenía añadido ese campo y asi es así borramos la relación ($instance) de ese tipo de contenido.
Por otra parte si está marcado ese tipo de contenido miramos si no existe la $instance de ese campo para ese tipo de contenido y si es así, no existe esa relación, rellenamos un array $instance para ese ‘bundle’ o tipo de cotenido y añadimos la $instance. Por lo que estará relacionado ese campo con ese tipo de contenido.

Prueba de funcionamiento

Una vez colocadas las funciones de generación validación del formulario, será necesario poder probarlas, para ello si hace falta desintalaremos y volveremos a instalar el módulo. E intentaremos acceder a la Configuración del Módulo. Debería aparecernos el formulario antes generado y debería realizar correctamente la validación y modificación de los campos de los tipos de contenido indicados.
También deberíamos probar desde el formulario de edición de dichos tipos de contenido si efectivamente aparece el campo en el formulario, de una manera similar a la siguiente…

Añadiendo el campo la presentación del Tipo de Contenido

Una vez almacenada la información deberíamos modificar la presentación de ese campo de anotaciones sólo en el caso de que el usuario que ha introducido el nodo (contenido) es el que lo esté visualizando, para ello utilizaremos el hook_node_load() por lo que deberemos introducir una nueva función en el fichero ejemplo.module con el siguiente código:
/**
 * implements hook_node_load
 */
function ejemplo_node_load($nodes, $types) {

  global $user;
 
// check to see if the person viewing the node is the author, if not then hide the
// annotation
  foreach ($nodes as $node) {
     if ($user->uid != $node->uid) {
        unset($node->annotation);
     }
  }

}
De esta manera a través del primer parámetro $nodes, que es un array con los distintos nodos a presentar, y la objeto global $user (donde se alamacenan los datos del usuario) vamos cogiendo cada nodo como la variable $node con un foreach y vamos comprobando si el usuario que actualmente está visitando la página es el autor del nodo, si no es así realizamos un unset del atributo del objeto que almacena la anotación para que no se presente.

Referencias

Licencia Creative Commons

Curso de desarrollo de módulos con Drupal 7 (II): Instalación y Desinstalación

En esta entrega generaremos el fichero module.install en el que colocaremos los hooks de instalación y desinstalación. Para ello crearemos un nuevo fichero en el módulo, en nuestro caso el ejemplo.install y lo colocaremos en la carpeta principal del módulo. Como todo fichero de php del módulo deberemos colocar la cabecera apropiada e incluirlo en el fichero .info. Dentro del fichero ejemplo.info incluiremos una línea con el siguiente código:
files[] = ejemplo.install
De esta manera el módulo configura la inclusión del fichero ejemplo.install para que Drupal sepa que dispone de él.
Por otra parte, dentro del fichero ejemplo.install incluiremos el siguiente código:
<?php
/**
* @file
* Fichero del módulo de ejemplo para drupal
*
* Descripción larga del fichero que netra dentro del módulo de ejemplo de Drupal
*/
/**
 * implements hook_install
 */

function ejemplo_install() {
}

/**
 * implements hook_uninstall
 */
function ejemplo_uninstall() { 

}
Como puede verse incluimos dos funciones nuevas en el fichero: ejemplo_install() y ejemplo_uninstall(). En este caso están vacías, pero dichas funciones va a ejecutarse cuando se realice la instalación y desinstalación del módulo respectivamente.
La instalación del módulo, cuando se está haciendo el desarrollo, se realiza la primera vez que entramos en Drupal  y existe la carpeta del módulo.
Por lo que puede llegar a ser necesario realizar manualmente la desinstalación del módulo para que aplique los cambios de la instalación al volver a entrar. Para realizar la desinstalación deberemos acceder al listado de módulos, y desactivar el módulo.
Después en el listado de módulos deberemos pulsar en la pestaña “Desinstalar”…

Como puede verse esa pestaña aparece en la parte superior derecha de la página. Pulsamos en ella y nos aparecerá un formulario de desinstalación de módulos similar al siguiente…

com puede verse aparecerá todos aquellos módulos desactivados, en los cuales esté permitida su desinstalación. Pulsaremos la checkbox la lado del módulo que queremos desinstalar y pulsaremos en el botón “Desinstalar”. Nos aparecerá una confirmación de la desinstalación del módulo, similar a la siguiente…

pulsaremos en el botón “Desinstalar”. Y nos aparecerá el resultado de la desinstalación, si todo ha ido correctamente, veremos una pantalla indicando que el módulo se ha desinstalado correctamente, similar a la siguiente…

De esta manera se ejecutará el hook_uninstall, en nuestro caso la función ejemplo_uninstall() del ejemplo.module.
Después podemos volver al listado de módulos y volver a activar el módulo, por lo que se ejecutará el hook_install, en nuestro caso la función ejemplo_uninstall().
La idea fundamental de estas dos funciones es que deberían ser totalmente atómicas en su concepto. Es decir, todo aquello que haga el hook_install, debería ser deshecho por el hook_uninstall.

Planificando el módulo

Es hora de decidir qué es lo que queremos que haga el nuevo módulo. En nuesto ejemplo, intentaremos añadir un campo nuevo a Drupal para luego poder usarlo desde los contenidos. Por lo que necesitaremos usar ese campo dentro del módulo.

Desde la instalación deberemos decirle a Drupal que queremos usar un nuevo campo.
Desde la administración del módulo podremos elegir que tipos de contenido tendrán disponible este nuevo campo.
Desde la desinstalación, deberemos mirar todos los tipos de contenido para ver cuales de ellos disponen de ese campo, después borrar el campo de aquellos tipos de contenido que lo tengan y luego borrar el campo para que drupal no lo use.

hook_install()

Desde el hook_install() deberemos decir que debe ejecutar drupal cuando el módulo se instala.
En nuestro caso, debemos usar el propio API de Drupal para retocar los campos disponible para los tipos de datos, por lo que no es necesario cambiar el modelo de la base de datos, y no tenemos que hacer uso del hook_schema(). En el caso de que tuviesemos que generar nuevas tablas y campos de tabla en el modelo de la base de datos, sí tendríamos quehacer uso de hook_schema().
Para incluir el campo deberemos incluir el códufo en el hook_install(), en nuestro caso, en la función ejemplo_install(), con el siguiente código:
function ejemplo_install() {

  // comprueba si existe el código
  $field = field_info_field(‘annotation’);

  // if the annotation field does not exist then create it
  if (empty($field)) {
    $field = array(
      ‘field_name’ => ‘annotation’,
      ‘type’ => ‘text_with_summary’,
      ‘entity_types’ => array(‘node’),
      ‘translatable’ => TRUE,
    );
    $field = field_create_field($field);
  }

}
Com puede verse en este código fundamentalmente estamos usando las funciones del API de Field, cuyos nombres siempre empiezan por “field_”.
Las dos primeras líneas intenta averiguar mediante la función “field_info_field()” si el campo para las anotaciones ‘annotation’ existe ya en el Drupal donde queremos instalar el módulo.
Si es así no hace nada, si no es así, intenta crear el campo mediante la llamada a la función “field_create_field()” donde le pasa como parámetro un array con los metadatos principales del campo que quiere crear, en nuestro caso:

  • field_name: nombre del campo que queremos crear.
  • type: tipo de campo, responde a los distintos tipos redefinidos dentro de drupal
  • entity_types: tipo de entidad sobre el cual queremos hacer uso del campo
  • translatable: boolean que representa si el campo es traducible o no.

hook_uninstall()

Como se ha explicado anteriormente será necesario deshacer las acciones realizadas desde la administración y desde la instalación del módulo, por lo que el código de nuestro ejemplo_uninstall() será el siguiente…
/**
 * implements hook_uninstall
 */
function ejemplo_uninstall() {

   watchdog(“Annotate Module”, “Uninstalling module and deleting fields”);
  
   $types = node_type_get_types();  
  
   foreach($types as $type) {
      delete_annotation($type);  
   }
  
   $field = field_info_field(‘annotation’);

   if ($field) {
      field_delete_field(‘annotation’);
   }
  
}

 Como podemos observar lo primero que hacemos es sacar un mensaje a través de la función watchdog, donde pasamos dos parámetros, el nombre del módulo que genera el mensaje y el mensaje en sí mismo. Para informar de lo que estamos haciendo.
Posteriormente cogemos el listado de tipos de contenidos como un array mediante la función node_type_get_types().
Después recorremos el array de tipos para ir borrando uno a uno el campo ‘annotation’ en todos y cada uno de ellos, a través de una función creada por nosotros que incluiremos más adelante.
Finalmente, miramos a ver si existe el campo ‘annotation’ en el Drupal y si es así lo eliminamos mediante la función field_delete_field(), donde le pasamos como parámetro el nombre del campo ‘annotation’.
De esta manera toda la información que gestiona el módulo será borrada, tanto los campos que hayamos utilizado en los distintos tipos de datos, como el campo en sí mismo.
Por lo que podemos decir que hemos conseguido mantener esa atomicidad en el comportamiento entre install, admin y uninstall, como explicamos anteriormente.

Para que funcione correctamente el hook_uninstall(), agregamos también la función delete_annotation() al fichero ejemplo.install..
/**
 * Function:  delete_annotation($type)
 * Purpose :  deletes instances of the annotation field from content types
 */
function delete_annotation($type) {

  $instance = field_info_instance(‘node’, ‘annotation’, $type->type);

  if ($instance) {
     field_delete_instance($instance);
  }

}
Como puede verse, según el tipo de contenido que pasamos, intentamos saber si dicho tipo tiene asociado el campo ‘annotation’, mediante la llamada a la función field_info_instance. Como primer parámetro pasamos el tipo de contenido que queremos comprobar ‘node’, los contenidos. Como segundo parámetro pasamos el nombre del campo ‘annotation’ y como tercer parámetro pasamos el nombre del tipo de contenido que estamos comprobando.
Si dicho campo está relacionado con el tipo de contenido la variable $instance tendrá un valor distinto a false, por lo que ejecutaremos el método field_delete_instance(), pasándole como parámetro la variable $instance, que eliminará dicha relación con el tipo de contenido.

Referencias: 

Licencia Creative Commons

Curso de Desarrollo de módulos con Drupal 7 (I): Introducción

En las siguientes entregar veremos cómo crear nuevos módulos de Drupal 7. Para realizar la programación utilizaremos Aptana Studio 3 , una distribución basada en Eclipse, como editor de código y gestor de proyectos PHP.
Para comenzar la programación necesitamos disponer de una instalación limpia de Drupal 7 que poder utilizar. Digamos que la hemos instalado en el directorio “c:xampphtdocsdrupaldev”.
Para los desarrollos con Drupal, es altamente recomendable la instalación de los módulos deve, tal como indica la XI entrega del curso de Drupal 7.
Arrancamos Aptana y vamos a realizar la importación del directorio de drupaldev como proyecto de Aptana.

Importación del proyecto en Aptana

Para ello en el “Project Exlorer” pulsamos el botón derecho del ratón y seleccionamos la opción “Import”…

Nos aparecerá una pantalla de selección  de tipo de importación similar a la siguiente…

Nos saldrán distintas opciones, expandimos la opción “General” y seleccionamos la opción “Existing Folder as New Project” y pulsamos en “Next>”, nos aparecerá una pantalla donde deberemos decir qué directorio debemos importar…

A través del botón “Browse…” seleccionamos el directorio de instalación de drupal que queremos importar, seleccionamos el tipo de proyecto “PHP”, ponemos el nombre de proyecto, por ejemplo “drupaldev” y pulsamos en el botón “Finish”. Veremos en el “Project Explorer” cómo ha aparecido una nueva carpeta llamada “drupaldev” que corresponde al proyecto que acabamos de importar…

Si expandimos la carpeta del proyecto podremos ver las carpetas y ficheros que se incluyen en el mismo, cualquier cambio que hagamos desde Aptana se reflejará en el directorio de Drupal y viceversa…

Creando el Módulo: Primeros pasos

 Una vez configurado el proyecto en Aptana, deberemos dar los primeros pasos en la generación del proyecto.
Todas las rutas de carpetas y ficheros serán relativas al proyecto de drupal en aptana. 
Crearemos una carpeta llamada “custom” en el directorio “sites/all/modules” del proyecto, para ello navegaremos por los directorio del proyecto hasta encontrar la carpeta “sites/all/modules” y pulsamos botón derecho encima de la carpeta “modules”, navegamos al menú “New” y pulsamos en la opción “Folder”…

a continuación nos saldrá una ventana en la que podremos selccionar la localización y el nomrbe de la carpeta…

y pulsamos en el botón “Finish”. Veremos que nos aparecerá en el Project Explorer dicha carpeta custom dentro de modules.

Carpeta de módulo y ficheros iniciales

Ahora es cuando debemos decidir el nombre del módulo ya que debemos crear una carpeta con el nombre para almacenar los ficheros del mismo. Pongamos por ejemplo que el el módulo se va a llamar “ejemplo”, por lo tanto deberemos crear una carpeta llamada “ejemplo” dentro de la carpeta custom, tal como describimos anterioremente.
 En el directorio del módulo debemos crear un fichero “info” con la información del módulo, el fichero debe llamarse “[nombredemodulo].info”, en nuestro caso deberá llamarse “ejemplo.info”.
Para ello pulsamos el botón derecho del ratón sobre la carpeta “ejemplo”, navegamos al menú “New” y seleccionamos la opción “File”…

a continuación, nos saldrá la pantalla de localización del fichero…

pondremos el nombre al fichero, en nuestro caso, “ejemplo.info” y pulsamos en “Finish”. Veremos que nos abrirá la edición del fichero recien creado en la parte derecha de la pantalla, el fichero estará vacío…

como puede verse en la captura, existen pestañas en la parte de edición de código, una por fichero abierto para edición.

Notas sobre las vistas de Eclipse(Aptana)

Dichas pestañas pueden cerrarse pulsando en la “X” que aprece al lado del nombre del fichero. Para volver a abrir el fichero para edición, basta con hacer doble clic en el nombre del fichero y veremos que aparecerá de nuevo en la parte de edición.
Si pulsamos doble clic sobre el nombre de la pestaña del fichero se colocará esta “vista” (como se llaman los componentes visuales de Eclipse y Aptana) a modo “pantalla completa”. Si queremos volver al modo de pantalla normal y así poder ver el resto de “vistas” volveremos a pulsar doble clic en el nombre de la pestaña.
Si aparece un * la lado del nombre del fichero es porque el fichero se ha modificado pero no se ha guardado todavía.
Para guardar el fichero bastará con pulsar “Control+S”.

Contenido del fichero .info

El fichero [nombredemodulo].info corresponde a la definición o información del módulo. Indica entre otras informaciones:

  • name: el nombre del módulo
  • description: descripción de las funcionalidades del módulo
  • core: versión de drupal para la que está desarrollado
  • package: nombre del paquete donde irá colocado el módulo
  • stylesheets[]:  ficheros CSS relacionados
  • scripts[]: ficheros JS relacionados
  • dependencies[]: módulos de los que depende el módulo
  • php: versión mínima de PHP para que funcione el módulo
  • files[]: ficheros que están disponibles en el módulo
  • configure: ruta de configuración del módulo

Para nuestro caso rellenaremos el fichero con el siguiente contenido:
name = ejemplo
description = modulo de ejemplo para drupal 7
core = 7.x
package = Plexxoo
php = 5.3
configure = admin/config/ejemplo/settings

Una vez copiado el contenido al fichero, lo salvamos, pulsando “Control+S”o pulsando en el icono del disquete.

Creación de ficheros Suplementarios del módulo

De esta manera el fichero info está configurado, pero tenemos un módulo que no hace nada, para ello deberemos añadir funcionalidades y otros ficheros al módulo y reflejar estos ficheros en el fichero info.
Crearemos 3 ficheros:

  • ejemplo.module
  • ejemplo.install
  • ejemplo.admin.inc

Estos tres ficheros nos servirán de base para el desarrollo del módulo. Ahora los incluiremos en el fichero ejemplo.info añadiendo las siguientes líneas:
files[] = ejemplo.module
files[] = ejemplo.install
files[] = ejemplo.admin.inc

De esta manera Drupal sabrá que tiene esos ficheros suplementarios relacionados con el módulo.
En el fichero ejemplo.module introducimos el siguiente contenido base:

<?php 
/** 
* @file 
* Fichero del módulo de ejemplo para drupal 

* Descripción larga del fichero que entra dentro del módulo de ejemplo de Drupal
*/
?>

El @file indica la descripción de uso del fichero, de cara a la documentación de Drupal.

Los hooks

Drupal se basa en un sistema de conectores para enganchar contra las funcionalidades de los módulos, tales como añadir un menú. Dichos conectores son principalmente funciones consultadas desde Drupal a los distintos módulos activados.
En este ejemplo utilizaremos un hook muy sencillo el “hook_help()”. cuando se habla de la palabra “hook”, en el módulo debe substiruirse con el nombre del módulo. De esta manera será necesario nombrarlo como “ejemplo_help()”.
 El siguiente código deberemos incluirlo en el fichero ejemplo.module dentro del bloque php…
 /**
* Implements hook_help.
*
* Displays help and module information.
*
* @param path
*   Which path of the site we’re using to display help
* @param arg
*   Array that holds the current path as returned from arg() function
*/
function ejemplo_help($path, $arg) {
  switch ($path) {
    case “admin/help#ejemplo”:
      return ‘<p>’.  t(“texto de ayuda del módulo”) .'</p>’;
      break;
  }
}
como pude verse tenemos una función nueva en el fichero que define lo que drupal debe hacer para atender la petición de ayuda sobre el módulo ejemplo.
Todas las funciones hook, pueden tener parámetros de entrada, para poder pasar el contexto en el cual se mueve el módulo y poder interactuar con los parámetros.
En este caso el parámetro principal de $path, que es que determina la ruta a través de la cual se desea acceder al contenido.
Así dependiendo de dicho path tenemos un switch que nos permite ofrecer salidas distintas. En este caso sólo hay un caso, que es que nos ofrece un código HTML de vuelta con el texto de la ayuda.
Dicho texto debería ser traducible ya que se utiliza la función t que permite la traducción de literales por parte de Drupal. Si existe esa traducción para el idioma seleccionado la presenta, sino deja el texto del literal.

Activando el módulo

Una vez realizados todos estos pasos deberemos activar el módulo que hemos creado. Como el módulo ya está instalado, debido a que está ya colocado en el directorio “sites/all/custom/ejemplo” no es necesario realizar la instalación. Para activarlo seguiremos los mismos pasos de activación de un módulo que describimos en la entrega de módulos.
Si accedemos a la Configuración->Módulos veremos nuestro módulo dentro de la categoría “Plexxoo”…

Lo único que tendremos que hacer es activar el módulo y volver a entrar al listado de módulos de la administración, veremos que el módulo está activado y nos aparecerán dos enlaces en la parte derecha del módulo: Ayuda y Configuración.
De momento el único enlace funcional es el de Ayuda, que el único hook que hemos escrito para ese módulo. Si pulsamos sobre él, veremos la siguiente pantalla…

 Como puede observarse desde la captura aparece el texto generado desde la función, así como un enlace a la configuración del módulo. Pero la gestión de la configuración lo veremos en la siguiente entrega.

Referencias:

Licencia Creative Commons

Suscríbete al Boletín

Si quieres estar al tanto de las novedades del blog, ya sabes :)
* = campo obligatorio

powered by MailChimp!

Uso de cookies

Este sitio web utiliza cookies para que usted tenga la mejor experiencia de usuario. Si continúa navegando está dando su consentimiento para la aceptación de las mencionadas cookies y la aceptación de nuestra política de cookies, pinche el enlace para mayor información. ACEPTAR

Aviso de cookies