You are here

class GeneralImageFormatter in Formatter Suite 8

Formats an image.

This class supports the display of an image field's styled image along with a caption that may be shown above or below the image and include:

  • The title from the image field.
  • The file name.
  • The file size.
  • The image width and height.
  • The image MIME type.

The image and caption may be linked to the entity or image file, and link attributes may be set to open the link in the current tab/window, a new tab/window, or to download the item.

Plugin annotation


@FieldFormatter(
  id          = "formatter_suite_general_image",
  label       = @Translation("Formatter Suite - General image"),
  weight      = 1000,
  field_types = {
    "image",
  }
)

Hierarchy

Expanded class hierarchy of GeneralImageFormatter

Related topics

File

src/Plugin/Field/FieldFormatter/GeneralImageFormatter.php, line 51

Namespace

Drupal\formatter_suite\Plugin\Field\FieldFormatter
View source
class GeneralImageFormatter extends ImageFormatter {

  /*---------------------------------------------------------------------
   *
   * Fields - dependency injection.
   *
   *---------------------------------------------------------------------*/

  /**
   * The entity repository service.
   *
   * @var \Drupal\Core\Entity\EntityRepository
   */
  protected $entityRepository;

  /*---------------------------------------------------------------------
   *
   * Construction.
   *
   *---------------------------------------------------------------------*/

  /**
   * Constructs a GeneralImageFormatter object.
   *
   * @param string $pluginId
   *   The pluginId for the formatter.
   * @param mixed $pluginDefinition
   *   The plugin implementation definition.
   * @param \Drupal\Core\Field\FieldDefinitionInterface $fieldDefinition
   *   The definition of the field to which the formatter is associated.
   * @param array $settings
   *   The formatter settings.
   * @param string $label
   *   The formatter label display setting.
   * @param string $view_mode
   *   The view mode.
   * @param array $thirdPartySettings
   *   Any third party settings settings.
   * @param \Drupal\Core\Session\AccountInterface $currentUser
   *   The current user.
   * @param \Drupal\Core\Entity\EntityStorageInterface $imageStyleStorage
   *   The image style storage.
   * @param \Drupal\Core\Entity\EntityRepository $entityRepository
   *   The entity repository.
   */
  public function __construct($pluginId, $pluginDefinition, FieldDefinitionInterface $fieldDefinition, array $settings, $label, $view_mode, array $thirdPartySettings, AccountInterface $currentUser, EntityStorageInterface $imageStyleStorage, EntityRepository $entityRepository) {
    parent::__construct($pluginId, $pluginDefinition, $fieldDefinition, $settings, $label, $view_mode, $thirdPartySettings, $currentUser, $imageStyleStorage);
    $this->entityRepository = $entityRepository;
  }

  /**
   * {@inheritdoc}
   */
  public static function create(ContainerInterface $container, array $configuration, $pluginId, $pluginDefinition) {
    return new static($pluginId, $pluginDefinition, $configuration['field_definition'], $configuration['settings'], $configuration['label'], $configuration['view_mode'], $configuration['third_party_settings'], $container
      ->get('current_user'), $container
      ->get('entity_type.manager')
      ->getStorage('image_style'), $container
      ->get('entity.repository'));
  }

  /*---------------------------------------------------------------------
   *
   * Configuration.
   *
   *---------------------------------------------------------------------*/

  /**
   * Returns an array of caption locations.
   *
   * @return string[]
   *   Returns an associative array with internal names as keys and
   *   human-readable translated names as values.
   */
  protected static function getCaptionLocations() {
    return [
      'none' => t('Do not display an image caption'),
      'above' => t('Display an image caption above the image'),
      'below' => t('Display an image caption below the image'),
    ];
  }

  /**
   * Returns an array of choices for how to open a link.
   *
   * @return string[]
   *   Returns an associative array with internal names as keys and
   *   human-readable translated names as values.
   */
  protected static function getOpenLinkInValues() {
    return [
      '_self' => t('Open in the same tab/window'),
      '_blank' => t('Open in a new tab/window'),
      'download' => t('Download the entity or image file'),
    ];
  }

