Hola Mundo, empezar a programar con Drupal 7

Este tutorial está orientado a programadores que conocen PHP, que han empezado a utilizar Drupal 7 a nivel de instalación e interfaz de administración, y que desean aprender a programar sus propios módulos. He querido empezar por el clásico “Hola Mundo” para hacer el ejemplo lo más sencillo posible conceptualmente, pero al mismo tiempo extenderlo con variantes que permitan hacerse una idea de cómo funciona Drupal y las posibilidades que nos ofrece.

A través de este tutorial podrás aprender a:

 

Creando tu primer módulo

Por supuesto podríamos crear el “Hola Mundo” en un bloque o una página directamente desde la interfaz, o incluso introducir un <?php echo “Hola Mundo”; ?> en una plantilla del tema, pero se trata de aprender a programar funcionalidades y en Drupal esto se hace desarrollando módulos.

Los módulos se suelen ubicar dentro del directorio /sites/all/modules. Allí creamos una carpeta para nuestro módulo que podemos llamar “saludar”. Para terminar de crear nuestro módulo necesitamos crear dentro el archivo saludar.info y el archivo saludar.module. El primero es un archivo de texto que contendrá la información de definición del archivo, y en el segundo empezaremos a programar con PHP.

saludar/saludar.info

name = Saludar
description = "Módulo que dice hola mundo"
package = Aprendiendo a programar con Drupal
core = 7.x

En saludar.info estamos diciendo que el módulo se llama “Saludar”, describimos lo que hace, lo clasificamos en la categoría “Aprendiendo a programar con Drupal” y especificamos que es compatible con Drupal 7.
Para comprobar que hemos creado el módulo correctamente nos vamos a la opción “Módulos” del menú de administración de nuestra web Drupal, en la ruta /admin/modules. Allí encontraremos nuestra categoría con nuestro primer módulo, y una casilla para activarlo.

Creando tu primer módulo

 

Crear una página para decir hola mundo

Para crear una página, es decir, programar la respuesta para una determinada url, utilizaremos la función hook_menu(). Cuando nuestra aplicación reciba la petición de la página “/saludar/hola-mundo”, Drupal comprobará si alguno de los módulos tiene programado un nombremodulo_menu() para esta dirección. Creamos pues nuestra función saludar_menu() que servirá de índice para las direcciones a las que responderá nuestro módulo saludar.

saludar/saludar.module

<?php
/**
 * @file
 * Archivo para empezar a programar con Drupal
 */

/**
 * Implementa hook_menu().
 */
function saludar_menu() {
  $items['saludar/hola-mundo'] = array(
    'title' => 'Saludar',
    'page callback' => 'saludar_hola_mundo',
    'access callback' => TRUE,
  );
  return $items;
}

/**
 * Callback que implementa la página: saludar/hola-mundo.
 */
function saludar_hola_mundo() {
  return "Hola Mundo";
}

Lo que hemos hecho es añadir una url al array de elementos $items, y para esa dirección elegimos un título para la página y la función que implementa el contenido, que a su vez devuelve como contenido un “Hola Mundo”. Con 'access callback' definimos con qué permisos pueden acceder a esta página, en este caso podrán todos los usuarios (TRUE).

Cada vez que implementamos un cambio en hook_menu() necesitamos vaciar la caché para poder visualizar estas modificaciones. En el menú de administración pulsamos en Configuración, y a continuación en Rendimiento (en el bloque de Desarrollo), donde podremos pulsar el botón “Vaciar todas las cachés”. Ahora sí, podemos ver nuestro primer “Hola Mundo” en la dirección “/saludar/hola-mundo” de nuestro sitio web.

Saludar Hola Mundo

Como puedes ver, además de la página se ha creado un enlace en el menú de Navegación. Esto es porque hemos obviado una de las opciones del array $items en el hook_menu(): 'type', cuyo valor por defecto es la constante MENU_NORMAL_ITEM. Si quisiéramos crear la página sin que aparezca el menú simplemente añadiríamos en el array:

'type' => MENU_CALLBACK,

¡Recuerda vaciar las cachés para ver los cambios!

 

Theming: maquetar el resultado con HTML

Hemos creado una página con el título Saludar y hemos mostrado en su interior el texto “Hola Mundo”. Como podéis comprobar el contenido de nuestra página se muestra dentro de un <div class=”content”>. Podríamos formatear un poco el resultado con HTML directamente en la función:

function saludar_hola_mundo() {
  return '<p class="saludo"><em>Hola Mundo</em></p>';
}

