client_hints-8.x-1.0-alpha3/src/Service/ClientHints.php
src/Service/ClientHints.php
<?php namespace Drupal\client_hints\Service; use Drupal\Core\Cache\Cache; use Drupal\Core\Cache\CacheBackendInterface; use Drupal\Core\Entity\EntityTypeManagerInterface; use Drupal\image\ImageStyleInterface; use Drupal\image\Plugin\ImageEffect\ResizeImageEffect; use Drupal\Core\Entity\EntityTypeManager; /** * Client hints service. */ class ClientHints { /** * The cache backend. * * @var \Drupal\Core\Cache\CacheBackendInterface */ protected $cacheBackend; /** * The entity type manager. * * @var \Drupal\Core\Entity\EntityTypeManagerInterface */ protected $entityTypeManager; /** * ClientHints constructor. * * @param \Drupal\Core\Cache\CacheBackendInterface $cache_backend * @param \Drupal\Core\Entity\EntityTypeManagerInterface $entity_type_manager */ public function __construct(CacheBackendInterface $cache_backend, EntityTypeManagerInterface $entity_type_manager) { $this->cacheBackend = $cache_backend; $this->entityTypeManager = $entity_type_manager; } /** * @param string $uri * @param int $dpr * @param int $width * * @return \Drupal\Core\GeneratedUrl|string * * @throws \Drupal\Component\Plugin\Exception\InvalidPluginDefinitionException * @throws \Drupal\Component\Plugin\Exception\PluginNotFoundException */ public function getImageRedirectUrl($uri, $dpr, $width) { $image_style_id = $this->getAppropriateImageStyleId($width * $dpr); /* @var $image_style \Drupal\image\Entity\ImageStyle */ $image_style = $this->entityTypeManager->getStorage('image_style')->load($image_style_id); return $image_style->buildUrl($uri); } /** * Gets the ID of the appropriate image style for a given width. * * @param int $target_width * * @return mixed * * @throws \Drupal\Component\Plugin\Exception\InvalidPluginDefinitionException * @throws \Drupal\Component\Plugin\Exception\PluginNotFoundException */ protected function getAppropriateImageStyleId($target_width) { $image_styles = $this->getImageStylesByWidth(); $wider_image_styles = array_filter($image_styles, function ($style_width) use ($target_width) { return $style_width > $target_width; }, ARRAY_FILTER_USE_KEY); // Return smallest appropriate image style's ID, if possible. if (!empty($wider_image_styles)) { return array_shift($wider_image_styles); } // Otherwise, return the biggest image style's ID. else { return array_pop($image_styles); } } /** * Gets a list of all image styles keyed by their respective width. * * @return string[] * * @throws \Drupal\Component\Plugin\Exception\InvalidPluginDefinitionException * @throws \Drupal\Component\Plugin\Exception\PluginNotFoundException */ protected function getImageStylesByWidth() { if ($cached = $this->cacheBackend->get('client_hints.styles')) { // Return the cached options. return $cached->data; } // Get image styles. /* @var $image_styles \Drupal\image\Entity\ImageStyle[] */ $image_styles = $this->entityTypeManager->getStorage('image_style')->loadMultiple(); $entity_type = $this->entityTypeManager->getDefinition('image_style'); $cache_tags = $entity_type->getListCacheTags(); foreach ($image_styles as $image_style) { // Get image style's output width... $width = $this->getImageStyleWidth($image_style); // ...and use that to key the style id in a list of image styles. $image_styles_by_width[$width] = $image_style->id(); Cache::mergeTags($cache_tags, $image_style->getCacheTags()); } // Sort the image style list by ascending width. ksort($image_styles_by_width); $this->cacheBackend->set('client_hints.styles', $image_styles_by_width, Cache::PERMANENT, $cache_tags); return $image_styles_by_width; } /** * Gets the width of an image style. * * @param \Drupal\image\ImageStyleInterface $style * * @return int */ protected function getImageStyleWidth(ImageStyleInterface $style) { $width = 0; $effects = $style->getEffects(); foreach ($effects as $effect) { if ($effect instanceof ResizeImageEffect) { $width = $effect->getConfiguration()['data']['width']; } } return $width; } }