class EntityFieldRenderer in Zircon Profile 8
Same name and namespace in other branches
- 8.0 core/modules/views/src/Entity/Render/EntityFieldRenderer.php \Drupal\views\Entity\Render\EntityFieldRenderer
Renders entity fields.
This is used to build render arrays for all entity field values of a view result set sharing the same relationship. An entity translation renderer is used internally to handle entity language properly.
Hierarchy
- class \Drupal\views\Entity\Render\RendererBase implements CacheableDependencyInterface
- class \Drupal\views\Entity\Render\EntityFieldRenderer uses EntityTranslationRenderTrait
Expanded class hierarchy of EntityFieldRenderer
1 file declares its use of EntityFieldRenderer
- Field.php in core/
modules/ views/ src/ Plugin/ views/ field/ Field.php - Contains \Drupal\views\Plugin\views\field\Field.
File
- core/
modules/ views/ src/ Entity/ Render/ EntityFieldRenderer.php, line 26 - Contains \Drupal\views\Entity\Render\EntityFieldRenderer.
Namespace
Drupal\views\Entity\RenderView source
class EntityFieldRenderer extends RendererBase {
use EntityTranslationRenderTrait;
/**
* The relationship being handled.
*
* @var string
*/
protected $relationship;
/**
* The entity manager.
*
* @var \Drupal\Core\Entity\EntityManagerInterface
*/
protected $entityManager;
/**
* A list of indexes of rows whose fields have already been rendered.
*
* @var int[]
*/
protected $processedRows = [];
/**
* Constructs an EntityFieldRenderer object.
*
* @param \Drupal\views\ViewExecutable $view
* The view whose fields are being rendered.
* @param string $relationship
* The relationship to be handled.
* @param \Drupal\Core\Language\LanguageManagerInterface $language_manager
* The language manager.
* @param \Drupal\Core\Entity\EntityTypeInterface $entity_type
* The entity type.
* @param \Drupal\Core\Entity\EntityManagerInterface $entity_manager
* The entity manager.
*/
public function __construct(ViewExecutable $view, $relationship, LanguageManagerInterface $language_manager, EntityTypeInterface $entity_type, EntityManagerInterface $entity_manager) {
parent::__construct($view, $language_manager, $entity_type);
$this->relationship = $relationship;
$this->entityManager = $entity_manager;
}
/**
* {@inheritdoc}
*/
public function getCacheContexts() {
return $this
->getEntityTranslationRenderer()
->getCacheContexts();
}
/**
* {@inheritdoc}
*/
public function getEntityTypeId() {
return $this->entityType
->id();
}
/**
* {@inheritdoc}
*/
protected function getEntityManager() {
return $this->entityManager;
}
/**
* {@inheritdoc}
*/
protected function getLanguageManager() {
return $this->languageManager;
}
/**
* {@inheritdoc}
*/
protected function getView() {
return $this->view;
}
/**
* {@inheritdoc}
*/
public function query(QueryPluginBase $query, $relationship = NULL) {
$this
->getEntityTranslationRenderer()
->query($query, $relationship);
}
/**
* Renders entity field data.
*
* @param \Drupal\views\ResultRow $row
* A single row of the query result.
* @param \Drupal\views\Plugin\views\field\Field $field
* (optional) A field to be rendered.
*
* @return array
* A renderable array for the entity data contained in the result row.
*/
public function render(ResultRow $row, Field $field = NULL) {
// The method is called for each field in each result row. In order to
// leverage multiple-entity building of formatter output, we build the
// render arrays for all fields in all rows on the first call.
if (!isset($this->build)) {
$this->build = $this
->buildFields($this->view->result);
}
if (isset($field)) {
$field_id = $field->options['id'];
// Pick the render array for the row / field we are being asked to render,
// and remove it from $this->build to free memory as we progress.
if (isset($this->build[$row->index][$field_id])) {
$build = $this->build[$row->index][$field_id];
unset($this->build[$row->index][$field_id]);
}
elseif (isset($this->build[$row->index])) {
// In the uncommon case where a field gets rendered several times
// (typically through direct Views API calls), the pre-computed render
// array was removed by the unset() above. We have to manually rebuild
// the render array for the row.
$build = $this
->buildFields([
$row,
])[$row->index][$field_id];
}
else {
// In case the relationship is optional, there might not be any fields
// to render for this row.
$build = [];
}
}
else {
// Same logic as above, in the case where we are being called for a whole
// row.
if (isset($this->build[$row->index])) {
$build = $this->build[$row->index];
unset($this->build[$row->index]);
}
else {
$build = $this
->buildFields([
$row,
])[$row->index];
}
}
return $build;
}
/**
* Builds the render arrays for all fields of all result rows.
*
* The output is built using EntityViewDisplay objects to leverage
* multiple-entity building and ensure a common code path with regular entity
* view.
* - Each relationship is handled by a separate EntityFieldRenderer instance,
* since it operates on its own set of entities. This also ensures different
* entity types are handled separately, as they imply different
* relationships.
* - Within each relationship, the fields to render are arranged in unique
* sets containing each field at most once (an EntityViewDisplay can
* only process a field once with given display options, but a View can
* contain the same field several times with different display options).
* - For each set of fields, entities are processed by bundle, so that
* formatters can operate on the proper field definition for the bundle.
*
* @param \Drupal\views\ResultRow[] $values
* An array of all ResultRow objects returned from the query.
*
* @return array
* A renderable array for the fields handled by this renderer.
*
* @see \Drupal\Core\Entity\Entity\EntityViewDisplay
*/
protected function buildFields(array $values) {
$build = [];
if ($values && ($field_ids = $this
->getRenderableFieldIds())) {
$entity_type_id = $this
->getEntityTypeId();
// Collect the entities for the relationship, fetch the right translation,
// and group by bundle. For each result row, the corresponding entity can
// be obtained from any of the fields handlers, so we arbitrarily use the
// first one.
$entities_by_bundles = [];
$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);
}
}
// Determine unique sets of fields that can be processed by the same
// display. Fields that appear several times in the View open additional
// "overflow" displays.
$display_sets = [];
foreach ($field_ids as $field_id) {
$field = $this->view->field[$field_id];
$field_name = $field->definition['field_name'];
$index = 0;
while (isset($display_sets[$index]['field_names'][$field_name])) {
$index++;
}
$display_sets[$index]['field_names'][$field_name] = $field;
$display_sets[$index]['field_ids'][$field_id] = $field;
}
// For each set of fields, build the output by bundle.
foreach ($display_sets as $display_fields) {
foreach ($entities_by_bundles as $bundle => $bundle_entities) {
// Create the display, and configure the field display options.
$display = EntityViewDisplay::create([
'targetEntityType' => $entity_type_id,
'bundle' => $bundle,
'status' => TRUE,
]);
foreach ($display_fields['field_ids'] as $field) {
$display
->setComponent($field->definition['field_name'], [
'type' => $field->options['type'],
'settings' => $field->options['settings'],
]);
}
// Let the display build the render array for the entities.
$display_build = $display
->buildMultiple($bundle_entities);
// Collect the field render arrays and index them using our internal
// row indexes and field IDs.
foreach ($display_build as $row_index => $entity_build) {
foreach ($display_fields['field_ids'] as $field_id => $field) {
$build[$row_index][$field_id] = !empty($entity_build[$field->definition['field_name']]) ? $entity_build[$field->definition['field_name']] : [];
}
}
}
}
}
return $build;
}
/**
* Returns a list of names of entity fields to be rendered.
*
* @return string[]
* An associative array of views fields.
*/
protected function getRenderableFieldIds() {
$field_ids = [];
foreach ($this->view->field as $field_id => $field) {
if ($field instanceof Field && $field->relationship == $this->relationship) {
$field_ids[] = $field_id;
}
}
return $field_ids;
}
}
Members
Name | Modifiers | Type | Description | Overrides |
---|---|---|---|---|
EntityFieldRenderer:: |
protected | property | The entity manager. | |
EntityFieldRenderer:: |
protected | property | A list of indexes of rows whose fields have already been rendered. | |
EntityFieldRenderer:: |
protected | property | The relationship being handled. | |
EntityFieldRenderer:: |
protected | function | Builds the render arrays for all fields of all result rows. | |
EntityFieldRenderer:: |
public | function |
The cache contexts associated with this object. Overrides RendererBase:: |
|
EntityFieldRenderer:: |
protected | function |
Returns the entity manager. Overrides EntityTranslationRenderTrait:: |
|
EntityFieldRenderer:: |
public | function |
Returns the entity type identifier. Overrides EntityTranslationRenderTrait:: |
|
EntityFieldRenderer:: |
protected | function |
Returns the language manager. Overrides EntityTranslationRenderTrait:: |
|
EntityFieldRenderer:: |
protected | function | Returns a list of names of entity fields to be rendered. | |
EntityFieldRenderer:: |
protected | function |
Returns the top object of a view. Overrides EntityTranslationRenderTrait:: |
|
EntityFieldRenderer:: |
public | function |
Alters the query if needed. Overrides RendererBase:: |
|
EntityFieldRenderer:: |
public | function |
Renders entity field data. Overrides RendererBase:: |
|
EntityFieldRenderer:: |
public | function |
Constructs an EntityFieldRenderer object. Overrides RendererBase:: |
|
EntityTranslationRenderTrait:: |
protected | property | The renderer to be used to render the entity row. | |
EntityTranslationRenderTrait:: |
public | function | Returns the entity translation matching the configured row language. | |
EntityTranslationRenderTrait:: |
protected | function | Returns the current renderer. | |
RendererBase:: |
protected | property | Contains an array of render arrays, one for each rendered entity. | |
RendererBase:: |
protected | property | The type of the entity being rendered. | |
RendererBase:: |
protected | property | The language manager. | |
RendererBase:: |
public | property | The view executable wrapping the view storage entity. | |
RendererBase:: |
public | function |
The maximum age for which this object may be cached. Overrides CacheableDependencyInterface:: |
|
RendererBase:: |
public | function |
The cache tags associated with this object. Overrides CacheableDependencyInterface:: |
|
RendererBase:: |
public | function | Runs before each entity is rendered. | 1 |