Commit 185668ed authored by catch's avatar catch
Browse files

Issue #3532741 by amateescu, smustgrave, plach: Switching workspaces shouldn't...

Issue #3532741 by amateescu, smustgrave, plach: Switching workspaces shouldn't clear the persistent entity cache
parent 193bcef1
Loading
Loading
Loading
Loading
Loading
+28 −16
Original line number Diff line number Diff line
@@ -46,13 +46,6 @@ abstract class ContentEntityStorageBase extends EntityStorageBase implements Con
   */
  protected $cacheBackend;

  /**
   * Stores the latest revision IDs for entities.
   *
   * @var array
   */
  protected $latestRevisionIds = [];

  /**
   * Constructs a ContentEntityStorageBase object.
   *
@@ -479,17 +472,20 @@ public function getLatestRevisionId($entity_id) {
      return NULL;
    }

    if (!isset($this->latestRevisionIds[$entity_id][LanguageInterface::LANGCODE_DEFAULT])) {
    $cached = $this->memoryCache->get("latest_revision_id:{$this->entityTypeId}:$entity_id");
    $latest_revision_ids = $cached ? $cached->data : [];
    if (!isset($latest_revision_ids[LanguageInterface::LANGCODE_DEFAULT])) {
      $result = $this->getQuery()
        ->latestRevision()
        ->condition($this->entityType->getKey('id'), $entity_id)
        ->accessCheck(FALSE)
        ->execute();

      $this->latestRevisionIds[$entity_id][LanguageInterface::LANGCODE_DEFAULT] = key($result);
      $latest_revision_ids[LanguageInterface::LANGCODE_DEFAULT] = key($result);
      $this->memoryCache->set("latest_revision_id:{$this->entityTypeId}:$entity_id", $latest_revision_ids, MemoryCacheInterface::CACHE_PERMANENT, [$this->memoryCacheTag]);
    }

    return $this->latestRevisionIds[$entity_id][LanguageInterface::LANGCODE_DEFAULT];
    return $latest_revision_ids[LanguageInterface::LANGCODE_DEFAULT];
  }

  /**
@@ -504,7 +500,9 @@ public function getLatestTranslationAffectedRevisionId($entity_id, $langcode) {
      return $this->getLatestRevisionId($entity_id);
    }

    if (!isset($this->latestRevisionIds[$entity_id][$langcode])) {
    $cached = $this->memoryCache->get("latest_revision_id:{$this->entityTypeId}:$entity_id");
    $latest_revision_ids = $cached ? $cached->data : [];
    if (!isset($latest_revision_ids[$langcode])) {
      $result = $this->getQuery()
        ->allRevisions()
        ->condition($this->entityType->getKey('id'), $entity_id)
@@ -516,9 +514,11 @@ public function getLatestTranslationAffectedRevisionId($entity_id, $langcode) {
        ->addTag('latest_translated_affected_revision')
        ->execute();

      $this->latestRevisionIds[$entity_id][$langcode] = key($result);
      $latest_revision_ids[$langcode] = key($result);
      $this->memoryCache->set("latest_revision_id:{$this->entityTypeId}:$entity_id", $latest_revision_ids, MemoryCacheInterface::CACHE_PERMANENT, [$this->memoryCacheTag]);
    }
    return $this->latestRevisionIds[$entity_id][$langcode];

    return $latest_revision_ids[$langcode];
  }

  /**
@@ -1202,12 +1202,13 @@ public function resetCache(?array $ids = NULL) {
    if ($ids) {
      parent::resetCache($ids);
      if ($this->entityType->isPersistentlyCacheable()) {
        $cids = [];
        $cids = $latest_revision_cids = [];
        foreach ($ids as $id) {
          unset($this->latestRevisionIds[$id]);
          $cids[] = $this->buildCacheId($id);
          $latest_revision_cids[] = "latest_revision_id:{$this->entityTypeId}:$id";
        }
        $this->cacheBackend->deleteMultiple($cids);
        $this->memoryCache->deleteMultiple($latest_revision_cids);
      }
    }
    else {
@@ -1215,8 +1216,19 @@ public function resetCache(?array $ids = NULL) {
      if ($this->entityType->isPersistentlyCacheable()) {
        $this->cacheBackend->deleteAll();
      }
      $this->latestRevisionIds = [];
    }
  }

  /**
   * Warns about deprecated/removed properties.
   */
  public function __get(string $name): mixed {
    if ($name === 'latestRevisionIds') {
      @trigger_error('Getting the static cache of latest revision IDs is deprecated in drupal:11.2.5 and is removed from drupal:12.0.0. You can retrieve it from the \'entity.memory_cache\' service instead. See https://www.drupal.org/node/3535160', E_USER_DEPRECATED);
      return [];
    }

    return $this->$name ?? NULL;
  }

}
+22 −5
Original line number Diff line number Diff line
@@ -164,7 +164,6 @@ protected function doSwitchWorkspace($workspace) {
    // Clear the static entity cache for the supported entity types.
    $cache_tags_to_invalidate = [];
    foreach (array_keys($this->workspaceInfo->getSupportedEntityTypes()) as $entity_type_id) {
      $this->entityTypeManager->getStorage($entity_type_id)->resetCache();
      $cache_tags_to_invalidate[] = 'entity.memory_cache:' . $entity_type_id;
    }
    $this->entityMemoryCache->invalidateTags($cache_tags_to_invalidate);
@@ -188,9 +187,19 @@ public function executeInWorkspace($workspace_id, callable $function) {
    }

    $previous_active_workspace = $this->getActiveWorkspace();

    // Switch to the requested workspace only if we're in Live or in another
    // workspace.
    $should_switch_workspace = !$previous_active_workspace || $previous_active_workspace->id() != $workspace_id;
    if ($should_switch_workspace) {
      $this->doSwitchWorkspace($workspace);
    }
    $result = $function();

    // Switch back if needed.
    if ($should_switch_workspace) {
      $this->doSwitchWorkspace($previous_active_workspace);
    }

    return $result;
  }
