Passed
Pull Request — master (#905)
by
unknown
03:49
created

Driver::setCollection()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 1
eloc 2
c 1
b 0
f 0
nc 1
nop 1
dl 0
loc 4
rs 10
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Phpfastcache\Drivers\Couchbasev4;
6
7
use Couchbase\BaseException as CouchbaseException;
8
use Couchbase\Bucket as CouchbaseBucket;
9
use Couchbase\Cluster;
10
use Couchbase\ClusterOptions;
11
use Couchbase\Collection;
12
use Couchbase\Exception\DocumentNotFoundException;
0 ignored issues
show
Bug introduced by
The type Couchbase\Exception\DocumentNotFoundException 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...
13
use Couchbase\Scope;
14
use Couchbase\UpsertOptions;
15
use DateTimeInterface;
16
use Phpfastcache\Cluster\AggregatablePoolInterface;
17
use Phpfastcache\Config\ConfigurationOption;
18
use Phpfastcache\Core\Item\ExtendedCacheItemInterface;
19
use Phpfastcache\Core\Pool\ExtendedCacheItemPoolInterface;
20
use Phpfastcache\Core\Pool\TaggableCacheItemPoolTrait;
21
use Phpfastcache\Entities\DriverStatistic;
22
use Phpfastcache\Event\EventManagerInterface;
23
use Phpfastcache\Exceptions\PhpfastcacheDriverCheckException;
24
use Phpfastcache\Exceptions\PhpfastcacheInvalidArgumentException;
25
use Phpfastcache\Exceptions\PhpfastcacheLogicException;
26
use ReflectionExtension;
27
28
/**
29
 * @property Cluster $instance Instance of driver service
30
 * @method Config getConfig()
31
 * @SuppressWarnings(PHPMD.CouplingBetweenObjects)
32
 */
33
class Driver implements AggregatablePoolInterface
34
{
35
    use TaggableCacheItemPoolTrait {
36
        __construct as __baseConstruct;
37
    }
38
39
    protected Scope $scope;
40
41
    protected Collection $collection;
42
43
    protected CouchbaseBucket $bucketInstance;
44
45
    protected int $currentParentPID = 0;
46
47
    public function __construct(ConfigurationOption $config, string $instanceId, EventManagerInterface $em)
48
    {
49
        $this->__baseConstruct($config, $instanceId, $em);
50
    }
51
52
    /**
53
     * @return bool
54
     */
55
    public function driverCheck(): bool
56
    {
57
        return extension_loaded('couchbase');
58
    }
59
60
    /**
61
     * @return bool
62
     * @throws PhpfastcacheDriverCheckException
63
     */
64
    protected function driverConnect(): bool
65
    {
66
        if (!\class_exists(ClusterOptions::class)) {
67
            throw new PhpfastcacheDriverCheckException('You are using the Couchbase PHP SDK 2.x which is no longer supported in Phpfastcache v9');
68
        }
69
70
        $extVersion = (new ReflectionExtension('couchbase'))->getVersion();
71
        if (version_compare($extVersion, '4.0.0', '<') || version_compare($extVersion, '5.0.0', '>=')) {
72
            throw new PhpfastcacheDriverCheckException("You are using Couchbase extension $extVersion, You need to use a Couchbase V4 extension");
73
        }
74
75
        $this->currentParentPID = posix_getppid();
76
77
        $schema = $this->getConfig()->getSecure() ? 'couchbases' : 'couchbase';
78
        $servers = $this->getConfig()->getServers();
79
80
        $connectionString = $schema . '://' . implode(',', $servers) . '?ppid=' . $this->currentParentPID;
81
82
        $options = $this->getConfig()->getClusterOptions();
83
        $options->credentials($this->getConfig()->getUsername(), $this->getConfig()->getPassword());
84
        $this->instance = new Cluster($connectionString, $options);
0 ignored issues
show
Unused Code introduced by
The call to Couchbase\Cluster::__construct() has too many arguments starting with $options. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

84
        $this->instance = /** @scrutinizer ignore-call */ new Cluster($connectionString, $options);

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress. Please note the @ignore annotation hint above.

Loading history...
85
86
        $this->setBucket($this->instance->bucket($this->getConfig()->getBucketName()));
0 ignored issues
show
Bug introduced by
The method bucket() does not exist on Couchbase\Cluster. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

86
        $this->setBucket($this->instance->/** @scrutinizer ignore-call */ bucket($this->getConfig()->getBucketName()));

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
87
        $this->setScope($this->getBucket()->scope($this->getConfig()->getScopeName()));
0 ignored issues
show
Bug introduced by
The method scope() does not exist on Couchbase\Bucket. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

87
        $this->setScope($this->getBucket()->/** @scrutinizer ignore-call */ scope($this->getConfig()->getScopeName()));

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
88
        $this->setCollection($this->getScope()->collection($this->getConfig()->getCollectionName()));
89
90
        return true;
91
    }
92
93
    /**
94
     * Work around for couchbase V4 not being fork safe
95
     * https://issues.couchbase.com/projects/PCBC/issues/PCBC-886
96
     * @return void
97
     * @throws PhpfastcacheDriverCheckException
98
     */
99
    protected function checkCurrentParentPID(): void
100
    {
101
        if ($this->currentParentPID !== posix_getppid()) {
102
            $this->driverConnect();
103
        }
104
    }
105
106
    /**
107
     * @param ExtendedCacheItemInterface $item
108
     * @return ?array<string, mixed>
109
     */
110
    protected function driverRead(ExtendedCacheItemInterface $item): ?array
111
    {
112
        try {
113
            $this->checkCurrentParentPID();
114
            /**
115
             * CouchbaseBucket::get() returns a GetResult interface
116
             */
117
            return $this->decodeDocument((array)$this->getCollection()->get($item->getEncodedKey())->content());
118
        } catch (DocumentNotFoundException) {
119
            return null;
120
        }
121
    }
122
123
    /**
124
     * @param ExtendedCacheItemInterface $item
125
     * @return bool
126
     * @throws PhpfastcacheInvalidArgumentException
127
     * @throws PhpfastcacheLogicException
128
     */
129
    protected function driverWrite(ExtendedCacheItemInterface $item): bool
130
    {
131
        $this->assertCacheItemType($item, Item::class);
132
133
        try {
134
            $this->checkCurrentParentPID();
135
            $this->getCollection()->upsert(
136
                $item->getEncodedKey(),
137
                $this->encodeDocument($this->driverPreWrap($item)),
138
                (new UpsertOptions())->expiry($item->getTtl())
139
            );
140
            return true;
141
        } catch (CouchbaseException) {
142
            return false;
143
        }
144
    }
145
146
    /**
147
     * @param ExtendedCacheItemInterface $item
148
     * @return bool
149
     * @throws PhpfastcacheInvalidArgumentException
150
     */
151
    protected function driverDelete(ExtendedCacheItemInterface $item): bool
152
    {
153
        $this->assertCacheItemType($item, Item::class);
154
155
        try {
156
            $this->checkCurrentParentPID();
157
            $this->getCollection()->remove($item->getEncodedKey());
158
            return true;
159
        } catch (DocumentNotFoundException) {
160
            return true;
161
        } catch (CouchbaseException) {
162
            return false;
163
        }
164
    }
165
166
    /**
167
     * @return bool
168
     */
169
    protected function driverClear(): bool
170
    {
171
        $this->checkCurrentParentPID();
172
        $this->instance->buckets()->flush($this->getConfig()->getBucketName());
0 ignored issues
show
Bug introduced by
The method buckets() does not exist on Couchbase\Cluster. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

172
        $this->instance->/** @scrutinizer ignore-call */ 
173
                         buckets()->flush($this->getConfig()->getBucketName());

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
173
        return true;
174
    }
175
176
    /**
177
     * @return DriverStatistic
178
     * @throws \Exception
179
     */
180
    public function getStats(): DriverStatistic
181
    {
182
        $this->checkCurrentParentPID();
183
        /**
184
         * Between SDK 2 and 3 we lost a lot of useful information :(
185
         * @see https://docs.couchbase.com/java-sdk/current/project-docs/migrating-sdk-code-to-3.n.html#management-apis
186
         */
187
        $info = $this->instance->diagnostics(\bin2hex(\random_bytes(16)));
0 ignored issues
show
Bug introduced by
The method diagnostics() does not exist on Couchbase\Cluster. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

187
        /** @scrutinizer ignore-call */ 
188
        $info = $this->instance->diagnostics(\bin2hex(\random_bytes(16)));

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
188
189
        return (new DriverStatistic())
190
            ->setSize(0)
191
            ->setRawData($info)
192
            ->setData(implode(', ', array_keys($this->itemInstances)))
193
            ->setInfo($info['sdk'] . "\n For more information see RawData.");
194
    }
195
196
    /**
197
     * @return Collection
198
     */
199
    public function getCollection(): Collection
200
    {
201
        return $this->collection;
202
    }
203
204
    /**
205
     * @param Collection $collection
206
     * @return Driver
207
     */
208
    public function setCollection(Collection $collection): Driver
209
    {
210
        $this->collection = $collection;
211
        return $this;
212
    }
213
214
    /**
215
     * @return Scope
216
     */
217
    public function getScope(): Scope
218
    {
219
        return $this->scope;
220
    }
221
222
    /**
223
     * @param Scope $scope
224
     * @return Driver
225
     */
226
    public function setScope(Scope $scope): Driver
227
    {
228
        $this->scope = $scope;
229
        return $this;
230
    }
231
232
    /**
233
     * @return CouchbaseBucket
234
     */
235
    protected function getBucket(): CouchbaseBucket
236
    {
237
        return $this->bucketInstance;
238
    }
239
240
    /**
241
     * @param CouchbaseBucket $couchbaseBucket
242
     */
243
    protected function setBucket(CouchbaseBucket $couchbaseBucket): void
244
    {
245
        $this->bucketInstance = $couchbaseBucket;
246
    }
247
248
249
    /**
250
     * @param array<string, mixed> $data
251
     * @return array<string, mixed>
252
     */
253
    protected function encodeDocument(array $data): array
254
    {
255
        $data[ExtendedCacheItemPoolInterface::DRIVER_DATA_WRAPPER_INDEX] = $this->encode($data[ExtendedCacheItemPoolInterface::DRIVER_DATA_WRAPPER_INDEX]);
256
        $data[ExtendedCacheItemPoolInterface::DRIVER_EDATE_WRAPPER_INDEX] = $data[ExtendedCacheItemPoolInterface::DRIVER_EDATE_WRAPPER_INDEX]
257
            ->format(DateTimeInterface::ATOM);
258
259
        if ($this->getConfig()->isItemDetailedDate()) {
260
            $data[ExtendedCacheItemPoolInterface::DRIVER_CDATE_WRAPPER_INDEX] = $data[ExtendedCacheItemPoolInterface::DRIVER_CDATE_WRAPPER_INDEX]
261
                ->format(\DateTimeInterface::ATOM);
262
263
            $data[ExtendedCacheItemPoolInterface::DRIVER_MDATE_WRAPPER_INDEX] = $data[ExtendedCacheItemPoolInterface::DRIVER_MDATE_WRAPPER_INDEX]
264
                ->format(\DateTimeInterface::ATOM);
265
        }
266
267
        return $data;
268
    }
269
270
    /**
271
     * @param array<string, mixed> $data
272
     * @return array<string, mixed>
273
     */
274
    protected function decodeDocument(array $data): array
275
    {
276
        $data[ExtendedCacheItemPoolInterface::DRIVER_DATA_WRAPPER_INDEX] = $this->decode($data[ExtendedCacheItemPoolInterface::DRIVER_DATA_WRAPPER_INDEX]);
277
        $data[ExtendedCacheItemPoolInterface::DRIVER_EDATE_WRAPPER_INDEX] = \DateTime::createFromFormat(
278
            \DateTimeInterface::ATOM,
279
            $data[ExtendedCacheItemPoolInterface::DRIVER_EDATE_WRAPPER_INDEX]
280
        );
281
282
        if ($this->getConfig()->isItemDetailedDate()) {
283
            $data[ExtendedCacheItemPoolInterface::DRIVER_CDATE_WRAPPER_INDEX] = \DateTime::createFromFormat(
284
                \DateTimeInterface::ATOM,
285
                $data[ExtendedCacheItemPoolInterface::DRIVER_CDATE_WRAPPER_INDEX]
286
            );
287
288
            $data[ExtendedCacheItemPoolInterface::DRIVER_MDATE_WRAPPER_INDEX] = \DateTime::createFromFormat(
289
                \DateTimeInterface::ATOM,
290
                $data[ExtendedCacheItemPoolInterface::DRIVER_MDATE_WRAPPER_INDEX]
291
            );
292
        }
293
294
        return $data;
295
    }
296
}
297