Passed
Push — master ( c93bd7...170400 )
by Georges
01:56
created

Driver::getCouchDbItemKey()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 1
nc 1
nop 1
dl 0
loc 3
rs 10
c 0
b 0
f 0
1
<?php
2
3
/**
4
 *
5
 * This file is part of phpFastCache.
6
 *
7
 * @license MIT License (MIT)
8
 *
9
 * For full copyright and license information, please see the docs/CREDITS.txt file.
10
 *
11
 * @author Khoa Bui (khoaofgod)  <[email protected]> https://www.phpfastcache.com
12
 * @author Georges.L (Geolim4)  <[email protected]>
13
 *
14
 */
15
declare(strict_types=1);
16
17
namespace Phpfastcache\Drivers\Couchdb;
18
19
use Doctrine\CouchDB\{CouchDBClient, CouchDBException};
0 ignored issues
show
Bug introduced by
The type Doctrine\CouchDB\CouchDBException 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...
Bug introduced by
The type Doctrine\CouchDB\CouchDBClient 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...
20
use Phpfastcache\Cluster\AggregatablePoolInterface;
21
use Phpfastcache\Core\Pool\{DriverBaseTrait, ExtendedCacheItemPoolInterface};
22
use Phpfastcache\Entities\DriverStatistic;
23
use Phpfastcache\Exceptions\{PhpfastcacheDriverException, PhpfastcacheInvalidArgumentException, PhpfastcacheLogicException};
24
use Psr\Cache\CacheItemInterface;
25
26
27
/**
28
 * Class Driver
29
 * @package phpFastCache\Drivers
30
 * @property CouchdbClient $instance Instance of driver service
31
 * @property Config $config Config object
32
 * @method Config getConfig() Return the config object
33
 */