Pero estaríamos mezclando contenido y presentación, así que vamos a ir un poco más allá para separarlo, maquetando el “Hola Mundo” con HTML en un archivo de plantilla aparte. Para ello devolvemos el resultado de la función theme():

 function saludar_hola_mundo() {
  $variables = array(
    'message' => 'Hola Mundo',
  );
  return theme('saludar_hola_mundo', $variables);
}

Ahora estamos introduciendo “Hola Mundo” en el array de variables que le vamos a pasar a la plantilla, y a continuación utilizamos la función theme() para generar el resultado de salida. Para ello la función theme() invoca el hook_theme(), utilizando el primer parámetro 'saludar_hola_mundo' como nombre del hook.

Por tanto el siguiente paso es implementar el hook_theme() para nuestro módulo en saludar.module, indicando la plantilla que formateará la salida de 'saludar_hola_mundo'. Al igual que con hook_menu(), la función que implementa el hook_theme() en el módulo se denomina nombremodulo_theme():

 /**
 * Implementa hook_theme().
 */
function saludar_theme() {
  return array(
    'saludar_hola_mundo' => array(
      'template' => 'saludar-hola-mundo',
    ),
  );
}

En nuestro hook_theme() estamos llamando a la plantilla (template): “saludar-hola-mundo”, para maquetar el callback: “saludar_hola_mundo”. Ahora solo falta crear la plantilla en nuestro módulo, creando un archivo con el nombre del template acabado en “.tpl.php”.

saludar/saludar-hola-mundo.tpl.php

 <p class="saludo"><em><?php echo $message; ?></em></p> 

Vaciamos las cachés para que coja el nuevo archivo y podemos comprobar el resultado. Como puedes ver estamos utilizando la variable “message” que definimos en la función saludar_hola_mundo(). A partir de aquí puedes añadir nuevas variables de contenido (por ejemplo la fecha) y modificar la plantilla para maquetar ese contenido con esas variables.

Theming

Al utilizar theme() estamos separando la presentación de la funcionalidad y el contenido, y permitiendo que esa presentación sea fácilmente sobreescrita en un tema. Por ejemplo un maquetador o “drupal themer” podría simplemente copiar el archivo saludar-hola-mundo.tpl.php del módulo en el tema y modificarlo, sobreescribiendo así el marcado HTML por defecto definido en nuestro módulo.

 

Programar un bloque que diga “Hola Mundo”

Hemos aprendido a crear nuestra primera página desde un módulo, con contenido maquetado. Ahora vamos a aprender a construir un bloque para poder colocar nuestro “Hola Mundo” en la región de la página o páginas donde queramos ubicarlo. Para crear el bloque tenemos primero que implementar en saludar.module el hook_block_info(), que define todos los bloques que nuestro módulo va a proveer:

 /**
 * Implementa hook_block_info().
 */
function saludar_block_info() {
  $blocks['hola_mundo'] = array(
    'info' => 'Bloque para Hola Mundo',
  );
  return $blocks;
}

En el array $blocks definimos todos los bloques de nuestro módulo y proporcionamos las opciones por defecto de cada bloque. Aquí hemos definido solamente “info”, pero podríamos haber definido si por defecto aparece activado o no, en qué región, con qué peso, etc. Estas opciones las puede configurar el administrador del sitio web drupal desde la pantalla de Bloques en el menú Estructura (/admin/structure/block). Allí vemos nuestro bloque, en la sección “Desactivado”.

Podemos colocarlo en una región, por ejemplo en la barra lateral, pero aún no podemos verlo porque nos falta un paso, construir el bloque con el contenido, mediante hook_block_view():

 /**
 * Implementa hook_block_view().
 */
function saludar_block_view($delta = '') {
  switch ($delta) {
    case 'hola_mundo':
      $block['content'] = saludar_hola_mundo();
      return $block;
  }
}

En esta función definimos lo que se ve en cada bloque que implementa nuestro módulo. La variable $delta es la que nos identifica el bloque, y para el caso 'hola_mundo' establecemos su contenido. Nuevamente en lugar de establecer el contenido del bloque directamente con “Hola Mundo”, estamos reutilizando la función saludar_hola_mundo() que escribimos anteriormente para utilizar la plantilla saludar-hola-mundo.tpl.php a través de hook_theme().

Bloque Hola Mundo