  /**
   * Returns an array of choices for where to link to.
   *
   * @return string[]
   *   Returns an associative array with internal names as keys and
   *   human-readable translated names as values.
   */
  protected static function getLinkTypes() {
    return [
      'content' => t("Link to the image field's entity"),
      'file' => t("Link to the image file"),
    ];
  }

  /**
   * {@inheritdoc}
   */
  public static function defaultSettings() {
    return array_merge([
      'captionLocation' => 'none',
      'captionIncludeTitle' => FALSE,
      'captionIncludeFilename' => FALSE,
      'captionIncludeSize' => FALSE,
      'captionIncludeDimensions' => FALSE,
      'captionIncludeMime' => FALSE,
      'classes' => '',
      'openLinkIn' => '_self',
    ], parent::defaultSettings());

    // Parent adds:
    // - image_style: the image style name.
    // - image_link: whether what to link the image to.
    //
    // This formatter uses the same two values, for compatability, but
    // presents a better UI.
  }

  /**
   * {@inheritdoc}
   */
  public function settingsSummary() {

    // Sanitize current settings.
    $this
      ->sanitizeSettings();

    // Get the image styles. Unset the empty 'No defined styles' option.
    // Note also that the current style choice could be invalid if the
    // indicated style has gone away.
    $imageStyles = image_style_options(FALSE);
    unset($imageStyles['']);
    $styleChoice = $this
      ->getSetting('image_style');
    $currentStyle = NULL;
    if (isset($imageStyles[$styleChoice]) === TRUE) {
      $currentStyle = $imageStyles[$styleChoice];
    }

    // Determine if the field has a title.
    $fieldDefinition = $this->fieldDefinition;
    $fieldSettings = $fieldDefinition
      ->getSettings();
    $hasTitle = FALSE;
    if (isset($fieldSettings['title_field']) === TRUE && boolval($fieldSettings['title_field']) === TRUE) {
      $hasTitle = TRUE;
    }

    // Summarize.
    $summary = [];
    if ($currentStyle === NULL) {
      $summary[] = $this
        ->t('Original image');
    }
    else {
      $summary[] = $this
        ->t('Image style "@style"', [
        '@style' => $currentStyle,
      ]);
    }
    $linkChoice = $this
      ->getSetting('image_link');
    $linkTypes = self::getLinkTypes();
    if (isset($linkTypes[$linkChoice]) === TRUE) {

      // The image is linked.
      $summary[] = $linkTypes[$linkChoice];
      $openInChoice = $this
        ->getSetting('openLinkIn');
      $openInValues = self::getOpenLinkInValues();
      if ($openInChoice !== 'download') {
        $summary[] = $openInValues[$openInChoice];
      }
      elseif ($linkChoice !== 'file') {

        // Ignore 'download' choice if the link type is not to a file.
        // Revert to '_blank'.
        $summary[] = $openInValues['_blank'];
      }
      else {
        $summary[] = $openInValues[$openInChoice];
      }
    }
    $captionChoice = $this
      ->getSetting('captionLocation');
    $captionLocations = self::getCaptionLocations();
    if ($captionChoice !== 'none' && isset($captionLocations[$captionChoice]) === TRUE) {
      $includes = [];
      if ($hasTitle === TRUE && $this
        ->getSetting('captionIncludeTitle') === TRUE) {
        $includes[] = (string) $this
          ->t('title');
      }
      if ($this
        ->getSetting('captionIncludeFilename') === TRUE) {
        $includes[] = (string) $this
          ->t('file name');
      }
      if ($this
        ->getSetting('captionIncludeSize') === TRUE) {
        $includes[] = (string) $this
          ->t('size');
      }
      if ($this
        ->getSetting('captionIncludeDimensions') === TRUE) {
        $includes[] = (string) $this
          ->t('dimensions');
      }
      if ($this
        ->getSetting('captionIncludeMime') === TRUE) {
        $includes[] = (string) $this
          ->t('MIME type');
      }
      if (empty($includes) === FALSE) {
        switch ($captionChoice) {
          case 'above':
            $summary[] = $this
              ->t('Caption above: @list', [
              '@list' => implode(', ', $includes),
            ]);
            break;
          default:
          case 'below':
            $summary[] = $this
              ->t('Caption below: @list', [
              '@list' => implode(', ', $includes),
            ]);
            break;
        }
      }
    }
    return $summary;
  }

