Skip to content
Snippets Groups Projects
Commit 392b69b1 authored by Bojan Zivanovic's avatar Bojan Zivanovic
Browse files

Merge pull request #21 from bojanz/rendered-entity

Rendered entity
parents 7485e64a 7789696c
No related branches found
No related tags found
No related merge requests found
views.field.rendered_entity:
type: views_field
label: 'Rendered entity'
mapping:
view_mode:
type: string
label: 'View mode'
<?php
use Drupal\Core\Entity\ContentEntityInterface;
use Drupal\Core\Entity\EntityTypeInterface;
/**
* Implements hook_views_data().
*/
function entity_views_data() {
$entity_types = \Drupal::entityTypeManager()->getDefinitions();
$entity_types = array_filter($entity_types, function (EntityTypeInterface $entity_type) {
return $entity_type->isSubclassOf(ContentEntityInterface::class);
});
$data = [];
foreach ($entity_types as $entity_type) {
/** @var \Drupal\Core\Entity\EntityTypeInterface $entity_type */
$base_table = $entity_type->getBaseTable() ?: $entity_type->id();
if ($entity_type->hasViewBuilderClass()) {
$data[$base_table]['rendered_entity'] = [
'field' => [
'title' => t('Rendered entity'),
'help' => t('Renders an entity in a view mode.'),
'id' => 'rendered_entity',
],
];
}
}
return $data;
}
<?php
/**
* @file
* Contains \Drupal\entity\Plugin\views\field\RenderedEntity.
*/
namespace Drupal\entity\Plugin\views\field;
use Drupal\Core\Cache\CacheableDependencyInterface;
use Drupal\Core\Entity\EntityManagerInterface;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Language\LanguageManagerInterface;
use Drupal\views\Entity\Render\EntityTranslationRenderTrait;
use Drupal\views\ResultRow;
use Symfony\Component\DependencyInjection\ContainerInterface;
/**
* Provides a field handler which renders an entity in a certain view mode.
*
* @ingroup views_field_handlers
*
* @ViewsField("rendered_entity")
*/
class RenderedEntity extends FieldPluginBase implements CacheableDependencyInterface {
use EntityTranslationRenderTrait;
/**
* The entity manager.
*
* @var \Drupal\Core\Entity\EntityManagerInterface
*/
protected $entityManager;
/**
* The language manager.
*
* @var \Drupal\Core\Language\LanguageManagerInterface
*/
protected $languageManager;
/**
* Constructs a new RenderedEntity object.
*
* @param array $configuration
* A configuration array containing information about the plugin instance.
* @param string $plugin_id
* The plugin_id for the plugin instance.
* @param array $plugin_definition
* The plugin implementation definition.
* @param \Drupal\Core\Entity\EntityManagerInterface $entity_manager
* The entity manager.
* @param \Drupal\Core\Language\LanguageManagerInterface $language_manager
* The language manager.
*/
public function __construct(array $configuration, $plugin_id, array $plugin_definition, EntityManagerInterface $entity_manager, LanguageManagerInterface $language_manager) {
parent::__construct($configuration, $plugin_id, $plugin_definition);
$this->entityManager = $entity_manager;
$this->languageManager = $language_manager;
}
/**
* {@inheritdoc}
*/
public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) {
return new static(
$configuration,
$plugin_id,
$plugin_definition,
$container->get('entity.manager'),
$container->get('language_manager')
);
}
/**
* {@inheritdoc}
*/
public function usesGroupBy() {
return FALSE;
}
/**
* {@inheritdoc}
*/
public function defineOptions() {
$options = parent::defineOptions();
$options['view_mode'] = ['default' => 'default'];
return $options;
}
/**
* {@inheritdoc}
*/
public function buildOptionsForm(&$form, FormStateInterface $form_state) {
parent::buildOptionsForm($form, $form_state);
$form['view_mode'] = [
'#type' => 'select',
'#options' => $this->entityManager->getViewModeOptions($this->getEntityTypeId()),
'#title' => $this->t('View mode'),
'#default_value' => $this->options['view_mode'],
];
}
/**
* {@inheritdoc}
*/
public function render(ResultRow $values) {
$entity = $this->getEntityTranslation($this->getEntity($values), $values);
if (isset($entity) && $entity->access('view')) {
$view_builder = $this->entityManager->getViewBuilder($this->getEntityTypeId());
return $view_builder->view($entity, $this->options['view_mode']);
}
return [];
}
/**
* {@inheritdoc}
*/
public function getCacheContexts() {
return [];
}
/**
* {@inheritdoc}
*/
public function getCacheTags() {
$view_display_storage = $this->entityManager->getStorage('entity_view_display');
$view_displays = $view_display_storage->loadMultiple($view_display_storage
->getQuery()
->condition('targetEntityType', $this->getEntityTypeId())
->execute());
$tags = [];
foreach ($view_displays as $view_display) {
$tags = array_merge($tags, $view_display->getCacheTags());
}
return $tags;
}
/**
* {@inheritdoc}
*/
public function getCacheMaxAge() {
return 0;
}
/**
* {@inheritdoc}
*/
public function query() {
// We purposefully do not call parent::query() because we do not want the
// default query behavior for Views fields. Instead, let the entity
// translation renderer provide the correct query behavior.
if ($this->languageManager->isMultilingual()) {
$this->getEntityTranslationRenderer()->query($this->query, $this->relationship);
}
}
/**
* {@inheritdoc}
*/
public function getEntityTypeId() {
return $this->getEntityType();
}
/**
* {@inheritdoc}
*/
protected function getEntityManager() {
return $this->entityManager;
}
/**
* {@inheritdoc}
*/
protected function getLanguageManager() {
return $this->languageManager;
}
/**
* {@inheritdoc}
*/
protected function getView() {
return $this->view;
}
/**
* {@inheritdoc}
*/
public function calculateDependencies() {
$dependencies = parent::calculateDependencies();
$view_mode = $this->entityManager
->getStorage('entity_view_mode')
->load($this->entityTypeId . '.' . $this->options['view_mode']);
if ($view_mode) {
$dependencies[$view_mode->getConfigDependencyKey()][] = $view_mode->getConfigDependencyName();
}
return $dependencies;
}
}
<?php
/**
* @file
* Contains \Drupal\entity\Tests\Plugin\views\field\RenderedEntityTest.
*/
namespace Drupal\entity\Tests\Plugin\views\field;
use Drupal\Core\Entity\Entity\EntityViewDisplay;
use Drupal\entity_test\Entity\EntityTest;
use Drupal\field\Entity\FieldConfig;
use Drupal\field\Entity\FieldStorageConfig;
use Drupal\user\Entity\Role;
use Drupal\user\Entity\User;
use Drupal\views\Tests\ViewKernelTestBase;
use Drupal\views\Tests\ViewTestData;
use Drupal\views\Views;
use Drupal\Core\Entity\Entity\EntityViewMode;
/**
* Tests the Drupal\entity\Plugin\views\field\RenderedEntity handler.
*
* @group entity
*/
class RenderedEntityTest extends ViewKernelTestBase {
/**
* Modules to enable.
*
* @var array
*/
public static $modules = ['entity_test', 'entity_module_test', 'field'];
/**
* Views used by this test.
*
* @var array
*/
public static $testViews = ['test_entity_rendered'];
/**
* The logged in user.
*
* @var \Drupal\user\UserInterface
*/
protected $user;
/**
* {@inheritdoc}
*/
protected function setUp($import_test_views = TRUE) {
parent::setUp($import_test_views);
if ($import_test_views) {
ViewTestData::createTestViews(get_class($this), ['entity_module_test']);
}
}
/**
* {@inheritdoc}
*/
protected function setUpFixtures() {
$this->installEntitySchema('user');
$this->installEntitySchema('entity_test');
$this->installConfig(['entity_test']);
EntityViewMode::create([
'id' => 'entity_test.foobar',
'targetEntityType' => 'entity_test',
'status' => TRUE,
'enabled' => TRUE,
'label' => 'My view mode',
])->save();
$display = EntityViewDisplay::create([
'targetEntityType' => 'entity_test',
'bundle' => 'entity_test',
'mode' => 'foobar',
'label' => 'My view mode',
'status' => TRUE,
]);
$display->save();
$field_storage = FieldStorageConfig::create([
'field_name' => 'test_field',
'entity_type' => 'entity_test',
'type' => 'string',
]);
$field_storage->save();
$field_config = FieldConfig::create([
'field_name' => 'test_field',
'entity_type' => 'entity_test',
'bundle' => 'entity_test',
]);
$field_config->save();
// Create some test entities.
for ($i = 1; $i <= 3; $i++) {
EntityTest::create([
'name' => "Article title $i",
'test_field' => "Test $i",
])->save();
}
$role = Role::create([
'id' => 'test_role',
]);
$role->grantPermission('bypass node access');
$role->save();
$this->user = User::create([
'name' => 'test user',
]);
$this->user->addRole($role->id());
$this->user->save();
parent::setUpFixtures();
}
/**
* Tests the default rendered entity output.
*/
public function testRenderedEntityWithoutField() {
\Drupal::currentUser()->setAccount($this->user);
EntityViewDisplay::load('entity_test.entity_test.foobar')
->removeComponent('test_field')
->save();
// The view should not display the body field.
$view = Views::getView('test_field_entity_test_rendered');
$build = $view->preview();
$renderer = \Drupal::service('renderer');
$renderer->renderPlain($build);
for ($i = 1; $i <= 3; $i++) {
$view_field = $view->style_plugin->getField($i - 1, 'rendered_entity');
$search_result = strpos($view_field, "Test $i") !== FALSE;
$this->assertFalse($search_result, "The text 'Test $i' not found in the view.");
}
}
/**
* Tests the rendered entity output with the body field configured to show.
*/
public function testRenderedEntityWithField() {
\Drupal::currentUser()->setAccount($this->user);
// Show the body on the node.x.foobar view mode.
EntityViewDisplay::load('entity_test.entity_test.foobar')->setComponent('test_field', ['type' => 'string', 'label' => 'above'])->save();
// The view should display the body field.
$view = Views::getView('test_field_entity_test_rendered');
$build = $view->preview();
$renderer = \Drupal::service('renderer');
$renderer->renderPlain($build);
for ($i = 1; $i <= 3; $i++) {
$view_field = $view->style_plugin->getField($i - 1, 'rendered_entity');
$search_result = strpos($view_field, "Test $i") !== FALSE;
$this->assertTrue($search_result, "The text 'Test $i' found in the view.");
}
}
}
langcode: en
status: true
dependencies:
module:
- entity_test
- user
id: test_field_entity_test_rendered
label: 'Test Rendered entity test'
module: views
description: ''
tag: ''
base_table: entity_test
base_field: id
core: 8.x
display:
default:
display_plugin: default
id: default
display_title: Master
position: 0
display_options:
access:
type: none
options: { }
cache:
type: none
options: { }
query:
type: views_query
options:
disable_sql_rewrite: false
distinct: false
replica: false
query_comment: ''
query_tags: { }
exposed_form:
type: basic
options:
submit_button: Apply
reset_button: false
reset_button_label: Reset
exposed_sorts_label: 'Sort by'
expose_sort_order: true
sort_asc_label: Asc
sort_desc_label: Desc
pager:
type: full
options:
items_per_page: 10
offset: 0
id: 0
total_pages: null
expose:
items_per_page: false
items_per_page_label: 'Items per page'
items_per_page_options: '5, 10, 25, 50'
items_per_page_options_all: false
items_per_page_options_all_label: '- All -'
offset: false
offset_label: Offset
tags:
previous: ' Previous'
next: 'Next ›'
first: '« First'
last: 'Last »'
quantity: 9
style:
type: default
options:
grouping: { }
row_class: ''
default_row_class: true
uses_fields: false
row:
type: fields
options:
inline: { }
separator: ''
hide_empty: false
default_field_elements: true
fields:
rendered_entity:
id: rendered_entity
table: entity_test
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: foobar
entity_type: entity_test
plugin_id: rendered_entity
filters: { }
sorts:
id:
id: id
table: entity_test
field: id
relationship: none
group_type: group
admin_label: ''
order: ASC
exposed: false
expose:
label: ''
entity_type: entity_test
entity_field: nid
plugin_id: standard
header: { }
footer: { }
empty: { }
relationships: { }
arguments: { }
display_extenders: { }
cache_metadata:
max-age: 0
contexts:
- 'languages:language_interface'
- url.query_args
- user.permissions
tags: { }
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment