background_batch.pages.inc in Background Process 7.2
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.
*/
/**
* Overview of current and recent batch jobs.
*/
function background_batch_overview_page() {
$data = array();
$bids = db_select('batch', 'b', array(
'target' => 'background_process',
))
->fields('b')
->orderBy('b.bid', 'DESC')
->execute()
->fetchAllAssoc('bid', PDO::FETCH_OBJ);
$processes = array();
foreach ($bids as $bid => $batch) {
$process = BackgroundProcess::loadByHandle('background_batch:' . $bid);
if ($process) {
$progress = sprintf("%.02f%%", $process
->getProgress() * 100);
$message = $process
->getProgressMessage();
$start = format_date((int) $process
->getStartTime(), 'small');
$eta = $process
->calculateETA();
$eta = $eta ? format_date((int) $process
->calculateETA(), 'small') : t('N/A');
}
else {
$batch = unserialize($batch->batch);
$current_set = $batch['sets'][$batch['current_set']];
list($progress, $message) = BackgroundBatchContext::processMessage($current_set);
$progress = sprintf("%.02f%%", $progress * 100);
$start = format_date((int) $current_set['start'], 'small');
$eta = empty($batch['finish_time']) ? t('Not running') : format_date((int) $batch['finish_time'], 'small');
}
$data[] = array(
l($bid, 'batch', array(
'query' => array(
'op' => 'start',
'id' => $bid,
),
)),
$progress,
$message,
$start,
$eta,
);
}
$header = array(
'Batch ID',
'Progress',
'Message',
'Started',
'Finished/ETA',
);
return theme('table', array(
'header' => $header,
'rows' => $data,
));
}
/**
* State-based dispatcher for the batch processing page.
*/
function background_batch_page() {
if (!variable_get('background_batch_enabled', BACKGROUND_BATCH_ENABLED)) {
module_load_include('inc', 'system', 'system.admin');
return system_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_query("SELECT batch FROM {batch} WHERE bid = :bid", array(
':bid' => $id,
), array(
'target' => 'background_process',
))
->fetchColumn();
if (!$data) {
return drupal_not_found();
}
$batch =& batch_get();
$batch = unserialize($data);
// 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':
return _batch_finished();
default:
drupal_goto('admin/config/system/batch/overview');
}
}
/**
* Start a batch job in the background
*/
function _background_batch_initiate($page) {
require_once 'includes/batch.inc';
$batch =& batch_get();
$id = $batch['id'];
$handle = 'background_batch:' . $id;
$process = BackgroundProcess::loadByHandle($handle);
if ($process) {
if ($process
->getStatus() == BACKGROUND_PROCESS_STATUS_RUNNING) {
// If batch is already in progress, goto to the status page instead of starting it.
return;
}
// If process is locked and hasn't started for 10 seconds, then relaunch
$process
->reDispatch();
return;
}
// Let's start it!
try {
global $user;
$process = BackgroundProcess::lock($handle)
->setServiceGroup(variable_get('background_batch_default_service_group', variable_get('background_process_default_service_group', 'default')))
->setUID($user->uid)
->setProgress(0, $batch['sets'][0]['init_message'])
->setCallback('_background_batch_process', array(
$id,
))
->setOption('batch_lifespan', variable_get('background_batch_process_lifespan', BACKGROUND_BATCH_PROCESS_LIFESPAN))
->setShutdownCallback('_batch_shutdown')
->keepAlive()
->ensureServiceHost();
if ($process
->getDispatcher() == 'foreground') {
if ($page) {
drupal_set_message(t('Batch is using the "foreground" dispatcher. If you leave this page, the batch processing will stop/pause.'), 'warning');
return;
}
else {
// Lifespan defaults to 1 second when running in foreground ... just like core.
$process
->setOption('batch_lifespan', 1);
}
}
$process
->dispatch();
} catch (Exception $e) {
// Race condition? Job already running?
throw $e;
}
}
function _background_batch_page_start() {
_background_batch_initiate(TRUE);
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() {
require_once 'includes/batch.inc';
$batch = batch_get();
$id = $batch['id'];
$delay = variable_get('background_batch_delay', BACKGROUND_BATCH_DELAY) * 1000000;
$handle = 'background_batch:' . $id;
$process = BackgroundProcess::loadByHandle($handle);
if ($process && $process
->getDispatcher() == 'foreground') {
drupal_set_message(t('Batch is using the "foreground" dispatcher. If you leave this page, the batch processing will stop/pause.'), 'warning');
$delay = 1;
}
$current_set = _batch_current_set();
drupal_set_title($current_set['title'], PASS_THROUGH);
// Merge required query parameters for batch processing into those provided by
// batch_set() or hook_batch_alter().
$batch['url_options']['query']['id'] = $batch['id'];
$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'], $batch['url_options']);
$js_setting['batch']['delay'] = variable_get('background_batch_delay', BACKGROUND_BATCH_DELAY) * 1000000;
drupal_add_js($js_setting, 'setting');
drupal_add_library('background_batch', 'background-process.batch');
return '<div id="progress"></div>';
}
/**
* 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'];
drupal_save_session(FALSE);
// Get progress
$handle = 'background_batch:' . $id;
$process = BackgroundProcess::loadByHandle($handle);
if ($process) {
// If process is locked and hasn't started for 10 seconds, then relaunch
#$process->reDispatch();
}
elseif ($batch['sets'][$batch['current_set']]['count'] == 0) {
// The background process has self-destructed, and the batch job is done.
$percentage = 100;
$message = '';
}
else {
// Not running?
_background_batch_initiate(FALSE);
$percentage = t('N/A');
$message = '';
// Refetch progress information
$process = BackgroundProcess::loadByHandle($handle);
}
if ($process) {
$percentage = $process
->getProgress() * 100;
$message = $process
->getProgressMessage();
$eta = $process
->calculateETA();
// Check wether ETA information should be shown.
if (variable_get('background_batch_show_eta', BACKGROUND_BATCH_PROCESS_ETA)) {
$message = "ETA: " . ($eta ? format_date((int) $eta, 'large') : t('N/A')) . "<br/>{$message}";
}
else {
$js_setting['batch']['initMessage'] = $message;
}
// If process is locked and hasn't started for 10 seconds, then relaunch
$process
->reDispatch();
}
drupal_json_output(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'];
$current_set = _batch_current_set();
drupal_set_title($current_set['title'], PASS_THROUGH);
$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. a nonexistent
// 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'];
$fallback = theme('maintenance_page', array(
'content' => $fallback,
'show_messages' => 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;
// Perform actual processing.
// Get progress
$handle = 'background_batch:' . $id;
$process = BackgroundProcess::loadByHandle($handle);
if ($process) {
if ($process
->getDispatcher() == 'foreground') {
drupal_set_message(t('Batch is using the "foreground" dispatcher. If you leave this page, the batch processing will stop/pause.'), 'warning');
}
// If process is locked and hasn't started for 10 seconds, then relaunch
#$process->reDispatch();
}
elseif ($batch['sets'][$batch['current_set']]['count'] == 0) {
// The background process has self-destructed, and the batch job is done.
$percentage = 100;
$message = '';
}
else {
// Not running?
_background_batch_initiate(FALSE);
$percentage = t('N/A');
$message = '';
// Refetch progress information
$process = BackgroundProcess::loadByHandle($handle);
}
if ($process) {
$percentage = $process
->getProgress() * 100;
$message = $process
->getProgressMessage();
$eta = $process
->calculateETA();
// Check wether ETA information should be shown.
if (variable_get('background_batch_show_eta', BACKGROUND_BATCH_PROCESS_ETA)) {
$message = "ETA: " . format_date((int) $eta, 'large') . "<br/>{$message}";
}
else {
$js_setting['batch']['initMessage'] = $message;
}
// If process is locked and hasn't started for 10 seconds, then relaunch
$process
->reDispatch();
}
if ($percentage == 100) {
$new_op = 'finished';
}
// PHP did not die; remove the fallback output.
ob_end_clean();
// Merge required query parameters for batch processing into those provided by
// batch_set() or hook_batch_alter().
$batch['url_options']['query']['id'] = $batch['id'];
$batch['url_options']['query']['op'] = $new_op;
$url = url($batch['url'], $batch['url_options']);
$element = array(
'#tag' => 'meta',
'#attributes' => array(
'http-equiv' => 'Refresh',
'content' => '0; URL=' . $url,
),
);
drupal_add_html_head($element, 'batch_progress_meta_refresh');
return theme('progress_bar', array(
'percent' => sprintf("%.02f", $percentage),
'message' => $message,
));
}
Functions
Name | Description |
---|---|
background_batch_overview_page | Overview of current and recent batch jobs. |
background_batch_page | State-based dispatcher for the batch processing page. |
_background_batch_initiate | Start a batch job in the background |
_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 |