view_mode_crop-1.0.x-dev/src/Plugin/Field/FieldFormatter/ViewModeCropImageFormatterTrait.php
src/Plugin/Field/FieldFormatter/ViewModeCropImageFormatterTrait.php
<?php
namespace Drupal\view_mode_crop\Plugin\Field\FieldFormatter;
use Drupal\Core\Cache\CacheableMetadata;
use Drupal\Core\Field\EntityReferenceFieldItemListInterface;
use Drupal\Core\Field\FieldItemListInterface;
use Drupal\Core\TypedData\TranslatableInterface;
use Drupal\field\FieldConfigInterface;
use Drupal\file\FileInterface;
use Drupal\media\MediaInterface;
use Drupal\view_mode_crop\CropImageHelper;
use Drupal\view_mode_crop\Plugin\Field\FieldType\ViewModeCropEntityReferenceItem;
/**
* Trait to support cropped images.
*/
trait ViewModeCropImageFormatterTrait {
/**
* Get the entities to be viewed.
*
* This overrides the file uri's to point to the cropped image files.
*
* @param \Drupal\Core\Field\EntityReferenceFieldItemListInterface $items
* The items.
* @param mixed $langcode
* The langcode.
*
* @return \Drupal\Core\Entity\EntityInterface[]
* The entities to view.
*
* @throws \Drupal\Core\TypedData\Exception\MissingDataException
*/
protected function getEntitiesToView(EntityReferenceFieldItemListInterface $items, $langcode) {
$entities = [];
// Add the default image if needed.
if ($items->isEmpty()) {
$default_image = $this->getFieldSetting('default_image');
// If we are dealing with a configurable field, look in both
// instance-level and field-level settings.
if (empty($default_image['uuid']) && $this->fieldDefinition instanceof FieldConfigInterface) {
$default_image = $this->fieldDefinition->getFieldStorageDefinition()
->getSetting('default_image');
}
if (!empty($default_image['uuid']) && $file = \Drupal::service('entity.repository')
->loadEntityByUuid('file', $default_image['uuid'])) {
// Clone the FieldItemList into a runtime-only object for the formatter,
// so that the fallback image can be rendered without affecting the
// field values in the entity being rendered.
$items = clone $items;
$items->setValue([
'target_id' => $file->id(),
'alt' => $default_image['alt'],
'title' => $default_image['title'],
'width' => $default_image['width'],
'height' => $default_image['height'],
'entity' => $file,
'_loaded' => TRUE,
'_is_default' => TRUE,
]);
// @phpstan-ignore-next-line
$file->_referringItem = $items[0];
}
}
foreach ($items as $delta => $item) {
// Ignore items where no entity could be loaded in prepareView().
if (!empty($item->_loaded)) {
if (!isset($item->entity)) {
throw new \RuntimeException('Missing entity');
}
$entity = clone $item->entity;
// Set the entity in the correct language for display.
if ($entity instanceof TranslatableInterface) {
$entity = \Drupal::service('entity.repository')->getTranslationFromContext($entity, $langcode);
}
$access = $this->checkAccess($entity);
// Add the access result's cacheability, ::view() needs it.
// @phpstan-ignore-next-line
$item->_accessCacheability = CacheableMetadata::createFromObject($access);
if ($access->isAllowed()) {
// Add the referring item, in case the formatter needs it.
$entity->_referringItem = $items[$delta];
$entities[$delta] = $entity;
}
}
}
$referring_item = NULL;
$items_entity = $items->getEntity();
if ($items_entity instanceof MediaInterface && isset($items_entity->_referringItem)) {
$referring_item = $items_entity->_referringItem;
}
foreach ($entities as $delta => $entity) {
if (!$entity instanceof FileInterface) {
continue;
}
$image_item = $items->get($delta);
if ($referring_item instanceof ViewModeCropEntityReferenceItem) {
$crop_data = $referring_item->getViewModeCropData();
// Get the delta from the parent entity of the referencing field.
foreach ($referring_item->getParent() as $parent_entity_field_item_delta => $parent_entity_field_item) {
if ($parent_entity_field_item->getPropertyPath() === $referring_item->getPropertyPath()) {
$delta = $parent_entity_field_item_delta;
break;
}
}
}
else {
/**
* @var \Drupal\view_mode_crop\Plugin\Field\FieldType\ViewModeCropImageItem $image_item
*/
$crop_data = $image_item->getViewModeCropData();
}
$view_mode = $this->viewMode;
if (!isset($crop_data[$view_mode])) {
// View mode is not set. Fall back to default.
$view_mode = 'default';
}
if (
!isset($crop_data[$view_mode]) ||
$crop_data[$view_mode]->x === NULL ||
$crop_data[$view_mode]->y === NULL ||
$crop_data[$view_mode]->w === NULL ||
$crop_data[$view_mode]->h === NULL
) {
continue;
}
$uri = CropImageHelper::getUri($image_item, $delta, $view_mode);
if (file_exists($uri)) {
if (!isset($entity->_initialUri)) {
// @phpstan-ignore-next-line
$entity->_initialUri = $entity->get('uri')->getString();
}
$entity->set('uri', $uri);
}
// Save the cropped dimensions, This will be used in
// ViewModeCropImageFormatter::viewElements.
/**
* @var object $entity
*/
$entity->viewModeCropWidth = $crop_data[$view_mode]->w;
$entity->viewModeCropHeight = $crop_data[$view_mode]->h;
}
return $entities;
}
/**
* {@inheritDoc}
*/
public function viewElements(FieldItemListInterface $items, $langcode) {
$elements = parent::viewElements($items, $langcode);
$files = $this->getEntitiesToView($items, $langcode);
$items_entity = $items->getEntity();
$referring_item = NULL;
if ($items_entity instanceof MediaInterface) {
if (!isset($items_entity->_referringItem)) {
throw new \RuntimeException('Missing referringItem');
}
$referring_item = $items_entity->_referringItem;
}
$field_name = $items->getFieldDefinition()->getName();
foreach ($files as $delta => $file) {
if (isset($elements[$delta]['#item'])) {
if (!empty($file->viewModeCropWidth) && !empty($file->viewModeCropHeight)) {
// Update the dimensions which are saved in
// ViewModeCropImageFormatterGetEntitiesToViewTrait::getEntitiesToView.
$elements[$delta]['#item']->width = $file->viewModeCropWidth;
$elements[$delta]['#item']->height = $file->viewModeCropHeight;
}
}
foreach ($items->getEntity()->getCacheTags() as $tag) {
$elements[$delta]['#cache']['tags'][] = $tag;
$elements[$delta]['#cache']['tags'][] = $tag . ':' . $field_name;
$elements[$delta]['#cache']['tags'][] = $tag . ':' . $field_name . ':' . $delta;
}
if ($referring_item) {
foreach ($referring_item->getEntity()->getCacheTags() as $tag) {
$elements[$delta]['#cache']['tags'][] = $tag;
$elements[$delta]['#cache']['tags'][] = $tag . ':' . $field_name;
$elements[$delta]['#cache']['tags'][] = $tag . ':' . $field_name . ':' . $delta;
}
}
$elements[$delta]['#cache']['tags'][] = $items->getFieldDefinition()
->getName();
}
return $elements;
}
}
