|
1 <?php |
|
2 |
|
3 /** |
|
4 * @file |
|
5 * Helper module for the Batch API tests. |
|
6 */ |
|
7 |
|
8 /** |
|
9 * Implement hook_menu(). |
|
10 */ |
|
11 function batch_test_menu() { |
|
12 $items = array(); |
|
13 |
|
14 $items['batch-test'] = array( |
|
15 'title' => 'Batch test', |
|
16 'page callback' => 'drupal_get_form', |
|
17 'page arguments' => array('batch_test_simple_form'), |
|
18 'access callback' => TRUE, |
|
19 ); |
|
20 // Simple form: one submit handler, setting a batch. |
|
21 $items['batch-test/simple'] = array( |
|
22 'title' => 'Simple', |
|
23 'type' => MENU_DEFAULT_LOCAL_TASK, |
|
24 'weight' => 0, |
|
25 ); |
|
26 // Multistep form: two steps, each setting a batch. |
|
27 $items['batch-test/multistep'] = array( |
|
28 'title' => 'Multistep', |
|
29 'page callback' => 'drupal_get_form', |
|
30 'page arguments' => array('batch_test_multistep_form'), |
|
31 'access callback' => TRUE, |
|
32 'type' => MENU_LOCAL_TASK, |
|
33 'weight' => 1, |
|
34 ); |
|
35 // Chained form: four submit handlers, several of which set a batch. |
|
36 $items['batch-test/chained'] = array( |
|
37 'title' => 'Chained', |
|
38 'page callback' => 'drupal_get_form', |
|
39 'page arguments' => array('batch_test_chained_form'), |
|
40 'access callback' => TRUE, |
|
41 'type' => MENU_LOCAL_TASK, |
|
42 'weight' => 2, |
|
43 ); |
|
44 // Programmatic form: the page submits the 'Chained' form through |
|
45 // drupal_form_submit(). |
|
46 $items['batch-test/programmatic'] = array( |
|
47 'title' => 'Programmatic', |
|
48 'page callback' => 'batch_test_programmatic', |
|
49 'access callback' => TRUE, |
|
50 'type' => MENU_LOCAL_TASK, |
|
51 'weight' => 3, |
|
52 ); |
|
53 // No form: fire a batch simply by accessing a page. |
|
54 $items['batch-test/no-form'] = array( |
|
55 'title' => 'Simple page', |
|
56 'page callback' => 'batch_test_no_form', |
|
57 'access callback' => TRUE, |
|
58 'type' => MENU_LOCAL_TASK, |
|
59 'weight' => 4, |
|
60 ); |
|
61 // No form: fire a batch; return > 100% complete |
|
62 $items['batch-test/large-percentage'] = array( |
|
63 'title' => 'Simple page with batch over 100% complete', |
|
64 'page callback' => 'batch_test_large_percentage', |
|
65 'access callback' => TRUE, |
|
66 'type' => MENU_LOCAL_TASK, |
|
67 'weight' => 5, |
|
68 ); |
|
69 // Tests programmatic form submission within a batch operation. |
|
70 $items['batch-test/nested-programmatic'] = array( |
|
71 'title' => 'Nested programmatic', |
|
72 'page callback' => 'batch_test_nested_drupal_form_submit', |
|
73 'access callback' => TRUE, |
|
74 'type' => MENU_LOCAL_TASK, |
|
75 'weight' => 6, |
|
76 ); |
|
77 // Landing page to test redirects. |
|
78 $items['batch-test/redirect'] = array( |
|
79 'title' => 'Redirect', |
|
80 'page callback' => 'batch_test_redirect_page', |
|
81 'access callback' => TRUE, |
|
82 'type' => MENU_LOCAL_TASK, |
|
83 'weight' => 7, |
|
84 ); |
|
85 // This item lives under 'admin' so that the page uses the admin theme. |
|
86 $items['admin/batch-test/test-theme'] = array( |
|
87 'page callback' => 'batch_test_theme_batch', |
|
88 'access callback' => TRUE, |
|
89 'type' => MENU_CALLBACK, |
|
90 ); |
|
91 |
|
92 return $items; |
|
93 } |
|
94 |
|
95 /** |
|
96 * Simple form. |
|
97 */ |
|
98 function batch_test_simple_form() { |
|
99 $form['batch'] = array( |
|
100 '#type' => 'select', |
|
101 '#title' => 'Choose batch', |
|
102 '#options' => array( |
|
103 'batch_0' => 'batch 0', |
|
104 'batch_1' => 'batch 1', |
|
105 'batch_2' => 'batch 2', |
|
106 'batch_3' => 'batch 3', |
|
107 'batch_4' => 'batch 4', |
|
108 ), |
|
109 ); |
|
110 $form['submit'] = array( |
|
111 '#type' => 'submit', |
|
112 '#value' => 'Submit', |
|
113 ); |
|
114 |
|
115 return $form; |
|
116 } |
|
117 |
|
118 /** |
|
119 * Submit handler for the simple form. |
|
120 */ |
|
121 function batch_test_simple_form_submit($form, &$form_state) { |
|
122 batch_test_stack(NULL, TRUE); |
|
123 |
|
124 $function = '_batch_test_' . $form_state['values']['batch']; |
|
125 batch_set($function()); |
|
126 |
|
127 $form_state['redirect'] = 'batch-test/redirect'; |
|
128 } |
|
129 |
|
130 |
|
131 /** |
|
132 * Multistep form. |
|
133 */ |
|
134 function batch_test_multistep_form($form, &$form_state) { |
|
135 if (empty($form_state['storage']['step'])) { |
|
136 $form_state['storage']['step'] = 1; |
|
137 } |
|
138 |
|
139 $form['step_display'] = array( |
|
140 '#markup' => 'step ' . $form_state['storage']['step'] . '<br/>', |
|
141 ); |
|
142 $form['submit'] = array( |
|
143 '#type' => 'submit', |
|
144 '#value' => 'Submit', |
|
145 ); |
|
146 |
|
147 return $form; |
|
148 } |
|
149 |
|
150 /** |
|
151 * Submit handler for the multistep form. |
|
152 */ |
|
153 function batch_test_multistep_form_submit($form, &$form_state) { |
|
154 batch_test_stack(NULL, TRUE); |
|
155 |
|
156 switch ($form_state['storage']['step']) { |
|
157 case 1: |
|
158 batch_set(_batch_test_batch_1()); |
|
159 break; |
|
160 case 2: |
|
161 batch_set(_batch_test_batch_2()); |
|
162 break; |
|
163 } |
|
164 |
|
165 if ($form_state['storage']['step'] < 2) { |
|
166 $form_state['storage']['step']++; |
|
167 $form_state['rebuild'] = TRUE; |
|
168 } |
|
169 |
|
170 // This will only be effective on the last step. |
|
171 $form_state['redirect'] = 'batch-test/redirect'; |
|
172 } |
|
173 |
|
174 /** |
|
175 * Form with chained submit callbacks. |
|
176 */ |
|
177 function batch_test_chained_form() { |
|
178 // This value is used to test that $form_state persists through batched |
|
179 // submit handlers. |
|
180 $form['value'] = array( |
|
181 '#type' => 'textfield', |
|
182 '#title' => 'Value', |
|
183 '#default_value' => 1, |
|
184 ); |
|
185 $form['submit'] = array( |
|
186 '#type' => 'submit', |
|
187 '#value' => 'Submit', |
|
188 ); |
|
189 $form['#submit'] = array( |
|
190 'batch_test_chained_form_submit_1', |
|
191 'batch_test_chained_form_submit_2', |
|
192 'batch_test_chained_form_submit_3', |
|
193 'batch_test_chained_form_submit_4', |
|
194 ); |
|
195 |
|
196 return $form; |
|
197 } |
|
198 |
|
199 /** |
|
200 * Submit handler #1 for the chained form. |
|
201 */ |
|
202 function batch_test_chained_form_submit_1($form, &$form_state) { |
|
203 batch_test_stack(NULL, TRUE); |
|
204 |
|
205 batch_test_stack('submit handler 1'); |
|
206 batch_test_stack('value = ' . $form_state['values']['value']); |
|
207 |
|
208 $form_state['values']['value']++; |
|
209 batch_set(_batch_test_batch_1()); |
|
210 |
|
211 // This redirect should not be taken into account. |
|
212 $form_state['redirect'] = 'should/be/discarded'; |
|
213 } |
|
214 |
|
215 /** |
|
216 * Submit handler #2 for the chained form. |
|
217 */ |
|
218 function batch_test_chained_form_submit_2($form, &$form_state) { |
|
219 batch_test_stack('submit handler 2'); |
|
220 batch_test_stack('value = ' . $form_state['values']['value']); |
|
221 |
|
222 $form_state['values']['value']++; |
|
223 batch_set(_batch_test_batch_2()); |
|
224 |
|
225 // This redirect should not be taken into account. |
|
226 $form_state['redirect'] = 'should/be/discarded'; |
|
227 } |
|
228 |
|
229 /** |
|
230 * Submit handler #3 for the chained form. |
|
231 */ |
|
232 function batch_test_chained_form_submit_3($form, &$form_state) { |
|
233 batch_test_stack('submit handler 3'); |
|
234 batch_test_stack('value = ' . $form_state['values']['value']); |
|
235 |
|
236 $form_state['values']['value']++; |
|
237 |
|
238 // This redirect should not be taken into account. |
|
239 $form_state['redirect'] = 'should/be/discarded'; |
|
240 } |
|
241 |
|
242 /** |
|
243 * Submit handler #4 for the chained form. |
|
244 */ |
|
245 function batch_test_chained_form_submit_4($form, &$form_state) { |
|
246 batch_test_stack('submit handler 4'); |
|
247 batch_test_stack('value = ' . $form_state['values']['value']); |
|
248 |
|
249 $form_state['values']['value']++; |
|
250 batch_set(_batch_test_batch_3()); |
|
251 |
|
252 // This is the redirect that should prevail. |
|
253 $form_state['redirect'] = 'batch-test/redirect'; |
|
254 } |
|
255 |
|
256 /** |
|
257 * Menu callback: programmatically submits the 'Chained' form. |
|
258 */ |
|
259 function batch_test_programmatic($value = 1) { |
|
260 $form_state = array( |
|
261 'values' => array('value' => $value) |
|
262 ); |
|
263 drupal_form_submit('batch_test_chained_form', $form_state); |
|
264 return 'Got out of a programmatic batched form.'; |
|
265 } |
|
266 |
|
267 /** |
|
268 * Menu callback: programmatically submits a form within a batch. |
|
269 */ |
|
270 function batch_test_nested_drupal_form_submit($value = 1) { |
|
271 // Set the batch and process it. |
|
272 $batch['operations'] = array( |
|
273 array('_batch_test_nested_drupal_form_submit_callback', array($value)), |
|
274 ); |
|
275 batch_set($batch); |
|
276 batch_process('batch-test/redirect'); |
|
277 } |
|
278 |
|
279 /** |
|
280 * Batch operation: submits form_test_mock_form using drupal_form_submit(). |
|
281 */ |
|
282 function _batch_test_nested_drupal_form_submit_callback($value) { |
|
283 $state['values']['test_value'] = $value; |
|
284 drupal_form_submit('batch_test_mock_form', $state); |
|
285 } |
|
286 |
|
287 /** |
|
288 * A simple form with a textfield and submit button. |
|
289 */ |
|
290 function batch_test_mock_form($form, $form_state) { |
|
291 $form['test_value'] = array( |
|
292 '#type' => 'textfield', |
|
293 ); |
|
294 $form['submit'] = array( |
|
295 '#type' => 'submit', |
|
296 '#value' => t('Submit'), |
|
297 ); |
|
298 |
|
299 return $form; |
|
300 } |
|
301 |
|
302 /** |
|
303 * Submit handler for the batch_test_mock form. |
|
304 */ |
|
305 function batch_test_mock_form_submit($form, &$form_state) { |
|
306 batch_test_stack('mock form submitted with value = ' . $form_state['values']['test_value']); |
|
307 } |
|
308 |
|
309 /** |
|
310 * Menu callback: fire a batch process without a form submission. |
|
311 */ |
|
312 function batch_test_no_form() { |
|
313 batch_test_stack(NULL, TRUE); |
|
314 |
|
315 batch_set(_batch_test_batch_1()); |
|
316 batch_process('batch-test/redirect'); |
|
317 } |
|
318 |
|
319 /** |
|
320 * Menu callback: fire a batch process without a form submission. |
|
321 */ |
|
322 function batch_test_large_percentage() { |
|
323 batch_test_stack(NULL, TRUE); |
|
324 |
|
325 batch_set(_batch_test_batch_5()); |
|
326 batch_process('batch-test/redirect'); |
|
327 } |
|
328 |
|
329 /** |
|
330 * Menu callback: successful redirection. |
|
331 */ |
|
332 function batch_test_redirect_page() { |
|
333 return 'Redirection successful.'; |
|
334 } |
|
335 |
|
336 /** |
|
337 * Batch 0: no operation. |
|
338 */ |
|
339 function _batch_test_batch_0() { |
|
340 $batch = array( |
|
341 'operations' => array(), |
|
342 'finished' => '_batch_test_finished_0', |
|
343 'file' => drupal_get_path('module', 'batch_test'). '/batch_test.callbacks.inc', |
|
344 ); |
|
345 return $batch; |
|
346 } |
|
347 |
|
348 /** |
|
349 * Batch 1: repeats a simple operation. |
|
350 * |
|
351 * Operations: op 1 from 1 to 10. |
|
352 */ |
|
353 function _batch_test_batch_1() { |
|
354 // Ensure the batch takes at least two iterations. |
|
355 $total = 10; |
|
356 $sleep = (1000000 / $total) * 2; |
|
357 |
|
358 $operations = array(); |
|
359 for ($i = 1; $i <= $total; $i++) { |
|
360 $operations[] = array('_batch_test_callback_1', array($i, $sleep)); |
|
361 } |
|
362 $batch = array( |
|
363 'operations' => $operations, |
|
364 'finished' => '_batch_test_finished_1', |
|
365 'file' => drupal_get_path('module', 'batch_test'). '/batch_test.callbacks.inc', |
|
366 ); |
|
367 return $batch; |
|
368 } |
|
369 |
|
370 /** |
|
371 * Batch 2: single multistep operation. |
|
372 * |
|
373 * Operations: op 2 from 1 to 10. |
|
374 */ |
|
375 function _batch_test_batch_2() { |
|
376 // Ensure the batch takes at least two iterations. |
|
377 $total = 10; |
|
378 $sleep = (1000000 / $total) * 2; |
|
379 |
|
380 $operations = array( |
|
381 array('_batch_test_callback_2', array(1, $total, $sleep)), |
|
382 ); |
|
383 $batch = array( |
|
384 'operations' => $operations, |
|
385 'finished' => '_batch_test_finished_2', |
|
386 'file' => drupal_get_path('module', 'batch_test') . '/batch_test.callbacks.inc', |
|
387 ); |
|
388 return $batch; |
|
389 } |
|
390 |
|
391 /** |
|
392 * Batch 3: both single and multistep operations. |
|
393 * |
|
394 * Operations: |
|
395 * - op 1 from 1 to 5, |
|
396 * - op 2 from 1 to 5, |
|
397 * - op 1 from 6 to 10, |
|
398 * - op 2 from 6 to 10. |
|
399 */ |
|
400 function _batch_test_batch_3() { |
|
401 // Ensure the batch takes at least two iterations. |
|
402 $total = 10; |
|
403 $sleep = (1000000 / $total) * 2; |
|
404 |
|
405 $operations = array(); |
|
406 for ($i = 1; $i <= round($total / 2); $i++) { |
|
407 $operations[] = array('_batch_test_callback_1', array($i, $sleep)); |
|
408 } |
|
409 $operations[] = array('_batch_test_callback_2', array(1, $total / 2, $sleep)); |
|
410 for ($i = round($total / 2) + 1; $i <= $total; $i++) { |
|
411 $operations[] = array('_batch_test_callback_1', array($i, $sleep)); |
|
412 } |
|
413 $operations[] = array('_batch_test_callback_2', array(6, $total / 2, $sleep)); |
|
414 $batch = array( |
|
415 'operations' => $operations, |
|
416 'finished' => '_batch_test_finished_3', |
|
417 'file' => drupal_get_path('module', 'batch_test') . '/batch_test.callbacks.inc', |
|
418 ); |
|
419 return $batch; |
|
420 } |
|
421 |
|
422 /** |
|
423 * Batch 4: batch within a batch. |
|
424 * |
|
425 * Operations: |
|
426 * - op 1 from 1 to 5, |
|
427 * - set batch 2 (op 2 from 1 to 10, should run at the end) |
|
428 * - op 1 from 6 to 10, |
|
429 */ |
|
430 function _batch_test_batch_4() { |
|
431 // Ensure the batch takes at least two iterations. |
|
432 $total = 10; |
|
433 $sleep = (1000000 / $total) * 2; |
|
434 |
|
435 $operations = array(); |
|
436 for ($i = 1; $i <= round($total / 2); $i++) { |
|
437 $operations[] = array('_batch_test_callback_1', array($i, $sleep)); |
|
438 } |
|
439 $operations[] = array('_batch_test_nested_batch_callback', array()); |
|
440 for ($i = round($total / 2) + 1; $i <= $total; $i++) { |
|
441 $operations[] = array('_batch_test_callback_1', array($i, $sleep)); |
|
442 } |
|
443 $batch = array( |
|
444 'operations' => $operations, |
|
445 'finished' => '_batch_test_finished_4', |
|
446 'file' => drupal_get_path('module', 'batch_test') . '/batch_test.callbacks.inc', |
|
447 ); |
|
448 return $batch; |
|
449 } |
|
450 |
|
451 /** |
|
452 * Batch 5: repeats a simple operation. |
|
453 * |
|
454 * Operations: op 1 from 1 to 10. |
|
455 */ |
|
456 function _batch_test_batch_5() { |
|
457 // Ensure the batch takes at least two iterations. |
|
458 $total = 10; |
|
459 $sleep = (1000000 / $total) * 2; |
|
460 |
|
461 $operations = array(); |
|
462 for ($i = 1; $i <= $total; $i++) { |
|
463 $operations[] = array('_batch_test_callback_5', array($i, $sleep)); |
|
464 } |
|
465 $batch = array( |
|
466 'operations' => $operations, |
|
467 'finished' => '_batch_test_finished_5', |
|
468 'file' => drupal_get_path('module', 'batch_test'). '/batch_test.callbacks.inc', |
|
469 ); |
|
470 return $batch; |
|
471 } |
|
472 |
|
473 /** |
|
474 * Menu callback: run a batch for testing theme used on the progress page. |
|
475 */ |
|
476 function batch_test_theme_batch() { |
|
477 batch_test_stack(NULL, TRUE); |
|
478 $batch = array( |
|
479 'operations' => array( |
|
480 array('_batch_test_theme_callback', array()), |
|
481 ), |
|
482 ); |
|
483 batch_set($batch); |
|
484 batch_process('batch-test/redirect'); |
|
485 } |
|
486 |
|
487 /** |
|
488 * Batch callback function for testing the theme used on the progress page. |
|
489 */ |
|
490 function _batch_test_theme_callback() { |
|
491 // Because drupalGet() steps through the full progressive batch before |
|
492 // returning control to the test function, we cannot test that the correct |
|
493 // theme is being used on the batch processing page by viewing that page |
|
494 // directly. Instead, we save the theme being used in a variable here, so |
|
495 // that it can be loaded and inspected in the thread running the test. |
|
496 global $theme; |
|
497 batch_test_stack($theme); |
|
498 } |
|
499 |
|
500 /** |
|
501 * Helper function: store or retrieve traced execution data. |
|
502 */ |
|
503 function batch_test_stack($data = NULL, $reset = FALSE) { |
|
504 if ($reset) { |
|
505 variable_del('batch_test_stack'); |
|
506 } |
|
507 if (!isset($data)) { |
|
508 return variable_get('batch_test_stack', array()); |
|
509 } |
|
510 $stack = variable_get('batch_test_stack', array()); |
|
511 $stack[] = $data; |
|
512 variable_set('batch_test_stack', $stack); |
|
513 } |