diff --git a/core/core.services.yml b/core/core.services.yml index c63bde7a4136a28b5db686eda7d15bf43b1b7aca..398a81d104a1bb727fb0ea55ee90272dfc8e82a9 100644 --- a/core/core.services.yml +++ b/core/core.services.yml @@ -940,7 +940,7 @@ services: class: Drupal\Core\ParamConverter\EntityRevisionParamConverter tags: - { name: paramconverter } - arguments: ['@entity_type.manager'] + arguments: ['@entity_type.manager', '@entity.repository'] paramconverter.configentity_admin: class: Drupal\Core\ParamConverter\AdminPathConfigEntityConverter tags: diff --git a/core/lib/Drupal/Core/ParamConverter/EntityRevisionParamConverter.php b/core/lib/Drupal/Core/ParamConverter/EntityRevisionParamConverter.php index 79e463badd61baed7dd64ec7cce28f5ae307a389..0d312795e9cee4e5b8be635abb1deed8ded0f8c5 100644 --- a/core/lib/Drupal/Core/ParamConverter/EntityRevisionParamConverter.php +++ b/core/lib/Drupal/Core/ParamConverter/EntityRevisionParamConverter.php @@ -2,6 +2,7 @@ namespace Drupal\Core\ParamConverter; +use Drupal\Core\Entity\EntityRepositoryInterface; use Drupal\Core\Entity\EntityTypeManagerInterface; use Symfony\Component\Routing\Route; @@ -31,14 +32,24 @@ class EntityRevisionParamConverter implements ParamConverterInterface { */ protected $entityTypeManager; + /** + * The entity repository. + * + * @var \Drupal\Core\Entity\EntityRepositoryInterface + */ + protected $entityRepository; + /** * Creates a new EntityRevisionParamConverter instance. * * @param \Drupal\Core\Entity\EntityTypeManagerInterface $entity_type_manager * The entity type manager. + * @param \Drupal\Core\Entity\EntityRepositoryInterface $entity_repository + * The entity repository. */ - public function __construct(EntityTypeManagerInterface $entity_type_manager) { + public function __construct(EntityTypeManagerInterface $entity_type_manager, EntityRepositoryInterface $entity_repository) { $this->entityTypeManager = $entity_type_manager; + $this->entityRepository = $entity_repository; } /** @@ -46,8 +57,8 @@ public function __construct(EntityTypeManagerInterface $entity_type_manager) { */ public function convert($value, $definition, $name, array $defaults) { list (, $entity_type_id) = explode(':', $definition['type'], 2); - $entity_storage = $this->entityTypeManager->getStorage($entity_type_id); - return $entity_storage->loadRevision($value); + $entity = $this->entityTypeManager->getStorage($entity_type_id)->loadRevision($value); + return $this->entityRepository->getTranslationFromContext($entity); } /** diff --git a/core/modules/node/src/Controller/NodeController.php b/core/modules/node/src/Controller/NodeController.php index 89a6d7e435ec5a67a3098d937dc41426b3b4f5da..e564cf59f96cd4355d24282e4c340c0927911a2b 100644 --- a/core/modules/node/src/Controller/NodeController.php +++ b/core/modules/node/src/Controller/NodeController.php @@ -126,6 +126,7 @@ public function add(NodeTypeInterface $node_type) { */ public function revisionShow($node_revision) { $node = $this->entityManager()->getStorage('node')->loadRevision($node_revision); + $node = $this->entityManager()->getTranslationFromContext($node); $node_view_controller = new NodeViewController($this->entityManager, $this->renderer); $page = $node_view_controller->view($node); unset($page['nodes'][$node->id()]['#cache']); diff --git a/core/modules/node/src/Tests/NodeTranslationUITest.php b/core/modules/node/src/Tests/NodeTranslationUITest.php index b4dce569bd05023d798a5f9421e47fbc807d7a5e..c4f04dc1d6a40504d908e19b4cd02fe1e61da6ba 100644 --- a/core/modules/node/src/Tests/NodeTranslationUITest.php +++ b/core/modules/node/src/Tests/NodeTranslationUITest.php @@ -445,4 +445,53 @@ protected function doTestTranslationEdit() { } } + /** + * Tests that revision translations are rendered properly. + */ + public function testRevisionTranslationRendering() { + $storage = \Drupal::entityTypeManager()->getStorage('node'); + + // Create a node. + $nid = $this->createEntity(['title' => 'First rev en title'], 'en'); + $node = $storage->load($nid); + $original_revision_id = $node->getRevisionId(); + + // Add a French translation. + $translation = $node->addTranslation('fr'); + $translation->title = 'First rev fr title'; + $translation->setNewRevision(FALSE); + $translation->save(); + + // Create a new revision. + $node->title = 'Second rev en title'; + $node->setNewRevision(TRUE); + $node->save(); + + // Get an English view of this revision. + $original_revision = $storage->loadRevision($original_revision_id); + $original_revision_url = $original_revision->toUrl('revision')->toString(); + + // Should be different from regular node URL. + $this->assertNotIdentical($original_revision_url, $original_revision->toUrl()->toString()); + $this->drupalGet($original_revision_url); + $this->assertResponse(200); + + // Contents should be in English, of correct revision. + $this->assertText('First rev en title'); + $this->assertNoText('First rev fr title'); + + // Get a French view. + $url_fr = $original_revision->getTranslation('fr')->toUrl('revision')->toString(); + + // Should have different URL from English. + $this->assertNotIdentical($url_fr, $original_revision->toUrl()->toString()); + $this->assertNotIdentical($url_fr, $original_revision_url); + $this->drupalGet($url_fr); + $this->assertResponse(200); + + // Contents should be in French, of correct revision. + $this->assertText('First rev fr title'); + $this->assertNoText('First rev en title'); + } + } diff --git a/core/modules/system/src/Tests/Entity/EntityRevisionsTest.php b/core/modules/system/src/Tests/Entity/EntityRevisionsTest.php index bee4ec283f5ec1be65a263beec505646b096aab9..28f46efb408f27bbe33d64d3397549bfd6ecfd9d 100644 --- a/core/modules/system/src/Tests/Entity/EntityRevisionsTest.php +++ b/core/modules/system/src/Tests/Entity/EntityRevisionsTest.php @@ -2,6 +2,8 @@ namespace Drupal\system\Tests\Entity; +use Drupal\entity_test\Entity\EntityTestMulRev; +use Drupal\language\Entity\ConfigurableLanguage; use Drupal\simpletest\WebTestBase; /** @@ -17,7 +19,7 @@ class EntityRevisionsTest extends WebTestBase { * * @var array */ - public static $modules = array('entity_test'); + public static $modules = array('entity_test', 'language'); /** * A user with permission to administer entity_test content. @@ -35,6 +37,9 @@ protected function setUp() { 'view test entity', )); $this->drupalLogin($this->webUser); + + // Enable an additional language. + ConfigurableLanguage::createFromLangcode('de')->save(); } /** @@ -113,4 +118,41 @@ protected function runRevisionsTests($entity_type) { $this->assertFieldById('edit-field-test-text-0-value', $entity->field_test_text->value, format_string('%entity_type: Text matches in UI.', array('%entity_type' => $entity_type))); } + /** + * Tests that an entity revision is upcasted in the correct language. + */ + public function testEntityRevisionParamConverter() { + // Create a test entity with multiple revisions and translations for them. + $entity = EntityTestMulRev::create([ + 'name' => 'default revision - en', + 'user_id' => $this->webUser, + 'language' => 'en', + ]); + $entity->addTranslation('de', ['name' => 'default revision - de']); + $entity->save(); + + $forward_revision = \Drupal::entityTypeManager()->getStorage('entity_test_mulrev')->loadUnchanged($entity->id()); + + $forward_revision->setNewRevision(); + $forward_revision->isDefaultRevision(FALSE); + + $forward_revision->name = 'forward revision - en'; + $forward_revision->save(); + + $forward_revision_translation = $forward_revision->getTranslation('de'); + $forward_revision_translation->name = 'forward revision - de'; + $forward_revision_translation->save(); + + // Check that the entity revision is upcasted in the correct language. + $revision_url = 'entity_test_mulrev/' . $entity->id() . '/revision/' . $forward_revision->getRevisionId() . '/view'; + + $this->drupalGet($revision_url); + $this->assertText('forward revision - en'); + $this->assertNoText('forward revision - de'); + + $this->drupalGet('de/' . $revision_url); + $this->assertText('forward revision - de'); + $this->assertNoText('forward revision - en'); + } + } diff --git a/core/modules/system/tests/modules/entity_test/entity_test.routing.yml b/core/modules/system/tests/modules/entity_test/entity_test.routing.yml index e4353c8771704b340c553e6bb45727dba399ab65..5b6d37b946a4dd8b60cfb221e67eb0a3a1a55020 100644 --- a/core/modules/system/tests/modules/entity_test/entity_test.routing.yml +++ b/core/modules/system/tests/modules/entity_test/entity_test.routing.yml @@ -68,6 +68,19 @@ entity.entity_test_rev.revision: requirements: _access: 'TRUE' +entity.entity_test_mulrev.revision: + path: '/entity_test_mulrev/{entity_test_mulrev}/revision/{entity_test_mulrev_revision}/view' + defaults: + _controller: '\Drupal\Core\Entity\Controller\EntityViewController::viewRevision' + options: + parameters: + entity_test_mulrev: + type: entity:entity_test_mulrev + entity_test_mulrev_revision: + type: entity_revision:entity_test_mulrev + requirements: + _access: 'TRUE' + entity.block.test_operation: path: '/admin/structure/block/manage/{block}/test_operation' defaults: diff --git a/core/tests/Drupal/KernelTests/Core/Entity/EntityRevisionTranslationTest.php b/core/tests/Drupal/KernelTests/Core/Entity/EntityRevisionTranslationTest.php index 9bfa5e18f3c002d77d616ca5d1ca8fb9d264877b..676a98abac33f2489b2cf9e518bf85ce41c99d0c 100644 --- a/core/tests/Drupal/KernelTests/Core/Entity/EntityRevisionTranslationTest.php +++ b/core/tests/Drupal/KernelTests/Core/Entity/EntityRevisionTranslationTest.php @@ -87,4 +87,49 @@ public function testRevertRevisionAfterTranslation() { $this->assertFalse($entity->hasTranslation('de')); } + /** + * Tests the translation values when saving a forward revision. + */ + public function testTranslationValuesWhenSavingForwardRevisions() { + $user = $this->createUser(); + $storage = $this->entityManager->getStorage('entity_test_mulrev'); + + // Create a test entity and a translation for it. + $entity = EntityTestMulRev::create([ + 'name' => 'default revision - en', + 'user_id' => $user->id(), + 'language' => 'en', + ]); + $entity->addTranslation('de', ['name' => 'default revision - de']); + $entity->save(); + + // Create a forward revision for the entity and change a field value for + // both languages. + $forward_revision = $this->reloadEntity($entity); + + $forward_revision->setNewRevision(); + $forward_revision->isDefaultRevision(FALSE); + + $forward_revision->name = 'forward revision - en'; + $forward_revision->save(); + + $forward_revision_translation = $forward_revision->getTranslation('de'); + $forward_revision_translation->name = 'forward revision - de'; + $forward_revision_translation->save(); + + $forward_revision_id = $forward_revision->getRevisionId(); + $forward_revision = $storage->loadRevision($forward_revision_id); + + // Change the value of the field in the default language, save the forward + // revision and check that the value of the field in the second language is + // also taken from the forward revision, *not* from the default revision. + $forward_revision->name = 'updated forward revision - en'; + $forward_revision->save(); + + $forward_revision = $storage->loadRevision($forward_revision_id); + + $this->assertEquals($forward_revision->name->value, 'updated forward revision - en'); + $this->assertEquals($forward_revision->getTranslation('de')->name->value, 'forward revision - de'); + } + } diff --git a/core/tests/Drupal/Tests/Core/ParamConverter/EntityRevisionParamConverterTest.php b/core/tests/Drupal/Tests/Core/ParamConverter/EntityRevisionParamConverterTest.php index 3f265d855ea4b73ccdc5098cb2f7ec8265877088..23ac69fd7f68024c76ec88ca93c2c73367569cc4 100644 --- a/core/tests/Drupal/Tests/Core/ParamConverter/EntityRevisionParamConverterTest.php +++ b/core/tests/Drupal/Tests/Core/ParamConverter/EntityRevisionParamConverterTest.php @@ -3,6 +3,7 @@ namespace Drupal\Tests\Core\ParamConverter; use Drupal\Core\Entity\EntityInterface; +use Drupal\Core\Entity\EntityRepositoryInterface; use Drupal\Core\Entity\EntityStorageInterface; use Drupal\Core\Entity\EntityTypeManagerInterface; use Drupal\Core\ParamConverter\EntityRevisionParamConverter; @@ -28,7 +29,10 @@ class EntityRevisionParamConverterTest extends UnitTestCase { protected function setUp() { parent::setUp(); - $this->converter = new EntityRevisionParamConverter($this->prophesize(EntityTypeManagerInterface::class)->reveal()); + $this->converter = new EntityRevisionParamConverter( + $this->prophesize(EntityTypeManagerInterface::class)->reveal(), + $this->prophesize(EntityRepositoryInterface::class)->reveal() + ); } protected function getTestRoute() { @@ -67,7 +71,9 @@ public function testConvert() { $entity_type_manager = $this->prophesize(EntityTypeManagerInterface::class); $entity_type_manager->getStorage('test')->willReturn($storage->reveal()); - $converter = new EntityRevisionParamConverter($entity_type_manager->reveal()); + $entity_repository = $this->prophesize(EntityRepositoryInterface::class); + $entity_repository->getTranslationFromContext($entity)->willReturn($entity); + $converter = new EntityRevisionParamConverter($entity_type_manager->reveal(), $entity_repository->reveal()); $route = $this->getTestRoute(); $result = $converter->convert(1, $route->getOption('parameters')['test_revision'], 'test_revision', ['test_revision' => 1]);