public function GeneralImageFormatter::viewElements in Formatter Suite 8
Builds a renderable array for a field value.
Parameters
\Drupal\Core\Field\FieldItemListInterface $items: The field values to be rendered.
string $langcode: The language that should be used to render the field.
Return value
array A renderable array for $items, as an array of child elements keyed by consecutive numeric indexes starting from 0.
Overrides ImageFormatter::viewElements
File
- src/
Plugin/ Field/ FieldFormatter/ GeneralImageFormatter.php, line 666
Class
- GeneralImageFormatter
- Formats an image.
Namespace
Drupal\formatter_suite\Plugin\Field\FieldFormatterCode
public function viewElements(FieldItemListInterface $items, $langCode) {
// Get the parent entities containing the field items. However, if
// there are no items, then fill in the default image, if any.
//
// Here we override behavior of the parent class. That class implements
// getEntitiesToView() and checks for an empty $items list. When empty,
// it gets the default image, if any, and creates a temporary items list
// containing the image. With a new temporary items list, it calls the
// parent's parent class getEntitiesToView() to get the associated
// entities for those items.
//
// This works for the image formaters BUT it doesn't expose that new
// temporary items list. And without that, we don't have some of the
// information we need for this formatter.
//
// So, here we check for an empty item list explicitly, fill in the
// default AND retain the new $items list for further use. The code is
// based upon getEntitiesToView() in ImageFormatterBase.
if ($items
->isEmpty() === TRUE) {
// The item list is empty. Look for a default image.
$defaultImage = $this
->getFieldSetting('default_image');
// If there is no default image for this field, look in the field
// definition instead.
$fieldDef = $this->fieldDefinition;
if (empty($defaultImage['uuid']) === TRUE && $fieldDef instanceof FieldConfigInterface) {
$storageDef = $fieldDef
->getFieldStorageDefinition();
$defaultImage = $storageDef
->getSetting('default_image');
}
// If there is still no default image found, then there is nothing
// to format.
if (empty($defaultImage['uuid']) === TRUE) {
return [];
}
// Get the image's File entity.
$imageFile = $this->entityRepository
->loadEntityByUuid('file', $defaultImage['uuid']);
// If that didn't work, then something is wrong with the image and,
// again, there is nothing to format.
if ($imageFile === NULL) {
return [];
}
// Create a new temporary FieldItemList for use in this formatter only.
$items = clone $items;
// Add the default image as a field item. Use the title, etc., from
// the default image.
$items
->setValue([
'target_id' => $imageFile
->id(),
'alt' => $defaultImage['alt'],
'title' => $defaultImage['title'],
'width' => $defaultImage['width'],
'height' => $defaultImage['height'],
'entity' => $imageFile,
'_loaded' => TRUE,
'_is_default' => TRUE,
]);
$imageFile->_referringItem = $items[0];
}
// Load the entities for the item list, using either the original item
// list or the temporary item list created above for the default image.
$files = $this
->getEntitiesToView($items, $langCode);
if (empty($files) === TRUE) {
return [];
}
$this
->sanitizeSettings();
//
// Get settings.
// -------------
// Get the formatter configuration.
$classes = $this
->getSetting('classes');
$openLinkIn = $this
->getSetting('openLinkIn');
$captionLocation = $this
->getSetting('captionLocation');
$captionIncludeTitle = $this
->getSetting('captionIncludeTitle');
$captionIncludeFilename = $this
->getSetting('captionIncludeFilename');
$captionIncludeSize = $this
->getSetting('captionIncludeSize');
$captionIncludeDimensions = $this
->getSetting('captionIncludeDimensions');
$captionIncludeMime = $this
->getSetting('captionIncludeMime');
// If the settings do not enable any of the possible caption components,
// then there is no caption.
if ($captionIncludeTitle === FALSE && $captionIncludeFilename === FALSE && $captionIncludeSize === FALSE && $captionIncludeDimensions === FALSE && $captionIncludeMime === FALSE) {
$captionLocation = 'none';
}
//
// Format each image.
// ------------------
// The parent image formatter does very little processing within the
// formatter. Instead, it sets a theme template and later processing
// of the template sets up the image's URL, including possibly use of
// an image style.
//
// Let the parent class do its processing. The returned array has one
// entry per item and a configuration that invokes the image module's
// 'image_formatter' theme.
$parentElements = parent::viewElements($items, $langCode);
$classes = explode(' ', $classes);
$classes[] = 'formatter_suite-general-image';
//
// Create render elements.
// -----------------------
// The parent elements created above only contain the field's images.
// To this we need to add:
// - A container wrapper that has the given classes.
// - A caption above or below each image, if enabled.
// - A title, if enabled.
// - A file name, if enabled.
// - A file size, if enabled.
// - Image dimensions, if enabled.
// - A file MIME type, if enabled.
//
// If linking is enabled, the image and caption need to be links using
// the indicated link attributes.
//
// The parent element needs to be nested within a wrapper that adds
// the above items. If the parent element has a URL, then that URL's
// options need to be adjusted to include the link attributes.
$elements = [];
foreach ($items as $delta => $item) {
if (isset($parentElements[$delta]) !== TRUE) {
// The parent formatter skipped this one? Skip it too.
continue;
}
// Get the URL, if any, from the parent. If there is a URL, add
// link attributes and update the parent elements.
$url = $parentElements[$delta]['#url'];
$mime = $files[$delta]
->getMimeType();
if ($url !== NULL) {
$urlOptions = $url
->getOptions();
if (isset($urlOptions['attributes']) === FALSE) {
$urlOptions['attributes'] = [];
}
$urlOptions['attributes']['type'] = $mime;
switch ($openLinkIn) {
case '_self':
$urlOptions['attributes']['target'] = '_self';
break;
case '_blank':
$urlOptions['attributes']['target'] = '_blank';
break;
case 'download':
$urlOptions['attributes']['download'] = '';
break;
}
$url
->setOptions($urlOptions);
$parentElements[$delta]['#url'] = $url;
}
// Assemble the caption's render elements.
$imageWeight = 0;
$captionWeight = 0;
$itemClasses = array_merge([], $classes);
$caption = [];
if ($captionLocation !== 'none') {
switch ($captionLocation) {
case 'above':
$captionWeight = 0;
$imageWeight = 1000;
$itemClasses[] = 'formatter_suite-general-image-above';
break;
default:
case 'below':
$imageWeight = 0;
$captionWeight = 1000;
$itemClasses[] = 'formatter_suite-general-image-below';
break;
}
$title = '';
if ($captionIncludeTitle === TRUE) {
// Prefer the title from the field, if any. Otherwise use the
// file's label.
if (isset($item->title) === TRUE) {
$title = $item->title;
}
else {
// Fall back to the file entity's label/name. But this too
// may be empty.
$title = $files[$delta]
->label();
}
if (empty($title) === FALSE) {
if ($url === NULL) {
$caption['title'] = [
'#type' => 'html_tag',
'#tag' => 'div',
'#value' => Html::escape($title),
'#weight' => $captionWeight++,
'#attributes' => [
'class' => [
'formatter_suite-image-caption-title',
],
],
];
}
else {
// Clone the URL because the render element modifies it
// to add attributes.
$localUrl = clone $url;
$caption['title'] = [
'#type' => 'link',
'#title' => $title,
'#options' => $localUrl
->getOptions(),
'#url' => $localUrl,
'#weight' => $captionWeight++,
'#attributes' => [
'class' => [
'formatter_suite-image-caption-title',
],
],
];
}
}
}
if ($captionIncludeFilename === TRUE) {
// The name of the original image file, not the styled image.
$filename = $files[$delta]
->getFilename();
// Only show the file name if it differs from the title, if the
// title was shown.
if (empty($title) === TRUE || $title !== $filename) {
if ($url === NULL) {
$caption['filename'] = [
'#type' => 'html_tag',
'#tag' => 'div',
'#value' => Html::escape($filename),
'#weight' => $captionWeight++,
'#attributes' => [
'class' => [
'formatter_suite-image-caption-filename',
],
],
];
}
else {
// Clone the URL because the render element modifies it
// to add attributes.
$localUrl = clone $url;
$caption['filename'] = [
'#type' => 'link',
'#title' => $filename,
'#options' => $localUrl
->getOptions(),
'#url' => $localUrl,
'#weight' => $captionWeight++,
'#attributes' => [
'class' => [
'formatter_suite-image-caption-filename',
],
],
];
}
}
}
if ($captionIncludeSize === TRUE) {
// The size of the original image, not the styled image.
$bytes = Utilities::formatBytes($files[$delta]
->getSize(), 1000, FALSE, 2);
if ($url === NULL) {
$caption['size'] = [
'#type' => 'html_tag',
'#tag' => 'div',
'#value' => $bytes,
'#weight' => $captionWeight++,
'#attributes' => [
'class' => [
'formatter_suite-image-caption-size',
],
],
];
}
else {
// Clone the URL because the render element modifies it
// to add attributes.
$localUrl = clone $url;
$caption['size'] = [
'#type' => 'link',
'#title' => $bytes,
'#options' => $localUrl
->getOptions(),
'#url' => $localUrl,
'#weight' => $captionWeight++,
'#attributes' => [
'class' => [
'formatter_suite-image-caption-size',
],
],
];
}
}
if ($captionIncludeDimensions === TRUE) {
// The dimensions of the original image, not the styled image.
$x = " ⨉ ";
$text = $item->width . $x . $item->height;
if ($url === NULL) {
$caption['dimensions'] = [
'#type' => 'html_tag',
'#tag' => 'div',
'#value' => $text,
'#weight' => $captionWeight++,
'#attributes' => [
'class' => [
'formatter_suite-image-caption-dimensions',
],
],
];
}
else {
// Clone the URL because the render element modifies it
// to add attributes.
$localUrl = clone $url;
$caption['dimensions'] = [
'#type' => 'link',
'#title' => $text,
'#options' => $localUrl
->getOptions(),
'#url' => $localUrl,
'#weight' => $captionWeight++,
'#attributes' => [
'class' => [
'formatter_suite-image-caption-dimensions',
],
],
];
}
}
if ($captionIncludeMime === TRUE) {
// The MIME type of the original image, not the styled image.
if ($url === NULL) {
$caption['mime'] = [
'#type' => 'html_tag',
'#tag' => 'div',
'#value' => Html::escape($mime),
'#weight' => $captionWeight++,
'#attributes' => [
'class' => [
'formatter_suite-image-caption-mime',
],
],
];
}
else {
// Clone the URL because the render element modifies it
// to add attributes.
$localUrl = clone $url;
$caption['mime'] = [
'#type' => 'link',
'#title' => $mime,
'#options' => $localUrl
->getOptions(),
'#url' => $localUrl,
'#weight' => $captionWeight++,
'#attributes' => [
'class' => [
'formatter_suite-image-caption-mime',
],
],
];
}
}
}
// Modify the image module's render elements.
//
// - Add a weight to order the image and caption properly.
//
// - Swap out the theme to go to our own theme, which is identical to
// the Image module's, except that it includes attributes on the
// link surrounding the image.
//
// - Add the URL options, such as the target and download attributes.
$parentElements[$delta]['#weight'] = $imageWeight;
$parentElements[$delta]['#theme'] = 'formatter_suite_general_image_formatter';
if ($url === NULL) {
// There is no URL. Add the class to the image itself.
$parentElements[$delta]['#item_attributes']['class'] = [
'formatter_suite-image',
];
}
else {
// There is a URL. Add the class to the link around the image.
$urlOptions = $url
->getOptions();
if (isset($urlOptions['attributes']) === TRUE) {
// Add the URL's attributes, such as target and download.
$urlAttributes = $urlOptions['attributes'];
$parentElements[$delta]['#attributes'] = $urlAttributes + [
'class' => [
'formatter_suite-image',
],
];
}
else {
$parentElements[$delta]['#attributes']['class'] = [
'formatter_suite-image',
];
}
}
// Create a container for the image and caption.
$elements[$delta] = [
'#type' => 'container',
'#attributes' => [
'class' => $itemClasses,
],
'#attached' => [
'library' => [
'formatter_suite/formatter_suite.usage',
],
],
'image' => $parentElements[$delta],
];
if (empty($caption) === FALSE) {
$elements[$delta] += $caption;
}
}
return $elements;
}