Procesamiento desatendido (Batch2ls)Php - Bibliotools

Controladores para procesamiento por lotesReferencia para desarrollo

Presentacion del grupo de utilidades

Php - Bibliotools Ofrece un conjunto de clases preparadas para controlar, ejecutar y mostrar el avance de procesos por lotes, que podrían tomar tiempos muy largos de proceso, de modo que que puedan ser invocados desde páginas en las que se mostrarán mensajes de estado y avance de aquellos, sincronizados con su marcha. Así mismo, permite integrar, familias de mensajes, con información asociada con la naturaleza u objetivos de dichos procedimientos, mostrar reportes de resultados y finalmente redirigir a lugares adecuados para continuar el trabajo sin incurrir en repeticiones.

La biblioteca esta integrada por dos componentes gráficos que son ofrecidos por TwBs2ls y cuatro clases controladoras que se ocupan de simplificar el manejo de las definiciones, registro y control de operación de los procesos. Son las siguientes:

  • Biblio2ls\Library\Batch\BatchProccessor
    Controlador e integrador unificado para procesos por lotes. Es invocado desde el controlador que responde a las solicitudes ajax y sincroniza, ejecuta, controla la marcha y devuelve las respuestas adecuadamente formateadas.
    No es necesario invocarlo ni crear instancias suyas. La GUI de usuario (BindedBatchComponent) se encarga de registrarla en el momento en que es insertada en la página que presentará el batch, para que pueda ser cargada por el controlador de respuestas ajax.
  • Biblio2ls\Library\Batch\BatchEntity
    Controla el registro, la lectura y los procesos de validación de Batchs. No es necesario crear instancias suyas, es usada de modo transparente por BatchProccessor y DefineBatch para registrar, validar y controlar los procesos.
  • Biblio2ls\Library\Batch\DefineBatch
    Esta clase ofrece un mecanismo sencillo para crear, declarar, registrar y accesar definiciones de procesos por lotes. Es el "Caballo de batalla"; debe ser instanciada para asegurar que los batchs se registren con la sintaxis y características requeridas. Requiere del uso de BatchOppsSet para asegurar que los conjuntos de operaciones estén bien definidos.
  • Biblio2ls\Library\Batch\BatchOppsSet
    Esta clase permite definir y parametrizar correctamente los grupos de operaciones que van a ser incorporados a un proceso por lotes. Debe usarse para preparar las definiciones de cada "bloque de operaciones" antes de pasarlas al controlador de definición y registro de batchs.
  • \TwBs2l\Component\BindedBatchComponent
    Componente gráfico ofrecido por TwBs2ls. Ofrece una GUI que integra una barra indicadora de avance de proceso, un contenedor para despliegue de resultados, botones activadores, (enlaces opcionales para llamar desde otros lugares) y crea el registro de acciones para ejecución del batch en la página a servir e inserta los manejadores de javascrip y ajax necesarios para controlar todo el proceso.
  • \TwBs2l\Component\ProgressiveLoader
    Extensión de BindedBatchComponent ofrecido para simular carga progresiva de páginas, mostrando indicaciones del estado de avance de procesos muy grandes que deben ser lanzados en respuesta a solicitudes del cliente y que al terminar deben liberar la página servida en respuesta a aquellas.
    Ejemplo: Al crear o eliminar un tipo de contenido el sistema de menús, los permisos y muchas otras partes del sistema y módulos de extensión deben reconstruirse y adaptarse a su presencia; y, es casi imposible establecer qué tan pesada puede ser la respuesta. En tales casos, se registra y lanza un batch de reconstrucción de configuraciones, cuya actividad es mostrada al recargar la página de edición, que "queda atrapada" hasta que el mismo termine. De modo que se asegura respuesta rápida, y actividad perceptible por el usuario, hasta que el sistema haya sido ajustado.
  • \foliate\form
    El módulo de extensión "foliate" implementa muchos elementos HTML para realizar tareas de captura y preparación de información. Los siguientes facilitan la creación y registro de procesos por lotes:
    \foliate\form\BindedBatchElement
    Este elemento Html facilita la adición de batchs a formularios. Basta con crear un array de definición al que se pasa como atributo un array de operaciones.
    \foliate\form\ProgressiveLoaderElement
    Este elemento es una extensión de BindedBatchElement creada para los casos en que el batch debe arrancar, sin intervensión del usuario, una vez se completa la carga de la página. Para ver un ejemplo vivo de su uso puede resultar útil consultar el código fuente del editor de tipos de contenidos: (ZfExtensor/extensions/foliate/admin/content_types.inc)
  • \TwBs2l\Component\BsRotator
    Componente gráfico opcional para integrar el despliegue de mensajes e imágenes informativas, complementarios, para que sean vistos por el usuario mientras el proceso se encuentra en ejecución.

