API de formularios Drupal 7: creación de formularios en Drupal
En lecciones anteriores nos familiarizamos con los hooks hook_block_info(), hook_block_view(), hook_menu(), hook_permission(), y ahora somos capaces de crear programáticamente tantas páginas y bloques como queramos. En esta lección, nos adentraremos en la Form API de Drupal 7 para la creación de formularios. Vamos a construir un formulario para la administración de funciones del módulo y trataremos de utilizar la mayor cantidad posible de hooks ya conocidos, para afianzar lo aprendido.
Para empezar, mostraremos 3 bloques. Creo que esto no será complicado para ti.
function sitemade_block_info(){ $blocks = array(); // inicializamos un array vacío $blocks[1]['info'] = 'Lista de usuarios'; // título del bloque en la administración $blocks[2]['info'] = 'Lista de nodos'; $blocks[3]['info'] = 'Lista de términos'; return $blocks; // devolvemos la lista de bloques } function sitemade_block_view($delta = ''){ $block = array(); // inicializamos un array vacío para el bloque switch ($delta){ case 1: // mismo delta que devolvimos en hook_block_info() $block['subject'] = 'Usuarios'; // título del bloque $block['content'] = ''; // inicializamos variable de contenido $query = db_select('users', 'u') // consulta a la tabla users ->fields('u', array('uid', 'name')) // seleccionamos campos ->orderBy('u.uid', 'DESC') // ordenamos de forma descendente ->range(0, 5) // obtenemos 5 usuarios ->execute(); // ejecutamos la consulta $users = $query->fetchAll(PDO::FETCH_ASSOC); // obtenemos resultados como array foreach($users as $user){ $block['content'] .= '
'; // base_path() devuelve la ruta base del sitio } break; case 2: $block['subject'] = 'Nodos'; $block['content'] = ''; $query = db_select('node', 'n') ->fields('n', array('nid', 'title')) ->orderBy('n.nid', 'DESC') ->range(0, 10) ->execute(); $nodes = $query->fetchAll(PDO::FETCH_ASSOC); foreach($nodes as $node){ $block['content'] .= '
'; } break; case 3: $block['subject'] = 'Términos'; $block['content'] = ''; $query = db_select('taxonomy_term_data', 't') ->fields('t', array('tid', 'name')) ->orderBy('t.tid', 'DESC') ->range(0, 10) ->execute(); $terms = $query->fetchAll(PDO::FETCH_ASSOC); foreach($terms as $term){ $block['content'] .= '
'; } break; } return $block; }
Limpiamos la caché para que los nuevos bloques aparezcan en la administración. Mostramos estos bloques en la barra lateral izquierda:
Ahora crearemos una página en la administración donde después colocaremos un formulario para administrar estos tres bloques:
function sitemade_permission(){ return array( 'admin content blocks' => array( 'title' => t('Administrar bloques de contenido'), 'description' => t('Nodos, Usuarios, Términos'), ), ); } function sitemade_menu(){ $items = array(); // inicializamos array de ítems del menú $items['admin/config/content/content_blocks'] = array( 'title' => 'Bloques de usuarios, nodos, términos', 'description' => 'Administración de bloques', 'page callback' => '_sitemade_content_blocks', 'access arguments' => array('admin content blocks'), ); return $items; } function _sitemade_content_blocks(){ $content = '¡Lorem ipsum!'; return $content; }
Hemos creado la página, debería aparecer como una página vacía en la URL admin/config/content/content_blocks:
Y no olvidemos asignar permisos al rol de administrador para acceder a esta página (esto lo hicimos con hook_permission()
):
Ahora modificaremos el código de nuestros hooks. Primero crearemos el formulario de administración. ¿Qué vamos a administrar en estos tres bloques? Propongo que sea el título del bloque y la cantidad de entidades mostradas (nodos, usuarios, términos).
Primero, cambiaremos la propiedad 'page callback'
en el hook hook_menu
:
function sitemade_menu(){ $items = array(); $items['admin/config/content/content_blocks'] = array( 'title' => 'Bloques de usuarios, nodos, términos', 'description' => 'Administración de bloques', 'page callback' => 'drupal_get_form', 'page arguments' => array('_sitemade_content_blocks'), 'access arguments' => array('admin content blocks'), ); return $items; }
drupal_get_form($form_id)
Un envoltorio para drupal_build_form()
cuando no se necesita $form_state
.
Parámetros
$form_id
: identificador único de la función que genera el array del formulario. Si existe una función con este nombre, se invoca para construir el formulario. Si se requieren formularios similares con distintos identificadores, pueden declararse en hook_forms()
.
Cualquier argumento adicional pasado será transmitido a la función constructora del formulario. Por ejemplo, el formulario de edición de nodos node_edit
requiere pasar el objeto nodo. Esto se puede lograr también con hook_form_alter()
y hook_FORM_ID_alter()
mediante $form_state['build_info']['args']
.
Valor de retorno
Un array que representa el formulario.
Entonces reescribimos la función _sitemade_content_blocks()
para que devuelva el array del formulario:
function _sitemade_content_blocks(){ $form = array(); $form['nodes-title'] = array( '#type' => 'textfield', '#title' => t('Título del bloque de nodos'), '#default_value' => variable_get('node_block', ''), '#size' => 60, '#maxlength' => 64, '#description' => t('Título para el bloque de nodos'), ); $form['node-selected'] = array( '#type' => 'select', '#title' => t('Cantidad de nodos en el bloque'), '#options' => drupal_map_assoc(range(1,10)), '#default_value' => variable_get('node_block_range', 5), '#description' => t('Número de nodos mostrados en el bloque'), ); $form['users-title'] = array( '#type' => 'textfield', '#title' => t('Título del bloque de usuarios'), '#default_value' => variable_get('user_block', ''), '#size' => 60, '#maxlength' => 64, '#description' => t('Título para el bloque de usuarios'), ); $form['user-selected'] = array( '#type' => 'select', '#title' => t('Cantidad de usuarios en el bloque'), '#options' => drupal_map_assoc(range(1,10)), '#default_value' => variable_get('user_block_range', 5), '#description' => t('Número de usuarios mostrados en el bloque'), ); $form['terms-title'] = array( '#type' => 'textfield', '#title' => t('Título del bloque de términos'), '#default_value' => variable_get('term_block', ''), '#size' => 60, '#maxlength' => 64, '#description' => t('Título para el bloque de términos'), ); $form['term-selected'] = array( '#type' => 'select', '#title' => t('Cantidad de términos en el bloque'), '#options' => drupal_map_assoc(range(1,10)), '#default_value' => variable_get('term_block_range', 5), '#description' => t('Número de términos mostrados en el bloque'), ); $form['actions'] = array('#type' => 'actions'); $form['actions']['submit'] = array( '#type' => 'submit', '#value' => t('Guardar'), ); return $form; }
Ahora debemos implementar el submit handler para procesar y guardar estos valores en el sistema de variables de Drupal:
function sitemade_content_blocks_submit($form, &$form_state){ variable_set('node_block', $form_state['values']['nodes-title']); variable_set('user_block', $form_state['values']['users-title']); variable_set('term_block', $form_state['values']['terms-title']); variable_set('node_block_range', $form_state['values']['node-selected']); variable_set('user_block_range', $form_state['values']['user-selected']); variable_set('term_block_range', $form_state['values']['term-selected']); }
Con esto, al enviar el formulario se guardarán los valores y serán utilizados luego por los bloques para mostrar la información correctamente configurada.
Ahora solo queda modificar el hook hook_block_view()
para que los títulos de los bloques y la cantidad de elementos mostrados se obtengan con variable_get()
, es decir, desde los valores guardados en el formulario.
function sitemade_block_view($delta = ''){ $block = array(); switch ($delta){ case 1: $block['subject'] = variable_get('user_block', 'Usuarios'); $block['content'] = ''; $query = db_select('users', 'u') ->fields('u', array('uid', 'name')) ->orderBy('u.uid', 'DESC') ->range(0, variable_get('user_block_range', 5)) ->execute(); $users = $query->fetchAll(PDO::FETCH_ASSOC); foreach($users as $user){ $block['content'] .= '
'; } break; case 2: $block['subject'] = variable_get('node_block', 'Nodos'); $block['content'] = ''; $query = db_select('node', 'n') ->fields('n', array('nid', 'title')) ->orderBy('n.nid', 'DESC') ->range(0, variable_get('node_block_range', 5)) ->execute(); $nodes = $query->fetchAll(PDO::FETCH_ASSOC); foreach($nodes as $node){ $block['content'] .= '
'; } break; case 3: $block['subject'] = variable_get('term_block', 'Términos'); $block['content'] = ''; $query = db_select('taxonomy_term_data', 't') ->fields('t', array('tid', 'name')) ->orderBy('t.tid', 'DESC') ->range(0, variable_get('term_block_range', 10)) ->execute(); $terms = $query->fetchAll(PDO::FETCH_ASSOC); foreach($terms as $term){ $block['content'] .= '
'; } break; } return $block; }
Con esto, los títulos y la cantidad de elementos mostrados en cada bloque dependerán de la configuración del formulario.
Y por supuesto: no olvides limpiar la caché después de realizar todos estos cambios para que Drupal registre las nuevas configuraciones.
Como resultado, obtendrás una administración totalmente funcional para personalizar los bloques de usuarios, nodos y términos desde una página accesible en la administración. Esta lección demuestra cómo usar Form API junto con los hooks más importantes en el desarrollo de módulos personalizados para Drupal 7.