Completed
Push — master ( 66ec7e...c9ec0a )
by Matze
07:32
created

Cache   A

Complexity

Total Complexity 11

Size/Duplication

Total Lines 111
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 7

Test Coverage

Coverage 0%

Importance

Changes 5
Bugs 0 Features 0
Metric Value
wmc 11
c 5
b 0
f 0
lcom 1
cbo 7
dl 0
loc 111
ccs 0
cts 45
cp 0
rs 10

5 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 4 1
B processRequest() 0 20 5
B processResponse() 0 27 3
A handleCached() 0 18 1
A generateCacheKey() 0 4 1
1
<?php
2
3
namespace BrainExe\Core\Middleware;
4
5
use BrainExe\Annotations\Annotations\Inject;
6
use BrainExe\Core\Annotations\Middleware;
7
use BrainExe\Core\Traits\CacheTrait;
8
use BrainExe\Core\Traits\LoggerTrait;
9
use DateTime;
10
use Doctrine\Common\Cache\CacheProvider;
11
use Symfony\Component\HttpFoundation\Request;
12
use Symfony\Component\HttpFoundation\Response;
13
use Symfony\Component\Routing\Route;
14
15
/**
16
 * @todo X-Invalidate
0 ignored issues
show
Coding Style introduced by
Comment refers to a TODO task

This check looks TODO comments that have been left in the code.

``TODO``s show that something is left unfinished and should be attended to.

Loading history...
17
 * @Middleware("Middleware.Cache")
18
 */
19
class Cache extends AbstractMiddleware
20
{
21
    use CacheTrait;
22
    use LoggerTrait;
23
24
    const DEFAULT_TTL = 60;
25
    const PREFIX = 'cache:';
26
27
    /**
28
     * @var bool
29
     */
30
    private $enabled;
31
32
    /**
33
     * @Inject("%cache.enabled%")
34
     * @param bool $cacheEnabled
35
     */
36
    public function __construct(bool $cacheEnabled)
37
    {
38
        $this->enabled = $cacheEnabled;
39
    }
40
41
    /**
42
     * {@inheritdoc}
43
     */
44
    public function processRequest(Request $request, Route $route)
45
    {
46
        if (!$this->enabled || !$route->hasOption('cache') || !$request->isMethod('GET')) {
47
            return null;
48
        }
49
50
        $cacheKey = $this->generateCacheKey($request);
51
52
        $ttl   = $route->getOption('cache');
53
        $cache = $this->getCache();
54
        if ($cache->contains($cacheKey)) {
55
            return $this->handleCached($cache, $cacheKey, $ttl);
56
        }
57
58
        // enable cache for current request. Store response later in given key
59
        $request->attributes->set('_cacheKey', $cacheKey);
60
        $request->attributes->set('_cacheTTL', $ttl);
61
62
        return null;
63
    }
64
65
    /**
66
     * {@inheritdoc}
67
     */
68
    public function processResponse(Request $request, Response $response)
69
    {
70
        if (!$response->isOk()) {
71
            return;
72
        }
73
74
        $cacheKey = $request->attributes->get('_cacheKey');
75
        $ttl      = $request->attributes->get('_cacheTTL');
76
        if (empty($cacheKey)) {
77
            return;
78
        }
79
80
        $cache = $this->getCache();
81
82
        $this->info(sprintf('miss: save into cache: %s', $cacheKey), [
83
            'application' => 'cache',
84
            'type'        => 'miss',
85
            'cacheKey'    => $cacheKey,
86
            'ttl'         => $ttl,
87
        ]);
88
89
        $cache->save($cacheKey, $response, $ttl);
90
91
        $response->headers->set('X-Cache', 'miss');
92
        $response->setMaxAge($ttl);
93
        $response->setExpires(new DateTime(sprintf('+%d seconds', $ttl)));
94
    }
95
96
    /**
97
     * @param CacheProvider $cache
98
     * @param string $cacheKey
99
     * @param int $ttl
100
     * @return Response
101
     */
102
    private function handleCached(CacheProvider $cache, string $cacheKey, int $ttl) : Response
103
    {
104
        $this->info(sprintf('hit: fetch from cache: %s', $cacheKey), [
105
            'application' => 'cache',
106
            'type'        => 'hit',
107
            'cacheKey'    => $cacheKey,
108
            'ttl'         => $ttl,
109
        ]);
110
111
        /** @var Response $response */
112
        $response = $cache->fetch($cacheKey);
113
114
        $response->headers->set('X-Cache', 'hit');
115
        $response->setMaxAge($ttl);
116
        $response->setExpires(new DateTime(sprintf('+%d seconds', $ttl)));
117
118
        return $response;
119
    }
120
121
    /**
122
     * @param Request $request
123
     * @return string
124
     */
125
    private function generateCacheKey(Request $request) : string
126
    {
127
        return self::PREFIX . $request->getRequestUri();
128
    }
129
}
130