function WorkspacesHooks::cron

Same name and namespace in other branches
  1. 11.x core/modules/workspaces/src/Hook/WorkspacesHooks.php \Drupal\workspaces\Hook\WorkspacesHooks::cron()

Implements hook_cron().

@internal

Attributes

#[Hook('cron')]

File

core/modules/workspaces/src/Hook/WorkspacesHooks.php, line 94

Class

WorkspacesHooks
Hook implementations for workspaces.

Namespace

Drupal\workspaces\Hook

Code

public function cron() : void {
  $this->workspaceManager
    ->executeOutsideWorkspace(function () {
    $deleted_workspace_ids = $this->state
      ->get('workspace.deleted', []);
    // Bail out early if there are no workspaces to purge.
    if (empty($deleted_workspace_ids)) {
      return;
    }
    $batch_size = Settings::get('entity_update_batch_size', 50);
    // Get the first deleted workspace from the list and delete the revisions
    // associated with it, along with the workspace association records.
    $workspace_id = reset($deleted_workspace_ids);
    $all_associated_revisions = [];
    foreach (array_keys($this->workspaceInfo
      ->getSupportedEntityTypes()) as $entity_type_id) {
      $all_associated_revisions[$entity_type_id] = $this->workspaceTracker
        ->getAllTrackedRevisions($workspace_id, $entity_type_id);
    }
    $all_associated_revisions = array_filter($all_associated_revisions);
    $count = 1;
    foreach ($all_associated_revisions as $entity_type_id => $associated_revisions) {
      /** @var \Drupal\Core\Entity\RevisionableStorageInterface $associated_entity_storage */
      $associated_entity_storage = $this->entityTypeManager
        ->getStorage($entity_type_id);
      // Sort the associated revisions in reverse ID order, so we can delete
      // the most recent revisions first, and only keep the revisions that
      // fit in the current batch.
      krsort($associated_revisions);
      $associated_revisions = array_slice($associated_revisions, 0, max(0, $batch_size - $count + 1), TRUE);
      // Get a list of default revisions tracked by the given workspace,
      // because they need to be handled differently than pending revisions.
      $initial_revision_ids = $this->workspaceTracker
        ->getTrackedInitialRevisions($workspace_id, $entity_type_id);
      // Load all the entities of this batch that are tracked through their
      // initial revision in a single storage call.
      $initial_revision_entities = [];
      if ($initial_entity_ids = array_intersect_key($initial_revision_ids, $associated_revisions)) {
        $initial_revision_entities = $associated_entity_storage->loadMultiple($initial_entity_ids);
      }
      foreach (array_keys($associated_revisions) as $revision_id) {
        // If the workspace is tracking the entity's default revision (i.e.
        // the entity was created inside that workspace), we need to delete
        // the whole entity after all of its pending revisions are gone.
        if (isset($initial_revision_ids[$revision_id])) {
          /** @var \Drupal\Core\Entity\RevisionableInterface&\Drupal\Core\Entity\EntityPublishedInterface $entity */
          $entity = $initial_revision_entities[$initial_revision_ids[$revision_id]] ?? NULL;
          if (!$entity) {
            continue;
          }
          // The entity might have gone live after it was created in this
          // workspace. This can happen when the entity is edited in multiple
          // workspaces at the same time and one of the others is published.
          // An entity with a published default revision is live content, so
          // we only delete the revision created in this workspace, not the
          // whole entity.
          if ($entity->isPublished()) {
            if ($entity->getRevisionId() != $revision_id) {
              $associated_entity_storage->deleteRevision($revision_id);
            }
            else {
              // The default revision of an entity can not be deleted, so we
              // only remove its tracking records.
              $this->workspaceTracker
                ->deleteTrackedEntities($workspace_id, $entity_type_id, [
                $entity->id(),
              ], [
                $revision_id,
              ]);
            }
          }
          else {
            $associated_entity_storage->delete([
              $entity,
            ]);
          }
        }
        else {
          // Delete the associated entity revision.
          $associated_entity_storage->deleteRevision($revision_id);
        }
        $count++;
      }
    }
    // The purging operation above might have taken a long time, so we need to
    // request a fresh list of tracked entities. If it is empty, we can go
    // ahead and remove the deleted workspace ID entry from state.
    $has_associated_revisions = FALSE;
    foreach (array_keys($this->workspaceInfo
      ->getSupportedEntityTypes()) as $entity_type_id) {
      if (!empty($this->workspaceTracker
        ->getAllTrackedRevisions($workspace_id, $entity_type_id))) {
        $has_associated_revisions = TRUE;
        break;

      }
    }
    if (!$has_associated_revisions) {
      unset($deleted_workspace_ids[$workspace_id]);
      $this->state
        ->set('workspace.deleted', $deleted_workspace_ids);
      // Delete any possible leftover association entries.
      $this->workspaceTracker
        ->deleteTrackedEntities($workspace_id);
    }
  });
}

Buggy or inaccurate documentation? Please file an issue. Need support? Need help programming? Connect with the Drupal community.