Completed
Push — master ( e223f8...0ed045 )
by Nate
01:52
created

Cache::applyCacheToResponseBody()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 16
Code Lines 7

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 0
Metric Value
dl 0
loc 16
ccs 0
cts 13
cp 0
rs 9.4285
c 0
b 0
f 0
cc 1
eloc 7
nc 1
nop 2
crap 2
1
<?php
2
3
/**
4
 * @copyright  Copyright (c) Flipbox Digital Limited
5
 * @license    https://github.com/flipbox/relay-stash/blob/master/LICENSE
6
 * @link       https://github.com/flipbox/relay-stash
7
 */
8
9
namespace Flipbox\Relay\Middleware;
10
11
use Flipbox\Relay\Exceptions\InvalidCachePoolException;
12
use Flipbox\Http\Stream\Factory as StreamFactory;
13
use Psr\Cache\CacheItemPoolInterface;
14
use Psr\Http\Message\RequestInterface;
15
use Psr\Http\Message\ResponseInterface;
16
use Psr\Http\Message\StreamInterface;
17
use Stash\Interfaces\ItemInterface;
18
19
/**
20
 * @author Flipbox Factory <[email protected]>
21
 * @since 1.0.0
22
 */
23
class Cache extends AbstractMiddleware
24
{
25
26
    /**
27
     * @var CacheItemPoolInterface The connection
28
     */
29
    public $pool;
30
31
    /**
32
     * @inheritdoc
33
     */
34
    public function init()
35
    {
36
        // Parent
37
        parent::init();
38
39
        // Ensure we have a valid pool
40
        if (!$this->pool instanceof CacheItemPoolInterface) {
41
            throw new InvalidCachePoolException(
42
                sprintf(
43
                    "The class '%s' requires a cache pool that is an instance of '%s', '%s' given.",
44
                    get_class($this),
45
                    CacheItemPoolInterface::class,
46
                    get_class($this->pool)
47
                )
48
            );
49
        }
50
    }
51
52
    /**
53
     * @inheritdoc
54
     */
55
    public function __invoke(
56
        RequestInterface $request,
57
        ResponseInterface $response,
58
        callable $next = null
59
    ): ResponseInterface {
60
        // Do parent (logging)
61
        parent::__invoke($request, $response);
62
63
        // Create a cache key
64
        $key = $this->getCacheKey($request);
65
66
        /** @var ItemInterface $item */
67
        $item = $this->pool->getItem($key);
68
69
        // If it's cached
70
        if ($item->isHit()) {
71
            return $this->applyCacheToResponseBody($response, $item);
72
        } else {
73
            // Log
74
            $this->info(
75
                "Item not found in Cache. [key: {key}]",
76
                [
77
                    'key' => $key
78
                ]
79
            );
80
        }
81
82
        // Lock item
83
        $item->lock();
84
85
        /** @var ResponseInterface $response */
86
        $response = $next($request, $response);
87
88
        // Only cache successful responses
89
        if ($this->isResponseSuccessful($response)) {
90
            $this->cacheResponse($response, $item);
91
        } else {
92
            // Log
93
            $this->info(
94
                "Did not save to cache because request was unsuccessful.",
95
                [
96
                    'key' => $key,
97
                    'statusCode' => $response->getStatusCode()
98
                ]
99
            );
100
        }
101
102
        return $response;
103
    }
104
105
    /**
106
     * @param ResponseInterface $response
107
     * @param ItemInterface $item
108
     * @return ResponseInterface
109
     */
110
    protected function applyCacheToResponseBody(ResponseInterface $response, ItemInterface $item)
111
    {
112
        // Log
113
        $this->info(
114
            "Item found in Cache. [key: {key}, expires: {expires}]",
115
            [
116
                'key' => $item->getKey(),
117
                'expires' => $item->getExpiration()->getTimestamp()
118
            ]
119
        );
120
121
        // Add response body
122
        return $response->withBody(
123
            StreamFactory::create($item->get())
124
        );
125
    }
126
127
    /**
128
     * @param ResponseInterface $response
129
     * @param ItemInterface $item
130
     */
131
    protected function cacheResponse(ResponseInterface $response, ItemInterface $item)
132
    {
133
        /** @var StreamInterface $body */
134
        $body = $response->getBody();
135
136
        // Set cache contents
137
        $item->set($body->getContents());
138
139
        // Save cache item
140
        $this->pool->save($item);
141
142
        // Rewind stream
143
        $body->rewind();
144
145
        // Log
146
        $this->info(
147
            "Save item to Cache. [key: {key}, expires: {expires}]",
148
            [
149
                'key' => $item->getKey(),
150
                'expires' => $item->getExpiration()->getTimestamp()
151
            ]
152
        );
153
    }
154
155
    /**
156
     * Returns the id used to cache a request.
157
     *
158
     * @param RequestInterface $request
159
     *
160
     * @return string
161
     */
162
    private function getCacheKey(RequestInterface $request): string
163
    {
164
        return $request->getMethod() . md5((string)$request->getUri());
165
    }
166
}
167