You are here

class EmbeddedUpdateRunner in Scheduled Updates 8

The default Embedded Update Runner.

Plugin annotation


@UpdateRunner(
  id = "default_embedded",
  label = @Translation("Embedded"),
  description = @Translation("Handles updates that are embedded on entities via entity reference fields."),
  update_types = {"embedded"}
)

Hierarchy

Expanded class hierarchy of EmbeddedUpdateRunner

File

src/Plugin/UpdateRunner/EmbeddedUpdateRunner.php, line 27
Contains \Drupal\scheduled_updates\Plugin\UpdateRunner\EmbeddedUpdateRunner.

Namespace

Drupal\scheduled_updates\Plugin\UpdateRunner
View source
class EmbeddedUpdateRunner extends BaseUpdateRunner implements EntityMonitorUpdateRunnerInterface {

  /**
   * Return all schedule updates that are referenced via Entity Reference
   * fields.
   *
   * @return ScheduledUpdate[]
   */
  protected function getEmbeddedUpdates() {
    $updates = [];

    /** @var String[] $fields */
    if ($entity_ids = $this
      ->getEntityIdsReferencingReadyUpdates()) {
      if ($entities = $this
        ->loadEntitiesToUpdate($entity_ids)) {
        $field_ids = $this
          ->getReferencingFieldIds();

        /** @var ContentEntityInterface $entity */
        foreach ($entities as $entity) {

          /** @var  $entity_update_ids - all update ids for this entity for our fields. */
          $entity_update_ids = [];

          /** @var  $field_update_ids - update ids keyed by field_id. */
          $field_update_ids = [];
          foreach ($field_ids as $field_id) {

            // Store with field id.
            $field_update_ids[$field_id] = $this
              ->getEntityReferenceTargetIds($entity, $field_id);

            // Add to all for entity.
            $entity_update_ids += $field_update_ids[$field_id];
          }

          // For all entity updates return only those ready to run.
          $ready_update_ids = $this
            ->getReadyUpdateIds($entity_update_ids);

          // Loop through updates attached to fields.
          foreach ($field_update_ids as $field_id => $update_ids) {

            // For updates attached to field get only those ready to run.
            $field_ready_update_ids = array_intersect($update_ids, $ready_update_ids);
            foreach ($field_ready_update_ids as $field_ready_update_id) {
              $updates[] = [
                'update_id' => $field_ready_update_id,
                // If this is revisionable entity use revision id as key for Runner Plugins that care about revisions.
                'entity_ids' => $entity
                  ->getRevisionId() ? [
                  $entity
                    ->getRevisionId() => $entity
                    ->id(),
                ] : [
                  $entity
                    ->id(),
                ],
                'field_id' => $field_id,
                'entity_type' => $this
                  ->updateEntityType(),
              ];
            }
          }
        }
      }
    }
    return $updates;
  }

  /**
   * {@inheritdoc}
   */
  protected function getAllUpdates() {
    return $this
      ->getEmbeddedUpdates();
  }

  /**
   * {@inheritdoc}
   */
  public function onEntityUpdate(ContentEntityInterface $entity) {
    if ($this->updateUtils
      ->supportsRevisionUpdates($this->scheduled_update_type)) {
      $this
        ->deactivateUpdates($entity);
      $this
        ->reactivateUpdates($entity);
    }
  }

  /**
   * Deactivate any Scheduled Updates that are previous revision but not on current.
   *
   * @param \Drupal\Core\Entity\ContentEntityInterface $entity
   */
  protected function deactivateUpdates(ContentEntityInterface $entity) {
    $current_update_ids = $this
      ->getUpdateIdsOnEntity($entity);

    // Loop through all previous revisions and deactive updates not on current revision.
    $revisions = $this
      ->getPreviousRevisionsWithUpdates($entity);
    if (empty($revisions)) {
      return;
    }
    $all_revisions_update_ids = [];
    foreach ($revisions as $revision) {

      // array_merge so so elements with same key are not replaced.
      $all_revisions_update_ids = array_merge($all_revisions_update_ids, $this
        ->getUpdateIdsOnEntity($revision));
    }
    $all_revisions_update_ids = array_unique($all_revisions_update_ids);
    $updates_ids_not_on_current = array_diff($all_revisions_update_ids, $current_update_ids);
    if ($updates_ids_not_on_current) {
      $storage = $this->entityTypeManager
        ->getStorage('scheduled_update');
      foreach ($updates_ids_not_on_current as $update_id) {

        /** @var ScheduledUpdateInterface $update */
        $update = $storage
          ->load($update_id);
        $update->status = ScheduledUpdateInterface::STATUS_INACTIVE;
        $update
          ->save();
      }
    }
  }

