Completed
Push — V6 ( e9a4a9...c00b85 )
by Georges
02:18
created

Driver::driverRead()   B

Complexity

Conditions 4
Paths 7

Size

Total Lines 23
Code Lines 16

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
c 0
b 0
f 0
dl 0
loc 23
rs 8.7972
cc 4
eloc 16
nc 7
nop 1
1
<?php
2
/**
3
 *
4
 * This file is part of phpFastCache.
5
 *
6
 * @license MIT License (MIT)
7
 *
8
 * For full copyright and license information, please see the docs/CREDITS.txt file.
9
 *
10
 * @author Khoa Bui (khoaofgod)  <[email protected]> http://www.phpfastcache.com
11
 * @author Georges.L (Geolim4)  <[email protected]>
12
 *
13
 */
14
15
namespace phpFastCache\Drivers\Cassandra;
16
17
use CouchbaseCluster as CouchbaseClient;
18
use phpFastCache\Core\Pool\DriverBaseTrait;
19
use phpFastCache\Core\Pool\ExtendedCacheItemPoolInterface;
20
use phpFastCache\Entities\driverStatistic;
21
use phpFastCache\Exceptions\phpFastCacheDriverCheckException;
22
use phpFastCache\Exceptions\phpFastCacheDriverException;
23
use phpFastCache\Exceptions\phpFastCacheInvalidArgumentException;
24
use Psr\Cache\CacheItemInterface;
25
use Cassandra;
26
use Cassandra\Session as CassandraSession;
27
28
/**
29
 * Class Driver
30
 * @package phpFastCache\Drivers
31
 * @property CassandraSession $instance Instance of driver service
32
 */
