Loading core/modules/workspaces/src/Hook/EntityOperations.php +4 −0 Original line number Diff line number Diff line Loading @@ -168,6 +168,10 @@ public function entityInsert(EntityInterface $entity): void { } $entity->setPublished(); // Ensure that the second (workspace-specific) revision is marked as new // early, so operations that are executed before the entity presave hook // (e.g. field-level presave) can take that into account. $entity->setNewRevision(); $entity->isDefaultRevision(FALSE); $entity->save(); } Loading core/modules/workspaces/tests/modules/workspaces_test/src/Hook/WorkspacesTestHooks.php +39 −0 Original line number Diff line number Diff line Loading @@ -5,8 +5,12 @@ namespace Drupal\workspaces_test\Hook; use Drupal\Core\Entity\EntityInterface; use Drupal\Core\Entity\EntityTypeInterface; use Drupal\Core\Field\BaseFieldDefinition; use Drupal\Core\Hook\Attribute\Hook; use Drupal\Core\KeyValueStore\KeyValueFactoryInterface; use Drupal\Core\StringTranslation\TranslatableMarkup; use Drupal\workspaces\WorkspaceInformationInterface; use Symfony\Component\DependencyInjection\Attribute\Autowire; /** Loading @@ -17,6 +21,7 @@ class WorkspacesTestHooks { public function __construct( #[Autowire(service: 'keyvalue')] protected readonly KeyValueFactoryInterface $keyValueFactory, protected readonly WorkspaceInformationInterface $workspaceInformation, ) {} /** Loading @@ -32,6 +37,24 @@ public function entityTypeAlter(array &$entity_types) : void { } } /** * Implements hook_entity_base_field_info(). */ #[Hook('entity_base_field_info')] public function entityBaseFieldInfo(EntityTypeInterface $entity_type): array { $fields = []; // Add the workspace revision field test to entity_test_mulrevpub. if ($entity_type->id() === 'entity_test_mulrevpub') { $fields['revision_test_field'] = BaseFieldDefinition::create('revision_test_field') ->setLabel(new TranslatableMarkup('Workspace Revision Field Test')) ->setDescription(new TranslatableMarkup('A test field that tracks isNewRevision() status during field presave.')) ->setRevisionable(TRUE); } return $fields; } /** * Implements hook_ENTITY_TYPE_translation_create() for 'entity_test_mulrevpub'. */ Loading @@ -56,6 +79,22 @@ public function entityCreate(EntityInterface $entity): void { #[Hook('entity_presave')] public function entityPresave(EntityInterface $entity): void { $this->incrementHookCount('hook_entity_presave', $entity); if (!$this->workspaceInformation->isEntitySupported($entity)) { return; } /** @var \Drupal\Core\Entity\RevisionableInterface|\Drupal\Core\Entity\EntityPublishedInterface $entity */ // Track the sequence of revisions created for this entity. $sequence_key = $entity->getEntityTypeId() . '.' . $entity->uuid() . '.revision_sequence'; $sequence = $this->keyValueFactory->get('ws_test')->get($sequence_key, []); $sequence[] = [ 'is_new' => $entity->isNew(), 'is_new_revision' => $entity->isNewRevision(), 'is_published' => $entity->isPublished(), 'is_default_revision' => $entity->isDefaultRevision(), ]; $this->keyValueFactory->get('ws_test')->set($sequence_key, $sequence); } /** Loading core/modules/workspaces/tests/modules/workspaces_test/src/Plugin/Field/FieldType/RevisionTestItem.php 0 → 100644 +46 −0 Original line number Diff line number Diff line <?php declare(strict_types=1); namespace Drupal\workspaces_test\Plugin\Field\FieldType; use Drupal\Core\Field\Attribute\FieldType; use Drupal\Core\StringTranslation\TranslatableMarkup; use Drupal\entity_test\Plugin\Field\FieldType\FieldTestItem; /** * Defines the 'revision_test_field' field type. * * This field type records entity revision status during preSave() for * testing workspace entity save operations. */ #[FieldType( id: "revision_test_field", label: new TranslatableMarkup("Revision Test Field"), description: new TranslatableMarkup("A test field that tracks entity revision status during saves."), )] class RevisionTestItem extends FieldTestItem { /** * {@inheritdoc} */ public function preSave(): void { parent::preSave(); /** @var \Drupal\Core\Entity\RevisionableInterface|\Drupal\Core\Entity\EntityPublishedInterface $entity */ $entity = $this->getEntity(); // Track the revision sequence of field pre-save for this entity. // @see \Drupal\workspaces_test\Hook\WorkspacesTestHooks::entityPresave() $sequence_key = $entity->getEntityTypeId() . '.' . $entity->uuid() . '.field_revision_sequence'; $sequence = \Drupal::keyValue('ws_test')->get($sequence_key, []); $sequence[] = [ 'is_new' => $entity->isNew(), 'is_new_revision' => $entity->isNewRevision(), 'is_published' => $entity->isPublished(), 'is_default_revision' => $entity->isDefaultRevision(), ]; \Drupal::keyValue('ws_test')->set($sequence_key, $sequence); } } core/modules/workspaces/tests/src/Kernel/WorkspaceEntityOperationsTest.php 0 → 100644 +123 −0 Original line number Diff line number Diff line <?php declare(strict_types=1); namespace Drupal\Tests\workspaces\Kernel; use Drupal\entity_test\Entity\EntityTestMulRevPub; use Drupal\KernelTests\KernelTestBase; use Drupal\Tests\user\Traits\UserCreationTrait; use Drupal\workspaces\Entity\Workspace; use PHPUnit\Framework\Attributes\Group; /** * Tests entity operations with workspaces. */ #[Group('workspaces')] class WorkspaceEntityOperationsTest extends KernelTestBase { use UserCreationTrait; use WorkspaceTestTrait; /** * {@inheritdoc} */ protected static $modules = [ 'entity_test', 'system', 'user', 'workspaces', 'workspaces_test', ]; /** * The entity type manager. * * @var \Drupal\Core\Entity\EntityTypeManagerInterface */ protected $entityTypeManager; /** * {@inheritdoc} */ protected function setUp(): void { parent::setUp(); $this->entityTypeManager = \Drupal::entityTypeManager(); $this->workspaceManager = \Drupal::service('workspaces.manager'); $this->installEntitySchema('entity_test_mulrevpub'); $this->installEntitySchema('workspace'); $this->installSchema('workspaces', ['workspace_association', 'workspace_association_revision']); $this->installConfig(['system']); $this->setUpCurrentUser([], [ 'create workspace', 'view any workspace', 'edit any workspace', 'delete any workspace', ]); $this->workspaces['stage'] = Workspace::create(['id' => 'stage', 'label' => 'Stage']); $this->workspaces['stage']->save(); } /** * Test published entity creation in a workspace. */ public function testEntityCreation(): void { $this->switchToWorkspace('stage'); // Create a published entity in the workspace. $entity = EntityTestMulRevPub::create([ 'name' => 'Test published entity in workspace', 'status' => TRUE, 'revision_test_field' => $this->randomString(), ]); $entity->save(); // Get the revision sequence that was tracked during entity saves. $sequence_key = 'entity_test_mulrevpub.' . $entity->uuid() . '.revision_sequence'; $revision_sequence = \Drupal::keyValue('ws_test')->get($sequence_key, []); $field_sequence_key = 'entity_test_mulrevpub.' . $entity->uuid() . '.field_revision_sequence'; $field_revision_sequence = \Drupal::keyValue('ws_test')->get($field_sequence_key, []); // We expect exactly 2 presave calls when a published entity is created in a // workspace: // 1. First save: unpublished default revision. // 2. Second save: published pending revision. $this->assertCount(2, $revision_sequence); $this->assertCount(2, $field_revision_sequence); // Verify the is_new_revision status. $this->assertTrue($revision_sequence[0]['is_new_revision']); $this->assertTrue($revision_sequence[1]['is_new_revision']); $this->assertTrue($field_revision_sequence[0]['is_new_revision']); $this->assertTrue($field_revision_sequence[1]['is_new_revision']); // Verify the is_new status. $this->assertTrue($revision_sequence[0]['is_new']); $this->assertFalse($revision_sequence[1]['is_new']); $this->assertTrue($field_revision_sequence[0]['is_new']); $this->assertFalse($field_revision_sequence[1]['is_new']); // Verify the publishing status of each revision. $this->assertFalse($revision_sequence[0]['is_published']); $this->assertTrue($revision_sequence[1]['is_published']); // The entity presave hook is fired after the field's presave() // implementation, so at this point the first revision is still published. $this->assertTrue($field_revision_sequence[0]['is_published']); $this->assertTrue($field_revision_sequence[1]['is_published']); // Verify the default revision status. $this->assertTrue($revision_sequence[0]['is_default_revision']); $this->assertFalse($revision_sequence[1]['is_default_revision']); $this->assertTrue($field_revision_sequence[0]['is_default_revision']); $this->assertFalse($field_revision_sequence[1]['is_default_revision']); } } Loading
core/modules/workspaces/src/Hook/EntityOperations.php +4 −0 Original line number Diff line number Diff line Loading @@ -168,6 +168,10 @@ public function entityInsert(EntityInterface $entity): void { } $entity->setPublished(); // Ensure that the second (workspace-specific) revision is marked as new // early, so operations that are executed before the entity presave hook // (e.g. field-level presave) can take that into account. $entity->setNewRevision(); $entity->isDefaultRevision(FALSE); $entity->save(); } Loading
core/modules/workspaces/tests/modules/workspaces_test/src/Hook/WorkspacesTestHooks.php +39 −0 Original line number Diff line number Diff line Loading @@ -5,8 +5,12 @@ namespace Drupal\workspaces_test\Hook; use Drupal\Core\Entity\EntityInterface; use Drupal\Core\Entity\EntityTypeInterface; use Drupal\Core\Field\BaseFieldDefinition; use Drupal\Core\Hook\Attribute\Hook; use Drupal\Core\KeyValueStore\KeyValueFactoryInterface; use Drupal\Core\StringTranslation\TranslatableMarkup; use Drupal\workspaces\WorkspaceInformationInterface; use Symfony\Component\DependencyInjection\Attribute\Autowire; /** Loading @@ -17,6 +21,7 @@ class WorkspacesTestHooks { public function __construct( #[Autowire(service: 'keyvalue')] protected readonly KeyValueFactoryInterface $keyValueFactory, protected readonly WorkspaceInformationInterface $workspaceInformation, ) {} /** Loading @@ -32,6 +37,24 @@ public function entityTypeAlter(array &$entity_types) : void { } } /** * Implements hook_entity_base_field_info(). */ #[Hook('entity_base_field_info')] public function entityBaseFieldInfo(EntityTypeInterface $entity_type): array { $fields = []; // Add the workspace revision field test to entity_test_mulrevpub. if ($entity_type->id() === 'entity_test_mulrevpub') { $fields['revision_test_field'] = BaseFieldDefinition::create('revision_test_field') ->setLabel(new TranslatableMarkup('Workspace Revision Field Test')) ->setDescription(new TranslatableMarkup('A test field that tracks isNewRevision() status during field presave.')) ->setRevisionable(TRUE); } return $fields; } /** * Implements hook_ENTITY_TYPE_translation_create() for 'entity_test_mulrevpub'. */ Loading @@ -56,6 +79,22 @@ public function entityCreate(EntityInterface $entity): void { #[Hook('entity_presave')] public function entityPresave(EntityInterface $entity): void { $this->incrementHookCount('hook_entity_presave', $entity); if (!$this->workspaceInformation->isEntitySupported($entity)) { return; } /** @var \Drupal\Core\Entity\RevisionableInterface|\Drupal\Core\Entity\EntityPublishedInterface $entity */ // Track the sequence of revisions created for this entity. $sequence_key = $entity->getEntityTypeId() . '.' . $entity->uuid() . '.revision_sequence'; $sequence = $this->keyValueFactory->get('ws_test')->get($sequence_key, []); $sequence[] = [ 'is_new' => $entity->isNew(), 'is_new_revision' => $entity->isNewRevision(), 'is_published' => $entity->isPublished(), 'is_default_revision' => $entity->isDefaultRevision(), ]; $this->keyValueFactory->get('ws_test')->set($sequence_key, $sequence); } /** Loading
core/modules/workspaces/tests/modules/workspaces_test/src/Plugin/Field/FieldType/RevisionTestItem.php 0 → 100644 +46 −0 Original line number Diff line number Diff line <?php declare(strict_types=1); namespace Drupal\workspaces_test\Plugin\Field\FieldType; use Drupal\Core\Field\Attribute\FieldType; use Drupal\Core\StringTranslation\TranslatableMarkup; use Drupal\entity_test\Plugin\Field\FieldType\FieldTestItem; /** * Defines the 'revision_test_field' field type. * * This field type records entity revision status during preSave() for * testing workspace entity save operations. */ #[FieldType( id: "revision_test_field", label: new TranslatableMarkup("Revision Test Field"), description: new TranslatableMarkup("A test field that tracks entity revision status during saves."), )] class RevisionTestItem extends FieldTestItem { /** * {@inheritdoc} */ public function preSave(): void { parent::preSave(); /** @var \Drupal\Core\Entity\RevisionableInterface|\Drupal\Core\Entity\EntityPublishedInterface $entity */ $entity = $this->getEntity(); // Track the revision sequence of field pre-save for this entity. // @see \Drupal\workspaces_test\Hook\WorkspacesTestHooks::entityPresave() $sequence_key = $entity->getEntityTypeId() . '.' . $entity->uuid() . '.field_revision_sequence'; $sequence = \Drupal::keyValue('ws_test')->get($sequence_key, []); $sequence[] = [ 'is_new' => $entity->isNew(), 'is_new_revision' => $entity->isNewRevision(), 'is_published' => $entity->isPublished(), 'is_default_revision' => $entity->isDefaultRevision(), ]; \Drupal::keyValue('ws_test')->set($sequence_key, $sequence); } }
core/modules/workspaces/tests/src/Kernel/WorkspaceEntityOperationsTest.php 0 → 100644 +123 −0 Original line number Diff line number Diff line <?php declare(strict_types=1); namespace Drupal\Tests\workspaces\Kernel; use Drupal\entity_test\Entity\EntityTestMulRevPub; use Drupal\KernelTests\KernelTestBase; use Drupal\Tests\user\Traits\UserCreationTrait; use Drupal\workspaces\Entity\Workspace; use PHPUnit\Framework\Attributes\Group; /** * Tests entity operations with workspaces. */ #[Group('workspaces')] class WorkspaceEntityOperationsTest extends KernelTestBase { use UserCreationTrait; use WorkspaceTestTrait; /** * {@inheritdoc} */ protected static $modules = [ 'entity_test', 'system', 'user', 'workspaces', 'workspaces_test', ]; /** * The entity type manager. * * @var \Drupal\Core\Entity\EntityTypeManagerInterface */ protected $entityTypeManager; /** * {@inheritdoc} */ protected function setUp(): void { parent::setUp(); $this->entityTypeManager = \Drupal::entityTypeManager(); $this->workspaceManager = \Drupal::service('workspaces.manager'); $this->installEntitySchema('entity_test_mulrevpub'); $this->installEntitySchema('workspace'); $this->installSchema('workspaces', ['workspace_association', 'workspace_association_revision']); $this->installConfig(['system']); $this->setUpCurrentUser([], [ 'create workspace', 'view any workspace', 'edit any workspace', 'delete any workspace', ]); $this->workspaces['stage'] = Workspace::create(['id' => 'stage', 'label' => 'Stage']); $this->workspaces['stage']->save(); } /** * Test published entity creation in a workspace. */ public function testEntityCreation(): void { $this->switchToWorkspace('stage'); // Create a published entity in the workspace. $entity = EntityTestMulRevPub::create([ 'name' => 'Test published entity in workspace', 'status' => TRUE, 'revision_test_field' => $this->randomString(), ]); $entity->save(); // Get the revision sequence that was tracked during entity saves. $sequence_key = 'entity_test_mulrevpub.' . $entity->uuid() . '.revision_sequence'; $revision_sequence = \Drupal::keyValue('ws_test')->get($sequence_key, []); $field_sequence_key = 'entity_test_mulrevpub.' . $entity->uuid() . '.field_revision_sequence'; $field_revision_sequence = \Drupal::keyValue('ws_test')->get($field_sequence_key, []); // We expect exactly 2 presave calls when a published entity is created in a // workspace: // 1. First save: unpublished default revision. // 2. Second save: published pending revision. $this->assertCount(2, $revision_sequence); $this->assertCount(2, $field_revision_sequence); // Verify the is_new_revision status. $this->assertTrue($revision_sequence[0]['is_new_revision']); $this->assertTrue($revision_sequence[1]['is_new_revision']); $this->assertTrue($field_revision_sequence[0]['is_new_revision']); $this->assertTrue($field_revision_sequence[1]['is_new_revision']); // Verify the is_new status. $this->assertTrue($revision_sequence[0]['is_new']); $this->assertFalse($revision_sequence[1]['is_new']); $this->assertTrue($field_revision_sequence[0]['is_new']); $this->assertFalse($field_revision_sequence[1]['is_new']); // Verify the publishing status of each revision. $this->assertFalse($revision_sequence[0]['is_published']); $this->assertTrue($revision_sequence[1]['is_published']); // The entity presave hook is fired after the field's presave() // implementation, so at this point the first revision is still published. $this->assertTrue($field_revision_sequence[0]['is_published']); $this->assertTrue($field_revision_sequence[1]['is_published']); // Verify the default revision status. $this->assertTrue($revision_sequence[0]['is_default_revision']); $this->assertFalse($revision_sequence[1]['is_default_revision']); $this->assertTrue($field_revision_sequence[0]['is_default_revision']); $this->assertFalse($field_revision_sequence[1]['is_default_revision']); } }