Passed
Pull Request — master (#905)
by
unknown
13:48
created

Driver::getCollection()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 1
eloc 1
c 1
b 0
f 0
nc 1
nop 0
dl 0
loc 3
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
27
/**
28
 * @property Cluster $instance Instance of driver service
29
 * @method Config getConfig()
30
 * @SuppressWarnings(PHPMD.CouplingBetweenObjects)
31
 */
32
class Driver implements AggregatablePoolInterface
33
{
34
    use TaggableCacheItemPoolTrait {
35
        __construct as __baseConstruct;
36
    }
37
38
    protected Scope $scope;
39
40
    protected Collection $collection;
41
42
    protected CouchbaseBucket $bucketInstance;
43
44
    protected int $currentParentPID = 0;
45
46
    public function __construct(ConfigurationOption $config, string $instanceId, EventManagerInterface $em)
47
    {
48
        $this->__baseConstruct($config, $instanceId, $em);
49
    }
50
51
    /**
52
     * @return bool
53
     */
54
    public function driverCheck(): bool
55
    {
56
        return extension_loaded('couchbase');
57
    }
58
59
    /**
60
     * @return bool
61
     * @throws PhpfastcacheDriverCheckException
62
     */
63
    protected function driverConnect(): bool
64
    {
65
        if (!\class_exists(ClusterOptions::class)) {
66
            throw new PhpfastcacheDriverCheckException('You are using the Couchbase PHP SDK 2.x which is no longer supported in Phpfastcache v9');
67
        }
68
69
        $this->currentParentPID = posix_getppid();
70
71
        $schema = $this->getConfig()->getSecure() ? 'couchbases' : 'couchbase';
72
        $servers = $this->getConfig()->getServers();
73
74
        $connectionString = $schema . '://' . implode(',', $servers) . '?ppid=' . $this->currentParentPID;
75
76
        $options = $this->getConfig()->getClusterOptions();
77
        $options->credentials($this->getConfig()->getUsername(), $this->getConfig()->getPassword());
78
        $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

78
        $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...
79
80
        $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

80
        $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...
81
        $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

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

166
        $this->instance->/** @scrutinizer ignore-call */ 
167
                         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...
167
        return true;
168
    }
169
170
    /**
171
     * @return DriverStatistic
172
     * @throws \Exception
173
     */
174
    public function getStats(): DriverStatistic
175
    {
176
        $this->checkCurrentParentPID();
177
        /**
178
         * Between SDK 2 and 3 we lost a lot of useful information :(
179
         * @see https://docs.couchbase.com/java-sdk/current/project-docs/migrating-sdk-code-to-3.n.html#management-apis
180
         */
181
        $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

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