34
class Driver implements ExtendedCacheItemPoolInterface, AggregatablePoolInterface
35
{
36
    public const COUCHDB_DEFAULT_DB_NAME = 'phpfastcache'; // Public because used in config
37
38
    use DriverBaseTrait;
39
40
    /**
41
     * @return bool
42
     */
43
    public function driverCheck(): bool
44
    {
45
        return class_exists(CouchDBClient::class);
46
    }
47
48
    /**
49
     * @return string
50
     */
51
    public function getHelp(): string
52
    {
53
        return <<<HELP
54
<p>
55
To install the Couchdb HTTP client library via Composer:
56
<code>composer require "doctrine/couchdb" "@dev"</code>
57
</p>
58
HELP;
59
    }
60
61
    /**
62
     * @return DriverStatistic
63
     */
64
    public function getStats(): DriverStatistic
65
    {
66
        $info = $this->instance->getDatabaseInfo();
67
68
        return (new DriverStatistic())
69
            ->setSize($info['sizes']['active'])
70
            ->setRawData($info)
71
            ->setData(implode(', ', array_keys($this->itemInstances)))
72
            ->setInfo('Couchdb version ' . $this->instance->getVersion() . "\n For more information see RawData.");
73
    }
74
75
    /**
76
     * @return bool
77
     * @throws PhpfastcacheLogicException
78
     */
79
    protected function driverConnect(): bool
80
    {
81
        if ($this->instance instanceof CouchDBClient) {
82
            throw new PhpfastcacheLogicException('Already connected to Couchdb server');
83
        }
84
85
        $clientConfig = $this->getConfig();
86
87
        $url = ($clientConfig->isSsl() ? 'https://' : 'http://');
88
        if ($clientConfig->getUsername()) {
89
            $url .= $clientConfig->getUsername();
90
            if ($clientConfig->getPassword()) {
91
                $url .= ":{$clientConfig->getPassword()}";
92
            }
93
            $url .= '@';
94
        }
95
        $url .= $clientConfig->getHost();
96
        $url .= ":{$clientConfig->getPort()}";
97
        $url .= '/' . $this->getDatabaseName();
98
99
        $this->instance = CouchDBClient::create(
100
            [
101
                'dbname' => $this->getDatabaseName(),
102
                'url' => $url,
103
                'timeout' => $clientConfig->getTimeout(),
104
            ]
105
        );
106
107
        $this->createDatabase();
108
109
        return true;
110
    }
111
112
    /**
113
     * @return string
114
     */
115
    protected function getDatabaseName(): string
116
    {
117
        return $this->getConfig()->getDatabase() ?: self::COUCHDB_DEFAULT_DB_NAME;
118
    }
119
120
    /**
121
     * @return void
122
     */
123
    protected function createDatabase()
124
    {
125
        if (!in_array($this->getDatabaseName(), $this->instance->getAllDatabases(), true)) {
126
            $this->instance->createDatabase($this->getDatabaseName());
127
        }
128
    }
129
130
    protected function getCouchDbItemKey(CacheItemInterface $item)
131
    {
132
        return 'pfc_' . $item->getEncodedKey();
133
    }
134
135
    /**
136
     * @param CacheItemInterface $item
137
     * @return null|array
138
     * @throws PhpfastcacheDriverException
139
     */
140
    protected function driverRead(CacheItemInterface $item)
141
    {
142
        try {
143
            $response = $this->instance->findDocument($this->getCouchDbItemKey($item));
144
        } catch (CouchDBException $e) {
145
            throw new PhpfastcacheDriverException('Got error while trying to get a document: ' . $e->getMessage(), 0, $e);
146
        }
147
148
        if ($response->status === 404 || empty($response->body['data'])) {
149
            return null;
150
        }
151
152
        if ($response->status === 200) {
153
            return $this->decode($response->body['data']);
154
        }
155
156
        throw new PhpfastcacheDriverException('Got unexpected HTTP status: ' . $response->status);
157
    }
158
159
    /**
160
     * @param CacheItemInterface $item
161
     * @return bool
162
     * @throws PhpfastcacheDriverException
163
     * @throws PhpfastcacheInvalidArgumentException
164
     */
165
    protected function driverWrite(CacheItemInterface $item): bool
166
    {
167
        /**
168
         * Check for Cross-Driver type confusion
169
         */
170
        if ($item instanceof Item) {
171
            try {
172
                $this->instance->putDocument(
173
                    ['data' => $this->encode($this->driverPreWrap($item))],
174
                    $this->getCouchDbItemKey($item),
175
                    $this->getLatestDocumentRevision($this->getCouchDbItemKey($item))
176
                );
177
            } catch (CouchDBException $e) {
178
                throw new PhpfastcacheDriverException('Got error while trying to upsert a document: ' . $e->getMessage(), 0, $e);
179
            }
180
            return true;
181
        }
182
183
        throw new PhpfastcacheInvalidArgumentException('Cross-Driver type confusion detected');
184
    }
185
186
    /**
187
     * @return string|null
188
     */
189
    protected function getLatestDocumentRevision($docId)
190
    {
191
        $path = '/' . $this->getDatabaseName() . '/' . urlencode($docId);
192
193
        $response = $this->instance->getHttpClient()->request(
194
            'HEAD',
195
            $path,
196
            null,
197
            false
198
        );
199
        if (!empty($response->headers['etag'])) {
200
            return trim($response->headers['etag'], " '\"\t\n\r\0\x0B");
201
        }
202
203
        return null;
204
    }
205
206
    /********************
207
     *
208
     * PSR-6 Extended Methods
209
     *
210
     *******************/
211
212
    /**
213
     * @param CacheItemInterface $item
214
     * @return bool
215
     * @throws PhpfastcacheDriverException
216
     * @throws PhpfastcacheInvalidArgumentException
217
     */
218
    protected function driverDelete(CacheItemInterface $item): bool
219
    {
220
        /**
221
         * Check for Cross-Driver type confusion
222
         */
223
        if ($item instanceof Item) {
224
            try {
225
                $this->instance->deleteDocument($this->getCouchDbItemKey($item), $this->getLatestDocumentRevision($this->getCouchDbItemKey($item)));
226
            } catch (CouchDBException $e) {
227
                throw new PhpfastcacheDriverException('Got error while trying to delete a document: ' . $e->getMessage(), 0, $e);
228
            }
229
            return true;
230
        }
231
232
        throw new PhpfastcacheInvalidArgumentException('Cross-Driver type confusion detected');
233
    }
234
235
    /**
236
     * @return bool
237
     * @throws PhpfastcacheDriverException
238
     */
239
    protected function driverClear(): bool
240
    {
241
        try {
242
            $this->instance->deleteDatabase($this->getDatabaseName());
243
            $this->createDatabase();
244
        } catch (CouchDBException $e) {
245
            throw new PhpfastcacheDriverException('Got error while trying to delete and recreate the database: ' . $e->getMessage(), 0, $e);
246
        }
247
248
        return true;
249
    }
250
}
251