Completed
Pull Request — master (#75)
by
unknown
05:21
created

CacheEntry   B

Complexity

Total Complexity 36

Size/Duplication

Total Lines 267
Duplicated Lines 0 %

Coupling/Cohesion

Components 2
Dependencies 4

Importance

Changes 6
Bugs 0 Features 1
Metric Value
wmc 36
c 6
b 0
f 1
lcom 2
cbo 4
dl 0
loc 267
rs 8.8

17 Methods

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