La biblioteca ha sido inspirada por el utilitario "batch" del API de Drupal 6x y puede se configura de manera muy similar. Pero, a diferencia de Drupal, incluye asistentes para facilitar la escritura del código necesario. Abajo se documenta e ilustra su manejo.

Biblio2ls\Library\Batch\DefineBatch

Asistente para definición, registro y acceso a procesos por lotes. Tiene como propósito asegurar que la sintaxis y el registro de los mismos en la base de datos sean correctos, y es empleada por BatchProccessor para controlar la ejecución de los mismos.

Instanciación:

  // directa, su constructor no requiere de parámetros especiales, pero se puede usar el id del batch 
  // si se desea recargar una definición almacenada en DB durante la sesión en curso.  
  $batchdef = new \Biblio2ls\Library\Batch\DefineBatch($batchId);

Uso:

Se presume que los conjuntos de funciones a ejecutar han sido bien definidos y las funciones han sido probadas.

  // se cuenta con al menos un array de definición de conjuntos de funciones
  $batchsets = [$batchset01, ..., $batchset_N];
  // se asigna nombre al batch (para manejar referencias internas y registrarlo)
  $batchId = 'ejemploDeBatch01';
  // se crea una instancia del asistente de definición
  $batchdef = new \Biblio2ls\Library\Batch\DefineBatch();
  // se emplean los métodos del asistente para configurar y guardar la definición
  $batchdef->setBatchId($batchId)
           ->setReportRedirect($urlderedireccion)  // path relativo a home del sitio
           ->setOperationSets($batchsets)
           ->save();  
  // los demás métodos ofrecidos por el asistente son opcionales. 
  // No se requieren para contar con un batch bien definido.

\TwBs2l\Component\BindedBatchComponent (Batch GUI)

Esta ofrece una interfaz gráfica integrada para lanzar y hacer seguimiento de la ejecución de "procesos por lotes". Esta sincronizada con las utilidades dispuestas para definirlos, registrarlos y controlarlos. Así mismo, permite integrar, familias de mensajes, con información asociada con la naturaleza u objetivos de dichos procedimientos. Por ejemplo: tips o información utilitaria vinculada con el proceso de instalación y configuración de un módulo de extensión.

Constructor:

  $Batch = new \TwBs2l\Component\BindedBatchComponent($batchid, $maxsteps, $pagesets, $hasreport, $rotatorsettings);
    donde:
      
  • $batchid cadena identificadora del batch. Es el id asignado al definirlo.
  • $maxsteps Cantidad de pasos esperada el el primer set de operaciones
  • $pagesets Cantidad de sets de operaciones asignadas al batch
  • $hasreport Si se muestra reporte dentro de la página al terminar
  • $rotatorsettings Preferencias del rotator si se emplea uno
  • $reportembeded Establece si el reporte se embebe o no en el formulario principal. Debe establecerse a FALSE cuando se instancia dentro de un formulario para pasar luego una instancia de la interfaz de reporte como sufijo del mismo. (ver ejemplo uso en formularios)

Métodos

  $Batch->toString();
    Inserta el controlador (oculto) dentro de la página a mostrar. 
    Una vez sea activado mostrará una barra de progreso.
  $Batch->getEstatusFlags($head, $operationsets);
    Devuelve una lista de tareas con marcas de verificación ocultas para motrar indicadores
    de paso por las mismas una vez hayan sido completadas. $head es un título opcional que
    debe se formateado antes de pasarlo al llamado.
  $Batch->getEnlace('0', 'texto del enlace');
    Entrega un enlace listo para agregar a la página en cualquier parte.
  $Batch->ScriptLlamador($itemid, $conprefijo)
    Devuelve un script que puede ser pasado como atributo action o target a buttons o forms
    para poder activarlo desde el formulario.
  $Batch->getButton($itemid, $TextoAMostrar, $context)
    Devuelve un botón de comando con id y atributos configurados adecuadamente para
    invocar el batch, de modo que quede oculto definitivamente en caso de que el batch deba presentar reportes.

Uso del componente en Formularios

