
Tutorial: Creación de un field en Drupal 7 utilizando "Field API" (Parte I)
Autor: fjavimartin
Fecha de Creación: 29/10/2014
Categorías:
Objetivo
En esta primera parte del tutorial nuestros objetivos serán los siguientes:
- Creación de un módulo que implemente un field formado por dos campos de texto mediante Field API.
- Creación de un widget que utilizaremos en el formulario de creación del contenido al que tengamos asignado nuestro field para introducir los valores que queramos guardar en la base de datos.
- Creación de un formatter encargado de formatear los datos de nuestro field y mostrarlos al visualizar el tipo de contenido en el que esté configurado.
1. Creación del fichero field_doble_texto.info
Comenzaremos por la creación del fichero .info de nuestro módulo. El nombre que asignaremos a nuestro módulo será field_doble_texto por lo que nuestro fichero se llamará field_doble_texto.info.
name = Test Equipos - Field_Doble_Text description = Módulo que almacena dos campos de texto version = 7.x-0.1 core = 7.x files[] = field_doble_texto.install files[] = field_doble_texto.module package = Desarrollos E-Quipos dependencies[] = field
No hay mucho que decir sobre este fichero. Fijamos un nombre/descripción y la dependencia de nuestro módulo con el módulo field incluido en el core de drupal 7.
Además del fichero field_doble_texto.module que contendrá la definición de casi todos los hooks de nuestro módulo también hemos añadido el fichero field_doble_texto.install para el que más tarde veremos que hook implementamos en él.
2. Creación del fichero field_doble_texto.module
El siguiente paso será la creación del fichero field_doble_texto.module al que comenzaremos añadiendo el el hook_help() que utilizaremos para incluir una pequeña descripción de nuestro módulo.
/** * Implementación del hook_help() */ function field_doble_texto_help($path, $arg) { switch($path) { case 'admin/help#field_doble_texto': $output = ''; $output .= '
'.t('Acerca de').'
'; $output .= '
'.t('Módulo field_doble_texto que contendrá la implementación de un field formado por dos campos de texto.').'
'; return $output; break; } }
3. Implementación del hook_field_info()
El primer paso será comunicar a drupal la existencia de un field nuevo mediante la implementación del hook_field_info(), pero antes de ver su implementación pasaremos a describir dos términos importantes en la creación de campos mediante Field API:
- Widget: Será el formulario que utilizaremos para introducir los datos de nuestro field. Este formulario se mostrará al crear el contenido que tenga asignado nuestro field.
- Formatter: Devolverá el código html que mostrará el contenido de nuestro field. Se mostrará cuando estemos visualizando el tipo de contenido que tenga asignado nuestro field.
/** * Implementación del hook_field_info() */ function field_doble_texto_field_info() { return array( 'field_doble_texto' => array( 'label' => t('Field - Campo Doble de Texto'), 'description' => t('Campo que contendrá dos campos de texto'), 'default_widget' => 'field_doble_texto_widget', 'default_formatter' => 'field_doble_texto_formatter', ), ); }
La función devolverá un array donde fijamos la etiqueta con la que identificamos nuestro campo y una pequeña descripción. Por último también tendremos que indicar los nombres del widget y el formatter que utilizaremos por defecto y que pasaremos a implementar a continuación.
4. Implementación del hook_field_install()
Una vez que hemos definido nuestro campo tendremos que informar a drupal sobre cómo queremos que se guarden los datos de nuestro field en la base de datos. Para esto será necesaria la implementación del hook_field_install().
/** * Implementación del hook_field_schema() */ function field_doble_texto_field_schema($field) { $columnas = array(); switch($field['type']) { case 'field_doble_texto': $columnas['texto1'] = array( 'type' => 'varchar', 'length' => 25, 'not null' => FALSE, ); $columnas['texto2'] = array( 'type' => 'varchar', 'length' => 25, 'not null' => FALSE, ); break; } return array ( 'columns' => $columnas, ); }
Determinamos el tipo y el tamaño de los dos campos que se crearán en la base de datos para alojar los datos que introduzcamos mediante el widget que más tarde definiremos.
Tenemos que tener en cuenta que este hook se ejecutará para todos los field's que tengamos definidos en nuestro módulo por lo que tendremos que incluir un switch que nos permita diferenciar entre ellos y definir los campos que crearemos en la base de datos para cada uno de ellos. Este switch será uso común en los distintos hooks del módulo.
La tabla que se creará al crear una instancia de nuestro field será parecida a la siguiente:
+--------------------------+------------------+------+-----+---------+-------+ | Field | Type | Null | Key | Default | Extra | +--------------------------+------------------+------+-----+---------+-------+ | entity_type | varchar(128) | NO | PRI | | | | bundle | varchar(128) | NO | MUL | | | | deleted | tinyint(4) | NO | PRI | 0 | | | entity_id | int(10) unsigned | NO | PRI | NULL | | | revision_id | int(10) unsigned | YES | MUL | NULL | | | language | varchar(32) | NO | PRI | | | | delta | int(10) unsigned | NO | PRI | NULL | | | field_doble_texto_texto1 | varchar(25) | YES | | NULL | | | field_doble_texto_texto2 | varchar(25) | YES | | NULL | | +--------------------------+------------------+------+-----+---------+-------+ 9 rows in set (0.29 sec)
Nota: El nombre de sistema que hemos elegido para nuestro field es “field_doble_texto”. De ahí el prefijo de cada campo.
5. Implementación del hook_field_is_empty()
Utilizaremos el hook_field_is_empty() para determinar si nuestro field está vacío, devolverá verdadero/falso. Tendremos que estar muy atentos a la implementación de este hook puesto que de su resultado dependerá que podamos guardar los valores introducidos mediante el widget en la base de datos. Para todos los casos en los que devuelva FALSE no se guardará nada.
Este hook será de implementación obligatoria puesto que se ejecutará en múltiples ocasiones durante el ciclo de vida de nuestro field.
/** * Implementación del hook_field_empty() */ function field_doble_texto_field_is_empty($item, $field) { switch($field['type']) { case 'field_doble_texto': // Comprobamos existencias key array para widget field_doble_texto_widget if ( array_key_exists('texto1', $item) && array_key_exists('texto2', $item) ) { $valor = empty($item['texto1']) && empty($item['texto2']); } return $valor; break; } }
Lo primero será asegurarnos de que estamos implementando el comportamiento deseado para nuestro field mediante el ya conocido switch.
La variable $item contendrá un array con los valores para los campos de nuestro field. Las claves del array tendrán el mismo nombre que las claves de los campos en el hook_field_install(). El contenido del array se parecerá bastante a lo siguiente:
$item = Array( 'texto1' => 'valor1', 'texto2 => 'valor2', );
Utilizaremos el contenido de este array para determinar si nuestro campo está vacío o no. En nuestro caso diremos que nuestro field está vacío si los campos “texto1” y “texto2” están vacíos.
6 . Implementación de nuestro widget
6.1 Implementación del hook_field_widget_info()
Esta función devolverá un array con todos los widget que implementará nuestro módulo, es decir, no solamente estaremos definiendo los widget que implementará nuestro field.
/** * Implementación del hook_field_widget_info() */ function field_doble_texto_field_widget_info() { return array( 'field_doble_texto_widget' => array( 'label' => t('Campo Doble Texto - Widget'), 'field types' => array('field_doble_texto'), ), ); }
En este hook simplemente definiremos la clave de nuestro widget, una etiqueta con una pequeña descripción y por último un array con los distintos field's que podrán utilizarlo.
6.2 Implementación del hook_field_widget_form()
Mediante este hook implementaremos los distintos formularios que utilizaremos para capturar los datos que finalmente guardemos en la base de datos.
Para cada field podremos implementar un número indeterminado de widgets y durante la configuración del mismo seleccionaremos el que queramos utilizar.
/**
* Implementación hook_field_widget_form()
*/
function field_doble_texto_field_widget_form(&$form, &$form_state, $field, $instance, $langcode, $items, $delta, $element) {
$element += array(
'#type' => $instance['widget']['type'],
'#default_value' => isset($items[$delta]) ? $items[$delta] : '',
);
return $element;
}
/**
* Implementación hook_element_info()
*/
function field_doble_texto_element_info() {
$elements = array();
$elements['field_doble_texto_widget'] = array(
'#input' => TRUE,
'#process' => array('field_doble_texto_widget_process'),
);
return $elements;
}
/**
* Implementación de la función que procesa el formulario para el widget field_doble_texto_widget
*/
function field_doble_texto_widget_process($element, $form_state, $complete_form) {
$element['texto1'] = array(
'#type' => 'textfield',
'#title' => t('Campo de Texto 1 - Field_doble_Texto'),
'#prefix' => '<div class="field-doble-texto-texto1">',
'#default_value' => isset($element['#value']['texto1']) ? $element['#value']['texto1'] : '',
'#suffix' => '</div>',
'#maxlength' => 25,
'#size' => 25,
);
$element['texto2'] = array(
'#type' => 'textfield',
'#title' => t('Campo de Texto 2 - Field_doble_Texto'),
'#prefix' => '<div class="field-doble-texto-texto2">',
'#default_value' => isset($element['#value']['texto2']) ? $element['#value']['texto2'] : '',
'#suffix' => '</div>',
'#maxlength' => 25,
'#size' => 25,
);
$element['#required'] = FALSE;
return $element;
}
En esta ocasión he utilizado el hook_element_info() para definir el formulario del widget. Este hook nos permite definir nuestros propios tipos de elementos para utilizarlos como formularios y especificar sus valores por defecto. Utilizar este widget nos permitirá desplazar la complejidad de la implementación de nuestros formularios a funciones separadas tal y como podéis ver en este caso mediante la función field_doble_texto_widget_process().
Las variables que recibimos en el hook_field_widget_form() tienen la siguiente información:
- $field: Array con información sobre el field que estamos utilizando.
- $instance: Array con la información sobre la instancia de nuestro field.
- $items: Array con los valores por defecto de los campos de nuestro widget.
- $delta: Para cada field podemos definir un número de valores indeterminado. Esta variable nos permitirá saber para que valor estamos ejecutando el widget.
- $element: Contendrá las propiedades básicas de nuestro widget.
Lo que tenemos que hacer es simplemente añadir, siempre añadir un array a la variable $element con nuestro tipo de elemento que se corresponderá con el nombre del widget $instance['widget']['type'] y le pasaremos el contenido de la variable $items[$delta], en caso de tener algún valor, para el número de ocurrencia que corresponda con los valores por defecto.
Mediante el hook_element_info() definiremos nuestro elemento y especificaremos la función encargada de procesarlo. Mediante la función field_doble_texto_widget_process nos encargaremos de añadir a $element los elementos que formaran nuestro widget y fijaremos los valores por defecto mediante la variable $element['#value'].
Nuestro field está casi operativo y ya podemos adjuntarlo a cualquiera de los contenidos que tengamos en drupal. Sólo nos falta implementar el formatter que muestre el contenido.

Imagen 1 – Widget simple field_doble_texto
7. Implementación del formatter
El último paso será la creación del formatter. Recordar, el formatter se encargará de mostrar el contenido de nuestro field.
/** * Implementación hook_field_formatter_info() */ function field_doble_texto_field_formatter_info() { return array( 'field_doble_texto_formatter' => array( 'label' => t('Campo Doble Texto - Formatter'), 'field types' => array('field_doble_texto'), ), ); }
Como para el widget, necesitaremos comunicar a drupal la existencia de nuestro formatter mediante el hook_field_formatter_info(). En este hook indicamos el nombre de sistema, una pequeña descripción del mismo y para que campos estará disponible.
/** * Implementación hook_field_formatter_view() */ function field_doble_texto_field_formatter_view($entity_type, $entity, $field, $instance, $langcode, $items, $display) { $element = array(); switch($display['type']) { case 'field_doble_texto_formatter': foreach ($items as $delta => $item) { $element[$delta]['texto1'] = array( '#markup' => '<div class="field-doble-texto-texto1">'.$item['texto1'].'</div>', ); $element[$delta]['texto2'] = array( '#markup' => '<div class="field-doble-texto-texto2">'.$item['texto2'].'</div>', ); } break; } return $element; }
Continuando con los parecidos razonables, mediante el hook_field_formatter_view() definiremos la salida en la que mostraremos el contenido de nuestro campo de una forma muy parecida al hook_field_widget_form(). Dispondremos de los valores introducidos mediante este último hook con la variable $items y el indicador de valor $delta.
El primer paso será diferenciar para que formatter se está ejecutando nuestro hook mediante un switch, accederemos a los valores del field mediante $items e incluiremos el código html que mostraremos en la variable $element.
Ahora nuestro field será completamente operativo y solamente tendremos que configurar nuestro campo como visible en la “Gestión de presentación” del tipo de contenido en el que lo tengamos implementado.

Imagen 2 – Gestionar Presentación del field_doble_texto
8. Nuestro Field y la Base de Datos
Hasta ahora, excepto por la implementación del hook_field_schema() todo lo relativo a la base de datos ha sido transparente, pero sería bueno echar un ojo a todas las tablas relacionadas con la creación de nuestro field:
- field_config: Tabla que recogerá toda la información sobre los campos creados mediante la Field API.
- field_config_instance: Tabla que recogerá toda la información necesaria sobre cada una de las instancias de nuestro campo que hayamos creado.
- field_data_field_doble_texto: Tabla que recogerá los valores introducidos en nuestro campo junto con el identificador de nodo que lo contiene.
- field_revision_field_doble_texto: Dado que podemos realizar varias revisiones de cada contenido que introduzcamos en drupal esta tabla nos permitirá almacenar los valores de nuestro campo para cada revisión.
9. Conclusiones
Una vez finalizado este tutorial habremos adquirido los conocimientos suficientes para implementar un field completo e inspeccionar los valores introducidos en las tablas de nuestra base de datos.
Podréis acceder a la segunda parte de este tutorial pinchando aquí.
Las fuentes utilizadas para elaborar este tutorial: