background_batch.pages.inc in Background Process 6
Same filename and directory in other branches
Pages for background batch.
@todo Implement proper error page instead of just 404.
File
background_batch/background_batch.pages.incView source
<?php
/**
* @file
*
* Pages for background batch.
*
* @todo Implement proper error page instead of just 404.
*/
/**
* System settings page.
*/
function background_batch_settings_form() {
$form = array();
$form['background_batch_delay'] = array(
'#type' => 'textfield',
'#default_value' => variable_get('background_batch_delay', BACKGROUND_BATCH_DELAY),
'#title' => 'Delay',
'#description' => t('Time in microseconds for progress refresh'),
);
$form['background_batch_process_lifespan'] = array(
'#type' => 'textfield',
'#default_value' => variable_get('background_batch_process_lifespan', BACKGROUND_BATCH_PROCESS_LIFESPAN),
'#title' => 'Process lifespan',
'#description' => t('Time in milliseconds for progress lifespan'),
);
$form['background_batch_show_eta'] = array(
'#type' => 'checkbox',
'#default_value' => variable_get('background_batch_show_eta', BACKGROUND_BATCH_PROCESS_ETA),
'#title' => 'Show ETA of batch process',
'#description' => t('Whether ETA (estimated time of arrival) information should be shown'),
);
return system_settings_form($form);
}
/**
* Overview of current and recent batch jobs.
*/
function background_batch_overview_page() {
$data = array();
$sql = "\nSELECT b.bid\nFROM {batch} b\nORDER BY b.bid\n";
$result = db_query($sql);
$bids = array();
while ($row = db_fetch_object($result)) {
$bids[] = $row->bid;
}
foreach ($bids as $bid) {
$progress = progress_get_progress('_background_batch:' . $bid);
$eta = progress_estimate_completion($progress);
$data[] = array(
$progress->end ? $bid : l($bid, 'batch', array(
'query' => array(
'op' => 'start',
'id' => $bid,
),
)),
sprintf("%.2f%%", $progress->progress * 100),
$progress->message,
$progress->start ? format_date((int) $progress->start, 'small') : t('N/A'),
$progress->end ? format_date((int) $progress->end, 'small') : ($eta ? format_date((int) $eta, 'small') : t('N/A')),
);
}
$header = array(
'Batch ID',
'Progress',
'Message',
'Started',
'Finished/ETA',
);
return theme('table', $header, $data);
}
/**
* Default page callback for batches.
*/
function background_batch_page() {
require_once 'includes/batch.inc';
$output = _background_batch_page();
if ($output === FALSE) {
drupal_access_denied();
}
elseif (isset($output)) {
// Force a page without blocks or messages to
// display a list of collected messages later.
print theme('page', $output, FALSE, FALSE);
}
}
/**
* State-based dispatcher for the batch processing page.
*/
function _background_batch_page() {
$id = isset($_REQUEST['id']) ? $_REQUEST['id'] : FALSE;
if (!$id) {
return drupal_not_found();
}
// Retrieve the current state of batch from db.
$data = db_result(db_query("SELECT batch FROM {batch} WHERE bid = %d", $id));
if (!$data) {
return drupal_not_found();
}
$batch =& batch_get();
$batch = unserialize($data);
// Manually call our alter if hook_batch_alter() is unsupported on this system.
if (empty($batch['batch_altered'])) {
background_batch_batch_alter($batch);
// Save batch to DB.
_batch_shutdown();
}
// Check if the current user owns (has access to) this batch.
global $user;
if ($batch['uid'] != $user->uid) {
return drupal_access_denied();
}
$op = isset($_REQUEST['op']) ? $_REQUEST['op'] : '';
switch ($op) {
case 'start':
return _background_batch_page_start();
case 'do':
return _background_batch_page_do_js();
case 'do_nojs':
return _background_batch_page_do_nojs();
case 'finished':
require_once 'includes/batch.inc';
progress_remove_progress('_background_batch:' . $id);
return _batch_finished();
default:
drupal_goto('admin/settings/batch/overview');
}
}
/**
* Start a batch job in the background
*/
function _background_batch_initiate($process = NULL) {
require_once 'includes/batch.inc';
$batch =& batch_get();
$id = $batch['id'];
$handle = 'background_batch:' . $id;
if (!$process) {
$process = background_process_get_process($handle);
}
if ($process) {
// If batch is already in progress, goto to the status page instead of starting it.
if ($process->exec_status == BACKGROUND_PROCESS_STATUS_RUNNING) {
return $process;
}
// If process is locked and hasn't started for X seconds, then relaunch
if ($process->exec_status == BACKGROUND_PROCESS_STATUS_LOCKED && $process->start_stamp + variable_get('background_process_redispatch_threshold', BACKGROUND_PROCESS_REDISPATCH_THRESHOLD) < time()) {
$process = BackgroundProcess::load($process);
$process
->dispatch();
}
return $process;
}
else {
// Hasn't run yet or has stopped. (re)start batch job.
$process = new BackgroundProcess($handle);
$process->service_host = 'background_batch';
if ($process
->lock()) {
$message = $batch['sets'][0]['init_message'];
progress_initialize_progress('_' . $handle, $message);
if (function_exists('progress_set_progress_start')) {
progress_set_progress_start('_' . $handle, $batch['timestamp']);
}
else {
db_query("UPDATE {progress} SET start = :start WHERE name = :name", array(
':start' => $batch['timestamp'],
':name' => '_' . $handle,
));
}
$result = $process
->execute('_background_batch_process', array(
$id,
));
return $process;
}
}
}
function _background_batch_page_start() {
_background_batch_initiate();
if (isset($_COOKIE['has_js']) && $_COOKIE['has_js']) {
return _background_batch_page_progress_js();
}
else {
return _background_batch_page_do_nojs();
}
}
/**
* Batch processing page with JavaScript support.
*/
function _background_batch_page_progress_js() {
$batch = batch_get();
// The first batch set gets to set the page title
// and the initialization and error messages.
$current_set = _batch_current_set();
drupal_set_title($current_set['title']);
drupal_add_js('misc/progress.js', 'core', 'header', FALSE, FALSE);
$js_setting['batch'] = array();
$js_setting['batch']['errorMessage'] = $current_set['error_message'] . '<br />' . $batch['error_message'];
// Check wether ETA information should be shown.
if (variable_get('background_batch_show_eta', BACKGROUND_BATCH_PROCESS_ETA)) {
$js_setting['batch']['initMessage'] = 'ETA: ' . t('N/A') . '<br/>' . $current_set['init_message'];
}
else {
$js_setting['batch']['initMessage'] = $current_set['init_message'];
}
$js_setting['batch']['uri'] = url($batch['url'], array(
'query' => array(
'id' => $batch['id'],
),
));
$js_setting['batch']['delay'] = variable_get('background_batch_delay', BACKGROUND_BATCH_DELAY);
drupal_add_js($js_setting, 'setting');
drupal_add_js(drupal_get_path('module', 'background_batch') . '/js/progress.js', 'module', 'header', FALSE, FALSE);
drupal_add_js(drupal_get_path('module', 'background_batch') . '/js/batch.js', 'module', 'header', FALSE, FALSE);
$output = '<div id="progress"></div>';
return $output;
}
/**
* Do one pass of execution and inform back the browser about progression
* (used for JavaScript-mode only).
*/
function _background_batch_page_do_js() {
// HTTP POST required.
if ($_SERVER['REQUEST_METHOD'] != 'POST') {
drupal_set_message(t('HTTP POST is required.'), 'error');
drupal_set_title(t('Error'));
return '';
}
$batch =& batch_get();
$id = $batch['id'];
session_save_session(FALSE);
$percentage = t('N/A');
$message = '';
if ($progress = progress_get_progress('_background_batch:' . $id)) {
$percentage = $progress->progress * 100;
$message = $progress->message;
progress_estimate_completion($progress);
// Check wether ETA information should be shown.
if (variable_get('background_batch_show_eta', BACKGROUND_BATCH_PROCESS_ETA)) {
$message = "ETA: " . ($progress->estimate ? format_date((int) $progress->estimate, 'large') : t('N/A')) . "<br/>{$message}";
}
else {
$js_setting['batch']['initMessage'] = $message;
}
}
if (count($batch['sets'][$batch['current_set']]['operations']) == 0) {
// The background process has self-destructed, and the batch job is done.
$percentage = 100;
$message = '';
}
elseif ($process = background_process_get_process('background_batch:' . $id)) {
_background_batch_initiate($process);
}
else {
// Not running ... and stale?
_background_batch_initiate();
}
drupal_json(array(
'status' => TRUE,
'percentage' => sprintf("%.02f", $percentage),
'message' => $message,
));
}
/**
* Output a batch processing page without JavaScript support.
*
* @see _batch_process()
*/
function _background_batch_page_do_nojs() {
$batch =& batch_get();
$id = $batch['id'];
_background_batch_initiate();
$current_set = _batch_current_set();
drupal_set_title($current_set['title']);
$new_op = 'do_nojs';
// This is one of the later requests: do some processing first.
// Error handling: if PHP dies due to a fatal error (e.g. non-existant
// function), it will output whatever is in the output buffer,
// followed by the error message.
ob_start();
$fallback = $current_set['error_message'] . '<br/>' . $batch['error_message'];
drupal_maintenance_theme();
$fallback = theme('maintenance_page', $fallback, FALSE, FALSE);
// We strip the end of the page using a marker in the template, so any
// additional HTML output by PHP shows up inside the page rather than
// below it. While this causes invalid HTML, the same would be true if
// we didn't, as content is not allowed to appear after </html> anyway.
list($fallback) = explode('<!--partial-->', $fallback);
print $fallback;
$percentage = t('N/A');
$message = '';
// Get progress
if ($progress = progress_get_progress('_background_batch:' . $id)) {
$percentage = $progress->progress * 100;
$message = $progress->message;
progress_estimate_completion($progress);
// Check wether ETA information should be shown.
if (variable_get('background_batch_show_eta', BACKGROUND_BATCH_PROCESS_ETA)) {
$message = "ETA: " . ($progress->estimate ? format_date((int) $progress->estimate, 'large') : t('N/A')) . "<br/>{$message}";
}
}
if (count($batch['sets'][$batch['current_set']]['operations']) == 0) {
// The background process has self-destructed, and the batch job is done.
$percentage = 100;
$message = '';
}
elseif ($process = background_process_get_process('background_batch:' . $id)) {
_background_batch_initiate($process);
}
else {
// Not running ... and stale?
_background_batch_initiate();
}
if ($percentage == 100) {
$new_op = 'finished';
}
// PHP did not die : remove the fallback output.
ob_end_clean();
$url = url($batch['url'], array(
'query' => array(
'id' => $batch['id'],
'op' => $new_op,
),
));
drupal_set_html_head('<meta http-equiv="Refresh" content="0; URL=' . $url . '">');
$output = theme('progress_bar', sprintf("%.02f", $percentage), $message);
return $output;
}
Functions
Name | Description |
---|---|
background_batch_overview_page | Overview of current and recent batch jobs. |
background_batch_page | Default page callback for batches. |
background_batch_settings_form | System settings page. |
_background_batch_initiate | Start a batch job in the background |
_background_batch_page | State-based dispatcher for the batch processing page. |
_background_batch_page_do_js | Do one pass of execution and inform back the browser about progression (used for JavaScript-mode only). |
_background_batch_page_do_nojs | Output a batch processing page without JavaScript support. |
_background_batch_page_progress_js | Batch processing page with JavaScript support. |
_background_batch_page_start |