Ahora sí, si actualizamos cualquier página podemos ver el bloque en la barra lateral, con el mensaje “Hola Mundo”, tal y como lo maquetamos en la plantilla. A este bloque no le hemos asignado ningún título, si quisiéramos proporcionar uno por defecto bastaría con utilizar la variable $block['subject'] en el hook_block_view().

 

Hacer el saludo configurable desde la interfaz de administración

Drupal, además de una plataforma para desarrollo de aplicaciones, es un potente CMS o gestor de contenidos. Esto es así porque la mayoría de los módulos no solo extienden la funcionalidad aportando algo nuevo, si no que tratan de poner en manos de los usuarios administradores herramientas para configurar esa funcionalidad y gestionar su contenido. Por tanto a la hora de desarrollar un módulo para Drupal puede ser muy importante programarlo para que sea configurable, y como vamos a ver a continuación, implementar el formulario de administración de las opciones del módulo es bastante sencillo.

Vamos a crear una página donde configurar el saludo de nuestro módulo, así el administrador podrá cambiar el texto del mensaje “Hola mundo” por cualquier otro saludo. Primero Colocaremos el acceso a esta página en el menú de Configuración dentro de la zona de Administración, en la url /admin/config:

Administración - Configuración

Añadimos un nuevo elemento en el array del hook_menu de nuestro módulo, en saludar.module:

   $items['admin/config/content/saludar'] = array(
    'title' => 'Saludar',
    'description' => 'Configurar las opciones para el saludo.',
    'page callback' => 'drupal_get_form',
    'page arguments' => array('saludar_configuracion'),
    'access arguments' => array('administer site configuration'),
    'file' => 'saludar.admin.inc',
  );

Al situar la página bajo la ruta “admin/config/content/” estamos ubicándola en ese menú, de título “Auditoría del contenido”, dentro de Administración – Configuración.

Administración - Configuración - Autoría del contenido

En esta ocasión configuramos la opción “page callback” para construir el formulario con la función drupal_get_form(), “page arguments” para establecer el id del formulario (“saludar_configuracion”) que le pasamos a drupal_get_form(), y “access arguments” para que sólo puedan acceder a la página de configuración de nuestro módulo aquellos usuarios cuyo rol tenga asignado el permiso “administer site configuration”, traducido en la página de permisos como “Administrar configuración del sitio”.

Por último hemos utilizado la opción “file” para programar el formulario de administración en un archivo diferente. Por supuesto podríamos omitirlo y seguir programando todo en saludar.module, pero a medida que el módulo empieza a crecer se hace más importante dividir la funcionalidad y dejar el .module con los hooks y funciones más generales, a modo de índice del módulo.

A continuación creamos el archivo saludar.admin.inc en nuestro módulo con tres funciones, una para definir el formulario de configuración, otra para validar dicho formulario y otra para procesar el envío del formulario ya validado.

saludar/saludar.admin.inc

 <?php
/**
 * @file
 * Callbacks de administración del módulo saludar.
 */

/**
 * Define el formulario de opciones de configuración.
 */
function saludar_configuracion() {
  $form['saludar_saludo'] = array(
    '#title' => 'Saludo que se muestra al usuario',
    '#type' => 'textfield',
    '#default_value' => variable_get('saludar_saludo', 'Hola Mundo'),
  );
  $form['submit'] = array(
      '#type' => 'submit',
      '#value' => 'Guardar configuración',
  );
  $form['#submit'][] = 'saludar_configuracion_submit';
  return $form;
}

/**
 * Valida el formulario de opciones de configuración.
 */
function saludar_configuracion_validate($form, &$form_state) {
  if (trim($form_state['values']['saludar_saludo']) == '') {
    form_set_error('saludar_saludo', 'El saludo no puede quedar vacío.');
  }
}

/**
 * Procesa el envío del formulario de opciones de configuración.
 */
function saludar_configuracion_submit($form, $form_state) {
  variable_set('saludar_saludo', $form_state['values']['saludar_saludo']);
  drupal_set_message("Se han guardado las opciones de configuración.");
}

En saludar_configuracion() definimos los elementos del formulario en un array . En este caso sólo presentaremos un campo de texto “textfield” para establecer el “Saludo que se muestra al usuario”. Puedes consultar la Drupal Form Api Reference para conocer todos los elementos y sus propiedades.

Este saludo lo vamos a guardar en la base de datos con una variable que llamaremos saludar_saludo (una vez más utilizamos saludar_ como prefijo para evitar colisiones con otros módulos). Por eso definimos el valor por defecto del campo de texto mediante la función de Drupal variable_get(), que mostrará el último valor registrado por el administrador, o la cadena 'Hola Mundo' si no se ha configurado el saludo aún.

     '#default_value' => variable_get('saludar_saludo', 'Hola Mundo'),

