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

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 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.         $path ltrim($path'/');
  117.         return 'rc/'.$this->signer->sign($path$runtimeConfig).'/'.$path;
  118.     }
  119.     /**
  120.      * Returns a web accessible URL.
  121.      *
  122.      * @param string $path          The path where the resolved file is expected
  123.      * @param string $filter        The name of the imagine filter in effect
  124.      * @param string $resolver
  125.      * @param int    $referenceType The type of reference to be generated (one of the UrlGenerator constants)
  126.      *
  127.      * @return string
  128.      */
  129.     public function generateUrl($path$filter, array $runtimeConfig = [], $resolver null$referenceType UrlGeneratorInterface::ABSOLUTE_URL)
  130.     {
  131.         $params = [
  132.             'path' => ltrim($path'/'),
  133.             'filter' => $filter,
  134.         ];
  135.         if ($resolver) {
  136.             $params['resolver'] = $resolver;
  137.         }
  138.         if (empty($runtimeConfig)) {
  139.             $filterUrl $this->router->generate('liip_imagine_filter'$params$referenceType);
  140.         } else {
  141.             $params['filters'] = $runtimeConfig;
  142.             $params['hash'] = $this->signer->sign($path$runtimeConfig);
  143.             $filterUrl $this->router->generate('liip_imagine_filter_runtime'$params$referenceType);
  144.         }
  145.         return $filterUrl;
  146.     }
  147.     /**
  148.      * Checks whether the path is already stored within the respective Resolver.
  149.      *
  150.      * @param string $path
  151.      * @param string $filter
  152.      * @param string $resolver
  153.      *
  154.      * @return bool
  155.      */
  156.     public function isStored($path$filter$resolver null)
  157.     {
  158.         return $this->getResolver($filter$resolver)->isStored($path$filter);
  159.     }
  160.     /**
  161.      * Resolves filtered path for rendering in the browser.
  162.      *
  163.      * @param string $path
  164.      * @param string $filter
  165.      * @param string $resolver
  166.      *
  167.      * @throws NotFoundHttpException if the path can not be resolved
  168.      *
  169.      * @return string The url of resolved image
  170.      */
  171.     public function resolve($path$filter$resolver null)
  172.     {
  173.         if (false !== mb_strpos($path'/../') || === mb_strpos($path'../')) {
  174.             throw new NotFoundHttpException(\sprintf("Source image was searched with '%s' outside of the defined root path"$path));
  175.         }
  176.         $preEvent = new CacheResolveEvent($path$filter);
  177.         $this->dispatchWithBC($preEventImagineEvents::PRE_RESOLVE);
  178.         $url $this->getResolver($preEvent->getFilter(), $resolver)->resolve($preEvent->getPath(), $preEvent->getFilter());
  179.         $postEvent = new CacheResolveEvent($preEvent->getPath(), $preEvent->getFilter(), $url);
  180.         $this->dispatchWithBC($postEventImagineEvents::POST_RESOLVE);
  181.         return $postEvent->getUrl();
  182.     }
  183.     /**
  184.      * @see ResolverInterface::store
  185.      *
  186.      * @param string $path
  187.      * @param string $filter
  188.      * @param string $resolver
  189.      */
  190.     public function store(BinaryInterface $binary$path$filter$resolver null)
  191.     {
  192.         $this->getResolver($filter$resolver)->store($binary$path$filter);
  193.     }
  194.     /**
  195.      * @param string|string[]|null $paths
  196.      * @param string|string[]|null $filters
  197.      */
  198.     public function remove($paths null$filters null)
  199.     {
  200.         if (null === $filters) {
  201.             $filters array_keys($this->filterConfig->all());
  202.         } elseif (!\is_array($filters)) {
  203.             $filters = [$filters];
  204.         }
  205.         if (!\is_array($paths)) {
  206.             $paths = [$paths];
  207.         }
  208.         $paths array_filter($paths);
  209.         $filters array_filter($filters);
  210.         $mapping = new \SplObjectStorage();
  211.         foreach ($filters as $filter) {
  212.             $resolver $this->getResolver($filternull);
  213.             $list = isset($mapping[$resolver]) ? $mapping[$resolver] : [];
  214.             $list[] = $filter;
  215.             $mapping[$resolver] = $list;
  216.         }
  217.         foreach ($mapping as $resolver) {
  218.             $resolver->remove($paths$mapping[$resolver]);
  219.         }
  220.     }
  221.     /**
  222.      * Gets a resolver for the given filter.
  223.      *
  224.      * In case there is no specific resolver, but a default resolver has been configured, the default will be returned.
  225.      *
  226.      * @param string $filter
  227.      * @param string $resolver
  228.      *
  229.      * @throws \OutOfBoundsException If neither a specific nor a default resolver is available
  230.      *
  231.      * @return ResolverInterface
  232.      */
  233.     protected function getResolver($filter$resolver)
  234.     {
  235.         // BC
  236.         if (!$resolver) {
  237.             $config $this->filterConfig->get($filter);
  238.             $resolverName = empty($config['cache']) ? $this->defaultResolver $config['cache'];
  239.         } else {
  240.             $resolverName $resolver;
  241.         }
  242.         if (!isset($this->resolvers[$resolverName])) {
  243.             throw new \OutOfBoundsException(\sprintf('Could not find resolver "%s" for "%s" filter type'$resolverName$filter));
  244.         }
  245.         return $this->resolvers[$resolverName];
  246.     }
  247.     /**
  248.      * BC Layer for Symfony < 4.3
  249.      */
  250.     private function dispatchWithBC(CacheResolveEvent $eventstring $eventName): void
  251.     {
  252.         if ($this->dispatcher instanceof ContractsEventDispatcherInterface) {
  253.             $this->dispatcher->dispatch($event$eventName);
  254.         } else {
  255.             $this->dispatcher->dispatch($eventName$event);
  256.         }
  257.     }
  258. }