Skip to content

Commit

Permalink
Added batch service and drush command
Browse files Browse the repository at this point in the history
  • Loading branch information
yeniatencio committed Nov 16, 2024
1 parent 65f0500 commit b0c5b69
Show file tree
Hide file tree
Showing 5 changed files with 367 additions and 0 deletions.
9 changes: 9 additions & 0 deletions drush.services.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,13 @@ services:
arguments: ['@keyvalue']
tags:
- { name: drush.command }
tide_core.batch_command:
class: \Drupal\tide_core\Commands\TideParagraphRevisionsCleanUp
tags:
- { name: drush.command }
arguments:
- '@entity_type.manager'
- '@logger.factory'
- '@tide_core.batch'


187 changes: 187 additions & 0 deletions src/Batch/BatchService.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,187 @@
<?php

namespace Drupal\tide_core\Batch;

use Drupal\Core\Entity\EntityTypeManagerInterface;
use Drupal\Core\Logger\LoggerChannelFactoryInterface;
use Drupal\Core\Batch\BatchBuilder;
use Drupal\Core\StringTranslation\StringTranslationTrait;

/**
* Defines a process and finish method for a batch.
*/
class BatchService implements BatchServiceInterface {

use StringTranslationTrait;

/**
* Entity type service.
*
* @var \Drupal\Core\Entity\EntityTypeManagerInterface
*/
protected $entityTypeManager;


/**
* The logger channel.
*
* @var \Drupal\Core\Logger\LoggerChannelInterface
*/
protected $loggerChannel;

/**
* Constructor.
*
* @param \Drupal\Core\Entity\EntityTypeManagerInterface $entityTypeManager
* Entity type service.
* @param \Drupal\Core\Logger\LoggerChannelFactoryInterface $loggerFactory
* The logger factory.
*/
public function __construct(EntityTypeManagerInterface $entityTypeManager, LoggerChannelFactoryInterface $loggerFactory) {
$this->entityTypeManager = $entityTypeManager;
$this->loggerChannel = $loggerFactory->get('tide_core');
}

/**
* {@inheritdoc}
*/
public function create(int $batchSize = 100, array $data = []): void {
if (empty($data)) {
$this->loggerChannel->notice('There is no data to process.');
}
else {
$batch = new BatchBuilder();
$batch->setTitle($this->t('Running batch process.'))
->setFinishCallback([self::class, 'batchFinished'])
->setInitMessage('Commencing')
->setProgressMessage('Processing...')
->setErrorMessage('An error occurred during processing.');

// Create chunks of all items.
$chunks = array_chunk($data, $batchSize);

// Process each chunk in the array.
foreach ($chunks as $id => $chunk) {
$args = [
$id,
$chunk,
];
$batch->addOperation([BatchService::class, 'batchProcess'], $args);
}
batch_set($batch->toArray());

$this->loggerChannel->notice('Batch created.');
drush_backend_batch_process();

// Finish.
$this->loggerChannel->notice('Batch operations end.');
}
}

/**
* {@inheritdoc}
*/
public static function batchProcess(int $batchId, array $chunk, array &$context): void {
if (!isset($context['sandbox']['progress'])) {
$context['sandbox']['progress'] = 0;
$context['sandbox']['max'] = 1000;
}
if (!isset($context['results']['updated'])) {
$context['results']['updated'] = 0;
$context['results']['skipped'] = 0;
$context['results']['failed'] = 0;
$context['results']['progress'] = 0;
$context['results']['process'] = 'Batch processing completed';
}

// Keep track of progress.
$context['results']['progress'] += count($chunk);

// Message above progress bar.
$context['message'] = t('Processing batch #@batch_id, batch size @batch_size for total @count items.', [
'@batch_id' => number_format($batchId),
'@batch_size' => number_format(count($chunk)),
'@count' => number_format($context['sandbox']['max']),
]);

foreach ($chunk as $dataProcessed) {
$result = self::cleanRevisions($dataProcessed['revision_list']);
switch ($result) {
case 1:
$context['results']['updated']++;
break;

case 0:
$context['results']['skipped']++;
break;
}
}
}

/**
* {@inheritdoc}
*/
public static function batchFinished(bool $success, array $results, array $operations, string $elapsed): void {
// Grab the messenger service, this will be needed if the batch was a
// success or a failure.
$messenger = \Drupal::messenger();
if ($success) {
// The success variable was true, which indicates that the batch process
// was successful (i.e. no errors occurred).
// Show success message to the user.
$messenger->addMessage(t('@process processed @count, skipped @skipped, updated @updated, failed @failed in @elapsed.', [
'@process' => $results['process'],
'@count' => $results['progress'],
'@skipped' => $results['skipped'],
'@updated' => $results['updated'],
'@failed' => $results['failed'],
'@elapsed' => $elapsed,
]));
// Log the batch success.
\Drupal::logger('batch_form_example')->info(
'@process processed @count, skipped @skipped, updated @updated, failed @failed in @elapsed.',
[
'@process' => $results['process'],
'@count' => $results['progress'],
'@skipped' => $results['skipped'],
'@updated' => $results['updated'],
'@failed' => $results['failed'],
'@elapsed' => $elapsed,
]
);
} else {
// An error occurred. $operations contains the operations that remained
// unprocessed. Pick the last operation and report on what happened.
$error_operation = reset($operations);
if ($error_operation) {
$message = t('An error occurred while processing %error_operation with arguments: @arguments', [
'%error_operation' => print_r($error_operation[0]),
'@arguments' => print_r($error_operation[1], TRUE),
]);
$messenger->addError($message);
}
}
}

/**
* {@inheritdoc}
*/
public static function cleanRevisions(array $revisionIds): int {
$storage = \Drupal::entityTypeManager()->getStorage('node');
/** @var \Drupal\Core\Entity\RevisionableStorageInterface $storage */
if (!empty($revisionIds)) {
if (count($revisionIds)) {
return 2;
}

foreach ($revisionIds as $revisionId) {
$storage->deleteRevision($revisionId);
}

return 1;
}
else {
return 0;
}
}
}
53 changes: 53 additions & 0 deletions src/Batch/BatchServiceInterface.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
<?php

