diff --git a/core/modules/workspaces/src/WorkspaceManager.php b/core/modules/workspaces/src/WorkspaceManager.php index faa5f8fface75f52454aedbfe06f0c5bc1aa7ebf..0fe39f50fe75e1c69b7847f1d7934e170439c09f 100644 --- a/core/modules/workspaces/src/WorkspaceManager.php +++ b/core/modules/workspaces/src/WorkspaceManager.php @@ -167,6 +167,31 @@ public function getActiveWorkspace() { * {@inheritdoc} */ public function setActiveWorkspace(WorkspaceInterface $workspace) { + $this->doSwitchWorkspace($workspace); + + // Set the workspace on the proper negotiator. + $request = $this->requestStack->getCurrentRequest(); + foreach ($this->negotiatorIds as $negotiator_id) { + $negotiator = $this->classResolver->getInstanceFromDefinition($negotiator_id); + if ($negotiator->applies($request)) { + $negotiator->setActiveWorkspace($workspace); + break; + } + } + + return $this; + } + + /** + * Switches the current workspace. + * + * @param \Drupal\workspaces\WorkspaceInterface $workspace + * The workspace to set as active. + * + * @throws \Drupal\workspaces\WorkspaceAccessException + * Thrown when the current user doesn't have access to view the workspace. + */ + protected function doSwitchWorkspace(WorkspaceInterface $workspace) { // If the current user doesn't have access to view the workspace, they // shouldn't be allowed to switch to it. if (!$workspace->access('view') && !$workspace->isDefaultWorkspace()) { @@ -179,22 +204,29 @@ public function setActiveWorkspace(WorkspaceInterface $workspace) { $this->activeWorkspace = $workspace; - // Set the workspace on the proper negotiator. - $request = $this->requestStack->getCurrentRequest(); - foreach ($this->negotiatorIds as $negotiator_id) { - $negotiator = $this->classResolver->getInstanceFromDefinition($negotiator_id); - if ($negotiator->applies($request)) { - $negotiator->setActiveWorkspace($workspace); - break; - } - } - $supported_entity_types = $this->getSupportedEntityTypes(); foreach ($supported_entity_types as $supported_entity_type) { $this->entityTypeManager->getStorage($supported_entity_type->id())->resetCache(); } + } - return $this; + /** + * {@inheritdoc} + */ + public function executeInWorkspace($workspace_id, callable $function) { + /** @var \Drupal\workspaces\WorkspaceInterface $workspace */ + $workspace = $this->entityTypeManager->getStorage('workspace')->load($workspace_id); + + if (!$workspace) { + throw new \InvalidArgumentException('The ' . $workspace_id . ' workspace does not exist.'); + } + + $previous_active_workspace = $this->getActiveWorkspace(); + $this->doSwitchWorkspace($workspace); + $result = $function(); + $this->doSwitchWorkspace($previous_active_workspace); + + return $result; } /** diff --git a/core/modules/workspaces/src/WorkspaceManagerInterface.php b/core/modules/workspaces/src/WorkspaceManagerInterface.php index 9ce720b3f148e6536a39ff1fe74c38307015114c..006a2bd86d8a1486539c07452108fb0030204f5d 100644 --- a/core/modules/workspaces/src/WorkspaceManagerInterface.php +++ b/core/modules/workspaces/src/WorkspaceManagerInterface.php @@ -49,6 +49,19 @@ public function getActiveWorkspace(); */ public function setActiveWorkspace(WorkspaceInterface $workspace); + /** + * Executes the given callback function in the context of a workspace. + * + * @param string $workspace_id + * The ID of a workspace. + * @param callable $function + * The callback to be executed. + * + * @return mixed + * The callable's return value. + */ + public function executeInWorkspace($workspace_id, callable $function); + /** * Determines whether runtime entity operations should be altered. * diff --git a/core/modules/workspaces/tests/src/Kernel/WorkspaceIntegrationTest.php b/core/modules/workspaces/tests/src/Kernel/WorkspaceIntegrationTest.php index 9d77cdf001f1a2c524c73c6a522d10c2d4efc846..f4f76e6f82d24f508622fe28e505def29585df84 100644 --- a/core/modules/workspaces/tests/src/Kernel/WorkspaceIntegrationTest.php +++ b/core/modules/workspaces/tests/src/Kernel/WorkspaceIntegrationTest.php @@ -36,6 +36,13 @@ class WorkspaceIntegrationTest extends KernelTestBase { */ protected $entityTypeManager; + /** + * The workspaces manager. + * + * @var \Drupal\workspaces\WorkspaceManagerInterface + */ + protected $workspacesManager; + /** * An array of test workspaces, keyed by workspace ID. * @@ -102,6 +109,7 @@ protected function initializeWorkspacesModule() { $this->enableModules(['workspaces']); $this->container = \Drupal::getContainer(); $this->entityTypeManager = \Drupal::entityTypeManager(); + $this->workspacesManager = \Drupal::service('workspaces.manager'); $this->installEntitySchema('workspace'); $this->installEntitySchema('workspace_association'); @@ -492,6 +500,57 @@ public function testDisallowedEntityCRUDInNonDefaultWorkspace() { $entity_test->delete(); } + /** + * @covers \Drupal\workspaces\WorkspaceManager::executeInWorkspace + */ + public function testExecuteInWorkspaceContext() { + $this->initializeWorkspacesModule(); + + // Create an entity in the default workspace. + $this->switchToWorkspace('live'); + $node = $this->createNode([ + 'title' => 'live node 1', + ]); + $node->save(); + + // Switch to the 'stage' workspace and change some values for the referenced + // entities. + $this->switchToWorkspace('stage'); + $node->title->value = 'stage node 1'; + $node->save(); + + // Switch back to the default workspace and run the baseline assertions. + $this->switchToWorkspace('live'); + $storage = $this->entityTypeManager->getStorage('node'); + + $this->assertEquals('live', $this->workspacesManager->getActiveWorkspace()->id()); + + $live_node = $storage->loadUnchanged($node->id()); + $this->assertEquals('live node 1', $live_node->title->value); + + $result = $storage->getQuery() + ->condition('title', 'live node 1') + ->execute(); + $this->assertEquals([$live_node->getRevisionId() => $node->id()], $result); + + // Try the same assertions in the context of the 'stage' workspace. + $this->workspacesManager->executeInWorkspace('stage', function () use ($node, $storage) { + $this->assertEquals('stage', $this->workspacesManager->getActiveWorkspace()->id()); + + $stage_node = $storage->loadUnchanged($node->id()); + $this->assertEquals('stage node 1', $stage_node->title->value); + + $result = $storage->getQuery() + ->condition('title', 'stage node 1') + ->execute(); + $this->assertEquals([$stage_node->getRevisionId() => $stage_node->id()], $result); + }); + + // Check that the 'stage' workspace was not persisted by the workspace + // manager. + $this->assertEquals('live', $this->workspacesManager->getActiveWorkspace()->id()); + } + /** * Checks entity load, entity queries and views results for a test scenario. *