es
En este caso de estudio, vamos a ver el proceso de diseño y desarrollo empleado para un sitio de eCommerce en Panamá, dedicado a la venta de seguros en línea. El sitio web fue implementado a través de Drupal 7.x con Drupal Commerce, aprovechando el extenso API y funcionalidades de productos para el manejo de de seguros y sus compras. La sección más importante del sitio incluye un extenso form multistep manejado por Ajax, el cual inicia con una interfaz *Click and Buy* de los varios seguros, recolección de datos para la generación de una solicitud de seguro, datos de compra y manejo del gateway, el todo manejado a través del sistema de Form de Drupal. **Sección de compra online – Form multistep** Entre las páginas del sitio, la más importante, la que incluye la funcionalidad principal y que recibió más tiempo de planificación y desarrollo fue el Proceso de Compra de Seguro, a través del cual el usuario puede decidir online la aseguradora y póliza que desea, llena una solicitud de seguro con su información personal, ingresa sus datos de compra, permite que el usuario confirme sus opciones y complete el proceso de pago. Dada la necesidad de una serie de formularios que aprovecharan tanto el API de Drupal Commerce como el manejo de entidades del Core, se decidió integrar ambos en un custom module que manejara la página con el form multistep – myproj_insurance_multiform. El módulo cuenta con las siguientes funciones esenciales: - **hook_menu** para definir URL de la página y varios URL para llamados Ajax específicos. Ejemplo: [prism:php] /** * Implements hook_menu(). * * Author: Cristiano Amici */ function myproj_insurance_multiform_menu() { $items = array(); $items['get_insurance'] = array( 'type' => MENU_CALLBACK, 'title' => 'Get insurance', 'page callback' => 'drupal_get_form', 'page arguments' => array('myproj_insurance_multiform_primary_form'), 'access callback' => TRUE, ); $items['get_insurance/gotoform'] = array( 'type' => MENU_CALLBACK, 'page callback' => 'myproj_insurance_multiform_gotoform', 'access callback' => TRUE, ); . . // Cualquier otro llamado Ajax necesario . return $items; } [/prism:php] - **module_primary_form**, el cual maneja el renderizado del form principal. En esta función, se carga el storage del form (con los datos ya ingresados en otros pasos), se valida el próximo paso del formulario y se busca la función que lo renderize. De esta forma, este form es actualizado via Ajax con el siguiente paso. Ejemplo: [prism:php] /** * Form implementation of first multiform. * * Author: Cristiano Amici * @see hook_menu() */ function myproj_insurance_multiform_primary_form($form, &$form_state) { // Check to see if anything has been stored. drupal_add_library('system', 'drupal.ajax'); if ($form_state['rebuild']) { $form_state['input'] = array(); } if (empty($form_state['storage'])) { if (isset($_SESSION['insurance_multiform_validation']['storage'])) { $form_state['storage'] = $_SESSION['insurance_multiform_validation']['storage']; unset($_SESSION['insurance_multiform_validation']['storage']); } else { // Save/reset validation array as session variable, to keep track of which steps were correctly submitted. myproj_insurance_multiform_initvalidation(); // No step has been set so start with the first. $form_state['storage'] = array( 'step' => myproj_insurance_multiform_getstep(1), ); } } else { $_SESSION['insurance_multiform_validation']['storage'] = $form_state['storage']; } // If a session variable is overwriting the current step, replace it. if (isset($_SESSION['insurance_multiform_validation']['current_step'])) { $form_state['storage']['step'] = myproj_insurance_multiform_getstep($_SESSION['insurance_multiform_validation']['current_step']); unset($_SESSION['insurance_multiform_validation']['current_step']); } // Return the current form. $function = $form_state['storage']['step']; // Set the current form to be rendered. $form = $function($form, $form_state); . . . return $form; } [/prism:php] - **module_primary_form_submit**, que maneja el proceso de submit del form activo. En esta función, cambiamos el siguiente formulario a mostrar (dependiendo del botón presionado por el usuario, “anterior” y “siguiente”) y llamamos la función de submit del formulario actual, con todo el manejo necesario de los datos. Sin embargo, hay 2 puntos esenciales que todas las funciones submit de los form deben manejar: 1. el guardado de los datos a manejar más adelante en storage. 2. la configuración del form_state a rebuild; esto último es esencial, ya que esta propiedad es la que le indica a Drupal de reconstruir el formulario via Ajax. En caso contrario, el formulario enviará otra solicitud al mismo URL, recargando la página y devolviendo el usuario al primer paso. Ejemplo: [prism:php] /** * Submit handler for the primary multiform. * * Author: Cristiano Amici * @see myproj_insurance_multiform_primary_form() */ function myproj_insurance_multiform_primary_form_submit($form, &$form_state) { $values = $form_state['values']; if (isset($values['back']) && $values['op'] == $values['back']) { // Moving back in form. $step = $form_state['storage']['step']; // Call current step submit handler if it exists to unset step form data. if (function_exists($step . '_submit')) { $function = $step . '_submit'; $function($form, $form_state); } // Remove the last saved step so we use it next. $last_step = array_pop($form_state['storage']['steps']); $form_state['storage']['step'] = $last_step; } else { // Record step. $step = $form_state['storage']['step']; $form_state['storage']['steps'][] = $step; // Call step submit handler if it exists. if (function_exists($step . '_submit')) { $function = $step . '_submit'; $function($form, $form_state); } } return; } [/prism:php] Ejemplo del submit del primer form: [prism:php] /** * Submit handler for the first form. * @see myproj_insurance_multiform_first_form() */ function myproj_insurance_multiform_first_form_submit($form, &$form_state) { $values = $form_state['values']; // Needed to pass to next form. $form_state['rebuild'] = TRUE; $validation = myproj_insurance_multiform_validatestep($_SESSION['insurance_multiform_validation'], 1, TRUE); if (!$validation) { unset($_SESSION['insurance_multiform_validation']); $form_state['rebuild'] = FALSE; $form_state['redirect'] = ''; } else { // Add the next step function callback. $form_state['storage']['step'] = 'myproj_insurance_multiform_second_form'; } } [/prism:php] Con esta estructura, es posible manejar de forma fácil y sencilla un form multistep aprovechando únicamente las funciones core de Drupal. El código fue estructurado en forma de varios archivos .inc, cada uno definiendo el formulario de un paso, para así facilitar la legibilidad y el manejo del código. El primer formulario, que consiste en una tabla dinámica multiproducto con opción de ClickAndBuy (añadiendo el producto al que se le dé click al carro de compras y prosiguiendo en el proceso), fue el que recibió el mayor detalle a nivel de estructura y diseño, dado el nivel de personalización de diseño que requirió, generación dinámica de elementos (aseguradora, opciones disponibles, precio variable en base a otros datos manejados por el back-end y otras opciones escogidas por el usuario) y la integración via Ajax con elementos de jQuery UI (como el tabs). Luego de discutirlo con el equipo de desarrollo, se implementó en base a una estructura similar a MVC, aprovechando el Theming system de Drupal e incluyendo una librería que manejara todos los cálculos empleados por el sistema. Los demás formularios se desarrollaron de forma más afín al API de formularios de Drupal, guardando la solicitud de seguro del usuario cuando fuera necesario y aprovechando el API de Drupal Commerce en aquellas secciones del proceso que lo requerían.