namespace Drupal\tide_core\Batch;

/**
* Defines batch service interface.
*/
interface BatchServiceInterface {

/**
* Create batch.
*
* @param int $batchSize
* Batch size.
* @param array $data
* The data to process.
*/
public function create(int $batchSize, array $data): void;

/**
* Batch operation callback.
*
* @param int $batchId
* The batch ID.
* @param array $batch
* Information about batch (items, size, total, ...).
* @param array $context
* Batch context.
*/
public static function batchProcess(int $batchId, array $batch, array &$context): void;

/**
* Handle batch completion.
*
* @param bool $success
* TRUE if all batch API tasks were completed successfully.
* @param array $results
* An results array from the batch processing operations.
* @param array $operations
* A list of the operations that had not been completed.
* @param string $elapsed
* Batch.inc kindly provides the elapsed processing time in seconds.
*/
public static function batchFinished(bool $success, array $results, array $operations, string $elapsed): void;

/**
* Delete node revisions.
*
* @param array $revisionIds
* The list of revision IDs.
*/
public static function cleanRevisions(array $revisionIds): int;
}
113 changes: 113 additions & 0 deletions src/Commands/TideParagraphRevisionsCleanUp.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
<?php

namespace Drupal\tide_core\Commands;

use Drupal\Core\Entity\EntityTypeManagerInterface;
use Drupal\Core\Logger\LoggerChannelFactoryInterface;
use Drush\Commands\DrushCommands;
use Drupal\tide_core\Batch\BatchServiceInterface;

/**
* Drush command.
*/
class TideParagraphRevisionsCleanUp extends DrushCommands {

/**
* Entity type service.
*
* @var \Drupal\Core\Entity\EntityTypeManagerInterface
*/
protected $entityTypeManager;

/**
* The logger channel.
*
* @var \Drupal\Core\Logger\LoggerChannelInterface
*/
protected $loggerChannel;

/**
* The batch service.
*
* @var \Drupal\modulename\BatchServiceInterface
*/
protected $batch;

/**
* Constructor.
*
* @param \Drupal\Core\Entity\EntityTypeManagerInterface $entityTypeManager
* Entity type service.
* @param \Drupal\Core\Logger\LoggerChannelFactoryInterface $loggerFactory
* Logger service.
* @param \Drupal\modulename\BatchServiceInterface $batch
* The batch service.
*/
public function __construct(EntityTypeManagerInterface $entityTypeManager, LoggerChannelFactoryInterface $loggerFactory, BatchServiceInterface $batch) {
$this->entityTypeManager = $entityTypeManager;
$this->loggerChannel = $loggerFactory->get('tide_core');
$this->batch = $batch;
}

/**
* Get node revisions per node.
*
* @return array
* A list of nodes with their corresponding node revisions.
*/
public function getNodeRevisions(string $timeAgo) {
$nodeRevisions = [];
$storage = $this->entityTypeManager->getStorage('node');

try {
$query = $storage->getQuery()
->condition('status', '1')
->condition('created', $timeAgo, '<')
->range(0, 500)
->accessCheck(FALSE);
$nids = $query->execute();

if (!empty($nids)) {
foreach($nids as $vid => $nid) {
$node = \Drupal::entityTypeManager()->getStorage('node')->load($nid);
$revisionIds = $storage->revisionIds($node);
$latestRevisionId = $storage->getLatestRevisionId($nid);
$nodeRevisions[$nid] = [
'revision_list' => $revisionIds,
'current_revision' => $latestRevisionId,
];
}
}
} catch (\Exception $e) {
$this->output()->writeln($e);
$this->loggerChannel->warning('Error found @e', ['@e' => $e]);
}

return $nodeRevisions;
}

/**
* Delete paragraphs revisions.
*
* @command tide_core:paragraph-revisions-cleanup
* @aliases dpr
*
* @usage tide_core:paragraph-revisions-cleanup --batch=150 --older='30 days'
*/
public function deleteParagraphRevision(array $options = ['batch' => 10, 'older' => '30 days']) {
$timeAgo = strtotime('-' . $options['older']);
$data = $this->getNodeRevisions($timeAgo);
if (!empty($data)) {
foreach ($data as $key => $value) {
foreach($value['revision_list'] as $krid => $rid) {
if ($value['current_revision'] == $rid) {
unset($data[$key]['revision_list'][$krid]);
}
}
unset($data[$key]['current_revision']);
}
}

$this->batch->create($options['batch'], $data);
}
}
5 changes: 5 additions & 0 deletions tide_core.services.yml
Original file line number Diff line number Diff line change
Expand Up @@ -35,3 +35,8 @@ services:
- '@logger.factory'
- '@file_system'
- '@monitoring.sensor_runner'
tide_core.batch:
class: 'Drupal\tide_core\Batch\BatchService'
arguments:
- '@entity_type.manager'
- '@logger.factory'

0 comments on commit b0c5b69

Please sign in to comment.