  /**
   * Reactive any updates that are on this entity that have been deactived previously.
   *
   * @see ::deactivateUpdates()
   *
   * @param \Drupal\Core\Entity\ContentEntityInterface $entity
   */
  protected function reactivateUpdates(ContentEntityInterface $entity) {
    if ($update_ids = $this
      ->getUpdateIdsOnEntity($entity)) {
      $storage = $this->entityTypeManager
        ->getStorage('scheduled_update');
      $query = $storage
        ->getQuery();
      $query
        ->condition('status', [
        ScheduledUpdateInterface::STATUS_UNRUN,
        ScheduledUpdateInterface::STATUS_REQUEUED,
      ], 'NOT IN');
      $query
        ->condition($this->entityTypeManager
        ->getDefinition('scheduled_update')
        ->getKey('id'), $update_ids, 'IN');
      $non_active_update_ids = $query
        ->execute();
      $non_active_updates = $storage
        ->loadMultiple($non_active_update_ids);
      foreach ($non_active_updates as $non_active_update) {
        $non_active_update->status = ScheduledUpdateInterface::STATUS_UNRUN;
      }
    }
  }

  /**
   * Get all update ids for this connected Update type.
   *
   * @todo Should results be cached per entity_id and revision_id to avoiding loading updates.
   *
   * @param \Drupal\Core\Entity\ContentEntityInterface $entity
   *
   * @param bool $include_inactive
   *
   * @return array
   */
  protected function getUpdateIdsOnEntity(ContentEntityInterface $entity, $include_inactive = FALSE) {
    $field_ids = $this
      ->getReferencingFieldIds();
    $update_ids = [];
    foreach ($field_ids as $field_id) {
      $field_update_ids = $this
        ->getEntityReferenceTargetIds($entity, $field_id);

      // This field could reference other update bundles
      // remove any that aren't of the attached scheduled update type.
      foreach ($field_update_ids as $field_update_id) {
        $update = $this->entityTypeManager
          ->getStorage('scheduled_update')
          ->load($field_update_id);
        if ($update && $update
          ->bundle() == $this->scheduled_update_type
          ->id()) {
          if (!$include_inactive) {
            if ($update->status->value == ScheduledUpdateInterface::STATUS_INACTIVE) {
              continue;
            }
          }
          $update_ids[$field_update_id] = $field_update_id;
        }
      }
    }
    return $update_ids;
  }

  /**
   * Get all previous revisions that have updates of the attached type.
   *
   * This function would be easier and more performant if this core issue with
   * Entity Query was fixed: https://www.drupal.org/node/2649268 Without this
   * fix can't filter query on type of update and whether they are active. So
   * therefore all previous revisions have to be loaded.
   *
   * @todo Help get that core issue fixed or rewrite this function query table
   *       fields directly.
   *
   * @param \Drupal\Core\Entity\ContentEntityInterface $entity
   *
   * @return \Drupal\Core\Entity\ContentEntityInterface[]
   */
  protected function getPreviousRevisionsWithUpdates(ContentEntityInterface $entity) {

    /** @var ContentEntityInterface[] $revisions */
    $revisions = [];
    $type = $entity
      ->getEntityType();
    $query = $this->entityTypeManager
      ->getStorage($entity
      ->getEntityTypeId())
      ->getQuery();
    $query
      ->allRevisions()
      ->condition($type
      ->getKey('id'), $entity
      ->id())
      ->condition($type
      ->getKey('revision'), $entity
      ->getRevisionId(), '<')
      ->sort($type
      ->getKey('revision'), 'DESC');
    if ($revision_ids = $query
      ->execute()) {
      $revision_ids = array_keys($revision_ids);
      $storage = $this->entityTypeManager
        ->getStorage($entity
        ->getEntityTypeId());
      foreach ($revision_ids as $revision_id) {

        /** @var ContentEntityInterface $revision */
        $revision = $storage
          ->loadRevision($revision_id);
        if ($update_ids = $this
          ->getUpdateIdsOnEntity($revision)) {
          $revisions[$revision_id] = $revision;
        }
      }
    }
    return $revisions;
  }

}

Members

