diff --git a/core/modules/workspaces/src/EntityOperations.php b/core/modules/workspaces/src/EntityOperations.php index 4c1e42dd9ef..6c4c66d7b0e 100644 --- a/core/modules/workspaces/src/EntityOperations.php +++ b/core/modules/workspaces/src/EntityOperations.php @@ -219,6 +219,40 @@ class EntityOperations implements ContainerInjectionInterface { } } + /** + * Acts after an entity translation has been added. + * + * @param \Drupal\Core\Entity\EntityInterface $translation + * The translation that was added. + * + * @see hook_entity_translation_insert() + */ + public function entityTranslationInsert(EntityInterface $translation): void { + if ($this->shouldSkipOperations($translation) + || !$this->workspaceInfo->isEntitySupported($translation) + || $translation->isSyncing() + ) { + return; + } + + // When a new translation is added to an existing entity, we need to add + // that translation to the default revision as well, otherwise the new + // translation wouldn't show up in entity queries or views which use the + // field data table as the base table. + $this->workspaceManager->executeOutsideWorkspace(function () use ($translation) { + $storage = $this->entityTypeManager->getStorage($translation->getEntityTypeId()); + $default_revision = $storage->load($translation->id()); + + $langcode = $translation->language()->getId(); + if (!$default_revision->hasTranslation($langcode)) { + $default_revision_translation = $default_revision->addTranslation($langcode, $translation->toArray()); + $default_revision_translation->setUnpublished(); + $default_revision_translation->setSyncing(TRUE); + $default_revision_translation->save(); + } + }); + } + /** * Acts on an entity before it is deleted. * diff --git a/core/modules/workspaces/tests/src/Kernel/WorkspaceContentTranslationTest.php b/core/modules/workspaces/tests/src/Kernel/WorkspaceContentTranslationTest.php new file mode 100644 index 00000000000..414876be531 --- /dev/null +++ b/core/modules/workspaces/tests/src/Kernel/WorkspaceContentTranslationTest.php @@ -0,0 +1,131 @@ +entityTypeManager = \Drupal::entityTypeManager(); + + $this->installEntitySchema('entity_test_mulrevpub'); + $this->installEntitySchema('user'); + $this->installEntitySchema('workspace'); + + $this->installConfig(['language', 'content_translation']); + + $this->installSchema('workspaces', ['workspace_association']); + + $language = ConfigurableLanguage::createFromLangcode('ro'); + $language->save(); + + $this->container->get('content_translation.manager') + ->setEnabled('entity_test_mulrevpub', 'entity_test_mulrevpub', TRUE); + + Workspace::create(['id' => 'stage', 'label' => 'Stage'])->save(); + } + + /** + * Tests translations created in a workspace. + * + * @covers \Drupal\workspaces\EntityOperations::entityTranslationInsert + */ + public function testTranslations(): void { + $storage = $this->entityTypeManager->getStorage('entity_test_mulrevpub'); + + // Create two untranslated nodes in Live, a published and an unpublished one. + $entity_published = $storage->create(['name' => 'live - 1 - published', 'status' => TRUE]); + $entity_published->save(); + $entity_unpublished = $storage->create(['name' => 'live - 2 - unpublished', 'status' => FALSE]); + $entity_unpublished->save(); + + // Activate the Stage workspace and add translations. + $this->switchToWorkspace('stage'); + + // Add a translation for each entity. + $entity_published->addTranslation('ro', ['name' => 'live - 1 - published - RO']); + $entity_published->save(); + + $entity_unpublished->addTranslation('ro', ['name' => 'live - 2 - unpublished - RO']); + $entity_unpublished->save(); + + // Both 'EN' and 'RO' translations are published in Stage. + $entity_published = $storage->loadUnchanged($entity_published->id()); + $this->assertTrue($entity_published->isPublished()); + $this->assertEquals('live - 1 - published', $entity_published->get('name')->value); + + $translation = $entity_published->getTranslation('ro'); + $this->assertTrue($translation->isPublished()); + $this->assertEquals('live - 1 - published - RO', $translation->get('name')->value); + + // Both 'EN' and 'RO' translations are unpublished in Stage. + $entity_unpublished = $storage->loadUnchanged($entity_unpublished->id()); + $this->assertFalse($entity_unpublished->isPublished()); + $this->assertEquals('live - 2 - unpublished', $entity_unpublished->get('name')->value); + + $translation = $entity_unpublished->getTranslation('ro'); + $this->assertEquals('live - 2 - unpublished - RO', $translation->get('name')->value); + $this->assertTrue($translation->isPublished()); + + // Switch to Live and check the translations. + $this->switchToLive(); + + // The 'EN' translation is still published in Live, but the 'RO' one is + // unpublished. + $entity_published = $storage->loadUnchanged($entity_published->id()); + $this->assertTrue($entity_published->isPublished()); + $this->assertEquals('live - 1 - published', $entity_published->get('name')->value); + + $translation = $entity_published->getTranslation('ro'); + $this->assertFalse($translation->isPublished()); + $this->assertEquals('live - 1 - published - RO', $translation->get('name')->value); + + // Both 'EN' and 'RO' translations are unpublished in Live. + $entity_unpublished = $storage->loadUnchanged($entity_unpublished->id()); + $this->assertFalse($entity_unpublished->isPublished()); + $this->assertEquals('live - 2 - unpublished', $entity_unpublished->get('name')->value); + + $translation = $entity_unpublished->getTranslation('ro'); + $this->assertFalse($translation->isPublished()); + $this->assertEquals('live - 2 - unpublished - RO', $translation->get('name')->value); + } + +} diff --git a/core/modules/workspaces/tests/src/Kernel/WorkspaceTestTrait.php b/core/modules/workspaces/tests/src/Kernel/WorkspaceTestTrait.php index a6e99937ff5..db8b6765731 100644 --- a/core/modules/workspaces/tests/src/Kernel/WorkspaceTestTrait.php +++ b/core/modules/workspaces/tests/src/Kernel/WorkspaceTestTrait.php @@ -71,6 +71,13 @@ trait WorkspaceTestTrait { \Drupal::service('workspaces.manager')->setActiveWorkspace($workspace); } + /** + * Switches the test runner's context to Live. + */ + protected function switchToLive(): void { + \Drupal::service('workspaces.manager')->switchToLive(); + } + /** * Creates a test workspace hierarchy. * diff --git a/core/modules/workspaces/workspaces.module b/core/modules/workspaces/workspaces.module index ab12654ad09..885364cc3cd 100644 --- a/core/modules/workspaces/workspaces.module +++ b/core/modules/workspaces/workspaces.module @@ -131,6 +131,15 @@ function workspaces_entity_update(EntityInterface $entity) { ->entityUpdate($entity); } +/** + * Implements hook_entity_translation_insert(). + */ +function workspaces_entity_translation_insert(EntityInterface $translation): void { + \Drupal::service('class_resolver') + ->getInstanceFromDefinition(EntityOperations::class) + ->entityTranslationInsert($translation); +} + /** * Implements hook_entity_predelete(). */