Completed
Push — master ( 5a5e00...cf2997 )
by Marco
11:54 queued 03:51
created

CouchbaseBucketCache::doSave()   A

Complexity

Conditions 3
Paths 4

Size

Total Lines 22
Code Lines 12

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 8
CRAP Score 3.1825

Importance

Changes 0
Metric Value
dl 0
loc 22
ccs 8
cts 11
cp 0.7272
rs 9.2
c 0
b 0
f 0
cc 3
eloc 12
nc 4
nop 3
crap 3.1825
1
<?php
2
/*
3
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
4
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
5
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
6
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
7
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
8
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
9
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
10
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
11
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
12
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
13
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
14
 *
15
 * This software consists of voluntary contributions made by many individuals
16
 * and is licensed under the MIT license. For more information, see
17
 * <http://www.doctrine-project.org>.
18
 */
19
20
declare(strict_types=1);
21
22
namespace Doctrine\Common\Cache;
23
24
use Couchbase\Bucket;
25
use Couchbase\Document;
26
use Couchbase\Exception;
27
28
/**
29
 * Couchbase ^2.3.0 cache provider.
30
 */
31
final class CouchbaseBucketCache extends CacheProvider
32
{
33
    private const MINIMUM_VERSION = '2.3.0';
34
35
    private const KEY_NOT_FOUND = 13;
36
37
    private const MAX_KEY_LENGTH = 250;
38
39
    private const THIRTY_DAYS_IN_SECONDS = 2592000;
40
41
    /**
42
     * @var Bucket
43
     */
44
    private $bucket;
45
46
    /**
47
     * CouchbaseCache constructor.
48
     * @param Bucket $bucket
49
     */
50 78
    public function __construct(Bucket $bucket)
51
    {
52 78
        if (version_compare(phpversion('couchbase'), self::MINIMUM_VERSION) < 0) {
53
            // Manager is required to flush cache and pull stats.
54
            throw new \RuntimeException(sprintf('ext-couchbase:^%s is required.', self::MINIMUM_VERSION));
55
        }
56
57 78
        $this->bucket = $bucket;
58 78
    }
59
60
    /**
61
     * {@inheritdoc}
62
     */
63 76
    protected function doFetch($id)
64
    {
65 76
        $id = $this->normalizeKey($id);
66
67
        try {
68 76
            $document = $this->bucket->get($id);
69 66
        } catch (Exception $e) {
0 ignored issues
show
Bug introduced by
The class Couchbase\Exception does not exist. Did you forget a USE statement, or did you not list all dependencies?

Scrutinizer analyzes your composer.json/composer.lock file if available to determine the classes, and functions that are defined by your dependencies.

It seems like the listed class was neither found in your dependencies, nor was it found in the analyzed files in your repository. If you are using some other form of dependency management, you might want to disable this analysis.

Loading history...
70 66
            return false;
71
        }
72
73 73
        if ($document instanceof Document && $document->value !== false) {
0 ignored issues
show
Bug introduced by
The class Couchbase\Document does not exist. Did you forget a USE statement, or did you not list all dependencies?

This error could be the result of:

1. Missing dependencies

PHP Analyzer uses your composer.json file (if available) to determine the dependencies of your project and to determine all the available classes and functions. It expects the composer.json to be in the root folder of your repository.

Are you sure this class is defined by one of your dependencies, or did you maybe not list a dependency in either the require or require-dev section?

2. Missing use statement

PHP does not complain about undefined classes in ìnstanceof checks. For example, the following PHP code will work perfectly fine:

if ($x instanceof DoesNotExist) {
    // Do something.
}

If you have not tested against this specific condition, such errors might go unnoticed.

Loading history...
74 73
            return unserialize($document->value);
75
        }
76
77
        return false;
78
    }
79
80
    /**
81
     * {@inheritdoc}
82
     */
83 73
    protected function doContains($id)
84
    {
85 73
        $id = $this->normalizeKey($id);
86
87
        try {
88 73
            $document = $this->bucket->get($id);
89 53
        } catch (Exception $e) {
0 ignored issues
show
Bug introduced by
The class Couchbase\Exception does not exist. Did you forget a USE statement, or did you not list all dependencies?

Scrutinizer analyzes your composer.json/composer.lock file if available to determine the classes, and functions that are defined by your dependencies.

It seems like the listed class was neither found in your dependencies, nor was it found in the analyzed files in your repository. If you are using some other form of dependency management, you might want to disable this analysis.

Loading history...
90 53
            return false;
91
        }
92
93 69
        if ($document instanceof Document) {
0 ignored issues
show
Bug introduced by
The class Couchbase\Document does not exist. Did you forget a USE statement, or did you not list all dependencies?

This error could be the result of:

1. Missing dependencies

PHP Analyzer uses your composer.json file (if available) to determine the dependencies of your project and to determine all the available classes and functions. It expects the composer.json to be in the root folder of your repository.

Are you sure this class is defined by one of your dependencies, or did you maybe not list a dependency in either the require or require-dev section?

2. Missing use statement

PHP does not complain about undefined classes in ìnstanceof checks. For example, the following PHP code will work perfectly fine:

if ($x instanceof DoesNotExist) {
    // Do something.
}

If you have not tested against this specific condition, such errors might go unnoticed.

Loading history...
94 69
            return ! $document->error;
95
        }
96
97
        return false;
98
    }
99
100
    /**
101
     * {@inheritdoc}
102
     */
103 74
    protected function doSave($id, $data, $lifeTime = 0)
104
    {
105 74
        $id = $this->normalizeKey($id);
106
107 74
        $lifeTime = $this->normalizeExpiry($lifeTime);
108
109
        try {
110 74
            $encoded = serialize($data);
111
112 74
            $document = $this->bucket->upsert($id, $encoded, [
113 74
                'expiry' => (int) $lifeTime,
114
            ]);
115
        } catch (Exception $e) {
0 ignored issues
show
Bug introduced by
The class Couchbase\Exception does not exist. Did you forget a USE statement, or did you not list all dependencies?

Scrutinizer analyzes your composer.json/composer.lock file if available to determine the classes, and functions that are defined by your dependencies.

It seems like the listed class was neither found in your dependencies, nor was it found in the analyzed files in your repository. If you are using some other form of dependency management, you might want to disable this analysis.

Loading history...
116
            return false;
117
        }
118
119 74
        if ($document instanceof Document) {
0 ignored issues
show
Bug introduced by
The class Couchbase\Document does not exist. Did you forget a USE statement, or did you not list all dependencies?

This error could be the result of:

1. Missing dependencies

PHP Analyzer uses your composer.json file (if available) to determine the dependencies of your project and to determine all the available classes and functions. It expects the composer.json to be in the root folder of your repository.

Are you sure this class is defined by one of your dependencies, or did you maybe not list a dependency in either the require or require-dev section?

2. Missing use statement

PHP does not complain about undefined classes in ìnstanceof checks. For example, the following PHP code will work perfectly fine:

if ($x instanceof DoesNotExist) {
    // Do something.
}

If you have not tested against this specific condition, such errors might go unnoticed.

Loading history...
120 74
            return ! $document->error;
121
        }
122
123
        return false;
124
    }
125
126
    /**
127
     * {@inheritdoc}
128
     */
129 45
    protected function doDelete($id)
130
    {
131 45
        $id = $this->normalizeKey($id);
132
133
        try {
134 45
            $document = $this->bucket->remove($id);
135 3
        } catch (Exception $e) {
0 ignored issues
show
Bug introduced by
The class Couchbase\Exception does not exist. Did you forget a USE statement, or did you not list all dependencies?

Scrutinizer analyzes your composer.json/composer.lock file if available to determine the classes, and functions that are defined by your dependencies.

It seems like the listed class was neither found in your dependencies, nor was it found in the analyzed files in your repository. If you are using some other form of dependency management, you might want to disable this analysis.

Loading history...
136 3
            return $e->getCode() === self::KEY_NOT_FOUND;
137
        }
138
139 43
        if ($document instanceof Document) {
0 ignored issues
show
Bug introduced by
The class Couchbase\Document does not exist. Did you forget a USE statement, or did you not list all dependencies?

This error could be the result of:

1. Missing dependencies

PHP Analyzer uses your composer.json file (if available) to determine the dependencies of your project and to determine all the available classes and functions. It expects the composer.json to be in the root folder of your repository.

Are you sure this class is defined by one of your dependencies, or did you maybe not list a dependency in either the require or require-dev section?

2. Missing use statement

PHP does not complain about undefined classes in ìnstanceof checks. For example, the following PHP code will work perfectly fine:

if ($x instanceof DoesNotExist) {
    // Do something.
}

If you have not tested against this specific condition, such errors might go unnoticed.

Loading history...
140 43
            return ! $document->error;
141
        }
142
143
        return false;
144
    }
145
146
    /**
147
     * {@inheritdoc}
148
     */
149 2
    protected function doFlush()
150
    {
151 2
        $manager = $this->bucket->manager();
152
153
        // Flush does not return with success or failure, and must be enabled per bucket on the server.
154
        // Store a marker item so that we will know if it was successful.
155 2
        $this->doSave(__METHOD__, true, 60);
0 ignored issues
show
Documentation introduced by
true is of type boolean, but the function expects a string.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
156
157 2
        $manager->flush();
158
159 2
        if ($this->doContains(__METHOD__)) {
160
            $this->doDelete(__METHOD__);
161
162
            return false;
163
        }
164
165 2
        return true;
166
    }
167
168
    /**
169
     * {@inheritdoc}
170
     */
171 1
    protected function doGetStats()
172
    {
173 1
        $manager          = $this->bucket->manager();
174 1
        $stats            = $manager->info();
175 1
        $nodes            = $stats['nodes'];
176 1
        $node             = $nodes[0];
177 1
        $interestingStats = $node['interestingStats'];
178
179
        return [
180 1
            Cache::STATS_HITS   => $interestingStats['get_hits'],
181 1
            Cache::STATS_MISSES => $interestingStats['cmd_get'] - $interestingStats['get_hits'],
182 1
            Cache::STATS_UPTIME => $node['uptime'],
183 1
            Cache::STATS_MEMORY_USAGE     => $interestingStats['mem_used'],
184 1
            Cache::STATS_MEMORY_AVAILABLE => $node['memoryFree'],
185
        ];
186
    }
187
188
    /**
189
     * @param string $id
190
     * @return string
191
     */
192 76
    private function normalizeKey(string $id) : string
193
    {
194 76
        $normalized = substr($id, 0, self::MAX_KEY_LENGTH);
195
196 76
        if ($normalized === false) {
197
            return $id;
198
        }
199
200 76
        return $normalized;
201
    }
202
203
    /**
204
     * Expiry treated as a unix timestamp instead of an offset if expiry is greater than 30 days.
205
     * @src https://developer.couchbase.com/documentation/server/4.1/developer-guide/expiry.html
206
     *
207
     * @param int $expiry
208
     * @return int
209
     */
210 74
    private function normalizeExpiry(int $expiry) : int
211
    {
212 74
        if ($expiry > self::THIRTY_DAYS_IN_SECONDS) {
213 1
            return time() + $expiry;
214
        }
215
216 73
        return $expiry;
217
    }
218
}
219