  /*---------------------------------------------------------------------
   *
   * Settings form.
   *
   *---------------------------------------------------------------------*/

  /**
   * Returns a brief description of the formatter.
   *
   * @return string
   *   Returns a brief translated description of the formatter.
   */
  protected function getDescription() {
    return $this
      ->t("Show an image using a selected style. Optionally link the image to the content entity or the image file, and optionally include a caption above or below the image.");
  }

  /**
   * {@inheritdoc}
   */
  public function settingsForm(array $form, FormStateInterface $formState) {

    // Below, some checkboxes and select choices show/hide other form
    // elements. We use Drupal's obscure 'states' feature, which adds
    // Javascript to elements to auto show/hide based upon a set of
    // simple conditions.
    //
    // Those conditions need to reference the form elements to check
    // (e.g. a checkbox), but the element ID and name are automatically
    // generated by the parent form. We cannot set them, or predict them,
    // so we cannot use them. We could use a class, but this form may be
    // shown multiple times on the same page, so a simple class would not be
    // unique. Instead, we create classes for this form only by adding a
    // random number marker to the end of the class name.
    $marker = rand();

    // Do not start with the parent form, which is ugly. Add that form's
    // elements directly below.
    $elements = [];

    // Add branding.
    $elements = Branding::addFieldFormatterBranding($elements);
    $elements['#attached']['library'][] = 'formatter_suite/formatter_suite.fieldformatter';

    // Add description.
    $elements['description'] = [
      '#type' => 'html_tag',
      '#tag' => 'div',
      '#value' => $this
        ->getDescription(),
      '#weight' => -1000,
      '#attributes' => [
        'class' => [
          'formatter_suite-settings-description',
        ],
      ],
    ];
    $weight = 100;

    // Determine if the field has a title.
    $fieldDefinition = $this->fieldDefinition;
    $fieldSettings = $fieldDefinition
      ->getSettings();
    $hasTitle = FALSE;
    if (isset($fieldSettings['title_field']) === TRUE && boolval($fieldSettings['title_field']) === TRUE) {
      $hasTitle = TRUE;
    }

    // Get image styles and a link to the styles configuration page.
    $imageStyles = image_style_options(FALSE);
    $imageStylesPage = Link::fromTextAndUrl($this
      ->t('Configure image styles'), Url::fromRoute('entity.image_style.collection'));
    $imageStyleAllowed = $this->currentUser
      ->hasPermission('administer image styles');

    // Prompt for each setting.
    $elements['image_style'] = [
      '#title' => $this
        ->t('Image style'),
      '#type' => 'select',
      '#options' => $imageStyles,
      '#empty_option' => $this
        ->t('None (original image)'),
      '#default_value' => $this
        ->getSetting('image_style'),
      '#description' => $imageStylesPage
        ->toRenderable() + [
        '#access' => $imageStyleAllowed,
      ],
      '#weight' => $weight++,
    ];
    $elements['classes'] = [
      '#title' => $this
        ->t('Custom classes'),
      '#type' => 'textfield',
      '#size' => 10,
      '#default_value' => $this
        ->getSetting('classes'),
      '#weight' => $weight++,
      '#attributes' => [
        'autocomplete' => 'off',
        'autocapitalize' => 'none',
        'spellcheck' => 'false',
        'autocorrect' => 'off',
      ],
      '#wrapper_attributes' => [
        'class' => [
          'formatter_suite-general-image-classes',
        ],
      ],
    ];
    $elements['sectionBreak2'] = [
      '#markup' => '<div class="formatter_suite-section-break"></div>',
      '#weight' => $weight++,
    ];
    $elements['image_link'] = [
      '#title' => $this
        ->t('Link image'),
      '#type' => 'select',
      '#options' => self::getLinkTypes(),
      '#empty_option' => $this
        ->t('Do not link the image'),
      '#default_value' => $this
        ->getSetting('image_link'),
      '#wrapper_attributes' => [
        'class' => [
          'formatter_suite-general-image-link-type',
        ],
      ],
      '#attributes' => [
        'class' => [
          'image_link-' . $marker,
        ],
      ],
      '#weight' => $weight++,
    ];
    $elements['openLinkIn'] = [
      '#title' => $this
        ->t('Use link to'),
      '#type' => 'select',
      '#options' => self::getOpenLinkInValues(),
      '#default_value' => $this
        ->getSetting('openLinkIn'),
      '#weight' => $weight++,
      '#wrapper_attributes' => [
        'class' => [
          'formatter_suite-general-image-open-link-in',
        ],
      ],
      '#states' => [
        'invisible' => [
          '.image_link-' . $marker => [
            'value' => '',
          ],
        ],
      ],
    ];
    $elements['sectionBreak3'] = [
      '#markup' => '<div class="formatter_suite-section-break"></div>',
      '#weight' => $weight++,
    ];
    $elements['captionLocation'] = [
      '#title' => $this
        ->t('Caption location'),
      '#type' => 'select',
      '#options' => self::getCaptionLocations(),
      '#default_value' => $this
        ->getSetting('captionLocation'),
      '#weight' => $weight++,
      '#wrapper_attributes' => [
        'class' => [
          'formatter_suite-general-image-caption-location',
        ],
      ],
      '#attributes' => [
        'class' => [
          'captionLocation-' . $marker,
        ],
      ],
    ];
    if ($hasTitle === TRUE) {
      $elements['captionIncludeTitle'] = [
        '#title' => $this
          ->t('Include title in caption'),
        '#type' => 'checkbox',
        '#default_value' => $this
          ->getSetting('captionIncludeTitle'),
        '#weight' => $weight++,
        '#wrapper_attributes' => [
          'class' => [
            'formatter_suite-general-image-caption-include-title',
          ],
        ],
        '#states' => [
          'invisible' => [
            '.captionLocation-' . $marker => [
              'value' => 'none',
            ],
          ],
        ],
      ];
    }
    $elements['captionIncludeFilename'] = [
      '#title' => $this
        ->t('Include file name in caption'),
      '#type' => 'checkbox',
      '#default_value' => $this
        ->getSetting('captionIncludeFilename'),
      '#weight' => $weight++,
      '#wrapper_attributes' => [
        'class' => [
          'formatter_suite-general-image-caption-include-filename',
        ],
      ],
      '#states' => [
        'invisible' => [
          '.captionLocation-' . $marker => [
            'value' => 'none',
          ],
        ],
      ],
    ];
    $elements['captionIncludeSize'] = [
      '#title' => $this
        ->t('Include file size in caption'),
      '#type' => 'checkbox',
      '#default_value' => $this
        ->getSetting('captionIncludeSize'),
      '#weight' => $weight++,
      '#wrapper_attributes' => [
        'class' => [
          'formatter_suite-general-image-caption-include-size',
        ],
      ],
      '#states' => [
        'invisible' => [
          '.captionLocation-' . $marker => [
            'value' => 'none',
          ],
        ],
      ],
    ];
    $elements['captionIncludeDimensions'] = [
      '#title' => $this
        ->t('Include image dimensions in caption'),
      '#type' => 'checkbox',
      '#default_value' => $this
        ->getSetting('captionIncludeDimensions'),
      '#weight' => $weight++,
      '#wrapper_attributes' => [
        'class' => [
          'formatter_suite-general-image-caption-include-dimensions',
        ],
      ],
      '#states' => [
        'invisible' => [
          '.captionLocation-' . $marker => [
            'value' => 'none',
          ],
        ],
      ],
    ];
    $elements['captionIncludeMime'] = [
      '#title' => $this
        ->t('Include MIME type in caption'),
      '#type' => 'checkbox',
      '#default_value' => $this
        ->getSetting('captionIncludeMime'),
      '#weight' => $weight++,
      '#wrapper_attributes' => [
        'class' => [
          'formatter_suite-general-image-caption-include-mime',
        ],
      ],
      '#states' => [
        'invisible' => [
          '.captionLocation-' . $marker => [
            'value' => 'none',
          ],
        ],
      ],
    ];
    return $elements;
  }

