cached_moderation_state-1.0.0-alpha2/src/BatchUpdateHandler.php

src/BatchUpdateHandler.php
<?php

namespace Drupal\cached_moderation_state;

use Drupal\Component\Plugin\Exception\InvalidPluginDefinitionException;
use Drupal\Component\Plugin\Exception\PluginNotFoundException;
use Drupal\Core\DependencyInjection\ContainerInjectionInterface;
use Drupal\Core\DependencyInjection\DependencySerializationTrait;
use Drupal\Core\Entity\EntityInterface;
use Drupal\Core\Entity\EntityTypeManagerInterface;
use Drupal\Core\Entity\RevisionableStorageInterface;
use Drupal\Core\Entity\SynchronizableInterface;
use Drupal\Core\Logger\LoggerChannelFactoryInterface;
use Drupal\Core\Logger\LoggerChannelInterface;
use Drupal\Core\Utility\Error;
use Symfony\Component\DependencyInjection\ContainerInterface;

/**
 * Facilitates batch updates to 'cached_moderation_state' for existing content.
 *
 * 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 BatchUpdateHandler implements BatchUpdateHandlerInterface, ContainerInjectionInterface {

  use DependencySerializationTrait;

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

  /**
   * Tracks whether an entity update caused by this service is in progress.
   *
   * This flag cannot be an instance property because of an unexpected issue
   * that occurs when accessing it while running via Drush; the property would
   * seem to always be FALSE from the perspective of `hook_entity_presave()`,
   * even after being set to TRUE before updating an entity.
   *
   * @var bool
   */
  protected static $entityUpdateInProgress = FALSE;

  /**
   * The logger for this class.
   *
   * @var \Drupal\Core\Logger\LoggerChannelInterface
   */
  protected $logger = NULL;

  /**
   * The logger factory service.
   *
   * @var \Drupal\Core\Logger\LoggerChannelFactoryInterface
   */
  protected $loggerFactory;

  /**
   * Constructs a BatchUpdateHandler object.
   *
   * @param \Drupal\Core\Entity\EntityTypeManagerInterface $entity_type_manager
   *   The entity type manager service.
   * @param \Drupal\Core\Logger\LoggerChannelFactoryInterface|null $logger_factory
   *   The logger factory service.
   */
  public function __construct(EntityTypeManagerInterface $entity_type_manager, ?LoggerChannelFactoryInterface $logger_factory = NULL) {
    if (!isset($logger_factory)) {
      @\trigger_error('Calling ' . __METHOD__ . '() without the $logger_factory argument is deprecated in cached_moderation_state:1.1.0 and will be required in cached_moderation_state:2.0.0. See https://www.drupal.org/node/3431365', \E_USER_DEPRECATED);

      /**
       * @var \Drupal\Core\Logger\LoggerChannelFactoryInterface
       */
      // @phpcs:disable DrupalPractice.Objects.GlobalDrupal.GlobalDrupal
      // @phpstan-ignore-next-line
      $logger_factory = \Drupal::service('logger.factory');
      // @phpcs:enable
    }

    $this->entityTypeManager = $entity_type_manager;
    $this->loggerFactory = $logger_factory;
  }

  /**
   * {@inheritdoc}
   */
  public static function create(ContainerInterface $container) {
    return new static(
      $container->get('entity_type.manager'),
      $container->get('logger.factory'),
    );
  }

  /**
   * {@inheritdoc}
   */
  public function getEntitiesForEntityType(string $entity_type_id, array $bundles = [], bool $only_uninitialized = FALSE) {
    $results = [];

    try {
      $entity_type = $this->entityTypeManager->getDefinition($entity_type_id);
      $storage = $this->entityTypeManager->getStorage($entity_type_id);

      $query = $storage->getQuery();
      $query->accessCheck(FALSE);

      // If the entity type is bundleable, filter by the supplied bundles.
      if (!empty($bundles) && $bundle_key = $entity_type->getKey('bundle')) {
        $query->condition($bundle_key, $bundles, 'IN');
      }

      // If the entity type is revisionable, query all entity revisions.
      if ($entity_type->isRevisionable()) {
        // The query results will now represent revision identifiers instead of
        // plain entity identifiers. A companion condition in ::loadEntities()
        // will ensure that the appropriate method is used to load the
        // corresponding entities.
        $query->allRevisions();
      }

      // Filter the result set to only contain results with uninitialized
      // 'cached_moderation_state' fields if desired.
      if ($only_uninitialized) {
        $query->notExists('cached_moderation_state.updated');
      }

      $results = $query->execute();

      // The entity query will produce array elements whose value represents a
      // plain entity identifier, and whose key represents a revision
      // identifier. The next line extracts the appropriate identifiers.
      $results = $entity_type->isRevisionable() ? \array_keys($results) : \array_values($results);

      // Prefix all of the resulting identifiers with their entity type.
      $results = \array_map(fn ($id) => "{$entity_type_id}:{$id}", $results);

      \sort($results, \SORT_NATURAL);
    }
    catch (InvalidPluginDefinitionException | PluginNotFoundException) {
    }

    return $results;
  }

  /**
   * {@inheritdoc}
   */
  public function isEntityUpdateInProgress(): bool {
    return self::$entityUpdateInProgress;
  }

  /**
   * {@inheritdoc}
   */
  public function loadEntities(array $entity_ids) {
    $entities_by_entity_type_id = [];
    foreach ($entity_ids as $entity_id) {
      // Ignore invalid entity identifiers.
      if (!\is_string($entity_id) || \strpos($entity_id, ':') === FALSE) {
        continue;
      }

      // Extract the entity type and entity identifier components.
      [$entity_type_id, $entity_id] = \explode(':', $entity_id, 2);

      // Group the entity identifier by its entity type.
      $entities_by_entity_type_id[$entity_type_id][$entity_id] = $entity_id;
    }

    $results = [];
    foreach ($entities_by_entity_type_id as $entity_type_id => $entity_ids) {
      try {
        $entity_type = $this->entityTypeManager->getDefinition($entity_type_id);
        $storage = $this->entityTypeManager->getStorage($entity_type_id);

        if ($entity_type->isRevisionable() && $storage instanceof RevisionableStorageInterface) {
          // We're working with revision identifiers. Load the entities by their
          // revision identifiers.
          $entities = $storage->loadMultipleRevisions($entity_ids);
        }
        else {
          // Load the entities by their regular identifiers.
          $entities = $storage->loadMultiple($entity_ids);
        }

        foreach ($entities as $entity) {
          // Add this entity to the resulting list of loaded entities.
          $results[] = $entity;
        }
      }
      catch (InvalidPluginDefinitionException | PluginNotFoundException) {
      }
    }

    return $results;
  }

  /**
   * Get the logger for this class.
   *
   * @return \Drupal\Core\Logger\LoggerChannelInterface
   *   The logger for this class.
   */
  protected function logger(): LoggerChannelInterface {
    if (!isset($this->logger)) {
      $this->logger = $this->loggerFactory->get('cached_moderation_state');
    }

    return $this->logger;
  }

  /**
   * {@inheritdoc}
   */
  public function updateEntities(array &$entity_ids, int $batch_size = 0): int {
    if ($batch_size < 0) {
      throw new \InvalidArgumentException('$batch_size is invalid');
    }

    // Batch the supplied list of entity identifiers.
    $entity_ids_batch = $batch_size ? \array_slice($entity_ids, 0, $batch_size) : $entity_ids;

    // Attempt to load the batch of entities, then advance the full entity list.
    $entities = $this->loadEntities($entity_ids_batch);
    $entity_ids = $batch_size ? \array_slice($entity_ids, $batch_size) : [];

    // Process the loaded batch of entities.
    foreach ($entities as $entity) {
      $this->updateEntity($entity);
    }

    return \count($entity_ids_batch);
  }

  /**
   * {@inheritdoc}
   */
  public function updateEntity(EntityInterface $entity): void {
    try {
      self::$entityUpdateInProgress = TRUE;

      // Update the entity's synchronization flag if applicable.
      //
      // Setting this flag to TRUE may prevent some entity CRUD hook
      // implementations from running, which is ideal to avoid producing
      // potentially unwanted side effects.
      if ($entity instanceof SynchronizableInterface) {
        $entity->setSyncing(TRUE);
      }

      $entity->save();
    }
    catch (\Exception $e) {
      Error::logException($this->logger(), $e);
    }
    finally {
      self::$entityUpdateInProgress = FALSE;

      if ($entity instanceof SynchronizableInterface) {
        $entity->setSyncing(FALSE);
      }
    }
  }

}

Главная | Обратная связь

drupal hosting | друпал хостинг | it patrol .inc