You are here

class EntityUpdateManager in Entity Usage 8.3

Same name and namespace in other branches
  1. 8 src/EntityUpdateManager.php \Drupal\entity_usage\EntityUpdateManager
  2. 8.2 src/EntityUpdateManager.php \Drupal\entity_usage\EntityUpdateManager

Class EntityUpdateManager.

@package Drupal\entity_usage

Hierarchy

Expanded class hierarchy of EntityUpdateManager

1 file declares its use of EntityUpdateManager
entity_usage.module in ./entity_usage.module
Contains entity_usage.module.
1 string reference to 'EntityUpdateManager'
entity_usage.services.yml in ./entity_usage.services.yml
entity_usage.services.yml
1 service uses EntityUpdateManager
entity_usage.entity_update_manager in ./entity_usage.services.yml
Drupal\entity_usage\EntityUpdateManager

File

src/EntityUpdateManager.php, line 15

Namespace

Drupal\entity_usage
View source
class EntityUpdateManager implements DestructableInterface {

  /**
   * Describes an insert source operation.
   */
  const OPERATION_INSERT = 'insert';

  /**
   * Describes an update source operation.
   */
  const OPERATION_UPDATE = 'update';

  /**
   * Describes a full deletion of a source operation.
   */
  const OPERATION_ENTITY_DELETE = 'entity_delete';

  /**
   * Describes the deletion of a single source revision.
   */
  const OPERATION_REVISION_DELETE = 'revision_delete';

  /**
   * Describes the deletion of a single translation of a source entity.
   */
  const OPERATION_TRANSLATION_DELETE = 'translation_delete';

  /**
   * The top-level entities being tracked during a given request.
   *
   * This is an indexed array where values are arrays with values:
   *  - entity: The entity being created/updated/deleted.
   *  - operation: The operation being performed on the entity.
   *  - original_entity: The original entity, if this is an update operation.
   *
   * @var array
   */
  protected $topLevelSources = [];

  /**
   * The usage track service.
   *
   * @var \Drupal\entity_usage\EntityUsage
   */
  protected $usageService;

  /**
   * The usage track manager.
   *
   * @var \Drupal\entity_usage\EntityUsageTrackManager
   */
  protected $trackManager;

  /**
   * The config factory.
   *
   * @var \Drupal\Core\Config\ImmutableConfig
   */
  protected $config;

  /**
   * EntityUpdateManager constructor.
   *
   * @param \Drupal\entity_usage\EntityUsage $usage_service
   *   The usage tracking service.
   * @param \Drupal\entity_usage\EntityUsageTrackManager $track_manager
   *   The PluginManager track service.
   * @param \Drupal\Core\Config\ConfigFactoryInterface $config_factory
   *   The config factory.
   */
  public function __construct(EntityUsage $usage_service, EntityUsageTrackManager $track_manager, ConfigFactoryInterface $config_factory) {
    $this->usageService = $usage_service;
    $this->trackManager = $track_manager;
    $this->config = $config_factory
      ->get('entity_usage.settings');
  }

  /**
   * Getter for the top-level sources we want to track.
   *
   * @return array
   *   An indexed array where values are:
   *  - entity: The entity being created/updated/deleted.
   *  - operation: The operation being performed on the entity.
   *  - original_entity: The original entity, if this is an update operation.
   */
  public function getTopLevelSources() {
    return $this->topLevelSources;
  }

  /**
   * Adds a new top-level source to be tracked at the end of the request.
   *
   * @param \Drupal\Core\Entity\EntityInterface $entity
   *   The entity we are tracking as top-level source entity.
   * @param string $operation
   *   The operation being performed.
   * @param \Drupal\Core\Entity\EntityInterface $original
   *   In update operations, the original entity.
   */
  public function addTopLevelSource(EntityInterface $entity, $operation, EntityInterface $original = NULL) {
    $this->topLevelSources[] = [
      'entity' => $entity,
      'operation' => $operation,
      'original' => $original,
    ];
  }

