Completed
Pull Request — master (#732)
by 12345
03:41
created

CacheManager::remove()   C

Complexity

Conditions 7
Paths 48

Size

Total Lines 30
Code Lines 17

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 0
loc 30
rs 6.7272
cc 7
eloc 17
nc 48
nop 2
1
<?php
2
3
namespace Liip\ImagineBundle\Imagine\Cache;
4
5
use Liip\ImagineBundle\Binary\BinaryInterface;
6
use Liip\ImagineBundle\Imagine\Cache\Resolver\ResolverInterface;
7
use Liip\ImagineBundle\Imagine\Filter\FilterConfiguration;
8
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
9
use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
10
use Symfony\Component\Routing\RouterInterface;
11
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
12
use Liip\ImagineBundle\ImagineEvents;
13
use Liip\ImagineBundle\Events\CacheResolveEvent;
14
15
class CacheManager
16
{
17
    /**
18
     * @var FilterConfiguration
19
     */
20
    protected $filterConfig;
21
22
    /**
23
     * @var RouterInterface
24
     */
25
    protected $router;
26
27
    /**
28
     * @var ResolverInterface[]
29
     */
30
    protected $resolvers = array();
31
32
    /**
33
     * @var SignerInterface
34
     */
35
    protected $signer;
36
37
    /**
38
     * @var \Symfony\Component\EventDispatcher\EventDispatcherInterface
39
     */
40
    protected $dispatcher;
41
42
    /**
43
     * @var string
44
     */
45
    protected $defaultResolver;
46
47
    /**
48
     * Constructs the cache manager to handle Resolvers based on the provided FilterConfiguration.
49
     *
50
     * @param FilterConfiguration      $filterConfig
51
     * @param RouterInterface          $router
52
     * @param SignerInterface          $signer
53
     * @param EventDispatcherInterface $dispatcher
54
     * @param string                   $defaultResolver
55
     */
56
    public function __construct(
57
        FilterConfiguration $filterConfig,
58
        RouterInterface $router,
59
        SignerInterface $signer,
60
        EventDispatcherInterface $dispatcher,
61
        $defaultResolver = null
62
    ) {
63
        $this->filterConfig = $filterConfig;
64
        $this->router = $router;
65
        $this->signer = $signer;
66
        $this->dispatcher = $dispatcher;
67
        $this->defaultResolver = $defaultResolver ?: 'default';
68
    }
69
70
    /**
71
     * Adds a resolver to handle cached images for the given filter.
72
     *
73
     * @param string            $filter
74
     * @param ResolverInterface $resolver
75
     */
76
    public function addResolver($filter, ResolverInterface $resolver)
77
    {
78
        $this->resolvers[$filter] = $resolver;
79
80
        if ($resolver instanceof CacheManagerAwareInterface) {
81
            $resolver->setCacheManager($this);
82
        }
83
    }
84
85
    /**
86
     * Gets a resolver for the given filter.
87
     *
88
     * In case there is no specific resolver, but a default resolver has been configured, the default will be returned.
89
     *
90
     * @param string $filter
91
     * @param string $resolver
92
     *
93
     * @return ResolverInterface
94
     *
95
     * @throws \OutOfBoundsException If neither a specific nor a default resolver is available.
96
     */
97
    protected function getResolver($filter, $resolver)
98
    {
99
        // BC
100
        if (false == $resolver) {
0 ignored issues
show
Bug Best Practice introduced by
It seems like you are loosely comparing $resolver of type string to the boolean false. If you are specifically checking for an empty string, consider using the more explicit === '' instead.
Loading history...
101
            $config = $this->filterConfig->get($filter);
102
103
            $resolverName = empty($config['cache']) ? $this->defaultResolver : $config['cache'];
104
        } else {
105
            $resolverName = $resolver;
106
        }
107
108
        if (!isset($this->resolvers[$resolverName])) {
109
            throw new \OutOfBoundsException(sprintf(
110
                'Could not find resolver "%s" for "%s" filter type',
111
                $resolverName,
112
                $filter
113
            ));
114
        }
115
116
        return $this->resolvers[$resolverName];
117
    }
118
119
    /**
120
     * Gets filtered path for rendering in the browser.
121
     * It could be the cached one or an url of filter action.
122
     *
123
     * @param string $path          The path where the resolved file is expected.
124
     * @param string $filter
125
     * @param array  $runtimeConfig
126
     * @param string $resolver
127
     *
128
     * @return string
129
     */
130
    public function getBrowserPath($path, $filter, array $runtimeConfig = array(), $resolver = null)
131
    {
132
        if (!empty($runtimeConfig)) {
133
            $rcPath = $this->getRuntimePath($path, $runtimeConfig);
134
135
            return $this->isStored($rcPath, $filter, $resolver) ?
136
                $this->resolve($rcPath, $filter, $resolver) :
137
                $this->generateUrl($path, $filter, $runtimeConfig, $resolver)
138
            ;
139
        }
140
141
        return $this->isStored($path, $filter, $resolver) ?
142
            $this->resolve($path, $filter, $resolver) :
143
            $this->generateUrl($path, $filter, array(), $resolver)
144
        ;
145
    }
146
147
    /**
148
     * Get path to runtime config image.
149
     *
150
     * @param string $path
151
     * @param array  $runtimeConfig
152
     *
153
     * @return string
154
     */
155
    public function getRuntimePath($path, array $runtimeConfig)
156
    {
157
        return 'rc/'.$this->signer->sign($path, $runtimeConfig).'/'.$path;
158
    }
159
160
    /**
161
     * Returns a web accessible URL.
162
     *
163
     * @param string $path          The path where the resolved file is expected.
164
     * @param string $filter        The name of the imagine filter in effect.
165
     * @param array  $runtimeConfig
166
     * @param string $resolver
167
     *
168
     * @return string
169
     */
170
    public function generateUrl($path, $filter, array $runtimeConfig = array(), $resolver = null)
171
    {
172
        $params = array(
173
            'path' => ltrim($path, '/'),
174
            'filter' => $filter,
175
        );
176
177
        if ($resolver) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $resolver of type string|null is loosely compared to true; this is ambiguous if the string can be empty. You might want to explicitly use !== null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For string values, the empty string '' is a special case, in particular the following results might be unexpected:

''   == false // true
''   == null  // true
'ab' == false // false
'ab' == null  // false

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
178
            $params['resolver'] = $resolver;
179
        }
180
181
        if (empty($runtimeConfig)) {
182
            $filterUrl = $this->router->generate('liip_imagine_filter', $params, UrlGeneratorInterface::ABSOLUTE_URL);
183
        } else {
184
            $params['filters'] = $runtimeConfig;
185
            $params['hash'] = $this->signer->sign($path, $runtimeConfig);
186
187
            $filterUrl = $this->router->generate('liip_imagine_filter_runtime', $params, UrlGeneratorInterface::ABSOLUTE_URL);
188
        }
189
190
        return $filterUrl;
191
    }
192
193
    /**
194
     * Checks whether the path is already stored within the respective Resolver.
195
     *
196
     * @param string $path
197
     * @param string $filter
198
     * @param string $resolver
199
     *
200
     * @return bool
201
     */
202
    public function isStored($path, $filter, $resolver = null)
203
    {
204
        return $this->getResolver($filter, $resolver)->isStored($path, $filter);
205
    }
206
207
    /**
208
     * Resolves filtered path for rendering in the browser.
209
     *
210
     * @param string $path
211
     * @param string $filter
212
     * @param string $resolver
213
     *
214
     * @return string The url of resolved image.
215
     *
216
     * @throws NotFoundHttpException if the path can not be resolved
217
     */
218
    public function resolve($path, $filter, $resolver = null)
219
    {
220
        if (false !== strpos($path, '/../') || 0 === strpos($path, '../')) {
221
            throw new NotFoundHttpException(sprintf("Source image was searched with '%s' outside of the defined root path", $path));
222
        }
223
224
        $preEvent = new CacheResolveEvent($path, $filter);
225
        $this->dispatcher->dispatch(ImagineEvents::PRE_RESOLVE, $preEvent);
226
227
        $url = $this->getResolver($preEvent->getFilter(), $resolver)->resolve($preEvent->getPath(), $preEvent->getFilter());
228
229
        $postEvent = new CacheResolveEvent($preEvent->getPath(), $preEvent->getFilter(), $url);
230
        $this->dispatcher->dispatch(ImagineEvents::POST_RESOLVE, $postEvent);
231
232
        return $postEvent->getUrl();
233
    }
234
235
    /**
236
     * @see ResolverInterface::store
237
     *
238
     * @param BinaryInterface $binary
239
     * @param string          $path
240
     * @param string          $filter
241
     * @param string          $resolver
242
     */
243
    public function store(BinaryInterface $binary, $path, $filter, $resolver = null)
244
    {
245
        $this->getResolver($filter, $resolver)->store($binary, $path, $filter);
246
    }
247
248
    /**
249
     * @param string|string[]|null $paths
250
     * @param string|string[]|null $filters
251
     */
252
    public function remove($paths = null, $filters = null)
253
    {
254
        if (null === $filters) {
255
            $filters = array_keys($this->filterConfig->all());
256
        }
257
        if (!is_array($filters)) {
258
            $filters = array($filters);
259
        }
260
        if (!is_array($paths)) {
261
            $paths = array($paths);
262
        }
263
264
        $paths = array_filter($paths);
265
        $filters = array_filter($filters);
266
267
        $mapping = new \SplObjectStorage();
268
        foreach ($filters as $filter) {
269
            $resolver = $this->getResolver($filter, null);
270
271
            $list = isset($mapping[$resolver]) ? $mapping[$resolver] : array();
272
273
            $list[] = $filter;
274
275
            $mapping[$resolver] = $list;
276
        }
277
278
        foreach ($mapping as $resolver) {
279
            $resolver->remove($paths, $mapping[$resolver]);
280
        }
281
    }
282
}
283