diff --git a/core/modules/workspaces/src/Entity/Handler/BlockContentWorkspaceHandler.php b/core/modules/workspaces/src/Entity/Handler/BlockContentWorkspaceHandler.php index d952518080..4e164cc599 100644 --- a/core/modules/workspaces/src/Entity/Handler/BlockContentWorkspaceHandler.php +++ b/core/modules/workspaces/src/Entity/Handler/BlockContentWorkspaceHandler.php @@ -5,19 +5,18 @@ use Drupal\Core\Entity\EntityInterface; /** - * Customizations for block content entities. + * Provides a custom workspace handler for block_content entities. * * @internal */ -class BlockContentWorkspaceHandler extends WorkspaceHandlerBase { +class BlockContentWorkspaceHandler extends DefaultWorkspaceHandler { /** * {@inheritdoc} */ - public function isEntitySupported(EntityInterface $entity) { - // Only reusable blocks can be tracked individually. Non-reusable or - // inline blocks are tracked as part of the entity they are a composite - // of. + public function isEntitySupported(EntityInterface $entity): bool { + // Only reusable blocks can be tracked individually. Non-reusable or inline + // blocks are tracked as part of the entity they are a composite of. /** @var \Drupal\block_content\BlockContentInterface $entity */ return $entity->isReusable(); } diff --git a/core/modules/workspaces/src/Entity/Handler/WorkspaceHandlerBase.php b/core/modules/workspaces/src/Entity/Handler/DefaultWorkspaceHandler.php similarity index 62% copy from core/modules/workspaces/src/Entity/Handler/WorkspaceHandlerBase.php copy to core/modules/workspaces/src/Entity/Handler/DefaultWorkspaceHandler.php index 545a8b255a..0016729e7d 100644 --- a/core/modules/workspaces/src/Entity/Handler/WorkspaceHandlerBase.php +++ b/core/modules/workspaces/src/Entity/Handler/DefaultWorkspaceHandler.php @@ -4,7 +4,6 @@ use Drupal\Core\Entity\EntityHandlerInterface; use Drupal\Core\Entity\EntityInterface; -use Drupal\Core\Entity\EntityPublishedInterface; use Drupal\Core\Entity\EntityTypeInterface; use Symfony\Component\DependencyInjection\ContainerInterface; @@ -13,7 +12,7 @@ * * @internal */ -class WorkspaceHandlerBase implements WorkspaceHandlerInterface, EntityHandlerInterface { +class DefaultWorkspaceHandler implements WorkspaceHandlerInterface, EntityHandlerInterface { /** * {@inheritdoc} @@ -25,8 +24,8 @@ public static function createInstance(ContainerInterface $container, EntityTypeI /** * {@inheritdoc} */ - public function isEntitySupported(EntityInterface $entity) { - return is_subclass_of($entity, EntityPublishedInterface::class) && $entity->getEntityType()->isRevisionable(); + public function isEntitySupported(EntityInterface $entity): bool { + return TRUE; } } diff --git a/core/modules/workspaces/src/Entity/Handler/WorkspaceHandlerBase.php b/core/modules/workspaces/src/Entity/Handler/IgnoredWorkspaceHandler.php similarity index 56% rename from core/modules/workspaces/src/Entity/Handler/WorkspaceHandlerBase.php rename to core/modules/workspaces/src/Entity/Handler/IgnoredWorkspaceHandler.php index 545a8b255a..21e4d4fbae 100644 --- a/core/modules/workspaces/src/Entity/Handler/WorkspaceHandlerBase.php +++ b/core/modules/workspaces/src/Entity/Handler/IgnoredWorkspaceHandler.php @@ -4,16 +4,15 @@ use Drupal\Core\Entity\EntityHandlerInterface; use Drupal\Core\Entity\EntityInterface; -use Drupal\Core\Entity\EntityPublishedInterface; use Drupal\Core\Entity\EntityTypeInterface; use Symfony\Component\DependencyInjection\ContainerInterface; /** - * Common customizations for most entity types. + * Defines a handler for entity types that are ignored by workspaces. * * @internal */ -class WorkspaceHandlerBase implements WorkspaceHandlerInterface, EntityHandlerInterface { +class IgnoredWorkspaceHandler implements WorkspaceHandlerInterface, EntityHandlerInterface { /** * {@inheritdoc} @@ -25,8 +24,8 @@ public static function createInstance(ContainerInterface $container, EntityTypeI /** * {@inheritdoc} */ - public function isEntitySupported(EntityInterface $entity) { - return is_subclass_of($entity, EntityPublishedInterface::class) && $entity->getEntityType()->isRevisionable(); + public function isEntitySupported(EntityInterface $entity): bool { + return FALSE; } } diff --git a/core/modules/workspaces/src/Entity/Handler/WorkspaceHandlerInterface.php b/core/modules/workspaces/src/Entity/Handler/WorkspaceHandlerInterface.php index e0c52a5dbf..5879746544 100644 --- a/core/modules/workspaces/src/Entity/Handler/WorkspaceHandlerInterface.php +++ b/core/modules/workspaces/src/Entity/Handler/WorkspaceHandlerInterface.php @@ -15,9 +15,9 @@ interface WorkspaceHandlerInterface { * Determines if an entity should be tracked in a workspace. * * At the general level, workspace support is determined for the entire entity - * type. If an entity type is supported, there maybe be further decisions - * each entity type may make to evaluate if a given entity is appropriate to - * be tracked in a workspace. + * type. If an entity type is supported, there may be further decisions each + * entity type can make to evaluate if a given entity is appropriate to be + * tracked in a workspace. * * @param \Drupal\Core\Entity\EntityInterface $entity * The entity we may be tracking. @@ -25,6 +25,6 @@ interface WorkspaceHandlerInterface { * @return bool * TRUE if this entity should be tracked in a workspace, FALSE otherwise. */ - public function isEntitySupported(EntityInterface $entity); + public function isEntitySupported(EntityInterface $entity): bool; } diff --git a/core/modules/workspaces/src/Entity/Workspace.php b/core/modules/workspaces/src/Entity/Workspace.php index 5c3c928af6..1e16282ed1 100644 --- a/core/modules/workspaces/src/Entity/Workspace.php +++ b/core/modules/workspaces/src/Entity/Workspace.php @@ -39,8 +39,8 @@ * "delete" = "\Drupal\workspaces\Form\WorkspaceDeleteForm", * "activate" = "\Drupal\workspaces\Form\WorkspaceActivateForm", * }, + * "workspace" = "\Drupal\workspaces\Entity\Handler\IgnoredWorkspaceHandler", * }, - * workspace = \Drupal\workspaces\WorkspaceInformationInterface::IGNORED, * admin_permission = "administer workspaces", * base_table = "workspace", * revision_table = "workspace_revision", diff --git a/core/modules/workspaces/src/EntityOperations.php b/core/modules/workspaces/src/EntityOperations.php index a94dff74d1..325a646680 100644 --- a/core/modules/workspaces/src/EntityOperations.php +++ b/core/modules/workspaces/src/EntityOperations.php @@ -253,15 +253,20 @@ public function entityPredelete(EntityInterface $entity) { */ public function entityFormAlter(array &$form, FormStateInterface $form_state, $form_id) { $entity = $form_state->getFormObject()->getEntity(); - if ($this->workspaceInfo->isEntityIgnored($entity) || !$this->workspaceInfo->isEntitySupported($entity)) { + if (!$this->workspaceInfo->isEntitySupported($entity) && !$this->workspaceInfo->isEntityIgnored($entity)) { return; } - // For supported entity types, signal the fact that this form is safe to use - // in a non-default workspace. + // For supported and ignored entity types, signal the fact that this form is + // safe to use in a workspace. // @see \Drupal\workspaces\FormOperations::validateForm() $form_state->set('workspace_safe', TRUE); + // There is nothing more to do for ignored entity types. + if ($this->workspaceInfo->isEntityIgnored($entity)) { + return; + } + // Add an entity builder to the form which marks the edited entity object as // a pending revision. This is needed so validation constraints like // \Drupal\path\Plugin\Validation\Constraint\PathAliasConstraintValidator diff --git a/core/modules/workspaces/src/EntityTypeInfo.php b/core/modules/workspaces/src/EntityTypeInfo.php index e8d5e35bea..55083bdc59 100644 --- a/core/modules/workspaces/src/EntityTypeInfo.php +++ b/core/modules/workspaces/src/EntityTypeInfo.php @@ -8,6 +8,8 @@ use Drupal\Core\Field\BaseFieldDefinition; use Drupal\Core\StringTranslation\TranslatableMarkup; use Drupal\workspaces\Entity\Handler\BlockContentWorkspaceHandler; +use Drupal\workspaces\Entity\Handler\DefaultWorkspaceHandler; +use Drupal\workspaces\Entity\Handler\IgnoredWorkspaceHandler; use Symfony\Component\DependencyInjection\ContainerInterface; /** @@ -45,32 +47,31 @@ public static function create(ContainerInterface $container) { */ public function entityTypeBuild(array &$entity_types) { foreach ($entity_types as $entity_type) { + if ($entity_type->hasHandlerClass('workspace')) { + continue; + } + + // Revisionable and publishable entity types are always supported. if ($entity_type->entityClassImplements(EntityPublishedInterface::class) && $entity_type->isRevisionable()) { - if (!$entity_type->get('workspace')) { - // Revisionable and publishable entity types are always supported. - $entity_type->set('workspace', WorkspaceInformationInterface::SUPPORTED); - - // Support for custom blocks has to be determined on a per-entity basis. - if ($entity_type->id() === 'block_content') { - $entity_type->set('workspace', WorkspaceInformationInterface::SUPPORTED_CUSTOM); - $entity_type->setHandlerClass('workspace', BlockContentWorkspaceHandler::class); - } - } + $entity_type->setHandlerClass('workspace', DefaultWorkspaceHandler::class); - $entity_type->addConstraint('EntityWorkspaceConflict'); - $entity_type->setRevisionMetadataKey('workspace', 'workspace'); + // Support for custom blocks has to be determined on a per-entity + // basis. + if ($entity_type->id() === 'block_content') { + $entity_type->setHandlerClass('workspace', BlockContentWorkspaceHandler::class); + } } // Internal entity types are allowed to perform CRUD operations inside a // workspace. - if ($entity_type->isInternal() && !$entity_type->get('workspace')) { - $entity_type->set('workspace', WorkspaceInformationInterface::IGNORED); + if ($entity_type->isInternal()) { + $entity_type->setHandlerClass('workspace', IgnoredWorkspaceHandler::class); } } } /** - * Removes the 'latest-version' link template provided by Content Moderation. + * Adds Workspace configuration to appropriate entity types. * * @param \Drupal\Core\Entity\EntityTypeInterface[] $entity_types * An array of entity types. @@ -79,6 +80,16 @@ public function entityTypeBuild(array &$entity_types) { */ public function entityTypeAlter(array &$entity_types) { foreach ($entity_types as $entity_type) { + if (!$this->workspaceInfo->isEntityTypeSupported($entity_type)) { + continue; + } + + // Workspace-support status has been declared in the "build" phase, now we + // can use that information and add additional configuration in the + // "alter" phase. + $entity_type->addConstraint('EntityWorkspaceConflict'); + $entity_type->setRevisionMetadataKey('workspace', 'workspace'); + // Non-default workspaces display the active revision on the canonical // route of an entity, so the latest version route is no longer needed. $link_templates = $entity_type->get('links'); diff --git a/core/modules/workspaces/src/WorkspaceInformation.php b/core/modules/workspaces/src/WorkspaceInformation.php index 3a0bf8d166..b590d7ce72 100644 --- a/core/modules/workspaces/src/WorkspaceInformation.php +++ b/core/modules/workspaces/src/WorkspaceInformation.php @@ -6,6 +6,7 @@ use Drupal\Core\Entity\EntityPublishedInterface; use Drupal\Core\Entity\EntityTypeInterface; use Drupal\Core\Entity\EntityTypeManagerInterface; +use Drupal\workspaces\Entity\Handler\IgnoredWorkspaceHandler; /** * General service for workspace support information. @@ -13,16 +14,16 @@ class WorkspaceInformation implements WorkspaceInformationInterface { /** - * An array of which entity types are supported. + * An array of workspace-support statuses, keyed by entity type ID. * - * @var string[] + * @var bool[] */ protected array $supported = []; /** - * An array of which entity types are ignored. + * An array of workspace-ignored statuses, keyed by entity type ID. * - * @var string[] + * @var bool[] */ protected array $ignored = []; @@ -36,32 +37,32 @@ public function __construct( public function isEntitySupported(EntityInterface $entity): bool { $entity_type = $entity->getEntityType(); - if ($entity_type->get('workspace') === static::SUPPORTED_CUSTOM) { - /** @var \Drupal\workspaces\Entity\Handler\WorkspaceHandlerInterface $handler */ - $handler = $this->entityTypeManager->getHandler($entity_type->id(), 'workspace'); - - return $handler->isEntitySupported($entity); + if (!$this->isEntityTypeSupported($entity_type)) { + return FALSE; } - return $this->isEntityTypeSupported($entity_type); + $handler = $this->entityTypeManager->getHandler($entity_type->id(), 'workspace'); + return $handler->isEntitySupported($entity); } /** * {@inheritdoc} */ public function isEntityTypeSupported(EntityTypeInterface $entity_type): bool { - $entity_type_id = $entity_type->id(); - if (!isset($this->supported[$entity_type_id])) { - if ($workspace_support = $entity_type->get('workspace')) { - $this->supported[$entity_type_id] = $workspace_support === static::SUPPORTED || $workspace_support === static::SUPPORTED_CUSTOM; + if (!isset($this->supported[$entity_type->id()])) { + if ($entity_type->hasHandlerClass('workspace')) { + $supported = !is_a($entity_type->getHandlerClass('workspace'), IgnoredWorkspaceHandler::class, TRUE); } else { - // Add a fallback check for entity types which might not have gone through - // the entity type manager's building phase. - $this->supported[$entity_type_id] = $entity_type->entityClassImplements(EntityPublishedInterface::class) && $entity_type->isRevisionable(); + // Fallback for cases when entity type info hasn't been altered yet, for + // example when the Workspaces module is being installed. + $supported = $entity_type->entityClassImplements(EntityPublishedInterface::class) && $entity_type->isRevisionable(); } + + $this->supported[$entity_type->id()] = $supported; } - return $this->supported[$entity_type_id]; + + return $this->supported[$entity_type->id()]; } /** @@ -83,25 +84,28 @@ public function getSupportedEntityTypes(): array { public function isEntityIgnored(EntityInterface $entity): bool { $entity_type = $entity->getEntityType(); - if ($entity_type->get('workspace') === static::SUPPORTED_CUSTOM) { - /** @var \Drupal\workspaces\Entity\Handler\WorkspaceHandlerInterface $handler */ - $handler = $this->entityTypeManager->getHandler($entity_type->id(), 'workspace'); + if ($this->isEntityTypeIgnored($entity_type)) { + return TRUE; + } - return $handler->isEntitySupported($entity) === FALSE; + if ($entity_type->hasHandlerClass('workspace')) { + $handler = $this->entityTypeManager->getHandler($entity_type->id(), 'workspace'); + return !$handler->isEntitySupported($entity); } - return $this->isEntityTypeIgnored($entity_type); + return FALSE; } /** * {@inheritdoc} */ public function isEntityTypeIgnored(EntityTypeInterface $entity_type): bool { - $entity_type_id = $entity_type->id(); - if (!isset($this->ignored[$entity_type_id])) { - $this->ignored[$entity_type_id] = $entity_type->get('workspace') === static::IGNORED; + if (!isset($this->ignored[$entity_type->id()])) { + $this->ignored[$entity_type->id()] = $entity_type->hasHandlerClass('workspace') + && is_a($entity_type->getHandlerClass('workspace'), IgnoredWorkspaceHandler::class, TRUE); } - return $this->ignored[$entity_type_id]; + + return $this->ignored[$entity_type->id()]; } } diff --git a/core/modules/workspaces/src/WorkspaceInformationInterface.php b/core/modules/workspaces/src/WorkspaceInformationInterface.php index b5868b0031..af32910ba5 100644 --- a/core/modules/workspaces/src/WorkspaceInformationInterface.php +++ b/core/modules/workspaces/src/WorkspaceInformationInterface.php @@ -6,32 +6,12 @@ use Drupal\Core\Entity\EntityTypeInterface; /** - * Provides an interface for workspace support information. + * Provides an interface for workspace-support information. */ interface WorkspaceInformationInterface { /** - * Indicates that CRUD operations for a non-supported entity type are allowed. - */ - const IGNORED = 'ignored'; - - /** - * Indicates that an entity type can belong to a workspace. - */ - const SUPPORTED = 'supported'; - - /** - * Indicates that some entities of a certain type may belong to a workspace. - * - * Entity types that need to check workspace support on a per-entity basis - * can do so by implementing a 'workspace' entity type handler. - * - * @see \Drupal\workspaces\Entity\Handler\BlockContentWorkspaceHandler - */ - const SUPPORTED_CUSTOM = 'supported_custom'; - - /** - * Determines if an individual entity can belong to a workspace. + * Determines whether an entity can belong to a workspace. * * @param \Drupal\Core\Entity\EntityInterface $entity * The entity to check. @@ -42,7 +22,7 @@ interface WorkspaceInformationInterface { public function isEntitySupported(EntityInterface $entity): bool; /** - * Determines if an entity type can belong to a workspace. + * Determines whether an entity type can belong to a workspace. * * @param \Drupal\Core\Entity\EntityTypeInterface $entity_type * The entity type to check. @@ -56,12 +36,15 @@ public function isEntityTypeSupported(EntityTypeInterface $entity_type): bool; * Returns an array of entity types that can belong to workspaces. * * @return \Drupal\Core\Entity\EntityTypeInterface[] - * The entity types that can belong to workspaces. + * An array of entity type definition objects. */ public function getSupportedEntityTypes(): array; /** - * Determines if CRUD operations for an entity are allowed. + * Determines whether CRUD operations for an entity are allowed. + * + * CRUD operations for an ignored entity are allowed in a workspace, but their + * revisions are not tracked. * * @param \Drupal\Core\Entity\EntityInterface $entity * The entity to check. @@ -73,7 +56,10 @@ public function getSupportedEntityTypes(): array; public function isEntityIgnored(EntityInterface $entity): bool; /** - * Determines if CRUD operations for a non-supported entity type are allowed. + * Determines whether CRUD operations for an entity type are allowed. + * + * CRUD operations for an ignored entity type are allowed in a workspace, but + * their revisions are not tracked. * * @param \Drupal\Core\Entity\EntityTypeInterface $entity_type * The entity type to check. diff --git a/core/modules/workspaces/src/WorkspaceManager.php b/core/modules/workspaces/src/WorkspaceManager.php index 5f4df8c0ef..bba37e5370 100644 --- a/core/modules/workspaces/src/WorkspaceManager.php +++ b/core/modules/workspaces/src/WorkspaceManager.php @@ -132,7 +132,7 @@ public function __construct(RequestStack $request_stack, EntityTypeManagerInterf $this->workspaceAssociation = $workspace_association; if (!$workspace_information instanceof WorkspaceInformationInterface) { - @trigger_error('Calling ' . __METHOD__ . '() without the $workspace_information argument is deprecated in drupal:10.2.0 and will be required in drupal:11.0.0', E_USER_DEPRECATED); + @trigger_error('Calling ' . __METHOD__ . '() without the $workspace_information argument is deprecated in drupal:10.3.0 and will be required in drupal:11.0.0. See https://www.drupal.org/node/3324297', E_USER_DEPRECATED); $this->workspaceInfo = \Drupal::service('workspaces.information'); // The negotiator IDs are always the last constructor argument. @@ -148,7 +148,7 @@ public function __construct(RequestStack $request_stack, EntityTypeManagerInterf * {@inheritdoc} */ public function isEntityTypeSupported(EntityTypeInterface $entity_type) { - @trigger_error(__METHOD__ . '() is deprecated in drupal:10.2.0 and is removed from drupal:11.0.0. Use \Drupal\workspaces\WorkspaceInformation::isEntityTypeSupported instead. See https://www.drupal.org/node/3324297', E_USER_DEPRECATED); + @trigger_error(__METHOD__ . '() is deprecated in drupal:10.3.0 and is removed from drupal:11.0.0. Use \Drupal\workspaces\WorkspaceInformation::isEntityTypeSupported instead. See https://www.drupal.org/node/3324297', E_USER_DEPRECATED); return $this->workspaceInfo->isEntityTypeSupported($entity_type); } @@ -156,7 +156,7 @@ public function isEntityTypeSupported(EntityTypeInterface $entity_type) { * {@inheritdoc} */ public function getSupportedEntityTypes() { - @trigger_error(__METHOD__ . '() is deprecated in drupal:10.2.0 and is removed from drupal:11.0.0. Use \Drupal\workspaces\WorkspaceInformation::getSupportedEntityTypes instead. See https://www.drupal.org/node/3324297', E_USER_DEPRECATED); + @trigger_error(__METHOD__ . '() is deprecated in drupal:10.3.0 and is removed from drupal:11.0.0. Use \Drupal\workspaces\WorkspaceInformation::getSupportedEntityTypes instead. See https://www.drupal.org/node/3324297', E_USER_DEPRECATED); return $this->workspaceInfo->getSupportedEntityTypes(); } @@ -297,7 +297,7 @@ public function executeOutsideWorkspace(callable $function) { * {@inheritdoc} */ public function shouldAlterOperations(EntityTypeInterface $entity_type) { - @trigger_error(__METHOD__ . '() is deprecated in drupal:10.2.0 and is removed from drupal:11.0.0. There is no replacement. See https://www.drupal.org/node/3324297', E_USER_DEPRECATED); + @trigger_error(__METHOD__ . '() is deprecated in drupal:10.3.0 and is removed from drupal:11.0.0. There is no replacement. See https://www.drupal.org/node/3324297', E_USER_DEPRECATED); return $this->workspaceInfo->isEntityTypeSupported($entity_type) && $this->hasActiveWorkspace(); } diff --git a/core/modules/workspaces/src/WorkspaceManagerInterface.php b/core/modules/workspaces/src/WorkspaceManagerInterface.php index 4709c77ab2..753657fc46 100644 --- a/core/modules/workspaces/src/WorkspaceManagerInterface.php +++ b/core/modules/workspaces/src/WorkspaceManagerInterface.php @@ -18,7 +18,7 @@ interface WorkspaceManagerInterface { * @return bool * TRUE if the entity type can belong to a workspace, FALSE otherwise. * - * @deprecated in drupal:10.1.0 and is removed from drupal:11.0.0. Use + * @deprecated in drupal:10.3.0 and is removed from drupal:11.0.0. Use * \Drupal\workspaces\WorkspaceInformation::isEntityTypeSupported instead. * * @see https://www.drupal.org/node/3324297 @@ -31,7 +31,7 @@ public function isEntityTypeSupported(EntityTypeInterface $entity_type); * @return \Drupal\Core\Entity\EntityTypeInterface[] * The entity types what can belong to workspaces. * - * @deprecated in drupal:10.1.0 and is removed from drupal:11.0.0. Use + * @deprecated in drupal:10.3.0 and is removed from drupal:11.0.0. Use * \Drupal\workspaces\WorkspaceInformation::getSupportedEntityTypes instead. * * @see https://www.drupal.org/node/3324297 @@ -108,7 +108,7 @@ public function executeOutsideWorkspace(callable $function); * TRUE if the entity operations or queries should be altered in the current * request, FALSE otherwise. * - * @deprecated in drupal:10.1.0 and is removed from drupal:11.0.0. There is no + * @deprecated in drupal:10.3.0 and is removed from drupal:11.0.0. There is no * replacement. * * @see https://www.drupal.org/node/3324297 diff --git a/core/modules/workspaces/tests/modules/workspaces_test/src/EntityTestRevPubWorkspaceHandler.php b/core/modules/workspaces/tests/modules/workspaces_test/src/EntityTestRevPubWorkspaceHandler.php new file mode 100644 index 0000000000..94e6aa4932 --- /dev/null +++ b/core/modules/workspaces/tests/modules/workspaces_test/src/EntityTestRevPubWorkspaceHandler.php @@ -0,0 +1,20 @@ +bundle() !== 'ignored_bundle'; + } + +} diff --git a/core/modules/workspaces/tests/modules/workspaces_test/workspaces_test.info.yml b/core/modules/workspaces/tests/modules/workspaces_test/workspaces_test.info.yml new file mode 100644 index 0000000000..62886a0b12 --- /dev/null +++ b/core/modules/workspaces/tests/modules/workspaces_test/workspaces_test.info.yml @@ -0,0 +1,7 @@ +name: 'Workspace Test' +type: module +description: 'Provides supporting code for testing workspaces.' +package: Testing +version: VERSION +dependencies: + - drupal:workspaces diff --git a/core/modules/workspaces/tests/src/Kernel/WorkspaceInformationTest.php b/core/modules/workspaces/tests/src/Kernel/WorkspaceInformationTest.php new file mode 100644 index 0000000000..604f0c99b5 --- /dev/null +++ b/core/modules/workspaces/tests/src/Kernel/WorkspaceInformationTest.php @@ -0,0 +1,176 @@ +entityTypeManager = \Drupal::entityTypeManager(); + $this->workspaceInformation = \Drupal::service('workspaces.information'); + $this->state = \Drupal::state(); + + $this->installEntitySchema('entity_test'); + $this->installEntitySchema('entity_test_rev'); + $this->installEntitySchema('entity_test_revpub'); + $this->installEntitySchema('workspace'); + + $this->installSchema('workspaces', ['workspace_association']); + + // Create a new workspace and activate it. + Workspace::create(['id' => 'stage', 'label' => 'Stage'])->save(); + $this->switchToWorkspace('stage'); + } + + /** + * Tests fully supported entity types. + */ + public function testSupportedEntityTypes() { + // Check a supported entity type. + $entity = $this->entityTypeManager->getStorage('entity_test_revpub')->create(); + + $this->assertTrue($this->workspaceInformation->isEntitySupported($entity)); + $this->assertTrue($this->workspaceInformation->isEntityTypeSupported($entity->getEntityType())); + + $this->assertFalse($this->workspaceInformation->isEntityIgnored($entity)); + $this->assertFalse($this->workspaceInformation->isEntityTypeIgnored($entity->getEntityType())); + + // Check that supported entity types are tracked in a workspace. This entity + // is published by default, so the second revision will be tracked. + $entity->save(); + $this->assertWorkspaceAssociation(['stage' => [2]], 'entity_test_revpub'); + } + + /** + * Tests an entity type with a custom workspace handler. + */ + public function testCustomSupportEntityTypes() { + $entity_type = clone $this->entityTypeManager->getDefinition('entity_test_revpub'); + $entity_type->setHandlerClass('workspace', EntityTestRevPubWorkspaceHandler::class); + $this->state->set('entity_test_revpub.entity_type', $entity_type); + $this->entityTypeManager->clearCachedDefinitions(); + + $entity = $this->entityTypeManager->getStorage('entity_test_revpub')->create([ + 'type' => 'supported_bundle', + ]); + + $this->assertTrue($this->workspaceInformation->isEntitySupported($entity)); + $this->assertTrue($this->workspaceInformation->isEntityTypeSupported($entity->getEntityType())); + $this->assertFalse($this->workspaceInformation->isEntityIgnored($entity)); + $this->assertFalse($this->workspaceInformation->isEntityTypeIgnored($entity->getEntityType())); + + // Check that supported entity types are tracked in a workspace. This entity + // is published by default, so the second revision will be tracked. + $entity->save(); + $this->assertWorkspaceAssociation(['stage' => [2]], 'entity_test_revpub'); + + $entity = $this->entityTypeManager->getStorage('entity_test_revpub')->create([ + 'type' => 'ignored_bundle', + ]); + + $this->assertFalse($this->workspaceInformation->isEntitySupported($entity)); + $this->assertTrue($this->workspaceInformation->isEntityTypeSupported($entity->getEntityType())); + $this->assertTrue($this->workspaceInformation->isEntityIgnored($entity)); + $this->assertFalse($this->workspaceInformation->isEntityTypeIgnored($entity->getEntityType())); + + // Check that an ignored entity can be saved, but won't be tracked. + $entity->save(); + $this->assertWorkspaceAssociation(['stage' => [2]], 'entity_test_revpub'); + } + + /** + * Tests ignored entity types. + */ + public function testIgnoredEntityTypes() { + $entity_type = clone $this->entityTypeManager->getDefinition('entity_test_rev'); + $entity_type->setHandlerClass('workspace', IgnoredWorkspaceHandler::class); + $this->state->set('entity_test_rev.entity_type', $entity_type); + $this->entityTypeManager->clearCachedDefinitions(); + + // Check an ignored entity type. CRUD operations for an ignored entity type + // are allowed in a workspace, but their revisions are not tracked. + $entity = $this->entityTypeManager->getStorage('entity_test_rev')->create(); + $this->assertTrue($this->workspaceInformation->isEntityIgnored($entity)); + $this->assertTrue($this->workspaceInformation->isEntityTypeIgnored($entity->getEntityType())); + + $this->assertFalse($this->workspaceInformation->isEntitySupported($entity)); + $this->assertFalse($this->workspaceInformation->isEntityTypeSupported($entity->getEntityType())); + + // Check that ignored entity types are not tracked in a workspace. + $entity->save(); + $this->assertWorkspaceAssociation(['stage' => []], 'entity_test_rev'); + } + + /** + * Tests unsupported entity types. + */ + public function testUnsupportedEntityTypes() { + // Check an unsupported entity type. + $entity_test = $this->entityTypeManager->getDefinition('entity_test'); + $this->assertFalse($entity_test->hasHandlerClass('workspace')); + + $entity = $this->entityTypeManager->getStorage('entity_test')->create(); + $this->assertFalse($this->workspaceInformation->isEntitySupported($entity)); + $this->assertFalse($this->workspaceInformation->isEntityTypeSupported($entity_test)); + + $this->assertFalse($this->workspaceInformation->isEntityIgnored($entity)); + $this->assertFalse($this->workspaceInformation->isEntityTypeIgnored($entity_test)); + + // Check that unsupported entity types can not be saved in a workspace. + $this->expectException(EntityStorageException::class); + $this->expectExceptionMessage('This entity can only be saved in the default workspace.'); + $entity->save(); + } + +} diff --git a/core/modules/workspaces/tests/src/Kernel/WorkspaceTestTrait.php b/core/modules/workspaces/tests/src/Kernel/WorkspaceTestTrait.php index 0fd6c43b45..69ca29f7ef 100644 --- a/core/modules/workspaces/tests/src/Kernel/WorkspaceTestTrait.php +++ b/core/modules/workspaces/tests/src/Kernel/WorkspaceTestTrait.php @@ -9,13 +9,6 @@ */ trait WorkspaceTestTrait { - /** - * The workspaces manager. - * - * @var \Drupal\workspaces\WorkspaceManagerInterface - */ - protected $workspaceManager; - /** * An array of test workspaces, keyed by workspace ID. * @@ -32,7 +25,6 @@ protected function initializeWorkspacesModule() { $this->enableModules(['workspaces']); $this->container = \Drupal::getContainer(); $this->entityTypeManager = \Drupal::entityTypeManager(); - $this->workspaceManager = \Drupal::service('workspaces.manager'); $this->installEntitySchema('workspace'); $this->installSchema('workspaces', ['workspace_association']);