  /**
   * {@inheritdoc}
   */
  public function destruct() {
    if (empty($this->topLevelSources)) {
      return;
    }
    foreach ($this->topLevelSources as $source) {
      switch ($source['operation']) {
        case self::OPERATION_INSERT:
          $this
            ->trackUpdateOnCreation($source['entity']);
          break;
        case self::OPERATION_UPDATE:
          $this
            ->trackUpdateOnEdition($source['entity'], $source['original']);
          break;
        case self::OPERATION_ENTITY_DELETE:
          $this
            ->trackUpdateOnDeletion($source['entity']);
          break;
        case self::OPERATION_TRANSLATION_DELETE:
          $this
            ->trackUpdateOnDeletion($source['entity'], 'translation');
          break;
        case self::OPERATION_REVISION_DELETE:
          $this
            ->trackUpdateOnDeletion($source['entity'], 'revision');
          break;
      }
    }
    $this
      ->resetProperties();
  }

  /**
   * Internal helper to make sure we clean up properties when destructing.
   *
   * This is mostly useful for making sure we have no bad failures in tests.
   */
  private function resetProperties() {
    $this->topLevelSources = NULL;
  }

  /**
   * Trigger a new usage calculation for a given source entity.
   *
   * @param \Drupal\Core\Entity\EntityInterface $entity
   *   The source entity we are dealing with.
   */
  public function recalculateUsageInformation(EntityInterface $entity) {
    $this
      ->trackUpdateOnCreation($entity);
  }

  /**
   * Track updates on creation of potential source entities.
   *
   * @param \Drupal\Core\Entity\EntityInterface $entity
   *   The entity we are dealing with.
   */
  protected function trackUpdateOnCreation(EntityInterface $entity) {
    if (!$this
      ->allowSourceEntityTracking($entity)) {
      return;
    }

    // Call all plugins that want to track entity usages. We need to call this
    // for all translations as well since Drupal stores new revisions for all
    // translations by default when saving an entity.
    if ($entity instanceof TranslatableInterface) {
      foreach ($entity
        ->getTranslationLanguages() as $translation_language) {
        if ($entity
          ->hasTranslation($translation_language
          ->getId())) {

          /** @var \Drupal\Core\Entity\EntityInterface $translation */
          $translation = $entity
            ->getTranslation($translation_language
            ->getId());
          foreach ($this
            ->getEnabledPlugins() as $plugin) {
            $plugin
              ->trackOnEntityCreation($translation);
          }
        }
      }
    }
    else {

      // Not translatable, just call the plugins with the entity itself.
      foreach ($this
        ->getEnabledPlugins() as $plugin) {
        $plugin
          ->trackOnEntityCreation($entity);
      }
    }
  }

  /**
   * Track updates on edit / update of potential source entities.
   *
   * @param \Drupal\Core\Entity\EntityInterface $entity
   *   The entity we are dealing with.
   */
  protected function trackUpdateOnEdition(EntityInterface $entity, EntityInterface $original) {
    if (!$this
      ->allowSourceEntityTracking($entity)) {
      return;
    }

    // Call all plugins that want to track entity usages. We need to call this
    // for all translations as well since Drupal stores new revisions for all
    // translations by default when saving an entity.
    if ($entity instanceof TranslatableInterface) {
      foreach ($entity
        ->getTranslationLanguages() as $translation_language) {
        if ($entity
          ->hasTranslation($translation_language
          ->getId())) {

          /** @var \Drupal\Core\Entity\ContentEntityInterface $translation */
          $translation = $entity
            ->getTranslation($translation_language
            ->getId());
          foreach ($this
            ->getEnabledPlugins() as $plugin) {
            $plugin
              ->trackOnEntityUpdate($translation, $original);
          }
        }
      }
    }
    else {

      // Not translatable, just call the plugins with the entity itself.
      foreach ($this
        ->getEnabledPlugins() as $plugin) {
        $plugin
          ->trackOnEntityUpdate($entity, $original);
      }
    }
  }

  /**
   * Track updates on deletion of entities.
   *
   * @param \Drupal\Core\Entity\EntityInterface $entity
   *   The entity we are dealing with.
   * @param string $type
   *   What type of deletion is being performed:
   *   - default: The main entity (default language, default revision) is being
   *   deleted (delete also other languages and revisions).
   *   - translation: Only one translation is being deleted.
   *   - revision: Onlyone revision is being deleted.
   *
   * @throws \InvalidArgumentException
   */
  protected function trackUpdateOnDeletion(EntityInterface $entity, $type = 'default') {

    // When an entity is being deleted the logic is much simpler and we don't
    // even need to call the plugins. Just delete the records that affect this
    // entity both as target and source.
    switch ($type) {
      case 'revision':
        $this->usageService
          ->deleteBySourceEntity($entity
          ->id(), $entity
          ->getEntityTypeId(), NULL, $entity
          ->getRevisionId());
        break;
      case 'translation':
        $this->usageService
          ->deleteBySourceEntity($entity
          ->id(), $entity
          ->getEntityTypeId(), $entity
          ->language()
          ->getId());
        break;
      case 'default':
        $this->usageService
          ->deleteBySourceEntity($entity
          ->id(), $entity
          ->getEntityTypeId());
        $this->usageService
          ->deleteByTargetEntity($entity
          ->id(), $entity
          ->getEntityTypeId());
        break;
      default:

        // We only accept one of the above mentioned types.
        throw new \InvalidArgumentException('EntityUpdateManager::trackUpdateOnDeletion called with unkown deletion type: ' . $type);
    }
  }

