Test Setup Failed
Push — testing ( e0bf91...3426ad )
by Roman
02:46
created

Connection::setAuthCredentials()   A

Complexity

Conditions 3
Paths 2

Size

Total Lines 7

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 3

Importance

Changes 0
Metric Value
dl 0
loc 7
ccs 2
cts 2
cp 1
rs 10
c 0
b 0
f 0
cc 3
nc 2
nop 1
crap 3
1
<?php
2
3
namespace lroman242\LaravelCassandra;
4
5
use Cassandra;
6
use Cassandra\BatchStatement;
7
use \lroman242\LaravelCassandra\Exceptions\CassandraNotSupportedException;
8
9
class Connection extends \Illuminate\Database\Connection
10
{
11
    const DEFAULT_PAGE_SIZE = 5000;
12
13
    /**
14
     * The Cassandra keyspace
15
     *
16
     * @var string
17
     */
18
    protected $keyspace;
19
20
    /**
21
     * The Cassandra cluster
22
     *
23
     * @var \Cassandra\Cluster
24
     */
25
    protected $cluster;
26
27
    /**
28
     * The Cassandra connection handler.
29
     *
30
     * @var \Cassandra\Session
31
     */
32
    protected $session;
33
34
    /**
35
     * The config
36
     *
37
     * @var array
38
     */
39
    protected $config;
40
41
    /**
42
     * Create a new database connection instance.
43
     *
44
     * @param array $config
45
     */
46 48
    public function __construct(array $config)
47
    {
48 48
        $this->config = $config;
49 48
        if (empty($this->config['page_size'])) {
50 48
            $this->config['page_size'] = self::DEFAULT_PAGE_SIZE;
51
        }
52
53
        // Create the connection
54 48
        $this->cluster = $this->createCluster();
55
56 48
        if (isset($config['keyspace'])) {
57 48
            $keyspaceName = $config['keyspace'];
58
59 48
            $this->keyspace = $keyspaceName;
60 48
            $this->session = $this->cluster->connect($keyspaceName);
61
        }
62
63 48
        $this->useDefaultPostProcessor();
64
65 48
        $this->useDefaultSchemaGrammar();
66
67 48
        $this->setQueryGrammar($this->getDefaultQueryGrammar());
68 48
    }
69
70
    /**
71
     * Begin a fluent query against a database table.
72
     *
73
     * @param string $table
74
     * @return Query\Builder
75
     */
76 5
    public function table($table)
77
    {
78 5
        $processor = $this->getPostProcessor();
79
80 5
        $query = new Query\Builder($this, null, $processor);
0 ignored issues
show
Documentation introduced by
$processor is of type object<Illuminate\Databa...y\Processors\Processor>, but the function expects a null|object<lroman242\La...sandra\Query\Processor>.

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...
81
82 5
        return $query->from($table);
83
    }
84
85
    /**
86
     * return Cassandra cluster.
87
     *
88
     * @return \Cassandra\Cluster
89
     */
90 1
    public function getCassandraCluster()
91
    {
92 1
        return $this->cluster;
93
    }
94
95
    /**
96
     * return Cassandra Session.
97
     *
98
     * @return \Cassandra\Session
99
     */
100 3
    public function getCassandraSession()
101
    {
102 3
        return $this->session;
103
    }
104
105
    /**
106
     * Return the Cassandra keyspace
107
     *
108
     * @return string
109
     */
110 1
    public function getKeyspace()
111
    {
112 1
        return $this->keyspace;
113
    }
114
115
    /**
116
     * Set username and password to cluster connection.
117
     *
118
     * @param Cassandra\Cluster $cluster
119
     */
120
    protected function setAuthCredentials(\Cassandra\Cluster\Builder $cluster)
121
    {
122 48
        // Authentication
123
        if (isset($this->config['username']) && isset($this->config['password'])) {
124 48
            $cluster->withCredentials($this->config['username'], $this->config['password']);
125
        }
126
    }
127 48
128 48
    /**
129
     * Set cluster contact points (IP addresses)
130
     *
131
     * @param Cassandra\Cluster $cluster
132 48
     */
133 48
    protected function setContactPoints(\Cassandra\Cluster\Builder $cluster)
134
    {
135 48
        if (!empty($this->config['host'])) {
136 48
            $contactPoints = $this->config['host'];
137
138
            if (is_string($contactPoints)) {
139 48
                $contactPoints = explode(',', $contactPoints);
140
            }
141
142 48
            call_user_func_array([$cluster, 'withContactPoints'], (array)$contactPoints);
143 48
        }
144
    }
145
146 48
    /**
147
     * Set connection communication port
148 48
     *
149 48
     * @param Cassandra\Cluster $cluster
150
     */
151
    protected function setContactPort(\Cassandra\Cluster\Builder $cluster)
152
    {
153
        if (!empty($this->config['port'])) {
154
            $cluster->withPort((int)$this->config['port']);
155 48
        }
156
    }
157
158 48
    /**
159 48
     * Set default consistency level
160
     *
161
     * @param Cassandra\Cluster $cluster
162 48
     */
163 48
    protected function setConsistencyLevel(\Cassandra\Cluster\Builder $cluster)
164
    {
165
        if (isset($this->config['consistency']) && in_array($this->config['consistency'], [
166 48
                Cassandra::CONSISTENCY_ANY, Cassandra::CONSISTENCY_ONE, Cassandra::CONSISTENCY_TWO,
167 48
                Cassandra::CONSISTENCY_THREE, Cassandra::CONSISTENCY_QUORUM, Cassandra::CONSISTENCY_ALL,
168
                Cassandra::CONSISTENCY_SERIAL, Cassandra::CONSISTENCY_QUORUM, Cassandra::CONSISTENCY_LOCAL_QUORUM,
169
                Cassandra::CONSISTENCY_EACH_QUORUM, Cassandra::CONSISTENCY_LOCAL_SERIAL, Cassandra::CONSISTENCY_LOCAL_ONE,
170 48
            ])) {
171
172
            $cluster->withDefaultConsistency($this->config['consistency']);
173
        }
174
    }
175
176 3
    /**
177
     * Set default timeouts to queries
178 3
     *
179 3
     * @param Cassandra\Cluster $cluster
180 3
     */
181
    protected function setTimeouts(\Cassandra\Cluster\Builder $cluster)
182
    {
183
        if (!empty($this->config['timeout'])) {
184
            $cluster->withDefaultTimeout(intval($this->config['timeout']));
185
        }
186
187 1
        if (!empty($this->config['connect_timeout'])) {
188
            $cluster->withConnectTimeout(floatval($this->config['connect_timeout']));
189 1
        }
190
191
        if (!empty($this->config['request_timeout'])) {
192
            $cluster->withRequestTimeout(floatval($this->config['request_timeout']));
193
        }
194
    }
195
196
    /**
197
     * Set default response size to queries
198
     *
199
     * @param Cassandra\Cluster $cluster
200
     */
201
    protected function setDefaultPageSize(\Cassandra\Cluster\Builder $cluster)
202 48
    {
203
        $cluster->withDefaultPageSize(intval(!empty($this->config['page_size']) ? $this->config['page_size'] : self::DEFAULT_PAGE_SIZE));
204 48
    }
205
206
    /**
207
     * Create a new Cassandra cluster object.
208
     *
209
     * @return \Cassandra\Cluster
210
     */
211
    protected function createCluster()
212
    {
213
        $cluster = Cassandra::cluster();
214
215
        // Authentication
216
        $this->setAuthCredentials($cluster);
217 6
218
        $this->setContactPort($cluster);
219 6
220
        // Contact Points/Host
221
        $this->setContactPoints($cluster);
222
223
        $this->setDefaultPageSize($cluster);
224
225
        $this->setConsistencyLevel($cluster);
226
227
        $this->setTimeouts($cluster);
228
229
        return $cluster->build();
230
    }
231
232
    /**
233
     * Disconnect from the underlying Cassandra connection.
234 7
     */
235 7
    public function disconnect()
236 1
    {
237
        $this->session->close();
238
        $this->session = null;
239 6
    }
240
241 6
    /**
242 6
     * Get the PDO driver name.
243 6
     *
244
     * @return string
245
     */
246 6
    public function getDriverName()
247 7
    {
248
        return 'cassandra';
249
    }
250
251
    /**
252
     * Run a select statement against the database.
253
     *
254
     * @param  string  $query
255
     * @param  array  $bindings
256
     * @param  bool  $useReadPdo
257
     * @param  array  $customOptions
258
     *
259 48
     * @return mixed
260
     */
261 48
    public function select($query, $bindings = [], $useReadPdo = true, array $customOptions = [])
262
    {
263
        return $this->statement($query, $bindings, $customOptions);
264
    }
265
266
    /**
267
     * Run an bulk insert statement against the database.
268
     *
269
     * @param  array  $queries
270
     * @param  array  $bindings
271
     * @param  int  $type
272
     * @param  array  $customOptions
273
     *
274
     * @return bool
275 10
     */
276
    public function insertBulk($queries = [], $bindings = [], $type = Cassandra::BATCH_LOGGED, array $customOptions = [])
277 10
    {
278
        return $this->batchStatement($queries, $bindings, $type, $customOptions);
279
    }
280
281
    /**
282
     * Execute a group of queries inside a batch statement against the database.
283 48
     *
284
     * @param  array  $queries
285 48
     * @param  array  $bindings
286
     * @param  int  $type
287
     * @param  array  $customOptions
288
     *
289
     * @return bool
290
     */
291 48
    public function batchStatement($queries = [], $bindings = [], $type = Cassandra::BATCH_LOGGED, array $customOptions = [])
292
    {
293 48
        return $this->run($queries, $bindings, function ($queries, $bindings) use ($type, $customOptions) {
0 ignored issues
show
Documentation introduced by
$queries is of type array, 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...
294
            if ($this->pretending()) {
295
                return [];
296
            }
297
298
            $batch = new BatchStatement($type);
299 48
300
            foreach ($queries as $k => $query) {
301
                $preparedStatement = $this->session->prepare($query);
302 48
                $batch->add($preparedStatement, $bindings[$k]);
303
            }
304
305
            return $this->session->execute($batch, $customOptions);
306
        });
307
    }
308
309 48
    /**
310
     * Execute an CQL statement and return the boolean result.
311 48
     *
312 1
     * @param  string  $query
313
     * @param  array   $bindings
314 48
     * @param  array  $customOptions
315
     *
316
     * @return mixed
317
     */
318
    public function statement($query, $bindings = [], array $customOptions = [])
319
    {
320
        return $this->runStatement($query, $bindings, $customOptions);
321
    }
322
323 1
    /**
324
     * Because Cassandra is an eventually consistent database, it's not possible to obtain
325 1
     * the affected count for statements so we're just going to return 0, based on the idea
326
     * that if the query fails somehow, an exception will be thrown
327
     *
328
     * @param  string  $query
329
     * @param  array   $bindings
330
     * @param  array  $customOptions
331
     *
332
     * @return int
333
     */
334
    public function affectingStatement($query, $bindings = [], array $customOptions = [])
335
    {
336
        return $this->runStatement($query, $bindings, $customOptions, 0, 1);
337
    }
338
339
    /**
340
     * @inheritdoc
341 48
     */
342 48
    protected function getDefaultPostProcessor()
343 2
    {
344
        return new Query\Processor();
345
    }
346 48
347
    /**
348
     * @inheritdoc
349 48
     */
350
    protected function getDefaultQueryGrammar()
351 48
    {
352
        return new Query\Grammar();
353 48
    }
354 48
355
    /**
356
     * @inheritdoc
357
     */
358
    protected function getDefaultSchemaGrammar()
359
    {
360 1
        //return new Schema\Grammar();
361
    }
362 1
363
    /**
364
     * Reconnect to the database if connection is missing.
365
     *
366
     * @return void
367
     */
368 1
    protected function reconnectIfMissingConnection()
369
    {
370 1
        if (is_null($this->session)) {
371
            $this->session = $this->createCluster($this->config)->connect($this->keyspace);
0 ignored issues
show
Unused Code introduced by
The call to Connection::createCluster() has too many arguments starting with $this->config.

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.

In this case you can add the @ignore PhpDoc annotation to the duplicate definition and it will be ignored.

Loading history...
372
        }
373
    }
374
375
    /**
376 1
     * Dynamically pass methods to the connection.
377
     *
378 1
     * @param  string  $method
379
     * @param  array   $parameters
380
     * @return mixed
381
     */
382
    public function __call($method, $parameters)
383
    {
384 1
        return call_user_func_array([$this->session, $method], $parameters);
385
    }
386 1
387
    /**
388
     * Execute an CQL statement and return the boolean result.
389
     *
390
     * @param string $query
391
     * @param array $bindings
392 1
     * @param array $customOptions
393
     * @param mixed $defaultFailed
394 1
     * @param mixed $defaultSuccess
395
     *
396
     * @return mixed
397
     */
398
    protected function runStatement($query, $bindings = [], array $customOptions = [], $defaultFailed = [], $defaultSuccess = null)
399
    {
400
        return $this->run($query, $bindings, function ($query, $bindings) use ($customOptions, $defaultFailed, $defaultSuccess) {
401
            if ($this->pretending()) {
402
                return $defaultFailed;
403
            }
404
405
            $preparedStatement = $this->session->prepare($query);
406
407
            //Add bindings
408
            $customOptions['arguments'] = $bindings;
409
410
            $result = $this->session->execute($preparedStatement, $customOptions);
411
412
            return $defaultSuccess === null ? $result : $defaultSuccess;
413
        });
414
    }
415
416
    /**
417
     * @inheritDoc
418
     */
419
    public function transaction(\Closure $callback, $attempts = 1)
420
    {
421
        throw new CassandraNotSupportedException("Transactions is not supported by Cassandra database");
422
    }
423
424
    /**
425
     * @inheritDoc
426
     */
427
    public function beginTransaction()
428
    {
429
        throw new CassandraNotSupportedException("Transactions is not supported by Cassandra database");
430
    }
431
432
    /**
433
     * @inheritDoc
434
     */
435
    public function commit()
436
    {
437
        throw new CassandraNotSupportedException("Transactions is not supported by Cassandra database");
438
    }
439
440
    /**
441
     * @inheritDoc
442
     */
443
    public function rollBack()
444
    {
445
        throw new CassandraNotSupportedException("Transactions is not supported by Cassandra database");
446
    }
447
448
    /**
449
     * @inheritDoc
450
     */
451
    public function transactionLevel()
452
    {
453
        throw new CassandraNotSupportedException("Transactions is not supported by Cassandra database");
454
    }
455
456
    //TODO: override isDoctrineAvailable method
457
    //TODO: override getDoctrineColumn method
458
    //TODO: override getDoctrineSchemaManager method
459
    //TODO: override getDoctrineConnection method
460
    //TODO: override getPdo method
461
    //TODO: override getReadPdo method
462
    //TODO: override setPdo method
463
    //TODO: override setReadPdo method
464
    //TODO: override setReconnector method
465
    //TODO: override reconnect method
466
    //TODO: override query method
467
468
    //TODO: override bindValues method
469
    //TODO: override cursor method
470
    //TODO: override unprepared method
471
472
    //TODO: check prepareBindings method
473
474
    //TODO: provide interface for $this->session->executeAsync
475
    //TODO: provide interface for $this->session->prepareAsync
476
    //TODO: provide interface for $this->session->closeAsync
477
    //TODO: provide interface for $this->session->schema
478
}
479