@@ -200,9 +209,17 @@ public function executeInWorkspace($workspace_id, callable $function) {
   */
  public function executeOutsideWorkspace(callable $function) {
    $previous_active_workspace = $this->getActiveWorkspace();

    // Switch to Live if we're in a workspace.
    if ($previous_active_workspace) {
      $this->doSwitchWorkspace(NULL);
    }
    $result = $function();

    // Switch back if needed.
    if ($previous_active_workspace) {
      $this->doSwitchWorkspace($previous_active_workspace);
    }

    return $result;
  }
+15 −0
Original line number Diff line number Diff line
@@ -62,10 +62,25 @@ protected function setUp(): void {
   * Tests switching workspace via the switcher block and admin page.
   */
  public function testSwitchingWorkspaces(): void {
    /** @var \Drupal\Core\Cache\CacheBackendInterface $entity_cache */
    $entity_cache = \Drupal::service('cache.entity');

    $node_type = $this->drupalCreateContentType();
    $node = $this->drupalCreateNode(['type' => $node_type->id()]);
    $this->assertFalse($entity_cache->get("values:node:{$node->id()}"));

    // Access the node page to prime its persistent cache.
    $this->drupalGet($node->toUrl());
    $this->assertNotFalse($entity_cache->get("values:node:{$node->id()}"));

    $vultures = Workspace::load('vultures');
    $gravity = Workspace::load('gravity');
    $this->switchToWorkspace($vultures);

    // Check that switching into a workspace doesn't invalidate the persistent
    // cache.
    $this->assertNotFalse($entity_cache->get("values:node:{$node->id()}"));

    // Confirm the block shows on the front page.
    $this->drupalGet('<front>');
    $page = $this->getSession()->getPage();