Commit 348530d2 authored by Pascal Glass's avatar Pascal Glass Committed by Sean Blommaert
Browse files

Issue #3281910: [FR]: Field Formatter

parent 33e98140
Loading
Loading
Loading
Loading
+10 −3
Original line number Diff line number Diff line
@@ -25,9 +25,16 @@ USAGE
------------

After generating the desired image styles for the different aspect ratio's,
create a media view mode for each aspect ratio. The module provides a Twig
filter to create URLs for the images styles (including an optimized WebP
version of the image when using
create a media view mode for each aspect ratio. The Easy Responsive Images
formatter can be used to select an aspect ratio for the image in the media
view mode. When using the media item in other content, render the media item
using the view mode needed for the specific display.


### Twig

The module also provides a Twig filter to create URLs for the images styles
(including an optimized WebP version of the image when using
[ImageAPI Optimize WebP](https://www.drupal.org/project/imageapi_optimize_webp)).

Create a template for your media view mode, eg. `media--image--16-9.html.twig`
+42 −0
Original line number Diff line number Diff line
<?php

/**
 * @file
 * DrImage core functions.
 */

use Drupal\Core\Routing\RouteMatchInterface;

/**
 * Implements hook_help().
 */
function easy_responsive_images_help($route_name, RouteMatchInterface $route_match) {
  switch ($route_name) {
    case 'easy_responsive_images.image':
      return '<p>' . t('For a full description of the module, visit the project page: https://drupal.org/project/drimage') . '</p>';
  }
}

/**
 * Implements hook_theme().
 */
function easy_responsive_images_theme() {
  return [
    'easy_responsive_images_formatter' => [
      'variables' => [
        'item' => NULL,
        'item_attributes' => NULL,
        'image_attributes' => [],
        'alt' => NULL,
        'width' => NULL,
        'height' => NULL,
        'loading_method' => NULL,
        'decoding_method' => NULL,
        'fetch_priority' => NULL,
        'data' => NULL,
        'src' => NULL,
        'srcset' => NULL,
      ],
    ],
  ];
}
+3 −0
Original line number Diff line number Diff line
@@ -3,3 +3,6 @@ services:
    class: Drupal\easy_responsive_images\TwigExtension\ImageUrl
    tags:
      - { name: twig.extension }
  easy_responsive_images.manager:
    class: Drupal\easy_responsive_images\EasyResponsiveImagesManager
    arguments: ['@entity_type.manager', '@module_handler', '@file_url_generator']
+206 −0
Original line number Diff line number Diff line
<?php

namespace Drupal\easy_responsive_images;

use Drupal\Core\Entity\EntityTypeManagerInterface;
use Drupal\Core\Extension\ModuleHandlerInterface;
use Drupal\Core\File\FileUrlGeneratorInterface;

/**
 * Manages easy responsive images.
 */
class EasyResponsiveImagesManager implements EasyResponsiveImagesManagerInterface {

  /**
   * The field formatter configuration.
   *
   * @var array|null
   */
  protected $configuration;

  /**
   * The entity type manager.
   *
   * @var \Drupal\Core\Entity\EntityTypeManagerInterface
   */
  protected EntityTypeManagerInterface $entityTypeManager;

  /**
   * The Module handler.
   *
   * @var \Drupal\Core\Extension\ModuleHandlerInterface
   */
  protected ModuleHandlerInterface $moduleHandler;

  /**
   * The file url generator.
   *
   * @var \Drupal\Core\File\FileUrlGeneratorInterface
   */
  protected FileUrlGeneratorInterface $fileUrlGenerator;

  /**
   * Constructs a new Easy Responsive Images object.
   *
   * @param \Drupal\Core\Entity\EntityTypeManagerInterface $entity_type_manager
   *   The entity type manager.
   * @param \Drupal\Core\Extension\ModuleHandlerInterface $module_handler
   *   The module handler.
   * @param \Drupal\Core\File\FileUrlGeneratorInterface $file_url_generator
   *   The file url generator.
   */
  public function __construct(EntityTypeManagerInterface $entity_type_manager, ModuleHandlerInterface $module_handler, FileUrlGeneratorInterface $file_url_generator) {
    $this->entityTypeManager = $entity_type_manager;
    $this->moduleHandler = $module_handler;
    $this->fileUrlGenerator = $file_url_generator;
  }

  /**
   * The initial image configuration array.
   *
   * @return array|null
   *   Returns the initial images configuration as an array.
   *
   * @throws \Drupal\Component\Plugin\Exception\InvalidPluginDefinitionException
   * @throws \Drupal\Component\Plugin\Exception\PluginNotFoundException
   */
  protected function initialImagesConfiguration(): ?array {
    if ($this->configuration === NULL) {
      $this->configuration = [];
      $image_style_storage = $this->entityTypeManager
        ->getStorage('image_style');
      $image_style_ids = $image_style_storage->getQuery()
        ->condition('name', 'responsive_', 'STARTS_WITH')
        ->execute();
      $loaded_styles = $image_style_storage->loadMultiple($image_style_ids);

      foreach ($loaded_styles as $style_name => $style) {
        $style_parts = explode('_', $style_name);
        // If style_parts array has 4 keys/values
        // (e.g. {"responsive", "16", "9", "100w"}) we are dealing
        // with a responsive image style.
        if (count($style_parts) === 4) {
          $aspect_w = $style_parts[1];
          $aspect_h = $style_parts[2];
          $width = str_replace('w', '', $style_parts[3]);
          $height = round($width / $aspect_w * $aspect_h, 0);
          $group = "${aspect_w}_${aspect_h}";

          // Process variables - build custom array.
          $this->configuration[$group][$style_name]['style'] = $style;
          $this->configuration[$group][$style_name]['width'] = $width;
          $this->configuration[$group][$style_name]['height'] = $height;
        }
        // If the style_parts array has two keys/values
        // (e.g. {"responsive", "1500w"}) we are dealing
        // with a scaling image.
        elseif (count($style_parts) === 2 && substr($style_parts[1], -1) === 'w') {
          $width = str_replace('w', '', $style_parts[1]);
          $group = 'scale';

          // Process variables - build custom array.
          $this->configuration[$group][$style_name]['style'] = $style;
          $this->configuration[$group][$style_name]['width'] = $width;
        }
      }
      return $this->configuration;
    }
    return $this->configuration;
  }

  /**
   * {@inheritdoc}
   */
  public function getAspectRatios(): array {
    $images_configuration = $this->initialImagesConfiguration();
    unset($images_configuration['scale']);
    $options = [];

    foreach ($images_configuration as $key => $image_config_item) {
      $options[$key] = str_replace('_', ':', $key);
    }

    return $options;
  }

  /**
   * {@inheritdoc}
   */
  public function getImagesByAspectRatio(string $uri, string $aspect_ratio): array {
    $images_configuration = $this->initialImagesConfiguration();
    $style_infos = $images_configuration[$aspect_ratio] ?? NULL;
    $style_urls = [];

    foreach ($style_infos as $style_info) {
      $style_url = $this->fileUrlGenerator->transformRelative(($style_info['style']->buildUrl($uri)));
      $style_url = $this->getWebpDerivatives($style_url, $uri);

      $style_urls[] = [
        'url' => $style_url,
        'width' => $style_info['width'],
        'height' => (int) $style_info['height'],
        'srcset_url' => $style_url . ' ' . $style_info['width'] . 'w',
      ];
    }

    usort($style_urls, static fn(array $a, array $b) => [$a['width']] <=> [$b['width']]);

    return $style_urls;
  }

  /**
   * {@inheritdoc}
   */
  public function getImagesByScale(string $uri): array {
    $images_configuration = $this->initialImagesConfiguration();
    $style_infos = $images_configuration['scale'] ?? NULL;
    $style_urls = [];

    foreach ($style_infos as $style_info) {
      $style_url = $this->fileUrlGenerator->transformRelative(($style_info['style']->buildUrl($uri)));
      $style_url = $this->getWebpDerivatives($style_url, $uri);

      $style_urls[] = [
        'url' => $style_url,
        'width' => $style_info['width'],
        'srcset_url' => $style_url . ' ' . $style_info['width'] . 'w',
      ];
    }

    usort($style_urls, fn(array $a, array $b) => [$a['width']] <=> [$b['width']]);

    return $style_urls;
  }

  /**
   * Get webp derivatives of an image.
   *
   * It checks if the module image_optimize_webp is installed
   * and the browser supports webp.
   *
   * @param string $url
   *   The url.
   * @param string $uri
   *   The uri.
   *
   * @return string
   *   Returns a WebP Derivative as a string.
   */
  protected function getWebpDerivatives(string $url, string $uri): string {
    // If the imageapi_optimize_webp module is installed and the browser
    // supports webp, return the webp version of the image.
    if ($this->moduleHandler->moduleExists('imageapi_optimize_webp')) {
      if (isset($_SERVER['HTTP_ACCEPT']) && strpos($_SERVER['HTTP_ACCEPT'], 'image/webp') !== FALSE) {
        $path_parts = pathinfo($uri);
        $original_extension = '.' . $path_parts['extension'];
        $pos = strrpos($url, $original_extension);
        if ($pos !== FALSE) {
          $url = substr_replace($url, $original_extension . '.webp', $pos, strlen($original_extension));
        }
      }
    }

    return $url;
  }

}
+44 −0
Original line number Diff line number Diff line
<?php

namespace Drupal\easy_responsive_images;

/**
 * Provides an interface for the EasyResponsiveImagesManager.
 */
interface EasyResponsiveImagesManagerInterface {

  /**
   * Get all available aspect ratios.
   *
   * @return array
   *   Return options array.
   */
  public function getAspectRatios(): array;

  /**
   * Get all images by a specific aspect ratio as an array.
   *
   * @param string $uri
   *   The uri.
   * @param string $aspect_ratio
   *   The aspect ratio.
   *
   * @return array
   *   Returns style_urls array
   *   consisting of url, width, height & srcset_url.
   */
  public function getImagesByAspectRatio(string $uri, string $aspect_ratio): array;

  /**
   * Get all images, where no aspect ratio should be used.
   *
   * @param string $uri
   *   The uri.
   *
   * @return array
   *   Returns style_urls as an array
   *   consisting of url, width, height, srcset_url.
   */
  public function getImagesByScale(string $uri): array;

}
Loading