Proyectos de Subversion Moodle

Rev

| Ultima modificación | Ver Log |

Rev Autor Línea Nro. Línea
1 efrain 1
<?php
2
 
3
namespace Kevinrob\GuzzleCache;
4
 
5
use GuzzleHttp\Psr7\PumpStream;
6
use Psr\Http\Message\RequestInterface;
7
use Psr\Http\Message\ResponseInterface;
8
 
9
class CacheEntry
10
{
11
    /**
12
     * @var RequestInterface
13
     */
14
    protected $request;
15
 
16
    /**
17
     * @var ResponseInterface
18
     */
19
    protected $response;
20
 
21
    /**
22
     * @var \DateTime
23
     */
24
    protected $staleAt;
25
 
26
    /**
27
     * @var \DateTime
28
     */
29
    protected $staleIfErrorTo;
30
 
31
    /**
32
     * @var \DateTime
33
     */
34
    protected $staleWhileRevalidateTo;
35
 
36
    /**
37
     * @var \DateTime
38
     */
39
    protected $dateCreated;
40
 
41
    /**
42
     * Cached timestamp of staleAt variable.
43
     *
44
     * @var int
45
     */
46
    protected $timestampStale;
47
 
48
    /**
49
     * @param RequestInterface $request
50
     * @param ResponseInterface $response
51
     * @param \DateTime $staleAt
52
     * @param \DateTime|null $staleIfErrorTo if null, detected with the headers (RFC 5861)
53
     * @param \DateTime|null $staleWhileRevalidateTo
54
     */
55
    public function __construct(
56
        RequestInterface $request,
57
        ResponseInterface $response,
58
        \DateTime $staleAt,
59
        \DateTime $staleIfErrorTo = null,
60
        \DateTime $staleWhileRevalidateTo = null
61
    ) {
62
        $this->dateCreated = new \DateTime();
63
 
64
        $this->request = $request;
65
        $this->response = $response;
66
        $this->staleAt = $staleAt;
67
 
68
        $values = new KeyValueHttpHeader($response->getHeader('Cache-Control'));
69
 
70
        if ($staleIfErrorTo === null && $values->has('stale-if-error')) {
71
            $this->staleIfErrorTo = (new \DateTime(
72
                '@'.($this->staleAt->getTimestamp() + (int) $values->get('stale-if-error'))
73
            ));
74
        } else {
75
            $this->staleIfErrorTo = $staleIfErrorTo;
76
        }
77
 
78
        if ($staleWhileRevalidateTo === null && $values->has('stale-while-revalidate')) {
79
            $this->staleWhileRevalidateTo = new \DateTime(
80
                '@'.($this->staleAt->getTimestamp() + (int) $values->get('stale-while-revalidate'))
81
            );
82
        } else {
83
            $this->staleWhileRevalidateTo = $staleWhileRevalidateTo;
84
        }
85
    }
86
 
87
    /**
88
     * @return ResponseInterface
89
     */
90
    public function getResponse()
91
    {
92
        return $this->response
93
            ->withHeader('Age', $this->getAge());
94
    }
95
 
96
    /**
97
     * @return ResponseInterface
98
     */
99
    public function getOriginalResponse()
100
    {
101
        return $this->response;
102
    }
103
 
104
    /**
105
     * @return RequestInterface
106
     */
107
    public function getOriginalRequest()
108
    {
109
        return $this->request;
110
    }
111
 
112
    /**
113
     * @param RequestInterface $request
114
     * @return bool
115
     */
116
    public function isVaryEquals(RequestInterface $request)
117
    {
118
        if ($this->response->hasHeader('Vary')) {
119
            if ($this->request === null) {
120
                return false;
121
            }
122
 
123
            foreach ($this->getVaryHeaders() as $key => $value) {
124
                if (!$this->request->hasHeader($key)
125
                    && !$request->hasHeader($key)
126
                ) {
127
                    // Absent from both
128
                    continue;
129
                } elseif ($this->request->getHeaderLine($key)
130
                    == $request->getHeaderLine($key)
131
                ) {
132
                    // Same content
133
                    continue;
134
                }
135
 
136
                return false;
137
            }
138
        }
139
 
140
        return true;
141
    }
142
 
143
    /**
144
     * Get the vary headers that should be honoured by the cache.
145
     *
146
     * @return KeyValueHttpHeader
147
     */
148
    public function getVaryHeaders()
149
    {
150
        return new KeyValueHttpHeader($this->response->getHeader('Vary'));
151
    }
152
 
153
    /**
154
     * @return \DateTime
155
     */
156
    public function getStaleAt()
157
    {
158
        return $this->staleAt;
159
    }
160
 
161
    /**
162
     * @return bool
163
     */
164
    public function isFresh()
165
    {
166
        return !$this->isStale();
167
    }
168
 
169
    /**
170
     * @return bool
171
     */
172
    public function isStale()
173
    {
174
        return $this->getStaleAge() > 0;
175
    }
176
 
177
    /**
178
     * @return int positive value equal staled
179
     */
180
    public function getStaleAge()
181
    {
182
        // This object is immutable
183
        if ($this->timestampStale === null) {
184
            $this->timestampStale = $this->staleAt->getTimestamp();
185
        }
186
 
187
        return time() - $this->timestampStale;
188
    }
189
 
190
    /**
191
     * @return bool
192
     */
193
    public function serveStaleIfError()
194
    {
195
        return $this->staleIfErrorTo !== null
196
            && $this->staleIfErrorTo->getTimestamp() >= (new \DateTime())->getTimestamp();
197
    }
198
 
199
    /**
200
     * @return bool
201
     */
202
    public function staleWhileValidate()
203
    {
204
        return $this->staleWhileRevalidateTo !== null
205
            && $this->staleWhileRevalidateTo->getTimestamp() >= (new \DateTime())->getTimestamp();
206
    }
207
 
208
    /**
209
     * @return bool
210
     */
211
    public function hasValidationInformation()
212
    {
213
        return $this->response->hasHeader('Etag') || $this->response->hasHeader('Last-Modified');
214
    }
215
 
216
    /**
217
     * Time in seconds how long the entry should be kept in the cache
218
     *
219
     * This will not give the time (in seconds) that the response will still be fresh for
220
     * from the HTTP point of view, but an upper bound on how long it is necessary and
221
     * reasonable to keep the response in a cache (to re-use it or re-validate it later on).
222
     *
223
     * @return int TTL in seconds (0 = infinite)
224
     */
225
    public function getTTL()
226
    {
227
        if ($this->hasValidationInformation()) {
228
            // No TTL if we have a way to re-validate the cache
229
            return 0;
230
        }
231
 
232
        $ttl = 0;
233
 
234
        // Keep it when stale if error
235
        if ($this->staleIfErrorTo !== null) {
236
            $ttl = max($ttl, $this->staleIfErrorTo->getTimestamp() - time());
237
        }
238
 
239
        // Keep it when stale-while-revalidate
240
        if ($this->staleWhileRevalidateTo !== null) {
241
            $ttl = max($ttl, $this->staleWhileRevalidateTo->getTimestamp() - time());
242
        }
243
 
244
        // Keep it until it become stale
245
        $ttl = max($ttl, $this->staleAt->getTimestamp() - time());
246
 
247
        // Don't return 0, it's reserved for infinite TTL
248
        return $ttl !== 0 ? (int) $ttl : -1;
249
    }
250
 
251
    /**
252
     * @return int Age in seconds
253
     */
254
    public function getAge()
255
    {
256
        return time() - $this->dateCreated->getTimestamp();
257
    }
258
 
259
    public function __sleep()
260
    {
261
        // Stream/Resource can't be serialized... So we copy the content into an implementation of `Psr\Http\Message\StreamInterface`
262
        if ($this->response !== null) {
263
            $responseBody = (string)$this->response->getBody();
264
            $this->response = $this->response->withBody(
265
                new PumpStream(
266
                    new BodyStore($responseBody),
267
                    [
268
                        'size' => mb_strlen($responseBody),
269
                    ]
270
                )
271
            );
272
        }
273
 
274
        $requestBody = (string)$this->request->getBody();
275
        $this->request = $this->request->withBody(
276
            new PumpStream(
277
                new BodyStore($requestBody),
278
                [
279
                    'size' => mb_strlen($requestBody)
280
                ]
281
            )
282
        );
283
 
284
        return array_keys(get_object_vars($this));
285
    }
286
 
287
    public function __wakeup()
288
    {
289
        // We re-create the stream of the response
290
        if ($this->response !== null) {
291
            $this->response = $this->response
292
                ->withBody(
293
                    \GuzzleHttp\Psr7\Utils::streamFor((string) $this->response->getBody())
294
                );
295
        }
296
        $this->request = $this->request
297
            ->withBody(
298
                \GuzzleHttp\Psr7\Utils::streamFor((string) $this->request->getBody())
299
            );
300
    }
301
 
302
}