Este libro está dirigido a todas aquellas personas que se dediquen a la programación con Drupal.
Drupal viene con un API para la creación de formularios.
La estructura del formulario se define en un array.
Un campo con autocompletado es un campo de texto que en la medida que vamos digitando nos aparece una lista con las opciones disponibles para este campo, filtrados por el texto que hemos ingresado.
En Drupal para que un campo funcione como autocomplete tenemos dos partes: por un lado tenemos un módulo que nos devuelve a través de una función los resultados que deseamos mostrar y por otro el campo de texto en el formulario donde se digitará el texto, y debajo del cual aparecerán las opciones con las cuales se podrán autocompletar.
CREACIÓN EN NUESTRO MÓDULO QUE DEVUELVE LOS RESULTADOS
Tenemos un listado de clientes, en una tabla llamada {cliente}. En uno de nuestros formularios necesitamos que conforme el usuario vaya digitando le aparezca la lista de los posibles clientes que estén de acuerdo con el texto que se está escribiendo.
A continuación mostramos los pasos para la creación de un campo de autocompletado. Es importante señalar que se puede hacer en cualquier orden; el orden que estamos poniendo es solo referencial.
PRIMER PASO: Creación del campo que tendrá el autocompletado
En nuestro fomulario colocamos un campo de tipo textfield, y le agregamos la propiedad autocomplete_path, donde colocaremos la ruta de drupal que responderá con los resultados conforme vayamos escribiendo. Tomemos nota de lo que hemos colocado en esta propiedad, pues será la que tenga que coincidir con la ruta del menú que llame a la función como veremos más abajo.
/**
* Definición del campo de texto que tendrá autocompletado.
* Se le agrega una propiedad autocomplete_path
*/
$form['datos']['cliente'] = array(
'#type' => 'textfield',
'#title' => check_plain('Cliente'),
'#required' => TRUE,
'#default_value' => isset($node->cliente) ? $node->cliente : '',
'#autocomplete_path' => 'clientes/autocomplete',
'#size' => 20,
'#maxlength' => 60,
'#weight' => 2,
);
SEGUNDO PASO: Creación de la función en el módulo que devolverá los resultados
Escribimos una función que recupere la lista de clientes.
function cliente_autocomplete($string = ''){
$matches = array();
$result = db_query_range("SELECT DISTINCT nombre
FROM {cliente}
WHERE LOWER(nombre) LIKE LOWER('%s%%')", $string, 0, 10);
while ($cliente = db_fetch_object($result)) {
$matches[$cliente->nombre] = check_plain($cliente->nombre);
}
drupal_json($matches);
}
TERCER PASO: Hacemos que nuestra función pueda ser accedida por http
Para que la función esté disponible vía http, en el hook_menu del módulo del mismo creamos una nueva entrada.
/**
* Implementacion del hook_menu
*/
function cliente_menu(){
$items = array();
//Creamos una entrad en el menú que acceda a nuestra función
$items['clientes/autocomplete'] = array(
'title' => 'Lista Clientes Autocomplete',
'page callback' => 'cliente_autocomplete',
'access arguments' => array('access content'),
'type' => MENU_CALLBACK
);
//Acá puede haber otros elementos del array
return $items;
}
Observemos que en page_callback tiene como valor el nombre de la función que creamos previamente.
Es IMPORTANTE notar que la clave del array, tiene la ruta 'clientes/autocomplete' y que es igual a la que colocamos en autocomplete_path al definir el campo en nuestro formulario.
Drupal provee una capa de abstracción para el acceso a base de datos, de tal manera que se pueda cambiar de motor de base de datos (MySQL, Postgres y cualquier otro que sea implementado posteriormente) utilizando el mismo código fuente. Se recomienda el uso de la capa de abstracción de Drupal, pues incluso de usarse solo el motor de MySQL nos previene de posibles incompatibilidades de código generados por el uso de otro tipo de extensión para la conexión. Por ejemplo un servidor puede estar usando PHP's MySQL Extensión o PHP's mysqli Extensión, los cuales tienen APIs distintas. El primero está desarrollado con principios de programación procedural, y el segundo con principios de programación orientado a objetos.
Por otra parte el uso de esta capa de abstracción añade algunos controles básicos de seguridad sobre las consultas efectuadas al servidor.
Entre las funciones más utilizadas de esta capa de abstracción tenemos dbquery(), db_query_range() y pager_query().
db_query($query)
La función db_query() nos permite enviar consultas sql a la base de datos, de manera similar a como lo haríamos con las funciones propias de cada motor de base de datos, por ejemplo mysql_query() para MySQL.
Otro aspecto importante de la función db_query() es que permite armar consultas, colocando caracteres que serán reemplazados por parámetros.
db_query_range($query)
Para seleccionar un rango de registros del total de resultados. Es decir, si ejecutamos una consulta que produce un total de 100 registros y necesitamos los registros del 10 al 20, podemos usar esta función.
pager_query($query, $limit = 10, $element = 0, $count_query = NULL)
Si queremos mostrar resultados paginados, es conveniente considerar la utilización de la función pager_query(), que nos permite obtener los resultados que corresponden a una página determinada. En este caso, si ejecutamos una consulta que produce un total de 100 registros y queremos mostrar un máximo de 10 registros por página, la página 1 tendrá los registros del 1 al 10, la página 2 los registros del 11 al 20, la página 3 los registros del 21 al 30 y así sucesivamente.
La idea es similar a la función db_query_range(), la cual es usada internamente por pager_query(), con la diferencia que en vez de indicarle el rango de registros, se indica el número de registros que se mostrarán por página, y la página que se quiere mostrar. Según la implementación actual la página que se quiere mostrar no se pasa como parámetro a la función sino que es un parámetro get llamado page. Es decir, en nuestra página existirá algo como http://www.mipagina/articulos?page=5, lo cual significa que estamos mostrando la página 5 de un listado de artículos.
Con la función pager_query(), tendremos posibilidad de calcular también el número total de registros y el número total de páginas, aunque como veremos más adelante en muchos casos es necesario enviar una consulta propia para calcular en número total de registros.
La versión de Drupal viene integrado con jquery. jquery es una biblioteca que facilita la manipulación de la estructura del html, el manejo de eventos, animaciones y peticiones ajax.
Una de las formas más comunes de agregar código javascript cuando usamos jquery es ponerlo en la función $(document).ready, lo cual significa que este código se ejecutará o estará disponible cuando el navegador terminado de cargar el árbol DOM.
$(document).ready(function(){
// Acá agregamos nuestro código
});
En Drupal 6, la forma recomendada de agregar nuestro código javascript es usar la propiedad behaviors del objeto Drupal. La propiedad behaviors es también un objeto. Para agregar nuestro código extendemos este objeto. Podemos agregar funciones a Drupal.behaviors de la siguiente manera:
Drupal.behaviors.miBehavior = function(context){
// Acá agregamos nuestro código
};
Cualquier función definida como propiedad de Drupal.behaviors será llamada cuando el árbol DOM se halla cargado.
En este capítulo explicaremos como crear un módulo para drupal. Trataremos, en la medida de lo posible de seguir las convenciones para la creación de módulos Drupal.
Los pasos a seguir para la creación de un módulo drupal son los siguientes:
ESCOGER UN NOMBRE CORTO Y ÚNICO PARA NUESTRO MÓDULO
El primer paso para crear un módulo de drupal es escoger un nombre que sea corto y que no se esté usando en otro módulo. Esta tarea que parece sencilla es de vital importancia pues del nombre de nuestro módulo dependerán muchas de nuestras acciones posteriores como por ejemplo el nombre de las funciones que utilicemos.
CREACIÓN DE LA CARPETA QUE ALBERGARÁ EL MÓDULO
Esta carpeta tendrá el mismo nombre que el nombre que hemos elegido.
EL SISTEMA DE HOOK
Drupal se comunica con el core a través de un sistema de hooks (ganchos).
Algunos módulos también implementan un sistema de hooks que amplían el sistema existente.
Una acción es algo que Drupal puede hacer, y que se puede establecer para que sea lanzado al producirse un evento. Es decir, para que sea llamado por un disparador (Trigger).
Desde el punto de vista de la programación una acción es una función que puede configurarse para que sea llamada cuando se produce un evento. Se parecen a los procedimientos almacenados. Si hay parámetros estos son guardados en la base de datos; los parámetros serán recuperados cuando la acción sea llamada.
DESCRIBIR LAS ACCIONES
Nuestro módulo necesita describir las acciones que implementa. Para ello hacemos uso del hook_action_info(). Este hook devuelve un array que tiene la descripción de las acciones de este módulo.
Observemos por ejemplo el siguiente código:
/**
* Implementación del hook_action_info().
*/
function workflow_autostatus_action_info(){
return array(
'workflow_autostatus_change_action' => array(
'description' => t('Change the node status'),
'type' => 'node',
'configurable' => FALSE,
'hooks' => array(
'nodeapi' => array('presave', 'insert', 'update', 'view'),
),
),
);
}
Cada elemento del array representa una acción. La llave de este array, además de identificar la acción, tiene el mismo nombre de la función que responderá cuando la acción sea llamada. Para la creación de las llaves que identifican las acciones se sigue unas reglas de nomenclatura: se comienza con el nombre del módulo, luego una descripción de lo que hace la acción y finalmente termina con la palabra _action.
Es decir: nombreMódulo + descripción + _action
En el ejemplo tenemos:
workflow_autostatus + change + _action = workflow_autostatus_chang_action
Cada elemento es, a su vez, un array, que tiene la siguiente estructura:
ESCRIBIR UN FUNCIÖN POR CADA ACCIÓN
Por cada acción que hemos definido, necesitamos escribir una función, que es la que se ejecutará cuando la acción sea llamada. El nombre de esta función es la misma que la llave del array que la define.
/**
* Implementación de la acción de Drupal definida en el hook action_info.
* Cambia el status del nodo, de acuerdo a lo especificado
*/
function workflow_autostatus_change_action(&$object, $context = array()){
global $user;
if (isset($object->nid)){
$result = db_query("select sid from workflow_node where nid = %d", $object->nid);
$statu = db_fetch_object($result);
db_query("update workflow_node set sid = 2 where nid = %d", $object->nid);
db_query("insert into workflow_node_history (nid, old_sid, sid, uid, stamp, comment) values(%d,%d,2,%d,%d,'cambio automático por actualización del nodo')", $object->nid, $statu->sid, $user->uid, time());
}
}
Usted podra asignar los permisos a los usuarios en Administer->User management->Permissions
Ejemplos
Y si tienes varios permisos, solo se agrega más elementos al array:
Drupal maneja las fechas en un formato timestamp, al igual que lo hace php. Eso significa que se almacenan las fechas en un número que indica la cantidad de segundos que han transcurrido desde el Unix Epoch, es decir desde el 1 de enero de 1970 a las 00 horas.
De manera que al ver las fechas en la base de datos veremos usualmente un número entero de 10 dígitos.
DAR FORMATO A UNA FECHA
Drupal dispone de la función format_date que nos permite darle formato a una fecha, de acuerdo a la configuración que halla hecho el usuario para la instalación de drupal, o incluso darle un formato personalizado. Con el uso de esta función además se mantiene la configuración de idioma establecido para el usuario de drupal.
USANDO LOS FORMATOS DE FECHA DEFINIDOS PARA DRUPAL
Para usar el formato definido en la configuración de drupal, para fecha corta, media o larga, podemos usar la función de la siguiente manera:
format_date($timestamp, $type);
Reemplazando $timestamp por la fecha en formato timestamp y $type por el tipo que puede ser 'small', 'medium' o 'large'.
Por ejemplo, consideramos la siguiente configuración:
(TODO: Imagen con configuración)
para poner el formato corto podemos usar algo como:
format_date(1250556783, 'small');
y nos mostrará algo como lo siguiente:
(TODO: Poner imagen)
(TODO: Agregar los otros tipos de formato)
USAR UN FORMATO PERSONALIZADO
Para usar un formato personalizado, se muy similar, solo que reemplazamos el parámetro $type, por 'custom', y agregamos un tercer parámetro con el formato. Por ejemplo podemos tener algo como:
format_date(1250556783, 'custom', 'D - m / y');
Y nos devolverá algo como:
(TODO: Imagen)