diff --git a/core/modules/views/src/Entity/Render/EntityFieldRenderer.php b/core/modules/views/src/Entity/Render/EntityFieldRenderer.php index 3c38da1760..101edd4a27 100644 --- a/core/modules/views/src/Entity/Render/EntityFieldRenderer.php +++ b/core/modules/views/src/Entity/Render/EntityFieldRenderer.php @@ -200,7 +200,8 @@ protected function buildFields(array $values) { $field = $this->view->field[current($field_ids)]; foreach ($values as $result_row) { if ($entity = $field->getEntity($result_row)) { - $entities_by_bundles[$entity->bundle()][$result_row->index] = $this->getEntityTranslation($entity, $result_row); + $relationship = isset($field->options['relationship']) ? $field->options['relationship'] : 'none'; + $entities_by_bundles[$entity->bundle()][$result_row->index] = $this->getEntityTranslation($entity, $result_row, $relationship); } } diff --git a/core/modules/views/src/Entity/Render/EntityTranslationRenderTrait.php b/core/modules/views/src/Entity/Render/EntityTranslationRenderTrait.php index 8fbc191d14..d70f25b83d 100644 --- a/core/modules/views/src/Entity/Render/EntityTranslationRenderTrait.php +++ b/core/modules/views/src/Entity/Render/EntityTranslationRenderTrait.php @@ -62,11 +62,13 @@ protected function getEntityTranslationRenderer() { * The entity object the field value being processed is attached to. * @param \Drupal\views\ResultRow $row * The result row the field value being processed belongs to. + * @param string $relationship + * The relationship to be used, or 'none' by default. * * @return \Drupal\Core\Entity\FieldableEntityInterface * The entity translation object for the specified row. */ - public function getEntityTranslation(EntityInterface $entity, ResultRow $row) { + public function getEntityTranslation(EntityInterface $entity, ResultRow $row, $relationship = 'none') { // We assume the same language should be used for all entity fields // belonging to a single row, even if they are attached to different entity // types. Below we apply language fallback to ensure a valid value is always diff --git a/core/modules/views/src/Entity/Render/EntityTranslationRendererBase.php b/core/modules/views/src/Entity/Render/EntityTranslationRendererBase.php index e77992dd01..bd64bd20e8 100644 --- a/core/modules/views/src/Entity/Render/EntityTranslationRendererBase.php +++ b/core/modules/views/src/Entity/Render/EntityTranslationRendererBase.php @@ -21,6 +21,21 @@ */ abstract public function getLangcode(ResultRow $row); + /** + * Returns the language code for the given row based on the relationship. + * + * @param \Drupal\views\ResultRow $row + * The result row. + * @param string $relationship + * The relationship to be used. + * + * @return string + * A language code. + */ + public function getLangcodeByRelationship(ResultRow $row, $relationship) { + return $this->getLangcode($row); + } + /** * {@inheritdoc} */ @@ -31,15 +46,25 @@ public function query(QueryPluginBase $query, $relationship = NULL) { * {@inheritdoc} */ public function preRender(array $result) { + $this->preRenderByRelationship($result, 'none'); + } + + /** + * Runs before each entity is rendered if a relationship is needed. + * + * @param \Drupal\views\ResultRow[] $result + * The full array of results from the query. + * @param string $relationship + * The relationship to be used. + */ + public function preRenderByRelationship(array $result, $relationship) { $view_builder = $this->view->rowPlugin->entityManager->getViewBuilder($this->entityType->id()); - /** @var \Drupal\views\ResultRow $row */ foreach ($result as $row) { - // @todo Take relationships into account. - // See https://www.drupal.org/node/2457999. - $entity = $row->_entity; - $entity->view = $this->view; - $this->build[$entity->id()] = $view_builder->view($entity, $this->view->rowPlugin->options['view_mode'], $this->getLangcode($row)); + if ($entity = $this->getEntity($row, $relationship)) { + $entity->view = $this->view; + $this->build[$entity->id()] = $view_builder->view($entity, $this->view->rowPlugin->options['view_mode'], $this->getLangcodeByRelationship($row, $relationship)); + } } } @@ -47,8 +72,47 @@ public function preRender(array $result) { * {@inheritdoc} */ public function render(ResultRow $row) { - $entity_id = $row->_entity->id(); - return $this->build[$entity_id]; + return $this->renderByRelationship($row, 'none'); + } + + /** + * Renders entity data. + * + * @param \Drupal\views\ResultRow $row + * A single row of the query result. + * @param string $relationship + * The relationship to be used. + * + * @return array + * A renderable array for the entity data contained in the result row. + */ + public function renderByRelationship(ResultRow $row, $relationship) { + if ($entity = $this->getEntity($row, $relationship)) { + $entity_id = $entity->id(); + return $this->build[$entity_id]; + } + } + + /** + * Gets the entity associated with a row. + * + * @param \Drupal\views\ResultRow $row + * The result row. + * @param string $relationship + * (optional) The relationship. + * + * @return \Drupal\Core\Entity\EntityInterface|null + * The entity might be optional, because the relationship entity might not + * always exist. + */ + protected function getEntity($row, $relationship = 'none') { + if ($relationship === 'none') { + return $row->_entity; + } + elseif (isset($row->_relationship_entities[$relationship])) { + return $row->_relationship_entities[$relationship]; + } + return NULL; } } diff --git a/core/modules/views/src/Entity/Render/RendererBase.php b/core/modules/views/src/Entity/Render/RendererBase.php index 60327f615f..b47dd43081 100644 --- a/core/modules/views/src/Entity/Render/RendererBase.php +++ b/core/modules/views/src/Entity/Render/RendererBase.php @@ -93,7 +93,7 @@ public function getCacheTags() { /** * Runs before each entity is rendered. * - * @param $result + * @param \Drupal\views\ResultRow[] $result * The full array of results from the query. */ public function preRender(array $result) { diff --git a/core/modules/views/src/Entity/Render/TranslationLanguageRenderer.php b/core/modules/views/src/Entity/Render/TranslationLanguageRenderer.php index 5b4b3561cd..8f293fb2ff 100644 --- a/core/modules/views/src/Entity/Render/TranslationLanguageRenderer.php +++ b/core/modules/views/src/Entity/Render/TranslationLanguageRenderer.php @@ -79,25 +79,28 @@ protected function getLangcodeTable(QueryPluginBase $query, $relationship) { /** * {@inheritdoc} */ - public function preRender(array $result) { + public function preRenderByRelationship(array $result, $relationship) { $view_builder = $this->view->rowPlugin->entityManager->getViewBuilder($this->entityType->id()); /** @var \Drupal\views\ResultRow $row */ foreach ($result as $row) { - $entity = $row->_entity; - $entity->view = $this->view; - $langcode = $this->getLangcode($row); - $this->build[$entity->id()][$langcode] = $view_builder->view($entity, $this->view->rowPlugin->options['view_mode'], $this->getLangcode($row)); + if ($entity = $this->getEntity($row, $relationship)) { + $entity->view = $this->view; + $langcode = $this->getLangcodeByRelationship($row, $relationship); + $this->build[$entity->id()][$langcode] = $view_builder->view($entity, $this->view->rowPlugin->options['view_mode'], $langcode); + } } } /** * {@inheritdoc} */ - public function render(ResultRow $row) { - $entity_id = $row->_entity->id(); - $langcode = $this->getLangcode($row); - return $this->build[$entity_id][$langcode]; + public function renderByRelationship(ResultRow $row, $relationship) { + if ($entity = $this->getEntity($row, $relationship)) { + $entity_id = $entity->id(); + $langcode = $this->getLangcodeByRelationship($row, $relationship); + return $this->build[$entity_id][$langcode]; + } } /** diff --git a/core/modules/views/src/Plugin/views/row/EntityRow.php b/core/modules/views/src/Plugin/views/row/EntityRow.php index e98133af72..c8c9b66f59 100644 --- a/core/modules/views/src/Plugin/views/row/EntityRow.php +++ b/core/modules/views/src/Plugin/views/row/EntityRow.php @@ -166,7 +166,11 @@ public function summaryTitle() { */ public function query() { parent::query(); - $this->getEntityTranslationRenderer()->query($this->view->getQuery()); + $relationship_table = NULL; + if (isset($this->options['relationship'], $this->view->relationship[$this->options['relationship']])) { + $relationship_table = $this->view->relationship[$this->options['relationship']]->alias; + } + $this->getEntityTranslationRenderer()->query($this->view->getQuery(), $relationship_table); } /** @@ -175,7 +179,7 @@ public function query() { public function preRender($result) { parent::preRender($result); if ($result) { - $this->getEntityTranslationRenderer()->preRender($result); + $this->getEntityTranslationRenderer()->preRenderByRelationship($result, isset($this->options['relationship']) ? $this->options['relationship'] : 'none'); } } @@ -183,7 +187,7 @@ public function preRender($result) { * {@inheritdoc} */ public function render($row) { - return $this->getEntityTranslationRenderer()->render($row); + return $this->getEntityTranslationRenderer()->renderByRelationship($row, isset($this->options['relationship']) ? $this->options['relationship'] : 'none'); } /** diff --git a/core/modules/views/src/Plugin/views/row/RowPluginBase.php b/core/modules/views/src/Plugin/views/row/RowPluginBase.php index 3c09eaf06a..0e6da98d03 100644 --- a/core/modules/views/src/Plugin/views/row/RowPluginBase.php +++ b/core/modules/views/src/Plugin/views/row/RowPluginBase.php @@ -90,7 +90,7 @@ public function buildOptionsForm(&$form, FormStateInterface $form_state) { $data = Views::viewsData()->get($relationship['table']); $base = $data[$relationship['field']]['relationship']['base']; if ($base == $this->base_table) { - $relationship_handler->init($executable, $relationship); + $relationship_handler->init($executable, $this->displayHandler, $relationship); $relationship_options[$relationship['id']] = $relationship_handler->adminLabel(); } } diff --git a/core/modules/views/tests/modules/views_test_config/test_views/views.view.test_entity_row.yml b/core/modules/views/tests/modules/views_test_config/test_views/views.view.test_entity_row.yml index ad9f748197..c786e20443 100644 --- a/core/modules/views/tests/modules/views_test_config/test_views/views.view.test_entity_row.yml +++ b/core/modules/views/tests/modules/views_test_config/test_views/views.view.test_entity_row.yml @@ -6,8 +6,8 @@ label: '' module: views description: '' tag: '' -base_table: taxonomy_term_field_data -base_field: nid +base_table: entity_test +base_field: id core: '8' display: default: @@ -21,10 +21,17 @@ display: offset: 0 type: none row: - type: 'entity:taxonomy_term' + type: 'entity:entity_test' options: relationship: none view_mode: full + relationships: + user_id: + table: entity_test + field: user_id + id: user_id + relationship: none + plugin_id: standard display_plugin: default display_title: Master id: default diff --git a/core/modules/views/tests/src/Kernel/Plugin/RowEntityTest.php b/core/modules/views/tests/src/Kernel/Plugin/RowEntityTest.php index 208a6f0ee3..e3b7487048 100644 --- a/core/modules/views/tests/src/Kernel/Plugin/RowEntityTest.php +++ b/core/modules/views/tests/src/Kernel/Plugin/RowEntityTest.php @@ -3,10 +3,10 @@ namespace Drupal\Tests\views\Kernel\Plugin; use Drupal\Core\Form\FormState; +use Drupal\entity_test\Entity\EntityTest; +use Drupal\user\Entity\User; use Drupal\views\Views; use Drupal\Tests\views\Kernel\ViewsKernelTestBase; -use Drupal\taxonomy\Entity\Vocabulary; -use Drupal\taxonomy\Entity\Term; /** * Tests the generic entity row plugin. @@ -21,7 +21,7 @@ class RowEntityTest extends ViewsKernelTestBase { * * @var array */ - public static $modules = ['taxonomy', 'text', 'filter', 'field', 'system', 'node', 'user']; + public static $modules = ['entity_test', 'field', 'system', 'user']; /** * Views used by this test. @@ -34,27 +34,55 @@ class RowEntityTest extends ViewsKernelTestBase { * {@inheritdoc} */ protected function setUp($import_test_views = TRUE) { - parent::setUp(); + parent::setUp($import_test_views); - $this->installEntitySchema('taxonomy_term'); - $this->installConfig(['taxonomy']); - \Drupal::service('router.builder')->rebuild(); + $this->installEntitySchema('entity_test'); + $this->installEntitySchema('user'); } /** * Tests the entity row handler. */ public function testEntityRow() { - $vocab = Vocabulary::create(['name' => $this->randomMachineName(), 'vid' => strtolower($this->randomMachineName())]); - $vocab->save(); - $term = Term::create(['name' => $this->randomMachineName(), 'vid' => $vocab->id()]); - $term->save(); + $user = User::create([ + 'name' => 'test user', + ]); + $user->save(); + $entity_test = EntityTest::create([ + 'user_id' => $user->id(), + 'name' => 'test entity test', + ]); + $entity_test->save(); + + // Ensure entities have different ids. + if ($entity_test->id() == $user->id()) { + $entity_test->delete(); + $entity_test = EntityTest::create([ + 'user_id' => $user->id(), + 'name' => 'test entity test', + ]); + $entity_test->save(); + } + + $view = Views::getView('test_entity_row'); + $build = $view->preview(); + $this->render($build); + + $this->assertText('test entity test'); + $this->assertNoText('Member for'); + + // Change the view to use a relationship to render the row. $view = Views::getView('test_entity_row'); + $display = &$view->storage->getDisplay('default'); + $display['display_options']['row']['type'] = 'entity:user'; + $display['display_options']['row']['options']['relationship'] = 'user_id'; + $view->setDisplay('default'); $build = $view->preview(); $this->render($build); - $this->assertText($term->getName(), 'The rendered entity appears as row in the view.'); + $this->assertNoText('test entity test'); + $this->assertText('Member for'); // Tests the available view mode options. $form = [];