From 6dc692bebc5ecbf0b24bce3b2a45a85850a8710b Mon Sep 17 00:00:00 2001 From: Francesco Placella <plach@183211.no-reply.drupal.org> Date: Tue, 8 Oct 2019 02:47:49 +0200 Subject: [PATCH] Issue #2925816 by godotislate, jens.de.geit, Berdir, Lendude, Anybody, mbovan, rollingnet, tstoeckler: Views plugin "Rendered Entity" must add langcode in render function --- .../src/Plugin/views/field/RenderedEntity.php | 2 +- ...ew.test_entity_field_renderered_entity.yml | 211 +++++++++++++ .../FieldRenderedEntityTranslationTest.php | 292 ++++++++++++++++++ 3 files changed, 504 insertions(+), 1 deletion(-) create mode 100644 core/modules/views/tests/modules/views_test_config/test_views/views.view.test_entity_field_renderered_entity.yml create mode 100644 core/modules/views/tests/src/Functional/Entity/FieldRenderedEntityTranslationTest.php diff --git a/core/modules/views/src/Plugin/views/field/RenderedEntity.php b/core/modules/views/src/Plugin/views/field/RenderedEntity.php index f70b03f5d958..90e5469eae8b 100644 --- a/core/modules/views/src/Plugin/views/field/RenderedEntity.php +++ b/core/modules/views/src/Plugin/views/field/RenderedEntity.php @@ -153,7 +153,7 @@ public function render(ResultRow $values) { $build['#access'] = $access; if ($access->isAllowed()) { $view_builder = $this->entityTypeManager->getViewBuilder($this->getEntityTypeId()); - $build += $view_builder->view($entity, $this->options['view_mode']); + $build += $view_builder->view($entity, $this->options['view_mode'], $entity->language()->getId()); } } return $build; diff --git a/core/modules/views/tests/modules/views_test_config/test_views/views.view.test_entity_field_renderered_entity.yml b/core/modules/views/tests/modules/views_test_config/test_views/views.view.test_entity_field_renderered_entity.yml new file mode 100644 index 000000000000..8a04ba1f638f --- /dev/null +++ b/core/modules/views/tests/modules/views_test_config/test_views/views.view.test_entity_field_renderered_entity.yml @@ -0,0 +1,211 @@ +langcode: en +status: true +dependencies: + config: + - core.entity_view_mode.node.default + module: + - node +id: test_entity_field_renderered_entity +label: test_entity_field_renderered_entity +module: views +description: '' +tag: '' +base_table: node_field_data +base_field: nid +core: 8.x +display: + default: + display_plugin: default + id: default + display_title: Master + position: 0 + display_options: + defaults: + fields: false + pager: false + sorts: false + pager: + options: + offset: 0 + type: none + row: + type: fields + sorts: + nid: + id: nid + table: node_field_data + field: nid + relationship: none + group_type: group + admin_label: '' + order: ASC + exposed: false + expose: + label: '' + entity_type: node + entity_field: nid + plugin_id: standard + title: + id: title + table: node_field_data + field: title + plugin_id: standard + entity_type: node + entity_field: title + rendering_language: '***LANGUAGE_entity_translation***' + fields: + rendered_entity: + id: rendered_entity + table: node + field: rendered_entity + relationship: none + group_type: group + admin_label: '' + label: '' + exclude: false + alter: + alter_text: false + text: '' + make_link: false + path: '' + absolute: false + external: false + replace_spaces: false + path_case: none + trim_whitespace: false + alt: '' + rel: '' + link_class: '' + prefix: '' + suffix: '' + target: '' + nl2br: false + max_length: 0 + word_boundary: true + ellipsis: true + more_link: false + more_link_text: '' + more_link_path: '' + strip_tags: false + trim: false + preserve_tags: '' + html: false + element_type: '' + element_class: '' + element_label_type: '' + element_label_class: '' + element_label_colon: false + element_wrapper_type: '' + element_wrapper_class: '' + element_default_classes: true + empty: '' + hide_empty: false + empty_zero: false + hide_alter_empty: true + view_mode: default + entity_type: node + plugin_id: rendered_entity + display_extenders: { } + cache_metadata: + max-age: -1 + contexts: + - 'languages:language_interface' + - 'user.node_grants:view' + tags: + - 'config:core.entity_view_display.node.article.default' + page_1: + display_plugin: page + id: page_1 + display_title: Page + position: 1 + display_options: + rendering_language: '***LANGUAGE_entity_translation***' + path: test_entity_field_renderered_entity/entity_translation + display_extenders: { } + cache_metadata: + max-age: -1 + contexts: + - 'languages:language_interface' + - 'user.node_grants:view' + tags: + - 'config:core.entity_view_display.node.article.default' + page_2: + display_plugin: page + id: page_2 + display_title: Page + position: 2 + display_options: + rendering_language: '***LANGUAGE_entity_default***' + path: test_entity_field_renderered_entity/entity_default + display_extenders: { } + cache_metadata: + max-age: -1 + contexts: + - 'languages:language_interface' + - 'user.node_grants:view' + tags: + - 'config:core.entity_view_display.node.article.default' + page_3: + display_plugin: page + id: page_3 + display_title: Page + position: 3 + display_options: + rendering_language: '***LANGUAGE_site_default***' + path: test_entity_field_renderered_entity/site_default + display_extenders: { } + cache_metadata: + max-age: -1 + contexts: + - 'languages:language_interface' + - 'user.node_grants:view' + tags: + - 'config:core.entity_view_display.node.article.default' + page_4: + display_plugin: page + id: page_4 + display_title: Page + position: 4 + display_options: + rendering_language: '***LANGUAGE_language_interface***' + path: test_entity_field_renderered_entity/language_interface + display_extenders: { } + cache_metadata: + max-age: -1 + contexts: + - 'languages:language_interface' + - 'user.node_grants:view' + tags: + - 'config:core.entity_view_display.node.article.default' + page_5: + display_plugin: page + id: page_5 + display_title: Page + position: 5 + display_options: + rendering_language: en + path: test_entity_field_renderered_entity/en + display_extenders: { } + cache_metadata: + max-age: -1 + contexts: + - 'languages:language_interface' + - 'user.node_grants:view' + tags: + - 'config:core.entity_view_display.node.article.default' + page_6: + display_plugin: page + id: page_6 + display_title: Page + position: 6 + display_options: + rendering_language: es + path: test_entity_field_renderered_entity/es + display_extenders: { } + cache_metadata: + max-age: -1 + contexts: + - 'languages:language_interface' + - 'user.node_grants:view' + tags: + - 'config:core.entity_view_display.node.article.default' diff --git a/core/modules/views/tests/src/Functional/Entity/FieldRenderedEntityTranslationTest.php b/core/modules/views/tests/src/Functional/Entity/FieldRenderedEntityTranslationTest.php new file mode 100644 index 000000000000..5f04bc9208d7 --- /dev/null +++ b/core/modules/views/tests/src/Functional/Entity/FieldRenderedEntityTranslationTest.php @@ -0,0 +1,292 @@ +<?php + +namespace Drupal\Tests\views\Functional\Entity; + +use Drupal\Core\Language\Language; +use Drupal\Tests\views\Functional\ViewTestBase; +use Symfony\Component\CssSelector\CssSelectorConverter; + +/** + * Tests the rendering of the 'rendered_entity' field and translations. + * + * @group views + */ +class FieldRenderedEntityTranslationTest extends ViewTestBase { + + /** + * {@inheritdoc} + */ + public static $modules = ['language', 'locale', 'content_translation', 'node']; + + /** + * {@inheritdoc} + */ + public static $testViews = ['test_entity_field_renderered_entity']; + + /** + * The entity type manager service. + * + * @var \Drupal\Core\Entity\EntityTypeManagerInterface + */ + protected $entityTypeManager; + + /** + * {@inheritdoc} + */ + protected function setUp($import_test_views = TRUE) { + parent::setUp($import_test_views); + + $this->entityTypeManager = $this->container->get('entity_type.manager'); + + $node_type = $this->entityTypeManager->getStorage('node_type')->create([ + 'type' => 'article', + 'label' => 'Article', + ]); + $node_type->save(); + + /** @var \Drupal\content_translation\ContentTranslationManagerInterface $content_translation_manager */ + $content_translation_manager = $this->container->get('content_translation.manager'); + + $content_translation_manager->setEnabled('node', 'article', TRUE); + + $language = $this->entityTypeManager->getStorage('configurable_language')->create([ + 'id' => 'es', + 'label' => 'Spanish', + ]); + $language->save(); + // Rebuild the container to setup the language path processors. + $this->rebuildContainer(); + } + + /** + * Tests that different translation mechanisms can be used for base fields. + */ + public function testTranslationRows() { + // First, an EN node with an ES translation. + /** @var \Drupal\node\NodeInterface $node */ + $node = $this->entityTypeManager->getStorage('node')->create([ + 'type' => 'article', + 'title' => 'example EN default', + ]); + $node->save(); + + $translation = $node->addTranslation('es'); + $translation->title->value = 'example ES translation'; + $translation->sticky->value = TRUE; + $translation->save(); + + // Next, an ES node with an EN translation. + $node = $this->entityTypeManager->getStorage('node')->create([ + 'type' => 'article', + 'title' => 'example ES default', + 'langcode' => 'es', + ]); + $node->save(); + + $translation = $node->addTranslation('en'); + $translation->title->value = 'example EN translation'; + $translation->sticky->value = TRUE; + $translation->save(); + + // Next an EN node with no translation. + $node = $this->entityTypeManager->getStorage('node')->create([ + 'type' => 'article', + 'title' => 'example EN no translation', + 'sticky' => FALSE, + ]); + $node->save(); + + // Next an ES node with no translation. + $node = $this->entityTypeManager->getStorage('node')->create([ + 'type' => 'article', + 'title' => 'example ES no translation', + 'sticky' => FALSE, + 'langcode' => 'es', + ]); + $node->save(); + + // Views are sorted first by node id ascending, and then title ascending. + // Confirm each node and node translation renders in its own language. + $this->drupalGet('test_entity_field_renderered_entity/entity_translation'); + $this->assertRows([ + [ + 'title' => 'example EN default', + ], + [ + 'title' => 'example ES translation', + ], + [ + 'title' => 'example EN translation', + ], + [ + 'title' => 'example ES default', + ], + [ + 'title' => 'example EN no translation', + ], + [ + 'title' => 'example ES no translation', + ], + ]); + + // Confirm each node and node translation renders in the default language of + // the node. + $this->drupalGet('test_entity_field_renderered_entity/entity_default'); + $this->assertRows([ + [ + 'title' => 'example EN default', + ], + [ + 'title' => 'example EN default', + ], + [ + 'title' => 'example ES default', + ], + [ + 'title' => 'example ES default', + ], + [ + 'title' => 'example EN no translation', + ], + [ + 'title' => 'example ES no translation', + ], + ]); + + // Confirm each node and node translation renders in the site's default + // language (en), with fallback if node does not have en content. + $this->drupalGet('test_entity_field_renderered_entity/site_default'); + $this->assertRows([ + [ + 'title' => 'example EN default', + ], + [ + 'title' => 'example EN default', + ], + [ + 'title' => 'example EN translation', + ], + [ + 'title' => 'example EN translation', + ], + [ + 'title' => 'example EN no translation', + ], + [ + 'title' => 'example ES no translation', + ], + ]); + + // Confirm each node and node translation renders in the site interface + // language (en), with fallback if node does not have en content. + $this->drupalGet('test_entity_field_renderered_entity/language_interface'); + $this->assertRows([ + [ + 'title' => 'example EN default', + ], + [ + 'title' => 'example EN default', + ], + [ + 'title' => 'example EN translation', + ], + [ + 'title' => 'example EN translation', + ], + [ + 'title' => 'example EN no translation', + ], + [ + 'title' => 'example ES no translation', + ], + ]); + + // Confirm each node and node translation renders in the site interface + // language (es), with fallback if node does not have es content. + $this->drupalGet('test_entity_field_renderered_entity/language_interface', ['language' => new Language(['id' => 'es'])]); + $this->assertRows([ + [ + 'title' => 'example ES translation', + ], + [ + 'title' => 'example ES translation', + ], + [ + 'title' => 'example ES default', + ], + [ + 'title' => 'example ES default', + ], + [ + 'title' => 'example EN no translation', + ], + [ + 'title' => 'example ES no translation', + ], + ]); + + // Confirm each node and node translation renders in specified language en. + $this->drupalGet('test_entity_field_renderered_entity/en'); + $this->assertRows([ + [ + 'title' => 'example EN default', + ], + [ + 'title' => 'example EN default', + ], + [ + 'title' => 'example EN translation', + ], + [ + 'title' => 'example EN translation', + ], + [ + 'title' => 'example EN no translation', + ], + [ + 'title' => 'example ES no translation', + ], + ]); + + // Confirm each node and node translation renders in specified language es. + $this->drupalGet('test_entity_field_renderered_entity/es'); + $this->assertRows([ + [ + 'title' => 'example ES translation', + ], + [ + 'title' => 'example ES translation', + ], + [ + 'title' => 'example ES default', + ], + [ + 'title' => 'example ES default', + ], + [ + 'title' => 'example EN no translation', + ], + [ + 'title' => 'example ES no translation', + ], + ]); + } + + /** + * Ensures that the rendered results are working as expected. + * + * @param array $expected + * The expected rows of the result. + */ + protected function assertRows(array $expected = []) { + $actual = []; + $rows = $this->cssSelect('div.views-row'); + foreach ($rows as $row) { + $actual[] = [ + 'title' => $row->find('xpath', (new CssSelectorConverter())->toXPath('h2 a .field--name-title'))->getText(), + ]; + } + $this->assertEquals($actual, $expected); + } + +} -- GitLab