Por último la función define el botón de submit y la función que procesará el envío, y devuelve el formulario.

Configuración del saludo

Como ejemplo de validación comprobamos que no se haya enviado una cadena vacía, accediendo al valor del campo que recibimos del array $form_state['values']. Si hay un error invocamos la función form_set_error(), definiendo el campo donde se ha producido y el mensaje de error correspondiente.

Validación de la configuración del saludo

Finalmente en la función saludar_configuracion_submit() procesamos el envío validado guardando el saludo en la base de datos mediante la función variable_set(), y emitimios un mensaje de confirmación mediante drupal_set_message().

Envío del formulario de configuración del saludo

Hemos visto que podemos controlar la validación y el envío del formulario a través de estas dos funciones, pero para este ejemplo podríamos hacerlo mucho más sencillo y ninguna de las dos serían necesarias. Por un lado la validación de campo obligatorio se puede implementar directamente con '#required' => TRUE. Por otro lado podemos utilizar la función system_settings_form(), que añade el botón de submit, e invoca internamente tras el envío a la función system_settings_form_submit(), que ya se encarga de guardar el valor del campo en una variable con el mismo nombre que el campo, en este caso "saludar_saludo". Simplificando el ejercicio, podríamos dejar el archivo saludar.admin.inc sólo con esta función:

 function saludar_configuracion() {
  $form['saludar_saludo'] = array(
    '#title' => 'Saludo que se muestra al usuario',
    '#type' => 'textfield',
    '#default_value' => variable_get('saludar_saludo', 'Hola Mundo'),
    '#required' => TRUE,
  );
  return system_settings_form($form);
} 

Ahora solo nos queda utilizar el valor de configuración guardado para mostrarlo en el saludo. Para hacer esto modificamos la función saludar_hola_mundo() del archivo saludar.module, que quedará así:

 function saludar_hola_mundo() {
  $variables = array(
    'message' => variable_get('saludar_saludo', 'Hola Mundo'),
  );
  return theme('saludar_hola_mundo', $variables);
}

Eso es todo, ahora nuestro “Hola Mundo” se ha convertido en un saludo configurable que mostraremos en la página o bloque que hemos creado para ello. Los bloques además tienen una página de configuración específica en la que podríamos haber incluido el campo para configurar el saludo, de manera similar a cómo lo hemos hecho en saludar.admin.inc, pero utilizando los hooks hook_block_configure() y hook_block_save(). Te lo dejo como ejercicio de investigación y práctica.

 

Saludando por su nombre al usuario que inicia sesión

Este ejercicio se puede hacer de manera muy sencilla, tan solo hay que responder al hook de inicio de sesión que se llama hook_user_login(), en nuestro saludar.module:

 /**
 * Implementa hook_user_login().
 */
function saludar_user_login(&$edit, $account) {
  drupal_set_message("Hola " . $account->name);
}

Ya sabemos como escribir un saludo en una página y en un bloque, ahora lo hacemos en un sitio nuevo. Estamos haciendo uso de la función drupal_set_message(), para escribir un mensaje de estado o confirmación, que también podría ser de advertencia o error, estableciendo un segundo parámetro.

Saludar al usuario por su nombre

El hook_user_login() nos proporciona el evento al que reaccionar y también el propio objeto usuario: $account, donde la propiedad “name” nos da su nombre. Pero... ¿y si quisiéramos saludarle también en otras ocasiones? Obviamente podemos programar el saludo o cualquier otra acción en cada hook de cada evento que deseemos, pero de nuevo vamos aprovechar la potencia de Drupal para dejar que sea el administrador y no el programador el que pueda cambiar y decidir en qué momento ejecutar esa acción.

 

Hacer configurable en la interfaz qué eventos mostrarán el saludo

Drupal dispone de un módulo del núcleo, Trigger, que permite desde la interfaz de administración activar ciertas acciones en determinados eventos del sistema, como cuando un usuario inicia sesión o cuando se crea contenido. Necesitamos activar este módulo porque vamos a crear una acción de saludar para que el administrador pueda decidir qué eventos van a accionar (“trigger”) el saludo, en el menú de administración Estructura – Disparadores (admin/structure/trigger).

Primero creamos la acción de saludar utilizando hook_action_info() en nuestro saludar.module:

 /**
 * Implementa hook_action_info().
 */