En muchos casos resulta conveniente utilizar batchs para procesamiento de solicitudes preparadas mediante formularios que recogen información del usuario por pasos y responden activando procesos que pueden ser muy grandes (p.ej Activar/desactivar módulos de extensión ó importar bases de datos con formato csv, etc.).
En tales circunstancias se debe tener presente que la acción de salida del reporte del batch (lanzada desde su botón aceptar) disparará los eventos registrados mediante los atributos #validate y #submit del formulario; pero con cambios significativos en la claves 'post' y 'values' de $form_state que se pueden emplear para identificar el cambio de estatus así:
$form_state['post'] contiene el item 'ID_DEL_BATCH-report-ok' => 'ok' y la clave $form_state['values'] posiblemente exista pero conteniendo un array vacío. de modo que en el método registrado bajo $form['#validate'] en este caso será metodo_preparador_de_form_validate($form, &$form_state) (ver más abajo) se puede emplear la instrucción:

  if(isset($form_state['post']['ID_DEL_BATCH-report-ok'])){
    // pasa la validación y sigue hacia submit
    // poner flags o marcas p.ej
    $form_state['onsubmit'] = 'success';
    // que van a ser empleadas en el siguiente paso para evitar recarga del batch
    // o errores de validación que no se produjeron
  }else{
    // procesamiento de validación normal
  } 

De modo que el mecanismo de definición del formulario refleje las condiciones siguiendo caminos alternativos así:

<?php
  // En el metodo de preparación del form, invocado por hybridzd_get_form() que es
  // el generador universal de formularios empleado por el sistema ver Foliate/FormAPI;
  // se inicia con un juego alternativo:
  function metodo_preparador_de_form(&$form_state){
    $formdef = [
      '#title' => 'Título a mostrar en el formulario',      
    ];
    if(isset($form_state['submitted']) && (is_array($form_state['submitted']))){
      $formdef['body'] = metodo_preparador_del_batch($form_state['submitted']);
      // es necesario incluir el archivo "batchscommon.inc" que ofrece el contenedor de reportes de batchs
      module_load_include('inc', 'Biblio2ls', 'includes/batchs2l/batchscommon');
      // y agregar el contenedor como sufijo para asegurar que el form que lo contiene
      // no se anide en el form principal. Además, al crear el body (ver abajo metodo_preparador_del_batch) 
      // se hace una anotación complementaria pasando un parámetro opcional como FALSE explícitamente.
      $formdef['#suffix'] = batchs2l_report_container('ID_DEL_BATCH');
    }else{
      $formdef['body'] = bloques_normales_para_recoger_data($form_state);
    }
    return $formdef;
  }
  
  // Las operaciones validate y submit se procesan con sendos métodos asociados a form
  function metodo_preparador_de_form_submit($form, &$form_state){
    // sólo se ejecuta si la validación no devolvio error.
    // si no viene flag de terminación desde _validate y $form_state['values']
    // contiene los valores esperados se crean los sets de operaciones necesarias
    if(!isset($form_state['onsubmit'])){
      // se crean los arrays de definición de operaciones
      // de acuerdo con las necesidades.
      $oopsets = metodo_definidor_de_operaciones($form_state['values']);
      // si hay sets de operaciones a ejecutar se pasan
      if(count($oopsets) > 0){ $form_state['submitted'] = $oopsets; }
    }
  }
  
  function metodo_preparador_de_form_validate($form, &$form_state){
    // sólo debe devolver un array que contenga la clave 'error' en caso de error
    // si la validación pasa puede devolver null.
    // Y, en caso de proceso terminado puede inyectar un flag en &$form_state
    // que fue pasado por referencia, para que sea usado en _form_submit() y en _form()
  }
  
  // Se escribe un método para preparación normal del cuerpo del formulario de entrada
  function bloques_normales_para_recoger_data($form_state){
    // instrucciones creando el array de definiciones de elementos html
  }
  
  // Se escribe un método para instanciar el componente y mostrar su interfaz de usuario
  // dentro de un elemento markup que será pasado como body
  function metodo_preparador_del_batch($oopsets){
    // los parametros fueron recogidos en el metodo submit, que los ha debido emplear
    // para definir los sets de operaciones y luego pasarlos como array a $form_state['submitted']
    $componente = new \TwBs2l\Component\BindedBatchComponent('ID_DEL_BATCH', 100, 1, 1, [], FALSE);
    // notese que se pasó rotatorsettings = [] y usaform = FALSE éste último es muy importante para
    // evitar que se aniden forms y se generen choques de trenes al validar los requests ajax
    $head = 'Carretazo a mostrar como encabezado del batch'
    // Se crea la GUI de control del batch
    $block = $componente->getEstatusFlags($head , $oopsets, TRUE). $componente->toString();
    // Prepara un botón llamador
    $button = '<p class="centrado">'.$componente->getButton(0, 'Configurar', 'primary').'</p>';
    $body = [
      '#type' = 'markup',
      '#requiere_dialogo_modal' = 1, // fuerza la carga de dialogo modal sin que se solape
      '#value' = $block . $button,
    ];
    return $body;
    // NÓTESE QUE NO SE PASA URL DE REDIRECCIÓN PORQUE TODO SE TRATA EN LOS CONTROLADORES DEL FORM
  }
  

 Ejemplo de simulación usando componente

