No artigo de hoje será explicado como criar uma operação em lote. Este recurso é muito interessante por que se trata de uma forma de processar grandes volumes de dados sem ocorrer o timed out do navegador.
Antes de expôr o assunto propriamente dito, gostaria de ressaltar o que não será abordado:
- hook_menu: Este hook será utilizado no artigo, porém não há necessidade de entendê-lo profundamente. Caso tenha interesse de estudá-lo . Entre neste outro artigo.
- Watchdog: mais informações.
- drupal_set_message: mais informações.
Agora sim! Vamos ao que interessa.
O que é uma operação em lote ?
- Conceito geral
- Permitir gerir de forma organizada grande volumes de dados;
- Permitir criar diversas operações, cada uma com suas responsabilidades;
- Para o Drupal
- Permitir operar grande volume de dados sem que aconteça o timed out na requisição.
Para fins didáticos, crie todos os algoritmos aqui mostrados dentro do seu arquivo .module. Caso você se interesse por algo mais profissional, faça o download do módulo. O download está no texto logo abaixo.
Vamos planejar!
Antes de por a mão no código, precisamos planejar o que queremos executar. Neste artigo vamos criar um batch operation para cadastrar artigos.
O código que será usado aqui já está pronto e modularizado; se deseja acompanhar com o módulo instalado, faça o download aqui (caso tenha interesse acesse o github).
Fluxo de processos de um batch
Após definirmos o que será feito, devemos saber como é um fluxo de processos de um batch.
Mapeamento e parametrização
Neste bloco, a primeira coisa que precisamos fazer é criar um módulo e depois implementar um hook_menu ou então implementar esse hook num módulo já criado.
[php]define(‘DCAMP_SP_IMPORTER_SETTINGS_PATH’, ‘admin/structure/importer’);
/**
* Implements hook_menu().
*/
function dcamp_sp_importer_menu() {
$items[DCAMP_SP_IMPORTER_SETTINGS_PATH] = array(
‘title’ => ‘Importer’,
‘page callback’ => ‘drupal_get_form’,
‘page arguments’ => array(‘dcamp_sp_settings_importer_form’),
‘access arguments’ => array(‘importer page’),
‘type’ => MENU_CALLBACK,
);
return $items;
}[/php]
Neste hook menu estamos definindo onde será chamado o formulário que definirá o que será executado no batch. Um detalhe importante, no atributo ‘access arguments’ existe uma permissão definida – está permissão não é padrão do Drupal. Para criá-la, precisamos implementar o hook_permission.
[php]/**
* Implements hook_permission().
*/
function dcamp_sp_importer_permission() {
return array(
‘importer page’ => array(
‘title’ => t(‘Access to importer page’),
‘description’ => t(‘Oppa gangnam style!’),
),
);
}[/php]
Lembre-se que toda vez que implementamos um novo hook precisamos limpar o cache do drupal. Para limpá-lo você tem duas formas, pela interface administrava ou drush.
Agora é preciso criar a função que define o formulário solicitado no hook menu.
[php]/*** Settings importer form.
* @param [array] $form
* @param [array] $form_state
* @return [array] $form
*/
function dcamp_sp_settings_importer_form($form, $form_state) {
$form[‘amount_articles’] = array(
‘#type’ => ‘textfield’,
‘#title’ => t("Articles’s amount to import"),
‘#required’ => TRUE,
‘#size’ => 4,
‘#maxlength’ => 4,
‘#default_value’ => 100,
‘#element_validate’ => array(‘element_validate_number’),
);
$form[‘submit’] = array(
‘#type’ => ‘submit’,
‘#value’ => t(‘Submit’),
);
return $form;
}[/php]
No código acima foi utilizado dois elementos de formulário: um campo do tipo textfield e um botão submit. Para maiores detalhes acesse a api de formulários.
Construído o formulário, será necessário criar a função de submissão. É nela que irá começar a brincadeira!
[php]/**
* Settings importer form submit callback.
* @param [array] $form [description]
* @param [array] $form_state [description]
*/
function dcamp_sp_settings_importer_form_submit(&$form, &$form_state){
// This number is the amount of articles already imported.
$article_number = variable_get(‘dcamp_sp_importer_article_number’, 0);
// Batch’s definitions.
$batch = array(
‘title’ => t(‘Processing Importer DCAMP’),
‘operations’ => array(
// Callback function for the operation and their arguments.
array(‘dcamp_sp_importer_importing’, array(
$form_state[‘values’][‘amount_articles’],
$article_number,
)
),
),
‘finished’ => ‘dcamp_sp_importer_importing_finished’,
‘init_message’ => t(‘Importer DCAMP is starting.’),
‘error_message’ => t(‘Importer DCAMP has encountered an error.’),
‘progress_message’ => t(‘Article importing’),
);
// I do not set a batch_process because here is a form submiting.
// For more details access: <a href="http://drupal.org/node/180528" target="_blank">http://drupal.org/node/180528</a>
batch_set($batch);
}[/php]
O que nos interessa nesse algoritmo acima é o que acontece dentro da variável $batch.
Para inicializar uma batch operations nós precisamos declarar um array() com o seguintes parâmetros:
- ‘title’: título que será usado na interface.
- ‘operations’: este array serve para definir quais funções deverão ser executadas no batch. A ordem de execução dessas funções segue a ordem definida no array.
Dentro de cada função declarada você pode também passar parâmetros, para isso basta criar um array.
- ‘finished’: aqui é declarado o nome da função que irá fazer a finalização do batch. Nele poderá expor os resultados do batch e redirecionar o usuário para uma outra interface.
- ‘init_message’: antes de iniciar a barra de progress (progress bar) o Drupal mostra essa mensagem.
- ‘error_message’: Está mensagem só aparecerá caso houve algum problema durante o batch.
- ‘progress_message’: Está mensagem irá aparecer embaixo do progress bar durante todo o processo.
Para que o batch seja iniciado é preciso executar a função batch_set(). Seu parâmetro é a variável $batch, que contém todas as propriedades necessárias para sua execução.
Após a execução dessa função, precisamos implementar as funções declaradas no $batch – mas isso estará apenas na parte 02 do artigo.
Para quem quiser continuar sem ter a parte 02 do artigo, basta fazer download do módulo (o link para download encontra-se no início desse artigo).