Completed
Pull Request — master (#365)
by Alessandro
03:29
created

CacheInvalidator::invalidateRegex()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 10
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 4
CRAP Score 2.032

Importance

Changes 0
Metric Value
dl 0
loc 10
ccs 4
cts 5
cp 0.8
rs 9.4285
c 0
b 0
f 0
cc 2
eloc 5
nc 2
nop 3
crap 2.032
1
<?php
2
3
/*
4
 * This file is part of the FOSHttpCache package.
5
 *
6
 * (c) FriendsOfSymfony <http://friendsofsymfony.github.com/>
7
 *
8
 * For the full copyright and license information, please view the LICENSE
9
 * file that was distributed with this source code.
10
 */
11
12
namespace FOS\HttpCache;
13
14
use FOS\HttpCache\Exception\ExceptionCollection;
15
use FOS\HttpCache\Exception\InvalidArgumentException;
16
use FOS\HttpCache\Exception\ProxyResponseException;
17
use FOS\HttpCache\Exception\ProxyUnreachableException;
18
use FOS\HttpCache\Exception\UnsupportedProxyOperationException;
19
use FOS\HttpCache\ProxyClient\Invalidation\BanCapable;
20
use FOS\HttpCache\ProxyClient\Invalidation\PurgeCapable;
21
use FOS\HttpCache\ProxyClient\Invalidation\RefreshCapable;
22
use FOS\HttpCache\ProxyClient\Invalidation\TagCapable;
23
use FOS\HttpCache\ProxyClient\ProxyClient;
24
use Symfony\Component\EventDispatcher\EventDispatcher;
25
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
26
27
/**
28
 * Manages HTTP cache invalidation.
29
 *
30
 * @author David de Boer <[email protected]>
31
 * @author David Buchmann <[email protected]>
32
 * @author André Rømcke <[email protected]>
33
 */
34
class CacheInvalidator
35
{
36
    /**
37
     * Value to check support of invalidatePath operation.
38
     */
39
    const PATH = 'path';
40
41
    /**
42
     * Value to check support of refreshPath operation.
43
     */
44
    const REFRESH = 'refresh';
45
46
    /**
47
     * Value to check support of invalidate and invalidateRegex operations.
48
     */
49
    const INVALIDATE = 'invalidate';
50
51
    /**
52
     * Value to check support of invalidateTags operation.
53
     */
54
    const TAGS = 'tags';
55
56
    /**
57
     * @var ProxyClient
58
     */
59
    private $cache;
60
61
    /**
62
     * @var EventDispatcherInterface
63
     */
64
    private $eventDispatcher;
65
66
    /**
67
     * Constructor.
68
     *
69
     * @param ProxyClient $cache HTTP cache
70
     */
71 12
    public function __construct(ProxyClient $cache)
72
    {
73 12
        $this->cache = $cache;
74 12
    }
75
76
    /**
77
     * Check whether this invalidator instance supports the specified
78
     * operation.
79
     *
80
     * Support for PATH means invalidatePath will work, REFRESH means
81
     * refreshPath works, TAGS means that invalidateTags works and
82
     * INVALIDATE is for the invalidate and invalidateRegex methods.
83
     *
84
     * @param string $operation one of the class constants
85
     *
86
     * @return bool
87
     *
88
     * @throws InvalidArgumentException
89
     */
90 3
    public function supports($operation)
91
    {
92
        switch ($operation) {
93 3
            case self::PATH:
94 2
                return $this->cache instanceof PurgeCapable;
95 3
            case self::REFRESH:
96 2
                return $this->cache instanceof RefreshCapable;
97 3
            case self::INVALIDATE:
98 2
                return $this->cache instanceof BanCapable;
99 3
            case self::TAGS:
100 2
                return $this->cache instanceof TagCapable;
101
            default:
102 1
                throw new InvalidArgumentException('Unknown operation '.$operation);
103
        }
104
    }
105
106
    /**
107
     * Set event dispatcher - may only be called once.
108
     *
109
     * @param EventDispatcherInterface $eventDispatcher
110
     *
111
     * @return $this
112
     *
113
     * @throws \Exception When trying to override the event dispatcher
114
     */
115 2
    public function setEventDispatcher(EventDispatcherInterface $eventDispatcher)
116
    {
117 2
        if ($this->eventDispatcher) {
118
            // if you want to set a custom event dispatcher, do so right after instantiating
119
            // the invalidator.
120 1
            throw new \Exception('You may not change the event dispatcher once it is set.');
121
        }
122 2
        $this->eventDispatcher = $eventDispatcher;
123 2
    }
124
125
    /**
126
     * Get the event dispatcher used by the cache invalidator.
127
     *
128
     * @return EventDispatcherInterface
129
     */
130 2
    public function getEventDispatcher()
131
    {
132 2
        if (!$this->eventDispatcher) {
133 1
            $this->eventDispatcher = new EventDispatcher();
134
        }
135
136 2
        return $this->eventDispatcher;
137
    }
138
139
    /**
140
     * Invalidate a path or URL.
141
     *
142
     * @param string $path    Path or URL
143
     * @param array  $headers HTTP headers (optional)
144
     *
145
     * @throws UnsupportedProxyOperationException
146
     *
147
     * @return $this
148
     */
149 1
    public function invalidatePath($path, array $headers = [])
150
    {
151 1
        if (!$this->cache instanceof PurgeCapable) {
152
            throw UnsupportedProxyOperationException::cacheDoesNotImplement('PURGE');
153
        }
154
155 1
        $this->cache->purge($path, $headers);
156
157 1
        return $this;
158
    }
159
160
    /**
161
     * Refresh a path or URL.
162
     *
163
     * @param string $path    Path or URL
164
     * @param array  $headers HTTP headers (optional)
165
     *
166
     * @see RefreshCapable::refresh()
167
     *
168
     * @throws UnsupportedProxyOperationException
169
     *
170
     * @return $this
171
     */
172 1
    public function refreshPath($path, array $headers = [])
173
    {
174 1
        if (!$this->cache instanceof RefreshCapable) {
175
            throw UnsupportedProxyOperationException::cacheDoesNotImplement('REFRESH');
176
        }
177
178 1
        $this->cache->refresh($path, $headers);
179
180 1
        return $this;
181
    }
182
183
    /**
184
     * Invalidate all cached objects matching the provided HTTP headers.
185
     *
186
     * Each header is a a POSIX regular expression, for example
187
     * ['X-Host' => '^(www\.)?(this|that)\.com$']
188
     *
189
     * @see BanCapable::ban()
190
     *
191
     * @param array $headers HTTP headers that path must match to be banned
192
     *
193
     * @throws UnsupportedProxyOperationException If HTTP cache does not support BAN requests
194
     *
195
     * @return $this
196
     */
197 1
    public function invalidate(array $headers)
198
    {
199 1
        if (!$this->cache instanceof BanCapable) {
200
            throw UnsupportedProxyOperationException::cacheDoesNotImplement('BAN');
201
        }
202
203 1
        $this->cache->ban($headers);
204
205 1
        return $this;
206
    }
207
208
    /**
209
     * Remove/Expire cache objects based on cache tags.
210
     *
211
     * @see TagCapable::tags()
212
     *
213
     * @param array $tags Tags that should be removed/expired from the cache
214
     *
215
     * @throws UnsupportedProxyOperationException If HTTP cache does not support Tags invalidation
216
     *
217
     * @return $this
218
     */
219 2
    public function invalidateTags(array $tags)
220
    {
221 2
        if (!$this->cache instanceof TagCapable) {
222
            throw UnsupportedProxyOperationException::cacheDoesNotImplement('Tags');
223
        }
224 2
        $this->cache->invalidateTags($tags);
225
226 2
        return $this;
227
    }
228
229
    /**
230
     * Invalidate URLs based on a regular expression for the URI, an optional
231
     * content type and optional limit to certain hosts.
232
     *
233
     * The hosts parameter can either be a regular expression, e.g.
234
     * '^(www\.)?(this|that)\.com$' or an array of exact host names, e.g.
235
     * ['example.com', 'other.net']. If the parameter is empty, all hosts
236
     * are matched.
237
     *
238
     * @see BanCapable::banPath()
239
     *
240
     * @param string       $path        Regular expression pattern for URI to
241
     *                                  invalidate
242
     * @param string       $contentType Regular expression pattern for the content
243
     *                                  type to limit banning, for instance 'text'
244
     * @param array|string $hosts       Regular expression of a host name or list of
245
     *                                  exact host names to limit banning
246
     *
247
     * @throws UnsupportedProxyOperationException If HTTP cache does not support BAN requests
248
     *
249
     * @return $this
250
     */
251 1
    public function invalidateRegex($path, $contentType = null, $hosts = null)
252
    {
253 1
        if (!$this->cache instanceof BanCapable) {
254
            throw UnsupportedProxyOperationException::cacheDoesNotImplement('BAN');
255
        }
256
257 1
        $this->cache->banPath($path, $contentType, $hosts);
258
259 1
        return $this;
260
    }
261
262
    /**
263
     * Send all pending invalidation requests.
264
     *
265
     * @return int The number of cache invalidations performed per caching server
266
     *
267
     * @throws ExceptionCollection If any errors occurred during flush
268
     */
269 3
    public function flush()
270
    {
271
        try {
272 3
            return $this->cache->flush();
273 1
        } catch (ExceptionCollection $exceptions) {
274 1
            foreach ($exceptions as $exception) {
275 1
                $event = new Event();
276 1
                $event->setException($exception);
277 1
                if ($exception instanceof ProxyResponseException) {
278 1
                    $this->getEventDispatcher()->dispatch(Events::PROXY_RESPONSE_ERROR, $event);
279 1
                } elseif ($exception instanceof ProxyUnreachableException) {
280 1
                    $this->getEventDispatcher()->dispatch(Events::PROXY_UNREACHABLE_ERROR, $event);
281
                }
282
            }
283
284 1
            throw $exceptions;
285
        }
286
    }
287
}
288