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;
}
}
