Implementa hook_forms() en tu proyecto!

27/11/2014
Implementa hook_forms() en tu proyecto!

Aprende una nueva técnica para organizar la arquitectura de tus formularios

Muchas veces necesitamos renderizar un mismo formulario varias veces en una misma página o también podemos necesitar customizar el formulario de creación de nodos para una determinada sección manteniendo el original. En este artículo veremos cómo podemos atacar este tipo de problemas de una forma sencilla y bastante limpia implementando hook_forms() en nuestros módulos.

¿hook_forms() para qué? Siempre puedo hacerlo de otras formas

Como ya sabréis en el mundo del desarrollo no sólo hay un camino para llegar a un mismo punto, la clave es ¿es ese el camino más corto? ¿el mejor asfaltado? ¿Si llueve te llenaras de barro?. Evidentemente ante los requerimientos comentados anteriormente podemos optar por alguna de las siguientes opciones:

  • Hacer N formularios con las mismas configuraciones: Esto puede hacer que tu código se convierta en un infierno más antes que después. No creo que debamos torturarnos gratuitamente.
  • Renderizar lo mismo form varias veces: Error! observarás por ejemplo ante un error de validación de un campo en el envío de un form se te mostrará en el mismo campo pero de otro form!.
  • Hacer un form_alter: Vale, puedes hacer un form_alter y que sólo te altere el formulario si estas en cierta ruta o bajo ciertas condiciones. Este camino te puede llevar al dolor igualmente y hacer que sea inmantenible en un plazo no muy lejano.

hook_forms() al rescate!

Mediante hook_forms() podemos indicar que un formulario, mediante su id_form, use como callback otro form, es decir, mapeamos varios forms_ids a determinados forms builders. Podemos centralizar toda la lógica de varios forms en uno sólo mientras que podemos tener variaciones de este primero pero manteniendo el builder centralizado.

Veamos un ejemplo de implementación de hook_forms()

Sigamos con el caso inicial, supongamos que queremos renderizar el formulario de contacto (contact_form) en una sección con algunas modificaciones pero manteniendo el formulario original para que no se vea afectado por nuestras modificaciones.
Para llegar a nuestro objetivo final seguiremos los siguientes pasos:

Paso 1: Creamos el bloque que renderizará nuestro formulario:

/**
 * Implements hook_block_info().
 */ 
function MY_MODULE_block_info() {
  $blocks['my_contact'] = array(
    'info' => t('My contact block'),
  );

  return $blocks;
}

/**
 * Implements hook_block_view().
 */ 
function MY_MODULE_block_view($delta = '') {
  switch ($delta) {
    case 'my_contact':      
      $block['content'] = drupal_get_form('my_contact_form');
      break;
  }
  
  return $block;
}

Como podéis ver hemos declarado un bloque sencillo que renderiza un formulario llamado “my_contact_form”.

Paso 2 : Mapeamos nuestro formulario con contact_form.

Aquí es donde está la clave, ahora implementando hook_forms() declararemos que nuestro formulario (my_contact_form) use como builder contact_form:

/**
 *  Implements hook_forms().
 */
function MY_MODULE_general_forms($form_id, $args) {
  $forms = array();
  // Mapeamos nuestro form con el contact_form:
  $forms['my_contact_form'] = array(
    'callback' => 'contact_form'
  );

  return $forms;
}

Paso 3: Realizamos las customizaciones necesarias

Una vez realizado esto ya podemos realizar nuestros form alter sólo a nuestro formulario sin que afecten al contact_form original el cual podremos mostrar inalterado en /contact:

/**
 *  Implements hook_form_FORM_ID_alter().
 */
function MY_MODULE_form_my_contact_form_alter(&$form, &$form_state, $form_id) {
  $form['custom_label'] = array(
    '#markup' => t('This text is only for my contact form'),
  );
}

Moraleja

En sólo 3 pasos hemos logrado tener de forma separado un formulario customizado sin afectar al original, ahorrándonos tener un form_alter complejo, evitando problemas en el futuro y evitando duplicar código.