  /**
   * Sanitize settings to insure that they are safe and valid.
   *
   * @internal
   * Drupal's class hierarchy for plugins and their settings does not
   * include a 'validate' function, like that for other classes with forms.
   * Validation must therefore occur on use, rather than on form submission.
   * @endinternal
   */
  protected function sanitizeSettings() {

    // Get current settings.
    //
    // Nothing to sanitize for the parent class's 'image_style'.
    // The style choice is checked on every use because styles come and go.
    $imageLink = $this
      ->getSetting('image_link');
    $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');

    // Get setting defaults.
    $defaults = $this
      ->defaultSettings();

    // Sanitize & validate.
    //
    // While <select> inputs constrain choices to those we define in the
    // form, it is possible to hack a form response and send other values back.
    // So check all <select> choices and use the default when a value is
    // empty or unknown.
    if (isset(self::getLinkTypes()[$imageLink]) === FALSE) {
      $this
        ->setSetting('image_link', $defaults['image_link']);
    }
    if (isset($this
      ->getOpenLinkInValues()[$openLinkIn]) === FALSE) {
      $this
        ->setSetting('openLinkIn', $defaults['openLinkIn']);
    }
    if (isset($this
      ->getCaptionLocations()[$captionLocation]) === FALSE) {
      $this
        ->setSetting('captionLocation', $defaults['captionLocation']);
    }

    // Insure boolean values are boolean.
    $this
      ->setSetting('captionIncludeTitle', boolval($captionIncludeTitle));
    $this
      ->setSetting('captionIncludeFilename', boolval($captionIncludeFilename));
    $this
      ->setSetting('captionIncludeSize', boolval($captionIncludeSize));
    $this
      ->setSetting('captionIncludeDimensions', boolval($captionIncludeDimensions));
    $this
      ->setSetting('captionIncludeMime', boolval($captionIncludeMime));

    // Classes are not sanitized or validated. They will be added to the link.
  }

  /*---------------------------------------------------------------------
   *
   * View.
   *
   *---------------------------------------------------------------------*/

  /**
   * {@inheritdoc}
   */
  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;
  }

}

Members

Namesort descending Modifiers Type Description Overrides
DependencySerializationTrait::$_entityStorages protected property An array of entity type IDs keyed by the property name of their storages.
DependencySerializationTrait::$_serviceIds protected property An array of service IDs keyed by property name used for serialization.
DependencySerializationTrait::__sleep public function 1
DependencySerializationTrait::__wakeup public function 2
EntityReferenceFormatterBase::prepareView public function Loads the entities referenced in that field across all the entities being viewed. Overrides FormatterBase::prepareView
EntityReferenceFormatterBase::view public function Overrides FormatterBase::view
FileFormatterBase::checkAccess protected function Checks access to the given entity. Overrides EntityReferenceFormatterBase::checkAccess
FileFormatterBase::needsEntityLoad protected function Returns whether the entity referenced by an item needs to be loaded. Overrides EntityReferenceFormatterBase::needsEntityLoad 1
FormatterBase::$fieldDefinition protected property The field definition.
FormatterBase::$label protected property The label display setting.
FormatterBase::$settings protected property The formatter settings. Overrides PluginSettingsBase::$settings
FormatterBase::$viewMode protected property The view mode.
FormatterBase::getFieldSetting protected function Returns the value of a field setting.
FormatterBase::getFieldSettings protected function Returns the array of field settings.
FormatterBase::isApplicable public static function Returns if the formatter can be used for the provided field. Overrides FormatterInterface::isApplicable 14
GeneralImageFormatter::$entityRepository protected property The entity repository service.
GeneralImageFormatter::create public static function Creates an instance of the plugin. Overrides ImageFormatter::create
GeneralImageFormatter::defaultSettings public static function Defines the default settings for this plugin. Overrides ImageFormatter::defaultSettings
GeneralImageFormatter::getCaptionLocations protected static function Returns an array of caption locations.
GeneralImageFormatter::getDescription protected function Returns a brief description of the formatter.
GeneralImageFormatter::getLinkTypes protected static function Returns an array of choices for where to link to.
GeneralImageFormatter::getOpenLinkInValues protected static function Returns an array of choices for how to open a link.
GeneralImageFormatter::sanitizeSettings protected function Sanitize settings to insure that they are safe and valid.
GeneralImageFormatter::settingsForm public function Returns a form to configure settings for the formatter. Overrides ImageFormatter::settingsForm
GeneralImageFormatter::settingsSummary public function Returns a short summary for the current formatter settings. Overrides ImageFormatter::settingsSummary
GeneralImageFormatter::viewElements public function Builds a renderable array for a field value. Overrides ImageFormatter::viewElements
GeneralImageFormatter::__construct public function Constructs a GeneralImageFormatter object. Overrides ImageFormatter::__construct
ImageFormatter::$currentUser protected property The current user.
ImageFormatter::$imageStyleStorage protected property The image style entity storage.
ImageFormatter::calculateDependencies public function Calculates dependencies for the configured plugin. Overrides PluginSettingsBase::calculateDependencies
ImageFormatter::onDependencyRemoval public function Informs the plugin that some configuration it depends on will be deleted. Overrides PluginSettingsBase::onDependencyRemoval
ImageFormatterBase::getEntitiesToView protected function Returns the referenced entities for display. Overrides EntityReferenceFormatterBase::getEntitiesToView
MessengerTrait::$messenger protected property The messenger. 29
MessengerTrait::messenger public function Gets the messenger. 29
MessengerTrait::setMessenger public function Sets the messenger.
PluginBase::$configuration protected property Configuration information passed into the plugin. 1
PluginBase::$pluginDefinition protected property The plugin implementation definition. 1
PluginBase::$pluginId protected property The plugin_id.
PluginBase::DERIVATIVE_SEPARATOR constant A string which is used to separate base plugin IDs from the derivative ID.
PluginBase::getBaseId public function Gets the base_plugin_id of the plugin instance. Overrides DerivativeInspectionInterface::getBaseId
PluginBase::getDerivativeId public function Gets the derivative_id of the plugin instance. Overrides DerivativeInspectionInterface::getDerivativeId
PluginBase::getPluginDefinition public function Gets the definition of the plugin implementation. Overrides PluginInspectionInterface::getPluginDefinition 3
PluginBase::getPluginId public function Gets the plugin_id of the plugin instance. Overrides PluginInspectionInterface::getPluginId
PluginBase::isConfigurable public function Determines if the plugin is configurable.
PluginSettingsBase::$defaultSettingsMerged protected property Whether default settings have been merged into the current $settings.
PluginSettingsBase::$thirdPartySettings protected property The plugin settings injected by third party modules.
PluginSettingsBase::getSetting public function Returns the value of a setting, or its default value if absent. Overrides PluginSettingsInterface::getSetting
PluginSettingsBase::getSettings public function Returns the array of settings, including defaults for missing settings. Overrides PluginSettingsInterface::getSettings
PluginSettingsBase::getThirdPartyProviders public function Gets the list of third parties that store information. Overrides ThirdPartySettingsInterface::getThirdPartyProviders
PluginSettingsBase::getThirdPartySetting public function Gets the value of a third-party setting. Overrides ThirdPartySettingsInterface::getThirdPartySetting
PluginSettingsBase::getThirdPartySettings public function Gets all third-party settings of a given module. Overrides ThirdPartySettingsInterface::getThirdPartySettings
PluginSettingsBase::mergeDefaults protected function Merges default settings values into $settings.
PluginSettingsBase::setSetting public function Sets the value of a setting for the plugin. Overrides PluginSettingsInterface::setSetting
PluginSettingsBase::setSettings public function Sets the settings for the plugin. Overrides PluginSettingsInterface::setSettings
PluginSettingsBase::setThirdPartySetting public function Sets the value of a third-party setting. Overrides ThirdPartySettingsInterface::setThirdPartySetting
PluginSettingsBase::unsetThirdPartySetting public function Unsets a third-party setting. Overrides ThirdPartySettingsInterface::unsetThirdPartySetting
StringTranslationTrait::$stringTranslation protected property The string translation service. 1
StringTranslationTrait::formatPlural protected function Formats a string containing a count of items.
StringTranslationTrait::getNumberOfPlurals protected function Returns the number of plurals supported by a given language.
StringTranslationTrait::getStringTranslation protected function Gets the string translation service.
StringTranslationTrait::setStringTranslation public function Sets the string translation service to use. 2
StringTranslationTrait::t protected function Translates a string to the current language or to a given language.