バッチ処理を設定します。
バッチ処理を設定することによって、PHP のタイムアウトによって途中で中断されることなく、一度の送信で複数のページリクエストにわたって処理されるようなフォームの実装が可能になります。処理の間、ユーザーには処理の進捗状況を示すプログレスバーが表示されます。
この API は主に、フォーム API のワークフローにおいて使いやすいように設計されていますが、必ずしもフォームを使用しないスクリプト (update.php のような) や、単純にページコールバックで使用することもできます(但しページコールバックでの使用は控え目にすべきでしょう)。
例:
<?php $batch = array( 'title' => t('Exporting'), 'operations' => array( array('my_function_1', array($account->uid, 'story')), array('my_function_2', array()), ), 'finished' => 'my_finished_callback', 'file' => 'path_to_file_containing_myfunctions', ); batch_set($batch); // フォームのサブミットハンドラ以外で必要 // batch_process の設定 batch_process('node/1'); ?>
バッチの 'title'、'init_message' 、 'progress_message' 、 もしくは 'error_message' にユーザからの入力文字列を含める場合は、batch_set() をコールする前に check_plain() や filter_xss() 等のフィルター関数で事前にサニタイズしておくことが必要です。さらに $context の 'results' や 'message' など、バッチ処理から返されるメッセージにユーザからの入力文字列を含める場合も同様です。
バッチ処理のサンプル:
<?php // 指定したタイプ、指定したユーザーのノードをロードする単純な例 function my_function_1($uid, $type, &$context) { // $context 配列は実行時のコンテキスト配列を収集します。(読み) // カレントオペレーションの「返り値」でもあります。 (書き) // 以下のキーが使用できます。 : // 'results' (読み / 書き): バッチ処理によってこれまでに収集された // 結果の配列です。カレントオペレーションでは現在の結果を追加できます。 // 'message' (書き): 進捗状況のページに表示されるメッセージです。 // 以下のキーは反復処理が必要な場合に使用できます。 : // 'sandbox' (読み / 書き): 反復処理の間、永続的に使用するデータを // 格納する配列で、自由な用途に使用できます。$_SESSION の代わりに // 使用することが推奨されます。バッチ処理の間、ユーザーが複数の // ウインドウを立ち上げた場合を想定すると、$_SESSION を使うことは // 安全ではありません。 // 'finished' (書き): 処理の進捗状況のパーセンテージを表す 0 と 1 の // 間の浮動小数点数です。 1 (もしくは設定なし) は処理が完結したと // いうことになり、バッチ処理は次のオペレーションに進みます。 $node = node_load(array('uid' => $uid, 'type' => $type)); $context['results'][] = $node->nid . ' : ' . check_plain($node->title); $context['message'] = check_plain($node->title); } // さらに高度な例: すべてのノードをロードします。そうとう時間がかかり、 // 反復処理が必要な場合です。 function my_function_2(&$context) { if (empty($context['sandbox'])) { $context['sandbox']['progress'] = 0; $context['sandbox']['current_node'] = 0; $context['sandbox']['max'] = db_query('SELECT COUNT(DISTINCT nid) FROM {node}')->fetchField(); } $limit = 5; $result = db_select('node') ->fields('node', array('nid')) ->condition('nid', $context['sandbox']['current_node'], '>') ->orderBy('nid') ->range(0, $limit) ->execute(); foreach ($result as $row) { $node = node_load($row->nid, NULL, TRUE); $context['results'][] = $node->nid . ' : ' . check_plain($node->title); $context['sandbox']['progress']++; $context['sandbox']['current_node'] = $node->nid; $context['message'] = check_plain($node->title); } if ($context['sandbox']['progress'] != $context['sandbox']['max']) { $context['finished'] = $context['sandbox']['progress'] / $context['sandbox']['max']; } } ?>
'finished' コールバックの例:
<?php function batch_test_finished($success, $results, $operations) { // 'success' パラメータはPHP の致命的エラーが検出されなかったことを意味します。 // その他のエラーマネジメントには 'results' が使用されます。 if ($success) { $message = format_plural(count($results), 'One post processed.', '@count posts processed.'); } else { $message = t('Finished with an error.'); } drupal_set_message($message); // リダイレクト先のページのデータの提供は $_SESSION を通して行われます。 foreach ($results as $result) { $items[] = t('Loaded node %title.', array('%title' => $result)); } $_SESSION['my_batch_results'] = $items; } ?>