improvements-2.x-dev/src/Plugin/Field/FieldFormatter/ImageWithMobileAlternativeOneFieldFormatter.php
src/Plugin/Field/FieldFormatter/ImageWithMobileAlternativeOneFieldFormatter.php
<?php namespace Drupal\improvements\Plugin\Field\FieldFormatter; use Drupal\breakpoint\BreakpointInterface; use Drupal\breakpoint\BreakpointManagerInterface; use Drupal\Core\Field\FieldDefinitionInterface; use Drupal\Core\Field\FieldItemListInterface; use Drupal\Core\Field\FormatterBase; use Drupal\Core\Form\FormStateInterface; use Drupal\file\FileInterface; use Drupal\image\Entity\ImageStyle; use Drupal\image\ImageStyleInterface; use Drupal\image\Plugin\Field\FieldType\ImageItem; /** * @FieldFormatter( * id = "image_with_mobile_alternative_one_field", * label = @Translation("Image with mobile alternative (one field)"), * field_types = { * "image", * } * ) */ class ImageWithMobileAlternativeOneFieldFormatter extends FormatterBase { /** * {@inheritdoc} */ public static function defaultSettings(): array { return [ 'image_style' => '', 'breakpoint_group' => '', 'mobile_breakpoint' => '', 'mobile_image_style' => '', ] + parent::defaultSettings(); } /** * {@inheritDoc} */ public function settingsForm(array $form, FormStateInterface $form_state): array { $image_styles_options = image_style_options(FALSE); $breakpoint_manager = \Drupal::service('breakpoint.manager'); /** @var BreakpointManagerInterface $breakpoint_manager */ $breakpoint_group = $this->getSetting('breakpoint_group'); // Image style $elements['image_style'] = [ '#type' => 'select', '#title' => t('Default image style'), '#options' => $image_styles_options, '#empty_option' => t('None (original image)'), '#default_value' => $this->getSetting('image_style'), ]; // Breakpoint group $elements['breakpoint_group'] = [ '#type' => 'select', '#title' => t('Breakpoint group'), '#options' => $breakpoint_manager->getGroups(), '#default_value' => $breakpoint_group, ]; // @TODO Add update form on ajax if ($breakpoint_group) { // Mobile breakpoint $elements['mobile_breakpoint'] = [ '#type' => 'select', '#title' => t('Mobile breakpoint'), '#options' => $this->getMobileBreakpointOptions($breakpoint_group), '#default_value' => $this->getSetting('mobile_breakpoint'), ]; // Mobile image style $elements['mobile_image_style'] = [ '#type' => 'select', '#title' => t('Mobile image style'), '#options' => $image_styles_options, '#empty_option' => t('None (original image)'), '#default_value' => $this->getSetting('mobile_image_style'), ]; } return $elements; } /** * {@inheritDoc} */ public function settingsSummary(): array { $summary = []; if ($image_style = $this->getSetting('image_style')) { $summary[] = t('Default image style') . ': ' . $this->getSetting('image_style'); } if ($breakpoint_group = $this->getSetting('breakpoint_group')) { $summary[] = t('Breakpoint group') . ': ' . $breakpoint_group; } if ($mobile_breakpoint = $this->getSetting('mobile_breakpoint')) { $summary[] = t('Mobile breakpoint') . ': ' . $mobile_breakpoint; } if ($mobile_image_style = $this->getSetting('mobile_image_style')) { $summary[] = t('Mobile image style') . ': ' . $mobile_image_style; } return $summary; } /** * {@inheritDoc} */ public function viewElements(FieldItemListInterface $items, $langcode): array { $elements = []; if ($items->isEmpty()) { return $elements; } $formatter_settigns = $this->getSettings(); $breakpoint_manager = \Drupal::service('breakpoint.manager'); /** @var BreakpointManagerInterface $breakpoint_manager */ $mobile_breakpoint = $breakpoint_manager->getBreakpointsByGroup($formatter_settigns['breakpoint_group'])[$formatter_settigns['mobile_breakpoint']]; /** @var ImageStyleInterface $default_image_style */ $default_image_style = $formatter_settigns['image_style'] ? ImageStyle::load($formatter_settigns['image_style']) : NULL; $default_image_item = $items->get(0); /** @var ImageItem $default_image_item */ $mobile_image_item = $items->get(1); /** @var ImageItem $mobile_image_item */ $default_image_entity = $default_image_item->entity; /** @var FileInterface $default_image_entity */ $mobile_image_entity = $mobile_image_item ? $mobile_image_item->entity : NULL; /** @var FileInterface $mobile_image_entity */ $default_image_url = $this->getImageStyleUrl($default_image_entity->getFileUri(), $formatter_settigns['image_style']); $default_image_dimensions = ['width' => $default_image_item->width, 'height' => $default_image_item->height]; if ($default_image_style) { $default_image_style->transformDimensions($default_image_dimensions, $default_image_entity->getFileUri()); } $elements[0] = [ '#theme' => 'picture', // Default image '#img' => [ 'src' => $default_image_url, 'alt' => '', ] + $default_image_dimensions, ]; if ($mobile_image_entity) { $mobile_image_url = $this->getImageStyleUrl($mobile_image_entity->getFileUri(), $formatter_settigns['mobile_image_style']); // Mobile image $elements[0]['#source'] = [ 'mobile' => [ 'srcset' => $mobile_image_url, 'type' => $mobile_image_entity->getMimeType(), 'media' => $mobile_breakpoint->getMediaQuery(), ], ]; } $elements['#all_in_one'] = TRUE; return $elements; } /** * {@inheritDoc} */ public static function isApplicable(FieldDefinitionInterface $field_definition): bool { return $field_definition->getFieldStorageDefinition()->isMultiple(); } /** * Return options for "mobile breakpoint" setting. */ private function getMobileBreakpointOptions(string $breakpoint_group): array { $breakpoint_manager = \Drupal::service('breakpoint.manager'); /** @var BreakpointManagerInterface $breakpoint_manager */ $breakpoints = $breakpoint_manager->getBreakpointsByGroup($breakpoint_group); return array_map(function ($breakpoint) { /** @var BreakpointInterface $breakpoint */ return $breakpoint->getLabel(); }, $breakpoints); } /** * Return url for image with image style. */ private function getImageStyleUrl(string $path, string $style_name): string { $file_url_generator = \Drupal::service('file_url_generator'); if ($style_name && ($image_style = ImageStyle::load($style_name))) { return $file_url_generator->transformRelative($image_style->buildUrl($path)); } return $file_url_generator->generateString($path); } }