Skip to content

Instantly share code, notes, and snippets.

@mikeshiyan
Last active November 21, 2018 15:10
Show Gist options
  • Save mikeshiyan/cd9ffbcc1919120d536f48f30db11891 to your computer and use it in GitHub Desktop.
Save mikeshiyan/cd9ffbcc1919120d536f48f30db11891 to your computer and use it in GitHub Desktop.
Base class for batches for Drupal 7 (min PHP 7.1).
<?php
/**
* Provides a base class for all batches.
*/
abstract class BatchBase {
/**
* Batch machine name.
*
* @var string
*/
protected $name;
/**
* A safe, translated string to use as the title for the progress page.
*
* @var string
*/
protected $title;
/**
* Number between 0 and 1 - the completion level for the operation.
*
* @var float
*/
protected $opFinished;
/**
* A text message displayed in the progress page.
*
* @var string
*/
protected $opMessage;
/**
* Number of items processed in a current operation.
*
* @var int
*/
protected $opProgress;
/**
* An array to store data between iterations in each operation.
*
* @var array
*/
protected $opSandbox;
/**
* Total number of items to process in a current operation.
*
* @var int
*/
protected $opTotal;
/**
* Returns the batch definition array.
*
* @return array
* An associative array defining the batch.
*/
public function getBatchDefinition(): array {
$definition = [
'_object' => $this,
'finished' => [self::class, 'runFinished'],
];
if (isset($this->title)) {
$definition['title'] = $this->title;
}
$operations = $this->getOperations();
$op_wrapper = [self::class, 'runOperation'];
if (!$operations) {
throw new \LogicException('No operations in the batch.');
}
foreach ($operations as $operation) {
$definition['operations'][] = [$op_wrapper, [$operation]];
}
return $definition;
}
/**
* Returns a list of batch operations.
*
* @return string[]
* Array of method names. Must not be empty.
*/
abstract public function getOperations(): array;
/**
* Static wrapper around batch 'operations' callbacks.
*
* Implementations don't need to override this method unless really needed.
*
* @param string $method
* Operation method name in the implementing class.
* @param array $context
* Batch context array.
*/
public static function runOperation(string $method, array &$context): void {
// Move the object to another place, so it's accessible by the 'finished'
// wrapper.
if (!isset($context['results']['_object'])) {
$current_set = &_batch_current_set();
if (!isset($current_set['_object'])) {
throw new \RuntimeException('Missing object in the current batch set.');
}
$context['results']['_object'] = $current_set['_object'];
unset($current_set['_object']);
}
/** @var static $batch */
$batch = $context['results']['_object'];
$batch->opFinished = &$context['finished'];
$batch->opMessage = &$context['message'];
$context['sandbox'] += ['progress' => 0, 'total' => NULL];
$batch->opSandbox = &$context['sandbox'];
$batch->opProgress = &$context['sandbox']['progress'];
$batch->opTotal = &$context['sandbox']['total'];
$callback = [$batch, $method];
$callback();
if ($batch->opTotal) {
$batch->opFinished = $batch->opProgress / $batch->opTotal;
}
if ($batch->opMessage && is_array($batch->opMessage)) {
$args = array_values($batch->opMessage) + [1 => []];
$args[1] += [
'!progress' => $batch->opProgress,
'!total' => $batch->opTotal ?? 0,
];
$batch->opMessage = t(...$args);
if ($batch->name && $batch->opFinished >= 1) {
watchdog($batch->name, $args[0], $args[1], WATCHDOG_INFO);
}
}
}
/**
* Static wrapper around the batch 'finished' callback.
*
* Implementations don't need to override this method unless really needed.
*
* @param bool $success
* Whether no fatal PHP errors or exceptions were detected.
* @param array $results
* The array of results gathered by the batch processing.
* @param array $operations
* Batch operations definitions.
* @param string $elapsed
* A translated representation of the elapsed time.
*/
public static function runFinished(bool $success, array $results, array $operations, string $elapsed): void {
$callback = [$results['_object'], 'finished'];
$callback($success, $elapsed);
}
/**
* This is executed after the batch has completed.
*
* This should be overridden to perform any result massaging that may be
* needed.
*
* @param bool $success
* Whether no fatal PHP errors or exceptions were detected.
* @param string $elapsed
* A translated representation of the elapsed time.
*/
public function finished(bool $success, string $elapsed): void {}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment