Completed
Push — master ( e57dc9...542683 )
by John
7s
created

CacheAdapter::setChildInvalidationConstraint()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 6
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 0
loc 6
rs 9.4285
cc 1
eloc 3
nc 1
nop 1
1
<?php
2
/*
3
 * This file is part of the KleijnWeb\RestETagBundle package.
4
 *
5
 * For the full copyright and license information, please view the LICENSE
6
 * file that was distributed with this source code.
7
 */
8
9
namespace KleijnWeb\RestETagBundle\Cache;
10
11
use Doctrine\Common\Cache\Cache;
12
use Symfony\Component\HttpFoundation\Request;
13
14
/**
15
 * @author John Kleijn <[email protected]>
16
 */
17
class CacheAdapter
18
{
19
    const KEY_VERSION = 1;
20
    const KEY_CHILDREN = 2;
21
22
    /**
23
     * @var Cache
24
     */
25
    private $cache;
26
27
    /**
28
     * @var string
29
     */
30
    private $childInvalidationConstraint;
31
32
    /**
33
     * @param Cache  $cache
34
     * @param string $childInvalidationConstraint
35
     */
36
    public function __construct(Cache $cache, $childInvalidationConstraint = '')
37
    {
38
        $this->cache = $cache;
39
        $this->childInvalidationConstraint = $childInvalidationConstraint;
40
    }
41
42
    /**
43
     * @param string $childInvalidationConstraint
44
     *
45
     * @return $this
46
     */
47
    public function setChildInvalidationConstraint($childInvalidationConstraint)
48
    {
49
        $this->childInvalidationConstraint = $childInvalidationConstraint;
50
51
        return $this;
52
    }
53
54
    /**
55
     * @param Request $request
56
     *
57
     * @return string
58
     */
59
    public function fetch(Request $request)
60
    {
61
        if (!$record = $this->cache->fetch($this->createKey($request))) {
62
            return '';
63
        }
64
65
        return $record[self::KEY_VERSION];
66
    }
67
68
    /**
69
     * @param Request $request
70
     *
71
     * @return bool
72
     */
73
    public function contains(Request $request)
74
    {
75
        return $this->containsKey($this->createKey($request));
76
    }
77
78
    /**
79
     * @param string $key
80
     *
81
     * @return bool
82
     */
83
    public function containsKey($key)
84
    {
85
        return $this->cache->contains($key);
86
    }
87
88
    /**
89
     * @param Request $request
90
     * @param string  $version
91
     *
92
     * @return mixed
93
     */
94
    public function update(Request $request, $version)
95
    {
96
        $segments = $this->getSegments($request);
97
        $paths = [];
98
        $path = '';
99
        foreach ($segments as $segment) {
100
            $path .= "/$segment";
101
            $paths[] = $path;
102
        }
103
104
        foreach ($paths as $i => $path) {
105
            $record = $this->cache->fetch($path);
106
            if ($record) {
107
                $this->invalidateChildren($record[self::KEY_CHILDREN], $version);
108
            } else {
109
                $record = [self::KEY_CHILDREN => []];
110
            }
111
            $record[self::KEY_VERSION] = $version;
112 View Code Duplication
            if (isset($paths[$i + 1])) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
113
                $record[self::KEY_CHILDREN][] = $paths[$i + 1];
114
            }
115
            $this->cache->save($path, $record);
116
        }
117
118
        return $version;
119
    }
120
121
    /**
122
     * @param Request $request
123
     * @param string  $version
124
     *
125
     * @return mixed
126
     */
127
    public function register(Request $request, $version)
128
    {
129
        $segments = $this->getSegments($request);
130
        $paths = [];
131
        $path = '';
132
        foreach ($segments as $segment) {
133
            $path .= "/$segment";
134
            $paths[] = $path;
135
        }
136
137
        foreach ($paths as $i => $path) {
138
            $record = $this->cache->fetch($path);
139
            if (!$record) {
140
                $record = [self::KEY_VERSION => $version, self::KEY_CHILDREN => []];
141
            }
142 View Code Duplication
            if (isset($paths[$i + 1])) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
143
                $record[self::KEY_CHILDREN][] = $paths[$i + 1];
144
            }
145
            $this->cache->save($path, $record);
146
        }
147
        $record = [self::KEY_VERSION => $version, self::KEY_CHILDREN => []];
148
        $this->cache->save($this->createKeyFromSegments($segments), $record);
149
150
        return $version;
151
    }
152
153
    private function invalidateChildren(array $children, $version)
154
    {
155
        foreach ($children as $child) {
156
            if ($this->childInvalidationConstraint !== ''
157
                && preg_match("/$this->childInvalidationConstraint/", $child)
158
            ) {
159
                // Stop recursive invalidation if it matches
160
                return;
161
            }
162
            $record = $this->cache->fetch($child);
163
            $record[self::KEY_VERSION] = $version;
164
            $this->cache->save($child, $record);
165
            if ($record) {
166
                $this->invalidateChildren($record[self::KEY_CHILDREN], $version);
167
            }
168
        }
169
    }
170
171
    /**
172
     * @param Request $request
173
     *
174
     * @return array
175
     */
176
    private function getSegments(Request $request)
177
    {
178
        $key = $request->getPathInfo();
179
        $segments = explode('/', ltrim($key, '/'));
180
        if ($query = $request->getQueryString()) {
181
            $segments[] = '?' . $query;
182
        }
183
184
        array_walk($segments, function (&$value) {
185
            $value = preg_replace('/[^[:print:]]/', '_', $value);
186
        });
187
188
        return array_filter($segments, function ($value) {
189
            return $value !== '';
190
        });
191
    }
192
193
    /**
194
     * @param Request $request
195
     *
196
     * @return string
197
     */
198
    private function createKey(Request $request)
199
    {
200
        return $this->createKeyFromSegments($this->getSegments($request));
201
    }
202
203
    /**
204
     * @param array $segments
205
     *
206
     * @return string
207
     */
208
    private function createKeyFromSegments(array $segments)
209
    {
210
        return '/' . implode('/', $segments);
211
    }
212
}
213