vendor/liip/imagine-bundle/Imagine/Cache/CacheManager.php line 220

Open in your IDE?
  1. <?php
  2. /*
  3.  * This file is part of the `liip/LiipImagineBundle` project.
  4.  *
  5.  * (c) https://github.com/liip/LiipImagineBundle/graphs/contributors
  6.  *
  7.  * For the full copyright and license information, please view the LICENSE.md
  8.  * file that was distributed with this source code.
  9.  */
  10. namespace Liip\ImagineBundle\Imagine\Cache;
  11. use Liip\ImagineBundle\Binary\BinaryInterface;
  12. use Liip\ImagineBundle\Events\CacheResolveEvent;
  13. use Liip\ImagineBundle\Imagine\Cache\Resolver\ResolverInterface;
  14. use Liip\ImagineBundle\Imagine\Filter\FilterConfiguration;
  15. use Liip\ImagineBundle\ImagineEvents;
  16. use Symfony\Component\EventDispatcher\EventDispatcherInterface;
  17. use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
  18. use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
  19. use Symfony\Component\Routing\RouterInterface;
  20. use Symfony\Contracts\EventDispatcher\EventDispatcherInterface as ContractsEventDispatcherInterface;
  21. class CacheManager
  22. {
  23.     /**
  24.      * @var FilterConfiguration
  25.      */
  26.     protected $filterConfig;
  27.     /**
  28.      * @var RouterInterface
  29.      */
  30.     protected $router;
  31.     /**
  32.      * @var ResolverInterface[]
  33.      */
  34.     protected $resolvers = [];
  35.     /**
  36.      * @var SignerInterface
  37.      */
  38.     protected $signer;
  39.     /**
  40.      * @var \Symfony\Component\EventDispatcher\EventDispatcherInterface
  41.      */
  42.     protected $dispatcher;
  43.     /**
  44.      * @var string
  45.      */
  46.     protected $defaultResolver;
  47.     /**
  48.      * @var bool
  49.      */
  50.     private $webpGenerate;
  51.     /**
  52.      * Constructs the cache manager to handle Resolvers based on the provided FilterConfiguration.
  53.      *
  54.      * @param string $defaultResolver
  55.      * @param bool   $webpGenerate
  56.      */
  57.     public function __construct(
  58.         FilterConfiguration $filterConfig,
  59.         RouterInterface $router,
  60.         SignerInterface $signer,
  61.         EventDispatcherInterface $dispatcher,
  62.         $defaultResolver null,
  63.         $webpGenerate false
  64.     ) {
  65.         $this->filterConfig $filterConfig;
  66.         $this->router $router;
  67.         $this->signer $signer;
  68.         $this->dispatcher $dispatcher;
  69.         $this->defaultResolver $defaultResolver ?: 'default';
  70.         $this->webpGenerate $webpGenerate;
  71.     }
  72.     /**
  73.      * Adds a resolver to handle cached images for the given filter.
  74.      *
  75.      * @param string $filter
  76.      */
  77.     public function addResolver($filterResolverInterface $resolver)
  78.     {
  79.         $this->resolvers[$filter] = $resolver;
  80.         if ($resolver instanceof CacheManagerAwareInterface) {
  81.             $resolver->setCacheManager($this);
  82.         }
  83.     }
  84.     /**
  85.      * Gets filtered path for rendering in the browser.
  86.      * It could be the cached one or an url of filter action.
  87.      *
  88.      * @param string $path          The path where the resolved file is expected
  89.      * @param string $filter
  90.      * @param string $resolver
  91.      * @param int    $referenceType
  92.      *
  93.      * @return string
  94.      */
  95.     public function getBrowserPath($path$filter, array $runtimeConfig = [], $resolver null$referenceType UrlGeneratorInterface::ABSOLUTE_URL)
  96.     {
  97.         if (!empty($runtimeConfig)) {
  98.             $rcPath $this->getRuntimePath($path$runtimeConfig);
  99.             return !$this->webpGenerate && $this->isStored($rcPath$filter$resolver) ?
  100.                 $this->resolve($rcPath$filter$resolver) :
  101.                 $this->generateUrl($path$filter$runtimeConfig$resolver$referenceType);
  102.         }
  103.         return !$this->webpGenerate && $this->isStored($path$filter$resolver) ?
  104.             $this->resolve($path$filter$resolver) :
  105.             $this->generateUrl($path$filter, [], $resolver$referenceType);
  106.     }
  107.     /**
  108.      * Get path to runtime config image.
  109.      *
  110.      * @param string $path
  111.      *
  112.      * @return string
  113.      */
  114.     public function getRuntimePath($path, array $runtimeConfig)
  115.     {
  116.         return 'rc/'.$this->signer->sign($path$runtimeConfig).'/'.$path;
  117.     }
  118.     /**
  119.      * Returns a web accessible URL.
  120.      *
  121.      * @param string $path          The path where the resolved file is expected
  122.      * @param string $filter        The name of the imagine filter in effect
  123.      * @param string $resolver
  124.      * @param int    $referenceType The type of reference to be generated (one of the UrlGenerator constants)
  125.      *
  126.      * @return string
  127.      */
  128.     public function generateUrl($path$filter, array $runtimeConfig = [], $resolver null$referenceType UrlGeneratorInterface::ABSOLUTE_URL)
  129.     {
  130.         $params = [
  131.             'path' => ltrim($path'/'),
  132.             'filter' => $filter,
  133.         ];
  134.         if ($resolver) {
  135.             $params['resolver'] = $resolver;
  136.         }
  137.         if (empty($runtimeConfig)) {
  138.             $filterUrl $this->router->generate('liip_imagine_filter'$params$referenceType);
  139.         } else {
  140.             $params['filters'] = $runtimeConfig;
  141.             $params['hash'] = $this->signer->sign($path$runtimeConfig);
  142.             $filterUrl $this->router->generate('liip_imagine_filter_runtime'$params$referenceType);
  143.         }
  144.         return $filterUrl;
  145.     }
  146.     /**
  147.      * Checks whether the path is already stored within the respective Resolver.
  148.      *
  149.      * @param string $path
  150.      * @param string $filter
  151.      * @param string $resolver
  152.      *
  153.      * @return bool
  154.      */
  155.     public function isStored($path$filter$resolver null)
  156.     {
  157.         return $this->getResolver($filter$resolver)->isStored($path$filter);
  158.     }
  159.     /**
  160.      * Resolves filtered path for rendering in the browser.
  161.      *
  162.      * @param string $path
  163.      * @param string $filter
  164.      * @param string $resolver
  165.      *
  166.      * @throws NotFoundHttpException if the path can not be resolved
  167.      *
  168.      * @return string The url of resolved image
  169.      */
  170.     public function resolve($path$filter$resolver null)
  171.     {
  172.         if (false !== mb_strpos($path'/../') || === mb_strpos($path'../')) {
  173.             throw new NotFoundHttpException(sprintf("Source image was searched with '%s' outside of the defined root path"$path));
  174.         }
  175.         $preEvent = new CacheResolveEvent($path$filter);
  176.         $this->dispatchWithBC($preEventImagineEvents::PRE_RESOLVE);
  177.         $url $this->getResolver($preEvent->getFilter(), $resolver)->resolve($preEvent->getPath(), $preEvent->getFilter());
  178.         $postEvent = new CacheResolveEvent($preEvent->getPath(), $preEvent->getFilter(), $url);
  179.         $this->dispatchWithBC($postEventImagineEvents::POST_RESOLVE);
  180.         return $postEvent->getUrl();
  181.     }
  182.     /**
  183.      * @see ResolverInterface::store
  184.      *
  185.      * @param string $path
  186.      * @param string $filter
  187.      * @param string $resolver
  188.      */
  189.     public function store(BinaryInterface $binary$path$filter$resolver null)
  190.     {
  191.         $this->getResolver($filter$resolver)->store($binary$path$filter);
  192.     }
  193.     /**
  194.      * @param string|string[]|null $paths
  195.      * @param string|string[]|null $filters
  196.      */
  197.     public function remove($paths null$filters null)
  198.     {
  199.         if (null === $filters) {
  200.             $filters array_keys($this->filterConfig->all());
  201.         } elseif (!\is_array($filters)) {
  202.             $filters = [$filters];
  203.         }
  204.         if (!\is_array($paths)) {
  205.             $paths = [$paths];
  206.         }
  207.         $paths array_filter($paths);
  208.         $filters array_filter($filters);
  209.         $mapping = new \SplObjectStorage();
  210.         foreach ($filters as $filter) {
  211.             $resolver $this->getResolver($filternull);
  212.             $list = isset($mapping[$resolver]) ? $mapping[$resolver] : [];
  213.             $list[] = $filter;
  214.             $mapping[$resolver] = $list;
  215.         }
  216.         foreach ($mapping as $resolver) {
  217.             $resolver->remove($paths$mapping[$resolver]);
  218.         }
  219.     }
  220.     /**
  221.      * Gets a resolver for the given filter.
  222.      *
  223.      * In case there is no specific resolver, but a default resolver has been configured, the default will be returned.
  224.      *
  225.      * @param string $filter
  226.      * @param string $resolver
  227.      *
  228.      * @throws \OutOfBoundsException If neither a specific nor a default resolver is available
  229.      *
  230.      * @return ResolverInterface
  231.      */
  232.     protected function getResolver($filter$resolver)
  233.     {
  234.         // BC
  235.         if (!$resolver) {
  236.             $config $this->filterConfig->get($filter);
  237.             $resolverName = empty($config['cache']) ? $this->defaultResolver $config['cache'];
  238.         } else {
  239.             $resolverName $resolver;
  240.         }
  241.         if (!isset($this->resolvers[$resolverName])) {
  242.             throw new \OutOfBoundsException(sprintf('Could not find resolver "%s" for "%s" filter type'$resolverName$filter));
  243.         }
  244.         return $this->resolvers[$resolverName];
  245.     }
  246.     /**
  247.      * BC Layer for Symfony < 4.3
  248.      */
  249.     private function dispatchWithBC(CacheResolveEvent $eventstring $eventName): void
  250.     {
  251.         if ($this->dispatcher instanceof ContractsEventDispatcherInterface) {
  252.             $this->dispatcher->dispatch($event$eventName);
  253.         } else {
  254.             $this->dispatcher->dispatch($eventName$event);
  255.         }
  256.     }
  257. }