33
class Driver implements ExtendedCacheItemPoolInterface
34
{
35
    const CASSANDRA_KEY_SPACE = 'phpfastcache';
36
    const CASSANDRA_TABLE = 'cacheItems';
37
38
    use DriverBaseTrait;
39
40
    /**
41
     * Driver constructor.
42
     * @param array $config
43
     * @throws phpFastCacheDriverException
44
     */
45 View Code Duplication
    public function __construct(array $config = [])
46
    {
47
        $this->setup($config);
48
49
        if (!$this->driverCheck()) {
50
            throw new phpFastCacheDriverCheckException(sprintf(self::DRIVER_CHECK_FAILURE, $this->getDriverName()));
51
        } else {
52
            $this->driverConnect();
53
        }
54
    }
55
56
    /**
57
     * @return bool
58
     */
59
    public function driverCheck()
60
    {
61
        return extension_loaded('Cassandra') && class_exists('Cassandra');
62
    }
63
64
    /**
65
     * @param \Psr\Cache\CacheItemInterface $item
66
     * @return mixed
67
     * @throws phpFastCacheInvalidArgumentException
68
     */
69
    protected function driverWrite(CacheItemInterface $item)
70
    {
71
        /**
72
         * Check for Cross-Driver type confusion
73
         */
74
        if ($item instanceof Item) {
75
            $cacheData = $this->encode($this->driverPreWrap($item));
76
            $options = new Cassandra\ExecutionOptions([
77
              'arguments' => [
78
                'cache_uuid' => new Cassandra\Uuid(),
79
                'cache_id' => $item->getKey(),
80
                'cache_data' => $this->encode($this->driverPreWrap($item)),
81
                'cache_creation_date' => new Cassandra\Timestamp((new \DateTime())->getTimestamp()),
82
                'cache_expiration_date' => new Cassandra\Timestamp($item->getExpirationDate()->getTimestamp()),
83
                'cache_length' => strlen($cacheData)
84
              ],
85
              'consistency' => Cassandra::CONSISTENCY_ALL,
86
              'serial_consistency' => Cassandra::CONSISTENCY_SERIAL
87
            ]);
88
89
            $query = sprintf('INSERT INTO %s.%s
90
                    (
91
                      cache_uuid, 
92
                      cache_id, 
93
                      cache_data, 
94
                      cache_creation_date, 
95
                      cache_expiration_date,
96
                      cache_length
97
                    )
98
                  VALUES (:cache_uuid, :cache_id, :cache_data, :cache_creation_date, :cache_expiration_date, :cache_length);
99
            ', self::CASSANDRA_KEY_SPACE, self::CASSANDRA_TABLE);
100
101
            $result = $this->instance->execute(new Cassandra\SimpleStatement($query), $options);
102
            /**
103
             * There's no real way atm
104
             * to know if the item has
105
             * been really upserted
106
             */
107
            return $result instanceof Cassandra\Rows;
1 ignored issue
show
Bug introduced by
The class Cassandra\Rows 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...
108
        } else {
109
            throw new phpFastCacheInvalidArgumentException('Cross-Driver type confusion detected');
110
        }
111
    }
112
113
    /**
114
     * @param \Psr\Cache\CacheItemInterface $item
115
     * @return mixed
116
     */
117
    protected function driverRead(CacheItemInterface $item)
118
    {
119
        try {
120
            $options = new Cassandra\ExecutionOptions([
121
              'arguments' => ['cache_id' => $item->getKey()],
122
              'page_size' => 1
123
            ]);
124
            $query = sprintf(
125
              'SELECT cache_data FROM %s.%s WHERE cache_id = :cache_id;',
126
              self::CASSANDRA_KEY_SPACE,
127
              self::CASSANDRA_TABLE
128
            );
129
            $results = $this->instance->execute(new Cassandra\SimpleStatement($query), $options);
130
131
            if($results instanceof Cassandra\Rows && $results->count() === 1){
1 ignored issue
show
Bug introduced by
The class Cassandra\Rows 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...
132
                return $this->decode($results->first()['cache_data']);
133
            }else{
134
                return null;
135
            }
136
        } catch (Cassandra\Exception $e) {
1 ignored issue
show
Bug introduced by
The class Cassandra\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...
137
            return null;
138
        }
139
    }
140
141
    /**
142
     * @param \Psr\Cache\CacheItemInterface $item
143
     * @return bool
144
     * @throws phpFastCacheInvalidArgumentException
145
     */
146
    protected function driverDelete(CacheItemInterface $item)
147
    {
148
        /**
149
         * Check for Cross-Driver type confusion
150
         */
151
        if ($item instanceof Item) {
152
            try {
153
                $options = new Cassandra\ExecutionOptions([
154
                  'arguments' => [
155
                    'cache_id' => $item->getKey(),
156
                  ],
157
                ]);
158
                $result = $this->instance->execute(new Cassandra\SimpleStatement(sprintf(
159
                  'DELETE FROM %s.%s WHERE cache_id = :cache_id;',
160
                  self::CASSANDRA_KEY_SPACE,
161
                  self::CASSANDRA_TABLE
162
                )), $options);
163
164
                /**
165
                 * There's no real way atm
166
                 * to know if the item has
167
                 * been really deleted
168
                 */
169
                return $result instanceof Cassandra\Rows;
1 ignored issue
show
Bug introduced by
The class Cassandra\Rows 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...
170
            } catch (Cassandra\Exception $e) {
1 ignored issue
show
Bug introduced by
The class Cassandra\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...
171
                return false;
172
            }
173
        } else {
174
            throw new phpFastCacheInvalidArgumentException('Cross-Driver type confusion detected');
175
        }
176
    }
177
178
    /**
179
     * @return bool
180
     */
181
    protected function driverClear()
182
    {
183
        try {
184
            $result = $this->instance->execute(new Cassandra\SimpleStatement(sprintf(
185
              'TRUNCATE %s.%s;',
186
              self::CASSANDRA_KEY_SPACE, self::CASSANDRA_TABLE
187
            )));
188
            /**
189
             * There's no real way atm
190
             * to know if the item has
191
             * been really deleted
192
             */
193
            return $result instanceof Cassandra\Rows;
1 ignored issue
show
Bug introduced by
The class Cassandra\Rows 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...
194
        } catch (Cassandra\Exception $e) {
1 ignored issue
show
Bug introduced by
The class Cassandra\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...
195
            return false;
196
        }
197
    }
198
199
    /**
200
     * @return bool
201
     */
202
    protected function driverConnect()
203
    {
204
        if ($this->instance instanceof CouchbaseClient) {
205
            throw new \LogicException('Already connected to Couchbase server');
206
        } else {
207
            $host = isset($this->config[ 'host' ]) ? $this->config[ 'host' ] : '127.0.0.1';
208
            $port = isset($this->config[ 'port' ]) ? $this->config[ 'port' ] : 9042;
209
            $timeout = isset($this->config[ 'timeout' ]) ? $this->config[ 'timeout' ] : 2;
210
            $password = isset($this->config[ 'password' ]) ? $this->config[ 'password' ] : '';
211
            $username = isset($this->config[ 'username' ]) ? $this->config[ 'username' ] : '';
212
213
            $clusterBuilder = Cassandra::cluster()
214
              ->withContactPoints($host)
215
              ->withPort($port);
216
217
            if(!empty($this->config['ssl']['enabled'])){
218
                if(!empty($this->config['ssl']['verify'])){
219
                    $sslBuilder = Cassandra::ssl()->withVerifyFlags(Cassandra::VERIFY_PEER_CERT);
220
                }else{
221
                    $sslBuilder = Cassandra::ssl()->withVerifyFlags(Cassandra::VERIFY_NONE);
222
                }
223
224
                $clusterBuilder->withSSL($sslBuilder->build());
225
            }
226
227
            $clusterBuilder->withConnectTimeout($timeout);
228
229
            if($username){
230
                $clusterBuilder->withCredentials($username, $password);
231
            }
232
233
            $this->instance = $clusterBuilder->build()->connect();
234
235
            /**
236
             * In case of emergency:
237
             * $this->instance->execute(
238
             *      new Cassandra\SimpleStatement(sprintf("DROP KEYSPACE %s;", self::CASSANDRA_KEY_SPACE))
239
             * );
240
             */
241
242
            $this->instance->execute(new Cassandra\SimpleStatement(sprintf(
243
              "CREATE KEYSPACE IF NOT EXISTS %s WITH REPLICATION = { 'class' : 'SimpleStrategy', 'replication_factor' : 1 };",
244
              self::CASSANDRA_KEY_SPACE
245
            )));
246
            $this->instance->execute(new Cassandra\SimpleStatement(sprintf('USE %s;', self::CASSANDRA_KEY_SPACE)));
247
            $this->instance->execute(new Cassandra\SimpleStatement(sprintf('
248
                CREATE TABLE IF NOT EXISTS %s (
249
                    cache_uuid uuid,
250
                    cache_id varchar,
251
                    cache_data text,
252
                    cache_creation_date timestamp,
253
                    cache_expiration_date timestamp,
254
                    cache_length int,
255
                    PRIMARY KEY (cache_id)
256
                );', self::CASSANDRA_TABLE
257
            )));
258
        }
259
260
        return true;
261
    }
262
263
    /********************
264
     *
265
     * PSR-6 Extended Methods
266
     *
267
     *******************/
268
269
    /**
270
     * @return driverStatistic
271
     */
272
    public function getStats()
273
    {
274
        $result = $this->instance->execute(new Cassandra\SimpleStatement(sprintf(
275
          'SELECT SUM(cache_length) as cache_size FROM %s.%s',
276
          self::CASSANDRA_KEY_SPACE,
277
          self::CASSANDRA_TABLE
278
        )));
279
280
        return (new driverStatistic())
281
          ->setSize($result->first()[ 'cache_size' ])
282
          ->setRawData([])
283
          ->setData(implode(', ', array_keys($this->itemInstances)))
284
          ->setInfo('The cache size represents only the cache data itself without counting data structures associated to the cache entries.');
285
    }
286
}