Bajo esta línea se mostrará una barra de progreso para hacer una simulación de avance en la ejecución de un proceso por lotes (haga click en el enlace o en el botón situados abajo para lanzarlo)

 Simulación de ejecución de proceso por lotes:

  • Test de proceso por lotes, grupo uno 
  • Test de proceso por lotes, grupo dos 

 

 

0%

 


 

Ejecutar usando enlace

  

 \TwBs2l\Component\ProgressiveLoader - Controlador de carga progresiva

Este componente utilitario fue creado para lanzar batchs de "sólo una vez" que deben ser ejecutados para completar tareas complejas previas a la carga de un formulario. Es definido como un "elemento" extensor de Foliate/FormAPI cuyos atributos simplifican el mecanismo de declaración y registro del batch asociado.

Situaciones típicas de uso:
  • Al crear un nuevo tipo de contenido, es necesario actualizar el sistema de menús antes de pasar al modo de edición, para que se refleje su existencia en el mismo y las funciones de administración asociadas puedan ser activadas.
  • Al usar o configurar por primera vez un elemento contribuido (como el campo Divipola) que requiere de la importación de una tabla de control muy grande. Pero, que podría afectar negativamente las utilidades de instalación (provocando un "time out" o situación similar que haga abortar la actualización)
Atributos
'#animated', '#hasreport', '#name', '#oppsets', '#reportembeded', '#title', '#type', '#value', '#weight', los demás atributos comunes a los elementos definidos por Foliate/FormAPI.
  • '#animated' = (boolean) 0 | 1 (sugerido).
    En caso de que el proceso sea muy largo conviene establecerlo a 1 para asegurar que el usuario perciba la actividad y no trate de recargar o cierre abruptamente la página, por creer que ha fallado su carga. Se mostrará una barra de progreso con mensajes de avance automáticos.
  • '#hasreport' = (boolean) 0 (sugerido) | 1 .
    En general no conviene que muestra reportes, pero puede haber casos en que sean necesarios.
  • '#name' = (requerido) 'nombre_de_instancia'.
  • '#oppsets' = (array) (requerido) El conjunto de operaciones a ejecutar.
  • '#reportembeded' = (boolean) 0(sugerido) | 1 .
  • '#title' = (string) ''.
  • '#type' = (requerido) 'progressive_loader'.
  • '#value' = (mixed) (sugerido) ''.
  • '#weight' = (requerido) (sugerido) -1000 para asegurar que se anime bajo el encabezado del formulario.
Ejemplo
El método de carga del formulario de Adición de tipos de contenido, establece si hubo validación y guardado del contenido. Y, en caso afirmativo, hace redirección al formulario de edición pasándole un flag que lo notifica de la creación de un contenido nuevo, para que lance un batch de configuración al mostrarse.
La instancia del elemento emplea el siguiente código:
<?php
  $form['autoajuste_menus'] = autoajuste_progresivo_content_type();
  ...
  function autoajuste_progresivo_content_type(){
      module_load_include('inc', 'Biblio2ls', 'includes/setup/setupbatch');
      $mnurgtit = 'Ajuste de definiciones de Menús';
      $mnurgmsg = 'Ajustando menú del módulo @step de @total: @name...';
      $mnrgbch = setupbatch_operationsSet_RegisterMenu($mnurgtit, $mnurgmsg);
      $mnubtch = setupbatch_operationsSet_Configure_menu_tree();
      $oppsets = [ $mnrgbch->toArray(), $mnubtch->toArray() ];
      $bloque = [
        '#title' => '', 
        '#value' => '',
        '#name' => 'content_autoajuste',
        '#type' => 'progressive_loader',
        '#animated' => 1, 
        '#hasreport' => 0, 
        '#reportembeded' => 0,
        '#oppsets' => $oppsets,
        '#weight' => -1000,
      ];
      return $bloque;
  }  

