Passed
Push — master ( b2988e...9f380c )
by Jonathan
33:05
created

RiakCache::doFetch()   B

Complexity

Conditions 5
Paths 13

Size

Total Lines 32
Code Lines 13

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 30

Importance

Changes 0
Metric Value
cc 5
eloc 13
nc 13
nop 1
dl 0
loc 32
ccs 0
cts 13
cp 0
crap 30
rs 8.439
c 0
b 0
f 0
1
<?php
2
3
namespace Doctrine\Common\Cache;
4
5
use Riak\Bucket;
0 ignored issues
show
Bug introduced by
The type Riak\Bucket was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
6
use Riak\Exception;
0 ignored issues
show
Bug introduced by
The type Riak\Exception was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
7
use Riak\Input;
0 ignored issues
show
Bug introduced by
The type Riak\Input was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
8
use Riak\Object;
0 ignored issues
show
Bug introduced by
The type Riak\Object was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
9
use function count;
10
use function serialize;
11
use function time;
12
use function unserialize;
13
14
/**
15
 * Riak cache provider.
16
 *
17
 * @link   www.doctrine-project.org
18
 */
19
class RiakCache extends CacheProvider
20
{
21
    public const EXPIRES_HEADER = 'X-Riak-Meta-Expires';
22
23
    /** @var Bucket */
24
    private $bucket;
25
26
    /**
27
     * Sets the riak bucket instance to use.
28
     */
29
    public function __construct(Bucket $bucket)
30
    {
31
        $this->bucket = $bucket;
32
    }
33
34
    /**
35
     * {@inheritdoc}
36
     */
37
    protected function doFetch($id)
38
    {
39
        try {
40
            $response = $this->bucket->get($id);
41
42
            // No objects found
43
            if (! $response->hasObject()) {
44
                return false;
45
            }
46
47
            // Check for attempted siblings
48
            $object = ($response->hasSiblings())
49
                ? $this->resolveConflict($id, $response->getVClock(), $response->getObjectList())
50
                : $response->getFirstObject();
51
52
            // Check for expired object
53
            if ($this->isExpired($object)) {
54
                $this->bucket->delete($object);
55
56
                return false;
57
            }
58
59
            return unserialize($object->getContent());
60
        } catch (Exception\RiakException $e) {
0 ignored issues
show
Bug introduced by
The type Riak\Exception\RiakException was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
61
            // Covers:
62
            // - Riak\ConnectionException
63
            // - Riak\CommunicationException
64
            // - Riak\UnexpectedResponseException
65
            // - Riak\NotFoundException
66
        }
67
68
        return false;
69
    }
70
71
    /**
72
     * {@inheritdoc}
73
     */
74
    protected function doContains($id)
75
    {
76
        try {
77
            // We only need the HEAD, not the entire object
78
            $input = new Input\GetInput();
0 ignored issues
show
Bug introduced by
The type Riak\Input\GetInput was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
79
80
            $input->setReturnHead(true);
81
82
            $response = $this->bucket->get($id, $input);
83
84
            // No objects found
85
            if (! $response->hasObject()) {
86
                return false;
87
            }
88
89
            $object = $response->getFirstObject();
90
91
            // Check for expired object
92
            if ($this->isExpired($object)) {
93
                $this->bucket->delete($object);
94
95
                return false;
96
            }
97
98
            return true;
99
        } catch (Exception\RiakException $e) {
100
            // Do nothing
101
        }
102
103
        return false;
104
    }
105
106
    /**
107
     * {@inheritdoc}
108
     */
109
    protected function doSave($id, $data, $lifeTime = 0)
110
    {
111
        try {
112
            $object = new Object($id);
113
114
            $object->setContent(serialize($data));
115
116
            if ($lifeTime > 0) {
117
                $object->addMetadata(self::EXPIRES_HEADER, (string) (time() + $lifeTime));
118
            }
119
120
            $this->bucket->put($object);
121
122
            return true;
123
        } catch (Exception\RiakException $e) {
124
            // Do nothing
125
        }
126
127
        return false;
128
    }
129
130
    /**
131
     * {@inheritdoc}
132
     */
133
    protected function doDelete($id)
134
    {
135
        try {
136
            $this->bucket->delete($id);
137
138
            return true;
139
        } catch (Exception\BadArgumentsException $e) {
0 ignored issues
show
Bug introduced by
The type Riak\Exception\BadArgumentsException was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
140
            // Key did not exist on cluster already
141
        } catch (Exception\RiakException $e) {
142
            // Covers:
143
            // - Riak\Exception\ConnectionException
144
            // - Riak\Exception\CommunicationException
145
            // - Riak\Exception\UnexpectedResponseException
146
        }
147
148
        return false;
149
    }
150
151
    /**
152
     * {@inheritdoc}
153
     */
154
    protected function doFlush()
155
    {
156
        try {
157
            $keyList = $this->bucket->getKeyList();
158
159
            foreach ($keyList as $key) {
160
                $this->bucket->delete($key);
161
            }
162
163
            return true;
164
        } catch (Exception\RiakException $e) {
165
            // Do nothing
166
        }
167
168
        return false;
169
    }
170
171
    /**
172
     * {@inheritdoc}
173
     */
174
    protected function doGetStats()
175
    {
176
        // Only exposed through HTTP stats API, not Protocol Buffers API
177
        return null;
178
    }
179
180
    /**
181
     * Check if a given Riak Object have expired.
182
     */
183
    private function isExpired(Object $object) : bool
184
    {
185
        $metadataMap = $object->getMetadataMap();
186
187
        return isset($metadataMap[self::EXPIRES_HEADER])
188
            && $metadataMap[self::EXPIRES_HEADER] < time();
189
    }
190
191
    /**
192
     * On-read conflict resolution. Applied approach here is last write wins.
193
     * Specific needs may override this method to apply alternate conflict resolutions.
194
     *
195
     * {@internal Riak does not attempt to resolve a write conflict, and store
196
     * it as sibling of conflicted one. By following this approach, it is up to
197
     * the next read to resolve the conflict. When this happens, your fetched
198
     * object will have a list of siblings (read as a list of objects).
199
     * In our specific case, we do not care about the intermediate ones since
200
     * they are all the same read from storage, and we do apply a last sibling
201
     * (last write) wins logic.
202
     * If by any means our resolution generates another conflict, it'll up to
203
     * next read to properly solve it.}
204
     *
205
     * @param string $id
206
     * @param string $vClock
207
     * @param array  $objectList
208
     *
209
     * @return Object
210
     */
211
    protected function resolveConflict($id, $vClock, array $objectList)
212
    {
213
        // Our approach here is last-write wins
214
        $winner = $objectList[count($objectList) - 1];
215
216
        $putInput = new Input\PutInput();
0 ignored issues
show
Bug introduced by
The type Riak\Input\PutInput was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
217
        $putInput->setVClock($vClock);
218
219
        $mergedObject = new Object($id);
220
        $mergedObject->setContent($winner->getContent());
221
222
        $this->bucket->put($mergedObject, $putInput);
223
224
        return $mergedObject;
225
    }
226
}
227