function saludar_action_info() {
  return array(
    'saludar_usuario_action' => array(
      'type' => 'user',
      'label' => 'Saludar al usuario',
      'configurable' => FALSE,
      'triggers' => array('any'),
    ),
  );
}

Cada elemento en el array que devuelve este hook define una acción, en este caso 'saludar_usuario_action', que clasificamos de tipo usuario, su etiqueta será “Saludar al usuario”, en principio no será configurable y estará disponible para cualquier disparador (se puede limitar qué disparadores tendrán la acción disponible). Con esta función implementada ya podemos seleccionar en la interfaz a qué disparadores queremos asignar esta acción, por ejemplo tras iniciar sesión.

Disparador: tras iniciar sesión

Lo siguiente es eliminar la función saludar_user_login() que implementamos en el apartado anterior, y sustituir ese hook por la acción genérica que accionarán los disparadores asignados en la interfaz.

 /**
 * Acción de drupal que saluda al usuario.
 */
function saludar_usuario_action() {
  $message = "¡Bienvenido!";
  if (user_is_logged_in()) {
    $message = "Hola " . $GLOBALS['user']->name;
  }
  drupal_set_message($message);
}

En la acción estamos teniendo en cuenta si el usuario es anónimo o está autenticado, saludándole por su nombre en ese caso. Para ello hacemos uso de la variable global “user”, que contiene el objeto usuario actual, y su propiedad “name” solo disponible si el objeto es un usuario autenticado.

Otra opción es utilizar la función format_username(), que directamente nos da el nombre del usuario o bien el nombre usado en el sitio para indicar usuarios anónimos, generalmente “Anónimo” (se define en Configuración – Personas – Opciones de la cuenta). Como ves la API de Drupal ya cuenta con muchas funciones de utilidad implementadas que conviene conocer.

 function saludar_usuario_action() {
  drupal_set_message("Hola " . format_username($GLOBALS['user']));
}

Ahora puedes comprobar que el saludo se muestra correctamente para los distintos eventos que configures en la página de Disparadores, y de paso ir conociéndolos y ver cuándo se ejecutan.

 

Traducir cadenas de texto con Drupal: t(“Hello World”)

La función t() sirve para poder traducir la cadena en los distintos idiomas que pudiera tener la web. El idioma por defecto es el inglés y es en este idioma como deberemos crear las cadenas de texto al programar. Por tanto en los ejemplos anteriores deberíamos sustituir la cadena “Hola Mundo” por la expresión t(“Hello World”), y así con todas las expresiones de texto por su equivalente en inglés bajo la función t(). De esta manera se podrán traducir desde la interfaz estas cadenas a cualquier idioma.

Traducir: Hellow World

Por supuesto las cadenas que contienen variables, como en el último ejemplo del saludo al usuario, también se pueden traducir. En la cadena de texto utilizamos variables con el símbolo @ delante, y definimos estas variables en un array como segundo parámetro de la función t().

     $message = t("Hola @name", array('@name' => $GLOBALS['user']->name));

Aunque se pueda traducir desde la interfaz, podríamos proporcionar con nuestro módulo sus cadenas de texto ya traducidas. Para ello crearíamos en el módulo una carpeta “translations” con un archivo “general.pot” que contendría todas las cadenas a traducir, y un archivo .po para cada idioma con las cadenas traducidas, por ejemplo: “es.po”. Existen herramientas para generar este tipo de archivos, y concretamente en Drupal encontrarás de gran utilidad el módulo Translation template extractor, con el que podrás fácilmente extraer estos archivos de traducción para las cadenas de texto de un módulo específico.

En estos primeros ejemplos he utilizado el español en el código para facilitar la comprensión. Pero Drupal está desarrollado por una comunidad internacional con el inglés como idioma base. Por ello es una buena práctica escribir todo en inglés, tanto los nombres de funciones y variables como los comentarios, lo que ayudará a que cualquier otro desarrollador de Drupal pueda entenderlo. Ésta y muchas otras directrices constituyen los estándares de programación de Drupal, que conviene conocer y acostumbrarse a seguir al desarrollar código. De esta manera podrías contribuir algún día a la comunidad con tus propios módulos ¿no?

Espero que este tutorial te haya servido y animado a continuar este camino. Puedes dejar aquí tus comentarios, cualquier duda, o sugerencia para mejorar el artículo. Os dejo el enlace para descargar el código del módulo saludar.

Redmamba