cached_moderation_state-1.0.0-alpha2/src/Commands/CachedModerationStateCommands.php
src/Commands/CachedModerationStateCommands.php
<?php
namespace Drupal\cached_moderation_state\Commands;
use Drupal\cached_moderation_state\BatchUpdateHandlerInterface;
use Drupal\cached_moderation_state\FieldConfigHandlerInterface;
use Drush\Commands\DrushCommands;
/**
* Drush command implementations for this module.
*
* Copyright (C) 2022 Library Solutions, LLC (et al.).
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*/
class CachedModerationStateCommands extends DrushCommands {
/**
* The batch update handler service.
*
* @var \Drupal\cached_moderation_state\BatchUpdateHandlerInterface
*/
protected $batchUpdateHandler;
/**
* The field config handler service.
*
* @var \Drupal\cached_moderation_state\FieldConfigHandlerInterface
*/
protected $fieldConfigHandler;
/**
* Constructs a CachedModerationStateCommands object.
*
* @param \Drupal\cached_moderation_state\BatchUpdateHandlerInterface $batch_update_handler
* The batch update handler service.
* @param \Drupal\cached_moderation_state\FieldConfigHandlerInterface $field_config_handler
* The field config handler service.
*/
public function __construct(BatchUpdateHandlerInterface $batch_update_handler, FieldConfigHandlerInterface $field_config_handler) {
$this->batchUpdateHandler = $batch_update_handler;
$this->fieldConfigHandler = $field_config_handler;
}
/**
* List all moderated bundles.
*
* @command cached-moderation-state:list-moderated-bundles
*
* @option format
* The output format to use.
*/
public function listModeratedBundles(array $options = ['format' => 'csv']) {
$results = [];
foreach ($this->fieldConfigHandler->getModeratedEntityTypes() as $entity_type) {
foreach ($this->fieldConfigHandler->getModeratedBundlesForEntityType($entity_type) as $bundle) {
$results[] = "{$entity_type->id()}:{$bundle}";
}
}
return $results;
}
/**
* Initialize the batch operation with a set of entity identifiers.
*
* @param string $entity_type_id
* The entity type from which the batch operation should be initialized.
* @param string[] $bundles
* The bundles from which the batch operation should be initialized.
* @param bool $only_uninitialized
* TRUE to only query entities with uninitialized fields.
* @param array $context
* Context information for the batch operation.
*/
public function runBatchInitializeStep(string $entity_type_id, array $bundles, bool $only_uninitialized, &$context): void {
$entity_ids = $this->batchUpdateHandler->getEntitiesForEntityType($entity_type_id, $bundles, $only_uninitialized);
foreach ($entity_ids as $entity_id) {
$context['results'][] = $entity_id;
}
$context['message'] = \dt('Collected @count entities.', [
'@count' => \count($context['results']),
]);
}
/**
* Process the list of entities using the specified batch size.
*
* @param int $batch_size
* The number of entities to process in a single run.
* @param array $context
* Context information for the batch operation.
*/
public function runBatchProcessStep(int $batch_size, &$context): void {
// Initialize the sandbox before the first batch.
if (empty($context['sandbox'])) {
$context['sandbox']['max'] = \count($context['results']);
$context['sandbox']['progress'] = 0;
}
// Exit immediately if there is no work to be done.
if ($context['sandbox']['max'] === 0) {
$context['message'] = \dt('No entities required updates.');
$context['finished'] = 1.0;
return;
}
// Process a batch of entities, incrementing the progress.
$context['sandbox']['progress'] += $this->batchUpdateHandler->updateEntities($context['results'], $batch_size);
// Update the progress indicator and status message.
$context['finished'] = $context['sandbox']['progress'] / $context['sandbox']['max'];
$context['message'] = \dt('Updated @progress of @max entities.', [
'@max' => $context['sandbox']['max'],
'@progress' => $context['sandbox']['progress'],
]);
}
/**
* Manually synchronize 'cached_moderation_state' field instances.
*
* This method will create or delete 'cached_moderation_state' field instances
* as needed to establish a one-to-one relationship of field instances to
* moderated entity bundles.
*
* This process is done automatically on module installation and every time a
* workflow is updated. Only use this command if something goes awry.
*
* @command cached-moderation-state:sync-fields
*/
public function syncFields() {
$this->fieldConfigHandler->sync();
$this->logger()->success(\dt("Synchronized 'cached_moderation_state' field instances."));
}
/**
* Updates 'cached_moderation_state' for the supplied bundles.
*
* @param string $bundles
* A comma-separated list of ENTITY_TYPE_ID:BUNDLE strings to update.
* @param array $options
* An array of additional options for this command.
*
* @command cached-moderation-state:update
*
* @option batch-size
* The number of entities to process at one time.
* @option only-uninitialized
* Only update entities with uninitialized fields.
*/
public function update(string $bundles = '', array $options = ['batch-size' => 20, 'only-uninitialized' => FALSE]): void {
if (empty($bundles)) {
throw new \RuntimeException(\dt('A list of bundles to update is required'));
}
$batch_size = $options['batch-size'];
$only_uninitialized = $options['only-uninitialized'];
$bundles_by_entity_type_id = [];
foreach (\preg_split('/,\\s*/', $bundles) as $bundle) {
if (\strpos($bundle, ':') === FALSE) {
throw new \InvalidArgumentException(\dt("Invalid bundle '{$bundle}'; bundles must follow the format ENTITY_TYPE_ID:BUNDLE"));
}
[$entity_type_id, $bundle] = \explode(':', $bundle, 2);
$bundles_by_entity_type_id[$entity_type_id][$bundle] = $bundle;
}
foreach ($bundles_by_entity_type_id as $entity_type_id => $bundles) {
// Add an operation to populate entities from this bundle.
$operations[] = [
[$this, 'runBatchInitializeStep'],
[
$entity_type_id,
$bundles,
$only_uninitialized,
],
];
}
// Add the final operation step to process the resulting entities.
$operations[] = [
[$this, 'runBatchProcessStep'],
[
$batch_size,
],
];
\batch_set(['operations' => $operations]);
\drush_backend_batch_process();
}
/**
* Updates all entities with a 'cached_moderation_state' field.
*
* @param array $options
* An array of additional options for this command.
*
* @command cached-moderation-state:update-all
*
* @option batch-size
* The number of entities to process at one time.
* @option only-uninitialized
* Only update entities with uninitialized fields.
*/
public function updateAll(array $options = ['batch-size' => 20, 'only-uninitialized' => FALSE]) {
$bundles = \implode(',', $this->listModeratedBundles());
$this->update($bundles, $options);
}
}