El mecanismo de definición de los sets de operaciones es muy simple. Se ilustra comentando el empleado para registrar los dos sets usados para el autoajuste de menús:
<?php
  function setupbatch_operationsSet_RegisterMenu($titulo = '', $msgpad = ''){
      // al asignar los parámetros opcionales se establecen tanto el título como 
      // el mensaje de progreso para el batch.
      $tit = ($titulo) ? $titulo : 'Registro de definiciones de Menús';
      $msg = ($msgpad) ? $msgpad : 'Registrando menú del módulo @step de @total: @name...';
      // Las operaciones se establecen como un array de arrays en las que cada subarray
      // tiene dos elementos: el nombre de un ejecutable y un array de parámetros.
      $operaciones = [
          ['setupbatch_registrar_menu_del_modulo', []],
      ];
      // Para registrar y controlar los sets de operaciones se crea una instancia del
      // asistemte para manejo de los mismos BatchOppsSet
      $batchset = new \Biblio2ls\Library\Batch\BatchOppsSet();
      // Y se asignan sus atributos:
      $batchset->setTitle($tit)
               ->setInitMessage('Leyendo definiciones ...')
               ->setProgressMessage($msgpad)
               ->setErrorMessage('Hubo errores de acceso a la base de datos. No fue posible registrar correctamente los módulos.')
               ->setCallstype('extend')
               ->setModule('Biblio2ls')               // Importante (módulo que contiene el código a ejecutar)
               ->setFile('includes/setup/setupbatch') // archivo con el código a ejecutar
               ->setFileExt('inc')
               /* declaración del método configurador del proceso */
               ->setInitialMethod('setupbatch_identificar_modulos_implementadores_de_hook_menu')
               /* declaración del método preparador del reporte de salida */
               ->setFinishedMethod('setupbatch_register_modules_menus_report')
               /* paso del set de operaciones a registrar */
               ->setOperations($operaciones);
      return $batchset;
  }  

Las signaturas de los métodos registrados por el método BatchOppsSet debe ajustarse al siguiente módelo:
<?php
  // En el ejemplo arriba la operación apunta a:
  function setupbatch_registrar_menu_del_modulo(&$context){
    // ...
  }
  // de modo que en general debe definirse para cada operación registrada:
  function operacion_x_del_set_y(&$context){
    // y para recuperar los argumentos diferentes de $context que  es requerido y pasado por referencia
    // en caso de haberlos definido, usar:
    $args = array_slice(func_get_args(), 1, func_num_args());
  }
  
  // El método iniciador se establece así:
  // en el ejemplo:
  function setupbatch_identificar_modulos_implementadores_de_hook_menu(&$context){
    // ...
  }
  // En general
  function metodo_iniciador_del_set_y_del_batch(&$context){
    // Nótese la presencia de  $context siendo pasado por referencia
  }
  
  // El método reportadodor se establece así:
  // en el ejemplo:
  function metodo_reportador($success, $results, $operations){
    // dónde $success es un booleano indicando si el proceso fue satisfactorio
    //       $results es un array de resultados recogidos en $context
    //     y $operations es un array que recoge errores reportados por las operaciones
    // ...    
    return $html; bloque html a mostrar como salida
  }
  

Como se puede observar el alma del modelo controlador de batchs se encuentra en el array $context que es usado para interconectar los métodos y permitir el paso de controles de entorno entre llamadas sucesivas desde el cliente y devolverle indicaciones de avance, etc.


 

 Escritura de código para controlar batchs

Como se indicó arriba, en el ejemplo de carga progresiva, el alma del control de batchs se encuentra en el parámetro $context que es común a los métodos declarados para realizar las acciones y sirve como vehículo de paso de valores entre ellos. Dicho parámetro es un array cuyas claves son literales (algunas reservadas para uso interno) y otras dispuestas para paso de información entre operaciones (de modo que se asegure su persistencia) entre llamados sucesivos al servidor

Estructura del array $context
<?php
  $context = [
    'sandbox'  => [], // array persistente para paso de valores entre métodos
    'results'  => [], // array para almacenar resultados por set de operaciones
    'finished' => 0,  // real entre 0 y 1, indica el porcentaje de avance del set de operaciones actual
    'message'  => '', // mensaje de salida del juego de iteraciones en curso
    'progress' => 0,  // medida de avance (entera, iteración en curso)
    'max'      => 0,  // entero (default 100) cantidad de iteraciones del set de operaciones en curso
    // Claves reservadas. Se enumeran destacando que no deben ser modificadas por las operaciones
    // pueden ser consultadas en caso de necesidad (para depuración)
    'callinfo' => []  // parametrización de acceso para invocar la operación en curso
    'operaciones' => [] // Set de operaciones actual
    'operacionencurso' => 0,...,n // identificador de la operación invocada
    'error' => [], // array de operaciones que reportan errores
    'error_message' => Mensaje (por defecto) a mostrar en caso de error en el grupo actual de operaciones    
  ];
Ciclo de ejecución del batch


 


Php - BiblioTools [Documentación]