Skip to content

Instantly share code, notes, and snippets.

@msankhala
Created November 25, 2022 12:49
Show Gist options
  • Save msankhala/2eff08854d83804ec045656fe14ea1e6 to your computer and use it in GitHub Desktop.
Save msankhala/2eff08854d83804ec045656fe14ea1e6 to your computer and use it in GitHub Desktop.
Drupal 9 batch api example using BatchBuilder
<?php
namespace Drupal\miax_content\Command;
use Drupal\Core\Batch\BatchBuilder;
use Drupal\Core\Entity\EntityTypeManagerInterface;
use Drupal\Core\Logger\LoggerChannelFactoryInterface;
use Drupal\Core\StringTranslation\StringTranslationTrait;
use Drush\Commands\DrushCommands;
use Drupal\miax_content\Services\DeleteFeedsBatchService;
/**
* A Drush commandfile.
*
* In addition to this file, you need a drush.services.yml
* in root of your module, and a composer.json file that provides the name
* of the services file to use.
*
* See these files for an example of injecting Drupal services:
* - http://cgit.drupalcode.org/devel/tree/src/Commands/DevelCommands.php
* - http://cgit.drupalcode.org/devel/tree/drush.services.yml
*/
class DeleteFeeds extends DrushCommands {
use StringTranslationTrait;
/**
* Entity type service.
*
* @var \Drupal\Core\Entity\EntityTypeManagerInterface
*/
private $entityTypeManager;
/**
* Logger service.
*
* @var \Drupal\Core\Logger\LoggerChannelFactoryInterface
*/
private $loggerChannelFactory;
/**
* Feeds batch service.
*
* @var \Drupal\miax_content\Services\DeleteFeedsBatchService
*/
private $deleteFeedsBatchService;
/**
* Constructs a new UpdateVideosStatsController object.
*
* @param \Drupal\Core\Entity\EntityTypeManagerInterface $entityTypeManager
* Entity type service.
* @param \Drupal\Core\Logger\LoggerChannelFactoryInterface $loggerChannelFactory
* Logger service.
* @param \Drupal\miax_content\Services\FeedsBatchService $feedsBatchService
* Feeds batch service.
*/
public function __construct(EntityTypeManagerInterface $entityTypeManager, LoggerChannelFactoryInterface $loggerChannelFactory, DeleteFeedsBatchService $deleteFeedsBatchService) {
$this->entityTypeManager = $entityTypeManager;
$this->loggerChannelFactory = $loggerChannelFactory;
$this->deleteFeedsBatchService = $deleteFeedsBatchService;
}
/**
* Delete the feeds of a given type.
*
* @param string $type
* Type of feed to update
* Argument provided to the drush command.
*
* @command test:feeds:delete-feeds
* @aliases test-fdel
*
* @usage test:feeds:delete-feeds foo
* foo is the type of feeds to delete.
*/
public function deleteFeed($type = '') {
// Ask for confirmation as this operation can not be undone.
$this->io()->warning(dt('This operation can not be undone. Are you sure you want to delete all feeds of type @type?', ['@type' => $type]));
$confirm = $this->io()->confirm(dt('Are you sure you want to delete all feeds of type @type?', ['@type' => $type]));
if (!$confirm) {
return;
}
// 1. Log the start of the script.
$this->loggerChannelFactory->get('miax_content')->info('Feeds @type delete batch operations start', ['@type' => $type]);
// Check the type of node given as argument, if not, set article as default.
if (strlen($type) == 0) {
print "No type of feed given, please provide a type of feed to delete.";
return;
}
// 2. Retrieve all feeds of this type.
try {
$storage = $this->entityTypeManager->getStorage('feeds_feed');
$query = $storage->getQuery()
->condition('type', $type);
// ->range(0, 1);
$fids = $query->execute();
}
catch (\Exception $e) {
$this->output()->writeln($e);
$this->loggerChannelFactory->get('miax_content')->warning('Error found @e', ['@e' => $e]);
}
// 3. Create the operations array for the batch.
$batchBuilder = new BatchBuilder();
// $operations = [];
$numOperations = 0;
$batchId = 1;
if (!empty($fids)) {
foreach ($fids as $fid) {
// Prepare the operation. Here we could do other operations on nodes.
$this->output()->writeln($this->t('Preparing batch: ') . $batchId);
$batchBuilder->addOperation([$this->deleteFeedsBatchService, 'deleteFeed'], [
$batchId,
$fid,
]);
$batchId++;
$numOperations++;
}
}
else {
$this->logger->warning($this->t('No feeds of this type @type', ['@type' => $type]));
}
// 4. Create the batch.
$batchBuilder
->setTitle($this->t('Deleting @num node(s)', ['@num' => $numOperations]))
->setFinishCallback([$this->deleteFeedsBatchService, 'deleteFeedFinished'])
->setErrorMessage($this->t('Batch has encountered an error'));
// 5. Add batch operations as new batch sets.
batch_set($batchBuilder->toArray());
// 6. Process the batch sets.
drush_backend_batch_process();
// 6. Show some information.
$this->logger()->notice($this->t("Batch operations end."));
// 7. Log some information.
$this->loggerChannelFactory->get('miax_content')->info($this->t('Delete batch operations end.'));
}
}
<?php
namespace Drupal\miax_content\Services;
use Drupal\Core\StringTranslation\StringTranslationTrait;
use Drupal\Core\DependencyInjection\DependencySerializationTrait;
/**
* Class DeleteFeedsBatchService provides the batch processing delete for feeds.
*/
class DeleteFeedsBatchService {
use StringTranslationTrait;
use DependencySerializationTrait;
/**
* Batch process callback.
*
* @param int $id
* Id of the batch.
* @param string $fid
* Feed id.
* @param object $context
* Context for operations.
*/
public function deleteFeed($id, $fid, &$context) {
// Simulate long process by waiting 100 microseconds.
// usleep(100);
// Delete the feed.
$feed = \Drupal::entityTypeManager()->getStorage('feeds_feed')->load($fid);
// print($feed->label());
// die;
// $feed->delete();
// Store some results for post-processing in the 'finished' callback.
// The contents of 'results' will be available as $results in the
// 'finished' function (in this example, batch_example_finished()).
$context['results'][] = $id;
$context['results'][] = $feed->label();
// Optional message displayed under the progressbar.
$context['message'] = $this->t('Running Batch "@id" @fid',
['@id' => $id, '@fid' => $feed->label()]
);
}
/**
* Batch Finished callback.
*
* @param bool $success
* Success of the operation.
* @param array $results
* Array of results for post processing.
* @param array $operations
* Array of operations.
*/
public function deleteFeedFinished($success, array $results, array $operations) {
$messenger = \Drupal::messenger();
if ($success) {
// Here we could do something meaningful with the results.
// We just display the number of nodes we processed...
$messenger->addMessage($this->t('@count results processed.', ['@count' => count($results)]));
}
else {
// An error occurred.
// $operations contains the operations that remained unprocessed.
$error_operation = reset($operations);
$messenger->addMessage(
$this->t('An error occurred while processing @operation with arguments : @args',
[
'@operation' => $error_operation[0],
'@args' => print_r($error_operation[0], TRUE),
]
)
);
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment