diff --git a/core/modules/views/src/Entity/Render/ConfigurableLanguageRenderer.php b/core/modules/views/src/Entity/Render/ConfigurableLanguageRenderer.php index 697ae8a..ce96c49 100644 --- a/core/modules/views/src/Entity/Render/ConfigurableLanguageRenderer.php +++ b/core/modules/views/src/Entity/Render/ConfigurableLanguageRenderer.php @@ -44,7 +44,7 @@ public function __construct(ViewExecutable $view, LanguageManagerInterface $lang /** * {@inheritdoc} */ - public function getLangcode(ResultRow $row) { + public function getLangcode(ResultRow $row, $relationship = 'none') { return $this->langcode; } diff --git a/core/modules/views/src/Entity/Render/DefaultLanguageRenderer.php b/core/modules/views/src/Entity/Render/DefaultLanguageRenderer.php index dbd3a72..55f5a5b 100644 --- a/core/modules/views/src/Entity/Render/DefaultLanguageRenderer.php +++ b/core/modules/views/src/Entity/Render/DefaultLanguageRenderer.php @@ -17,8 +17,10 @@ class DefaultLanguageRenderer extends EntityTranslationRendererBase { /** * {@inheritdoc} */ - public function getLangcode(ResultRow $row) { - return $row->_entity->getUntranslated()->language()->getId(); + public function getLangcode(ResultRow $row, $relationship = 'none') { + if ($entity = $this->getEntity($row, $relationship)) { + return $entity->getUntranslated()->language()->getId(); + } } } diff --git a/core/modules/views/src/Entity/Render/EntityFieldRenderer.php b/core/modules/views/src/Entity/Render/EntityFieldRenderer.php index b00a572..3c2c84a 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) { $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); } // Determine unique sets of fields that can be processed by the same diff --git a/core/modules/views/src/Entity/Render/EntityTranslationRenderTrait.php b/core/modules/views/src/Entity/Render/EntityTranslationRenderTrait.php index 7f9f44c..20f6815 100644 --- a/core/modules/views/src/Entity/Render/EntityTranslationRenderTrait.php +++ b/core/modules/views/src/Entity/Render/EntityTranslationRenderTrait.php @@ -67,18 +67,20 @@ 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 // picked. $translation = $entity; if ($entity instanceof TranslatableInterface && count($entity->getTranslationLanguages()) > 1) { - $langcode = $this->getEntityTranslationRenderer()->getLangcode($row); + $langcode = $this->getEntityTranslationRenderer()->getLangcode($row, $relationship); $translation = $this->getEntityManager()->getTranslationFromContext($entity, $langcode); } return $translation; diff --git a/core/modules/views/src/Entity/Render/EntityTranslationRendererBase.php b/core/modules/views/src/Entity/Render/EntityTranslationRendererBase.php index 4da6672..9a5cdf3 100644 --- a/core/modules/views/src/Entity/Render/EntityTranslationRendererBase.php +++ b/core/modules/views/src/Entity/Render/EntityTranslationRendererBase.php @@ -20,11 +20,13 @@ * * @param \Drupal\views\ResultRow $row * The result row. + * @param string $relationship + * The relationship to be used, or 'none' by default. * * @return string * A language code. */ - abstract public function getLangcode(ResultRow $row); + abstract public function getLangcode(ResultRow $row, $relationship = 'none'); /** * {@inheritdoc} @@ -33,27 +35,62 @@ public function query(QueryPluginBase $query, $relationship = NULL) { } /** - * {@inheritdoc} + * Runs before each entity is rendered. + * + * @param \Drupal\views\ResultRow[] $result + * The full array of results from the query. + * @param string $relationship + * The relationship to be used, or 'none' by default. */ - public function preRender(array $result) { + public function preRender(array $result, $relationship = 'none') { $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->getLangcode($row, $relationship)); + } } } /** - * {@inheritdoc} + * Renders entity data. + * + * @param \Drupal\views\ResultRow $row + * A single row of the query result. + * @param string $relationship + * The relationship to be used, or 'none' by default. + * + * @return array + * A renderable array for the entity data contained in the result row. */ - public function render(ResultRow $row) { - $entity_id = $row->_entity->id(); - return $this->build[$entity_id]; + public function render(ResultRow $row, $relationship = 'none') { + if ($entity = $this->getEntity($row, $relationship)) { + $entity_id = $entity->id(); + return $this->build[$entity_id]; + } + } + + /** + * Gets the entity assosiated 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 deb1806..0a65d82 100644 --- a/core/modules/views/src/Entity/Render/RendererBase.php +++ b/core/modules/views/src/Entity/Render/RendererBase.php @@ -90,7 +90,7 @@ public function getCacheContexts() { /** * 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 c94243b..34d918d 100644 --- a/core/modules/views/src/Entity/Render/TranslationLanguageRenderer.php +++ b/core/modules/views/src/Entity/Render/TranslationLanguageRenderer.php @@ -48,31 +48,34 @@ public function query(QueryPluginBase $query, $relationship = NULL) { /** * {@inheritdoc} */ - public function preRender(array $result) { + public function preRender(array $result, $relationship = 'none') { $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->getLangcode($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 render(ResultRow $row, $relationship = 'none') { + if ($entity = $this->getEntity($row, $relationship)) { + $entity_id = $entity->id(); + $langcode = $this->getLangcode($row, $relationship); + return $this->build[$entity_id][$langcode]; + } } /** * {@inheritdoc} */ - public function getLangcode(ResultRow $row) { + public function getLangcode(ResultRow $row, $relationship = 'none') { return isset($row->{$this->langcodeAlias}) ? $row->{$this->langcodeAlias} : $this->languageManager->getDefaultLanguage()->getId(); } diff --git a/core/modules/views/src/Plugin/views/row/EntityRow.php b/core/modules/views/src/Plugin/views/row/EntityRow.php index e95e5fa..c0034d4 100644 --- a/core/modules/views/src/Plugin/views/row/EntityRow.php +++ b/core/modules/views/src/Plugin/views/row/EntityRow.php @@ -172,7 +172,13 @@ public function summaryTitle() { */ public function query() { parent::query(); - $this->getEntityTranslationRenderer()->query($this->view->getQuery()); + if (isset($this->options['relationship'], $this->view->relationship[$this->options['relationship']])) { + $relationship = $this->view->relationship[$this->options['relationship']]->alias; + } + else { + $relationship = NULL; + } + $this->getEntityTranslationRenderer()->query($this->view->getQuery(), $relationship); } /** @@ -181,7 +187,7 @@ public function query() { public function preRender($result) { parent::preRender($result); if ($result) { - $this->getEntityTranslationRenderer()->preRender($result); + $this->getEntityTranslationRenderer()->preRender($result, isset($this->options['relationship']) ? $this->options['relationship'] : 'none'); } } @@ -189,7 +195,7 @@ public function preRender($result) { * Overrides Drupal\views\Plugin\views\row\RowPluginBase::render(). */ public function render($row) { - return $this->getEntityTranslationRenderer()->render($row); + return $this->getEntityTranslationRenderer()->render($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 059a415..9c84f8e 100644 --- a/core/modules/views/src/Plugin/views/row/RowPluginBase.php +++ b/core/modules/views/src/Plugin/views/row/RowPluginBase.php @@ -96,7 +96,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/src/Tests/Plugin/EntityRowTest.php b/core/modules/views/src/Tests/Plugin/EntityRowTest.php new file mode 100644 index 0000000..46a6366 --- /dev/null +++ b/core/modules/views/src/Tests/Plugin/EntityRowTest.php @@ -0,0 +1,101 @@ +installEntitySchema('entity_test'); + $this->installEntitySchema('user'); + } + + /** + * Tests the entity row handler. + */ + public function testEntityRow() { + $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->assertNoText('test entity test'); + $this->assertText('Member for'); + + // Tests the available view mode options. + $form = array(); + $form_state = new FormState(); + $form_state->set('view', $view->storage); + $view->rowPlugin->buildOptionsForm($form, $form_state); + + $this->assertTrue(isset($form['view_mode']['#options']['default']), 'Ensure that the default view mode is available'); + } + +} diff --git a/core/modules/views/src/Tests/Plugin/RowEntityTest.php b/core/modules/views/src/Tests/Plugin/RowEntityTest.php deleted file mode 100644 index 7de0305..0000000 --- a/core/modules/views/src/Tests/Plugin/RowEntityTest.php +++ /dev/null @@ -1,71 +0,0 @@ -installEntitySchema('taxonomy_term'); - $this->installConfig(array('taxonomy')); - \Drupal::service('router.builder')->rebuild(); - } - - /** - * Tests the entity row handler. - */ - public function testEntityRow() { - $vocab = entity_create('taxonomy_vocabulary', array('name' => $this->randomMachineName(), 'vid' => strtolower($this->randomMachineName()))); - $vocab->save(); - $term = entity_create('taxonomy_term', array('name' => $this->randomMachineName(), 'vid' => $vocab->id() )); - $term->save(); - - $view = Views::getView('test_entity_row'); - $build = $view->preview(); - $this->render($build); - - $this->assertText($term->getName(), 'The rendered entity appears as row in the view.'); - - // Tests the available view mode options. - $form = array(); - $form_state = new FormState(); - $form_state->set('view', $view->storage); - $view->rowPlugin->buildOptionsForm($form, $form_state); - - $this->assertTrue(isset($form['view_mode']['#options']['default']), 'Ensure that the default view mode is available'); - } - -} 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 ad9f748..c786e20 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