cached_moderation_state-1.0.0-alpha2/src/Form/BatchUpdateForm.php
src/Form/BatchUpdateForm.php
<?php
namespace Drupal\cached_moderation_state\Form;
use Drupal\cached_moderation_state\BatchUpdateHandlerInterface;
use Drupal\cached_moderation_state\FieldConfigHandlerInterface;
use Drupal\Core\Entity\EntityTypeBundleInfoInterface;
use Drupal\Core\Form\FormBase;
use Drupal\Core\Form\FormStateInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;
/**
* Provides a form for batch updates to cached_moderation_state.
*
* 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 BatchUpdateForm extends FormBase {
/**
* The batch update handler service.
*
* @var \Drupal\cached_moderation_state\BatchUpdateHandlerInterface
*/
protected $batchUpdateHandler;
/**
* The entity type bundle information service.
*
* @var \Drupal\Core\Entity\EntityTypeBundleInfoInterface
*/
protected $entityTypeBundleInfo;
/**
* The field config handler service.
*
* @var \Drupal\cached_moderation_state\FieldConfigHandlerInterface
*/
protected $fieldConfigHandler;
/**
* Constructs a BatchUpdateForm object.
*
* @param \Drupal\cached_moderation_state\BatchUpdateHandlerInterface $batch_update_handler
* The batch update handler service.
* @param \Drupal\Core\Entity\EntityTypeBundleInfoInterface $entity_type_bundle_info
* The entity type bundle information service.
* @param \Drupal\cached_moderation_state\FieldConfigHandlerInterface $field_config_handler
* The field config handler service.
*/
public function __construct(BatchUpdateHandlerInterface $batch_update_handler, EntityTypeBundleInfoInterface $entity_type_bundle_info, FieldConfigHandlerInterface $field_config_handler) {
$this->batchUpdateHandler = $batch_update_handler;
$this->entityTypeBundleInfo = $entity_type_bundle_info;
$this->fieldConfigHandler = $field_config_handler;
}
/**
* {@inheritdoc}
*/
public static function create(ContainerInterface $container) {
return new static(
$container->get('cached_moderation_state.batch_update_handler'),
$container->get('entity_type.bundle.info'),
$container->get('cached_moderation_state.field_config_handler'),
);
}
/**
* {@inheritdoc}
*/
public function buildForm(array $form, FormStateInterface $form_state) {
$form['usage_info'] = ['#markup' => $this->t('<p>Use this form to update the cached moderation state for moderated bundles. It is recommended to update all moderated bundles immediately after installing this module for the first time, or if you recently moderated a bundle for which moderation state data already exists.</p>')];
$form['developer_info'] = ['#markup' => $this->t('<p>This module offers a batch update service that can be used to aid in writing <code>hook_post_update_NAME()</code> implementations. Check the project page for more information.</p>')];
$form['bundles'] = [
'#type' => 'select',
'#title' => $this->t('Select moderated bundles to update'),
'#description' => $this->t('Only moderated bundle options are listed here. If you believe a bundle option is missing, you should ensure that it is moderated.'),
'#options' => $this->getModeratedBundleOptions(),
'#multiple' => TRUE,
'#required' => TRUE,
];
$form['batch_size'] = [
'#type' => 'number',
'#title' => $this->t('Batch size'),
'#description' => $this->t('Enter the number of entities to update in each batch. An error may occur if the batch size is too large.'),
'#default_value' => 20,
'#required' => TRUE,
'#min' => 0,
'#step' => 1,
];
$form['only_uninitialized'] = [
'#type' => 'checkbox',
'#title' => $this->t('Only update entities with uninitialized fields'),
'#description' => $this->t('All entities are updated by default; however, when this option is enabled, entities will only be updated if they have an uninitialized cached moderation state field.'),
];
$form['actions']['#type'] = 'actions';
$form['actions']['submit'] = [
'#type' => 'submit',
'#value' => $this->t('Update cached moderation states'),
'#button_type' => 'primary',
];
return $form;
}
/**
* Get a list of moderated bundle options.
*
* @return array
* A list of moderated bundle options.
*/
protected function getModeratedBundleOptions() {
$results = [];
foreach ($this->fieldConfigHandler->getModeratedEntityTypes() as $entity_type) {
$bundle_info = $this->entityTypeBundleInfo->getBundleInfo($entity_type->id());
$entity_type_label = $entity_type->getLabel();
if (!\is_string($entity_type_label)) {
$entity_type_label = $entity_type_label->render();
}
foreach ($this->fieldConfigHandler->getModeratedBundlesForEntityType($entity_type) as $bundle) {
$results[$entity_type_label]["{$entity_type->id()}:{$bundle}"] = $bundle_info[$bundle]['label'];
}
\asort($results[$entity_type_label]);
}
\ksort($results);
return $results;
}
/**
* {@inheritdoc}
*/
public function getFormId() {
return 'cached_moderation_state_update_form';
}
/**
* 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, array &$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'] = $this->t('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, array &$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) {
$this->messenger()->addStatus($this->t('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'] = $this->t('Updated @progress of @max entities.', [
'@max' => $context['sandbox']['max'],
'@progress' => $context['sandbox']['progress'],
]);
// Display the final status message at the destination upon completion.
if ($context['finished'] >= 1.0) {
$this->messenger()->addStatus($context['message']);
}
}
/**
* {@inheritdoc}
*/
public function submitForm(array &$form, FormStateInterface $form_state) {
$batch_size = \intval($form_state->getValue('batch_size'));
$bundles = $form_state->getValue('bundles');
$only_uninitialized = !empty($form_state->getValue('only_uninitialized'));
$bundles_by_entity_type_id = [];
foreach ($bundles as $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([
'title' => $this->t('Updating cached moderation states'),
'init_message' => $this->t('Collecting entities to update...'),
'operations' => $operations,
]);
}
}