Namesort descending Modifiers Type Description Overrides
BaseUpdateRunner::$accountSwitcher protected property
BaseUpdateRunner::$entityTypeManager protected property @var \Drupal\Core\Entity\EntityTypeManagerInterface
BaseUpdateRunner::$fieldManager protected property @var \Drupal\Core\Entity\EntityFieldManagerInterface
BaseUpdateRunner::$field_ids protected property The entity reference field ids target connected update types.
BaseUpdateRunner::$isRunByCron protected property If the runner is currently run by cron.
BaseUpdateRunner::$isUserSwitched protected property If the runner is currently switched to a different user.
BaseUpdateRunner::$items_to_release protected property Queue items that will be released after updates in queue are run.
BaseUpdateRunner::$scheduled_update_type protected property @var \Drupal\scheduled_updates\entity\ScheduledUpdateType
BaseUpdateRunner::$updateUtils protected property
BaseUpdateRunner::addActiveUpdateConditions protected function Add conditions to a query to select updates to run.
BaseUpdateRunner::addItemToRelease protected function
BaseUpdateRunner::addUpdatesToQueue public function Add all updates to queue. Overrides UpdateRunnerInterface::addUpdatesToQueue
BaseUpdateRunner::buildConfigurationForm public function Form constructor. Overrides PluginFormInterface::buildConfigurationForm 1
BaseUpdateRunner::create public static function Creates an instance of the plugin. Overrides ContainerFactoryPluginInterface::create
BaseUpdateRunner::displayMessage protected function Display message about updates.
BaseUpdateRunner::getAfterRun public function Get After Run behavior configuration.
BaseUpdateRunner::getDescription public function Get the description of the Runner Plugin. Overrides UpdateRunnerInterface::getDescription 1
BaseUpdateRunner::getEntityIdsReferencingReadyUpdates protected function Get all entity ids for entities that reference updates that are ready to run. 1
BaseUpdateRunner::getEntityReferenceTargetIds public function Get target entity ids for an entity reference field on a entity. Overrides UpdateRunnerInterface::getEntityReferenceTargetIds
BaseUpdateRunner::getInvalidUpdateBehavior public function Get how this runner should handle invalid entity updates. Overrides UpdateRunnerInterface::getInvalidUpdateBehavior
BaseUpdateRunner::getQueue public function Get the Queue for this Update Runner. Overrides UpdateRunnerInterface::getQueue
BaseUpdateRunner::getReadyUpdateIds protected function Get updates that are ready to be run for this Runner.
BaseUpdateRunner::getReferencingFieldIds public function Get all field ids that are attached to the entity type to be updated and target this update type. Overrides UpdateRunnerInterface::getReferencingFieldIds
BaseUpdateRunner::getUpdateType protected function Get Scheduled Update Type from the Form State.
BaseUpdateRunner::isRunByCron public function @inheritdoc Overrides UpdateRunnerInterface::isRunByCron
BaseUpdateRunner::loadEntitiesToUpdate protected function Load multi entities to update. 1
BaseUpdateRunner::prepareEntityForUpdate protected function Prepare an entity to be updated.
BaseUpdateRunner::releaseClaimedItems protected function
BaseUpdateRunner::removeUpdate protected function Remove update from reference field value.
BaseUpdateRunner::runUpdate protected function Run an individual update from the queue.
BaseUpdateRunner::runUpdatesInQueue public function Run all updates that are in the queue. Overrides UpdateRunnerInterface::runUpdatesInQueue
BaseUpdateRunner::setEntityRevision protected function Set a entity to use a new revision is applicable.
BaseUpdateRunner::setRunByCron public function @inheritdoc Overrides UpdateRunnerInterface::setRunByCron
BaseUpdateRunner::submitConfigurationForm public function Form submission handler. Overrides PluginFormInterface::submitConfigurationForm
BaseUpdateRunner::switchUser protected function Switch to another user to run an update if necessary.
BaseUpdateRunner::switchUserBack protected function If the user has been switch to run an update switch the user back.
BaseUpdateRunner::transferFieldValues protected function Transfer field values from update to entity to be updated.
BaseUpdateRunner::updateEntityType public function Return the entity id of the entity type being updated. Overrides UpdateRunnerInterface::updateEntityType
BaseUpdateRunner::validateConfigurationForm public function Form validation handler. Overrides PluginFormInterface::validateConfigurationForm 1
BaseUpdateRunner::__construct public function BaseUpdateRunner constructor. Overrides PluginBase::__construct
ClassUtilsTrait::bundleLabel protected function
ClassUtilsTrait::definitionClassImplementsInterface protected function Determines if the class for an entity type definition implements and interface.
ClassUtilsTrait::entityLabel protected function
ClassUtilsTrait::entityTypeManager protected function
ClassUtilsTrait::getEntityOwner protected function Get the entity owner if applicable.
ClassUtilsTrait::getRevisionOwner protected function Get the revision owner for an ContentEntity.
ClassUtilsTrait::implementsInterface protected function Determines if an object or class name implements any interfaces in a list.
ClassUtilsTrait::revisionOwnerInterfaces protected function Get class names of interfaces that support revision ownership.
ClassUtilsTrait::targetSupportBundles protected function
ClassUtilsTrait::targetTypeBundleLabel protected function
ClassUtilsTrait::targetTypeLabel public function
ClassUtilsTrait::typeSupportsBundles protected function
DependencySerializationTrait::$_entityStorages protected property An array of entity type IDs keyed by the property name of their storages.
DependencySerializationTrait::$_serviceIds protected property An array of service IDs keyed by property name used for serialization.
DependencySerializationTrait::__sleep public function 1
DependencySerializationTrait::__wakeup public function 2
EmbeddedUpdateRunner::deactivateUpdates protected function Deactivate any Scheduled Updates that are previous revision but not on current.
EmbeddedUpdateRunner::getAllUpdates protected function Get all schedule updates for this types that should be added to queue. Overrides BaseUpdateRunner::getAllUpdates
EmbeddedUpdateRunner::getEmbeddedUpdates protected function Return all schedule updates that are referenced via Entity Reference fields.
EmbeddedUpdateRunner::getPreviousRevisionsWithUpdates protected function Get all previous revisions that have updates of the attached type.
EmbeddedUpdateRunner::getUpdateIdsOnEntity protected function Get all update ids for this connected Update type.
EmbeddedUpdateRunner::onEntityUpdate public function Fires when entity of type to be updated is changed. Overrides EntityMonitorUpdateRunnerInterface::onEntityUpdate
EmbeddedUpdateRunner::reactivateUpdates protected function Reactive any updates that are on this entity that have been deactived previously.
MessengerTrait::$messenger protected property The messenger. 29
MessengerTrait::messenger public function Gets the messenger. 29
MessengerTrait::setMessenger public function Sets the messenger.
PluginBase::$configuration protected property Configuration information passed into the plugin. 1
PluginBase::$pluginDefinition protected property The plugin implementation definition. 1
PluginBase::$pluginId protected property The plugin_id.
PluginBase::DERIVATIVE_SEPARATOR constant A string which is used to separate base plugin IDs from the derivative ID.
PluginBase::getBaseId public function Gets the base_plugin_id of the plugin instance. Overrides DerivativeInspectionInterface::getBaseId
PluginBase::getDerivativeId public function Gets the derivative_id of the plugin instance. Overrides DerivativeInspectionInterface::getDerivativeId
PluginBase::getPluginDefinition public function Gets the definition of the plugin implementation. Overrides PluginInspectionInterface::getPluginDefinition 3
PluginBase::getPluginId public function Gets the plugin_id of the plugin instance. Overrides PluginInspectionInterface::getPluginId
PluginBase::isConfigurable public function Determines if the plugin is configurable.
StringTranslationTrait::$stringTranslation protected property The string translation service. 1
StringTranslationTrait::formatPlural protected function Formats a string containing a count of items.
StringTranslationTrait::getNumberOfPlurals protected function Returns the number of plurals supported by a given language.
StringTranslationTrait::getStringTranslation protected function Gets the string translation service.
StringTranslationTrait::setStringTranslation public function Sets the string translation service to use. 2
StringTranslationTrait::t protected function Translates a string to the current language or to a given language.
UpdateRunnerInterface::AFTER_ARCHIVE constant
UpdateRunnerInterface::AFTER_DELETE constant
UpdateRunnerInterface::INVALID_ARCHIVE constant
UpdateRunnerInterface::INVALID_DELETE constant
UpdateRunnerInterface::INVALID_REQUEUE constant
UpdateRunnerInterface::REVISIONS_BUNDLE_DEFAULT constant
UpdateRunnerInterface::REVISIONS_NO constant
UpdateRunnerInterface::REVISIONS_YES constant
UpdateRunnerInterface::USER_OWNER constant
UpdateRunnerInterface::USER_REVISION_OWNER constant
UpdateRunnerInterface::USER_UPDATE_OWNER constant
UpdateRunnerInterface::USER_UPDATE_RUNNER constant