'Batch test', 'page callback' => 'drupal_get_form', 'page arguments' => array('batch_test_simple_form'), 'access callback' => TRUE, ); // Simple form: one submit handler, setting a batch. $items['batch-test/simple'] = array( 'title' => 'Simple', 'type' => MENU_DEFAULT_LOCAL_TASK, 'weight' => 0, ); // Multistep form: two steps, each setting a batch. $items['batch-test/multistep'] = array( 'title' => 'Multistep', 'page callback' => 'drupal_get_form', 'page arguments' => array('batch_test_multistep_form'), 'access callback' => TRUE, 'type' => MENU_LOCAL_TASK, 'weight' => 1, ); // Chained form: four submit handlers, several of which set a batch. $items['batch-test/chained'] = array( 'title' => 'Chained', 'page callback' => 'drupal_get_form', 'page arguments' => array('batch_test_chained_form'), 'access callback' => TRUE, 'type' => MENU_LOCAL_TASK, 'weight' => 2, ); // Programmatic form: the page submits the 'Chained' form through // drupal_form_submit(). $items['batch-test/programmatic'] = array( 'title' => 'Programmatic', 'page callback' => 'batch_test_programmatic', 'access callback' => TRUE, 'type' => MENU_LOCAL_TASK, 'weight' => 3, ); // No form: fire a batch simply by accessing a page. $items['batch-test/no-form'] = array( 'title' => 'Simple page', 'page callback' => 'batch_test_no_form', 'access callback' => TRUE, 'type' => MENU_LOCAL_TASK, 'weight' => 4, ); // No form: fire a batch; return > 100% complete $items['batch-test/large-percentage'] = array( 'title' => 'Simple page with batch over 100% complete', 'page callback' => 'batch_test_large_percentage', 'access callback' => TRUE, 'type' => MENU_LOCAL_TASK, 'weight' => 5, ); // Tests programmatic form submission within a batch operation. $items['batch-test/nested-programmatic'] = array( 'title' => 'Nested programmatic', 'page callback' => 'batch_test_nested_drupal_form_submit', 'access callback' => TRUE, 'type' => MENU_LOCAL_TASK, 'weight' => 6, ); // Landing page to test redirects. $items['batch-test/redirect'] = array( 'title' => 'Redirect', 'page callback' => 'batch_test_redirect_page', 'access callback' => TRUE, 'type' => MENU_LOCAL_TASK, 'weight' => 7, ); // This item lives under 'admin' so that the page uses the admin theme. $items['admin/batch-test/test-theme'] = array( 'page callback' => 'batch_test_theme_batch', 'access callback' => TRUE, 'type' => MENU_CALLBACK, ); return $items; } /** * Simple form. */ function batch_test_simple_form() { $form['batch'] = array( '#type' => 'select', '#title' => 'Choose batch', '#options' => array( 'batch_0' => 'batch 0', 'batch_1' => 'batch 1', 'batch_2' => 'batch 2', 'batch_3' => 'batch 3', 'batch_4' => 'batch 4', ), ); $form['submit'] = array( '#type' => 'submit', '#value' => 'Submit', ); return $form; } /** * Submit handler for the simple form. */ function batch_test_simple_form_submit($form, &$form_state) { batch_test_stack(NULL, TRUE); $function = '_batch_test_' . $form_state['values']['batch']; batch_set($function()); $form_state['redirect'] = 'batch-test/redirect'; } /** * Multistep form. */ function batch_test_multistep_form($form, &$form_state) { if (empty($form_state['storage']['step'])) { $form_state['storage']['step'] = 1; } $form['step_display'] = array( '#markup' => 'step ' . $form_state['storage']['step'] . '
', ); $form['submit'] = array( '#type' => 'submit', '#value' => 'Submit', ); return $form; } /** * Submit handler for the multistep form. */ function batch_test_multistep_form_submit($form, &$form_state) { batch_test_stack(NULL, TRUE); switch ($form_state['storage']['step']) { case 1: batch_set(_batch_test_batch_1()); break; case 2: batch_set(_batch_test_batch_2()); break; } if ($form_state['storage']['step'] < 2) { $form_state['storage']['step']++; $form_state['rebuild'] = TRUE; } // This will only be effective on the last step. $form_state['redirect'] = 'batch-test/redirect'; } /** * Form with chained submit callbacks. */ function batch_test_chained_form() { // This value is used to test that $form_state persists through batched // submit handlers. $form['value'] = array( '#type' => 'textfield', '#title' => 'Value', '#default_value' => 1, ); $form['submit'] = array( '#type' => 'submit', '#value' => 'Submit', ); $form['#submit'] = array( 'batch_test_chained_form_submit_1', 'batch_test_chained_form_submit_2', 'batch_test_chained_form_submit_3', 'batch_test_chained_form_submit_4', ); return $form; } /** * Submit handler #1 for the chained form. */ function batch_test_chained_form_submit_1($form, &$form_state) { batch_test_stack(NULL, TRUE); batch_test_stack('submit handler 1'); batch_test_stack('value = ' . $form_state['values']['value']); $form_state['values']['value']++; batch_set(_batch_test_batch_1()); // This redirect should not be taken into account. $form_state['redirect'] = 'should/be/discarded'; } /** * Submit handler #2 for the chained form. */ function batch_test_chained_form_submit_2($form, &$form_state) { batch_test_stack('submit handler 2'); batch_test_stack('value = ' . $form_state['values']['value']); $form_state['values']['value']++; batch_set(_batch_test_batch_2()); // This redirect should not be taken into account. $form_state['redirect'] = 'should/be/discarded'; } /** * Submit handler #3 for the chained form. */ function batch_test_chained_form_submit_3($form, &$form_state) { batch_test_stack('submit handler 3'); batch_test_stack('value = ' . $form_state['values']['value']); $form_state['values']['value']++; // This redirect should not be taken into account. $form_state['redirect'] = 'should/be/discarded'; } /** * Submit handler #4 for the chained form. */ function batch_test_chained_form_submit_4($form, &$form_state) { batch_test_stack('submit handler 4'); batch_test_stack('value = ' . $form_state['values']['value']); $form_state['values']['value']++; batch_set(_batch_test_batch_3()); // This is the redirect that should prevail. $form_state['redirect'] = 'batch-test/redirect'; } /** * Menu callback: programmatically submits the 'Chained' form. */ function batch_test_programmatic($value = 1) { $form_state = array( 'values' => array('value' => $value) ); drupal_form_submit('batch_test_chained_form', $form_state); return 'Got out of a programmatic batched form.'; } /** * Menu callback: programmatically submits a form within a batch. */ function batch_test_nested_drupal_form_submit($value = 1) { // Set the batch and process it. $batch['operations'] = array( array('_batch_test_nested_drupal_form_submit_callback', array($value)), ); batch_set($batch); batch_process('batch-test/redirect'); } /** * Batch operation: submits form_test_mock_form using drupal_form_submit(). */ function _batch_test_nested_drupal_form_submit_callback($value) { $state['values']['test_value'] = $value; drupal_form_submit('batch_test_mock_form', $state); } /** * A simple form with a textfield and submit button. */ function batch_test_mock_form($form, $form_state) { $form['test_value'] = array( '#type' => 'textfield', ); $form['submit'] = array( '#type' => 'submit', '#value' => t('Submit'), ); return $form; } /** * Submit handler for the batch_test_mock form. */ function batch_test_mock_form_submit($form, &$form_state) { batch_test_stack('mock form submitted with value = ' . $form_state['values']['test_value']); } /** * Menu callback: fire a batch process without a form submission. */ function batch_test_no_form() { batch_test_stack(NULL, TRUE); batch_set(_batch_test_batch_1()); batch_process('batch-test/redirect'); } /** * Menu callback: fire a batch process without a form submission. */ function batch_test_large_percentage() { batch_test_stack(NULL, TRUE); batch_set(_batch_test_batch_5()); batch_process('batch-test/redirect'); } /** * Menu callback: successful redirection. */ function batch_test_redirect_page() { return 'Redirection successful.'; } /** * Batch 0: no operation. */ function _batch_test_batch_0() { $batch = array( 'operations' => array(), 'finished' => '_batch_test_finished_0', 'file' => drupal_get_path('module', 'batch_test'). '/batch_test.callbacks.inc', ); return $batch; } /** * Batch 1: repeats a simple operation. * * Operations: op 1 from 1 to 10. */ function _batch_test_batch_1() { // Ensure the batch takes at least two iterations. $total = 10; $sleep = (1000000 / $total) * 2; $operations = array(); for ($i = 1; $i <= $total; $i++) { $operations[] = array('_batch_test_callback_1', array($i, $sleep)); } $batch = array( 'operations' => $operations, 'finished' => '_batch_test_finished_1', 'file' => drupal_get_path('module', 'batch_test'). '/batch_test.callbacks.inc', ); return $batch; } /** * Batch 2: single multistep operation. * * Operations: op 2 from 1 to 10. */ function _batch_test_batch_2() { // Ensure the batch takes at least two iterations. $total = 10; $sleep = (1000000 / $total) * 2; $operations = array( array('_batch_test_callback_2', array(1, $total, $sleep)), ); $batch = array( 'operations' => $operations, 'finished' => '_batch_test_finished_2', 'file' => drupal_get_path('module', 'batch_test') . '/batch_test.callbacks.inc', ); return $batch; } /** * Batch 3: both single and multistep operations. * * Operations: * - op 1 from 1 to 5, * - op 2 from 1 to 5, * - op 1 from 6 to 10, * - op 2 from 6 to 10. */ function _batch_test_batch_3() { // Ensure the batch takes at least two iterations. $total = 10; $sleep = (1000000 / $total) * 2; $operations = array(); for ($i = 1; $i <= round($total / 2); $i++) { $operations[] = array('_batch_test_callback_1', array($i, $sleep)); } $operations[] = array('_batch_test_callback_2', array(1, $total / 2, $sleep)); for ($i = round($total / 2) + 1; $i <= $total; $i++) { $operations[] = array('_batch_test_callback_1', array($i, $sleep)); } $operations[] = array('_batch_test_callback_2', array(6, $total / 2, $sleep)); $batch = array( 'operations' => $operations, 'finished' => '_batch_test_finished_3', 'file' => drupal_get_path('module', 'batch_test') . '/batch_test.callbacks.inc', ); return $batch; } /** * Batch 4: batch within a batch. * * Operations: * - op 1 from 1 to 5, * - set batch 2 (op 2 from 1 to 10, should run at the end) * - op 1 from 6 to 10, */ function _batch_test_batch_4() { // Ensure the batch takes at least two iterations. $total = 10; $sleep = (1000000 / $total) * 2; $operations = array(); for ($i = 1; $i <= round($total / 2); $i++) { $operations[] = array('_batch_test_callback_1', array($i, $sleep)); } $operations[] = array('_batch_test_nested_batch_callback', array()); for ($i = round($total / 2) + 1; $i <= $total; $i++) { $operations[] = array('_batch_test_callback_1', array($i, $sleep)); } $batch = array( 'operations' => $operations, 'finished' => '_batch_test_finished_4', 'file' => drupal_get_path('module', 'batch_test') . '/batch_test.callbacks.inc', ); return $batch; } /** * Batch 5: repeats a simple operation. * * Operations: op 1 from 1 to 10. */ function _batch_test_batch_5() { // Ensure the batch takes at least two iterations. $total = 10; $sleep = (1000000 / $total) * 2; $operations = array(); for ($i = 1; $i <= $total; $i++) { $operations[] = array('_batch_test_callback_5', array($i, $sleep)); } $batch = array( 'operations' => $operations, 'finished' => '_batch_test_finished_5', 'file' => drupal_get_path('module', 'batch_test'). '/batch_test.callbacks.inc', ); return $batch; } /** * Menu callback: run a batch for testing theme used on the progress page. */ function batch_test_theme_batch() { batch_test_stack(NULL, TRUE); $batch = array( 'operations' => array( array('_batch_test_theme_callback', array()), ), ); batch_set($batch); batch_process('batch-test/redirect'); } /** * Batch callback function for testing the theme used on the progress page. */ function _batch_test_theme_callback() { // Because drupalGet() steps through the full progressive batch before // returning control to the test function, we cannot test that the correct // theme is being used on the batch processing page by viewing that page // directly. Instead, we save the theme being used in a variable here, so // that it can be loaded and inspected in the thread running the test. global $theme; batch_test_stack($theme); } /** * Helper function: store or retrieve traced execution data. */ function batch_test_stack($data = NULL, $reset = FALSE) { if ($reset) { variable_del('batch_test_stack'); } if (!isset($data)) { return variable_get('batch_test_stack', array()); } $stack = variable_get('batch_test_stack', array()); $stack[] = $data; variable_set('batch_test_stack', $stack); }