  /**
   * Check if an entity is allowed to be tracked as source.
   *
   * @param \Drupal\Core\Entity\EntityInterface $entity
   *   The entity object.
   *
   * @return bool
   *   Whether the entity can be tracked or not.
   */
  protected function allowSourceEntityTracking(EntityInterface $entity) {
    $allow_tracking = FALSE;
    $entity_type = $entity
      ->getEntityType();
    $enabled_source_entity_types = $this->config
      ->get('track_enabled_source_entity_types');
    if (!is_array($enabled_source_entity_types) && $entity_type
      ->entityClassImplements('\\Drupal\\Core\\Entity\\ContentEntityInterface')) {

      // When no settings are defined, track all content entities by default.
      $allow_tracking = TRUE;
    }
    elseif (is_array($enabled_source_entity_types) && in_array($entity_type
      ->id(), $enabled_source_entity_types, TRUE)) {
      $allow_tracking = TRUE;
    }
    return $allow_tracking;
  }

  /**
   * Get the enabled tracking plugins, all plugins are enabled by default.
   *
   * @return \Drupal\entity_usage\EntityUsageTrackInterface[]
   *   The enabled plugin instances.
   */
  protected function getEnabledPlugins() {
    $all_plugin_ids = array_keys($this->trackManager
      ->getDefinitions());
    $enabled_plugins = $this->config
      ->get('track_enabled_plugins');
    $enabled_plugin_ids = is_array($enabled_plugins) ? $enabled_plugins : $all_plugin_ids;
    $plugins = [];
    foreach (array_intersect($all_plugin_ids, $enabled_plugin_ids) as $plugin_id) {

      /** @var EntityUsageTrackInterface $instance */
      $plugins[$plugin_id] = $this->trackManager
        ->createInstance($plugin_id);
    }
    return $plugins;
  }

}

Members

Namesort descending Modifiers Type Description Overrides
EntityUpdateManager::$config protected property The config factory.
EntityUpdateManager::$topLevelSources protected property The top-level entities being tracked during a given request.
EntityUpdateManager::$trackManager protected property The usage track manager.
EntityUpdateManager::$usageService protected property The usage track service.
EntityUpdateManager::addTopLevelSource public function Adds a new top-level source to be tracked at the end of the request.
EntityUpdateManager::allowSourceEntityTracking protected function Check if an entity is allowed to be tracked as source.
EntityUpdateManager::destruct public function Performs destruct operations. Overrides DestructableInterface::destruct
EntityUpdateManager::getEnabledPlugins protected function Get the enabled tracking plugins, all plugins are enabled by default.
EntityUpdateManager::getTopLevelSources public function Getter for the top-level sources we want to track.
EntityUpdateManager::OPERATION_ENTITY_DELETE constant Describes a full deletion of a source operation.
EntityUpdateManager::OPERATION_INSERT constant Describes an insert source operation.
EntityUpdateManager::OPERATION_REVISION_DELETE constant Describes the deletion of a single source revision.
EntityUpdateManager::OPERATION_TRANSLATION_DELETE constant Describes the deletion of a single translation of a source entity.
EntityUpdateManager::OPERATION_UPDATE constant Describes an update source operation.
EntityUpdateManager::recalculateUsageInformation public function Trigger a new usage calculation for a given source entity.
EntityUpdateManager::resetProperties private function Internal helper to make sure we clean up properties when destructing.
EntityUpdateManager::trackUpdateOnCreation protected function Track updates on creation of potential source entities.
EntityUpdateManager::trackUpdateOnDeletion protected function Track updates on deletion of entities.
EntityUpdateManager::trackUpdateOnEdition protected function Track updates on edit / update of potential source entities.
EntityUpdateManager::__construct public function EntityUpdateManager constructor.