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

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