Passed
Branch testing (e1d3e5)
by Roman
07:46
created

Connection::beginTransaction()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1

Importance

Changes 0
Metric Value
dl 0
loc 4
ccs 2
cts 2
cp 1
rs 10
c 0
b 0
f 0
cc 1
nc 1
nop 0
crap 1
1
<?php
2
3
namespace lroman242\LaravelCassandra;
4
5
use Cassandra;
6
use Cassandra\BatchStatement;
7
use Cassandra\Cluster\Builder as ClusterBuilder;
8
use \lroman242\LaravelCassandra\Exceptions\CassandraNotSupportedException;
9
10
class Connection extends \Illuminate\Database\Connection
11
{
12
    const DEFAULT_PAGE_SIZE = 5000;
13
14
    /**
15
     * The Cassandra keyspace
16
     *
17
     * @var string
18
     */
19
    protected $keyspace;
20
21
    /**
22
     * The Cassandra cluster
23
     *
24
     * @var \Cassandra\Cluster
25
     */
26
    protected $cluster;
27
28
    /**
29
     * The Cassandra connection handler.
30
     *
31
     * @var \Cassandra\Session
32
     */
33
    protected $session;
34
35
    /**
36
     * The config
37
     *
38
     * @var array
39
     */
40
    protected $config;
41
42
    /**
43
     * Create a new database connection instance.
44
     *
45
     * @param array $config
46
     */
47 48
    public function __construct(array $config)
48
    {
49 48
        $this->config = $config;
50 48
        if (empty($this->config['page_size'])) {
51 48
            $this->config['page_size'] = self::DEFAULT_PAGE_SIZE;
52
        }
53
54
        // Create the connection
55 48
        $this->cluster = $this->createCluster();
56
57 48
        if (isset($config['keyspace'])) {
58 48
            $keyspaceName = $config['keyspace'];
59
60 48
            $this->keyspace = $keyspaceName;
61 48
            $this->session = $this->cluster->connect($keyspaceName);
62
        }
63
64 48
        $this->useDefaultPostProcessor();
65
66 48
        $this->useDefaultSchemaGrammar();
67
68 48
        $this->setQueryGrammar($this->getDefaultQueryGrammar());
69 48
    }
70
71
    /**
72
     * Begin a fluent query against a database table.
73
     *
74
     * @param string $table
75
     * @return Query\Builder
76
     */
77 5
    public function table($table)
78
    {
79 5
        $processor = $this->getPostProcessor();
80
81 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...
82
83 5
        return $query->from($table);
84
    }
85
86
    /**
87
     * return Cassandra cluster.
88
     *
89
     * @return \Cassandra\Cluster
90
     */
91 1
    public function getCassandraCluster()
92
    {
93 1
        return $this->cluster;
94
    }
95
96
    /**
97
     * return Cassandra Session.
98
     *
99
     * @return \Cassandra\Session
100
     */
101 3
    public function getCassandraSession()
102
    {
103 3
        return $this->session;
104
    }
105
106
    /**
107
     * Return the Cassandra keyspace
108
     *
109
     * @return string
110
     */
111 1
    public function getKeyspace()
112
    {
113 1
        return $this->keyspace;
114
    }
115
116
    /**
117
     * Set username and password to cluster connection.
118
     * Set cluster contact points (IP addresses)
119
     * Set connection communication port
120
     *
121
     * @param \Cassandra\Cluster\Builder $cluster
122
     */
123 48
    protected function setConnectionOptions(ClusterBuilder $cluster)
124
    {
125
        // Authentication
126 48
        if (isset($this->config['username']) && isset($this->config['password'])) {
127 48
            $cluster->withCredentials($this->config['username'], $this->config['password']);
128
        }
129
130 48
        if (!empty($this->config['host'])) {
131 48
            $contactPoints = $this->config['host'];
132
133 48
            if (is_string($contactPoints)) {
134 48
                $contactPoints = explode(',', $contactPoints);
135
            }
136
137 48
            call_user_func_array([$cluster, 'withContactPoints'], (array)$contactPoints);
138
        }
139
140 48
        if (!empty($this->config['port'])) {
141 48
            $cluster->withPort((int)$this->config['port']);
142
        }
143 48
    }
144
145
    /**
146
     * Set default consistency level
147
     * Set default timeouts to queries
148
     * Set default response size to queries
149
     *
150
     * @param \Cassandra\Cluster\Builder $cluster
151
     */
152 48
    protected function setDefaultQueryOptions(ClusterBuilder $cluster)
153
    {
154 48
        if (isset($this->config['consistency']) && in_array($this->config['consistency'], [
155 48
                Cassandra::CONSISTENCY_ANY, Cassandra::CONSISTENCY_ONE, Cassandra::CONSISTENCY_TWO,
156
                Cassandra::CONSISTENCY_THREE, Cassandra::CONSISTENCY_QUORUM, Cassandra::CONSISTENCY_ALL,
157
                Cassandra::CONSISTENCY_SERIAL, Cassandra::CONSISTENCY_QUORUM, Cassandra::CONSISTENCY_LOCAL_QUORUM,
158
                Cassandra::CONSISTENCY_EACH_QUORUM, Cassandra::CONSISTENCY_LOCAL_SERIAL, Cassandra::CONSISTENCY_LOCAL_ONE,
159
            ])) {
160
161 48
            $cluster->withDefaultConsistency($this->config['consistency']);
162
        }
163
164 48
        if (!empty($this->config['timeout'])) {
165 48
            $cluster->withDefaultTimeout(intval($this->config['timeout']));
166
        }
167
168 48
        if (!empty($this->config['connect_timeout'])) {
169 48
            $cluster->withConnectTimeout(floatval($this->config['connect_timeout']));
170
        }
171
172 48
        if (!empty($this->config['request_timeout'])) {
173 48
            $cluster->withRequestTimeout(floatval($this->config['request_timeout']));
174
        }
175
176 48
        $cluster->withDefaultPageSize(intval(!empty($this->config['page_size']) ? $this->config['page_size'] : self::DEFAULT_PAGE_SIZE));
177 48
    }
178
179
    /**
180
     * Create a new Cassandra cluster object.
181
     *
182
     * @return \Cassandra\Cluster
183
     */
184 48
    protected function createCluster()
185
    {
186 48
        $cluster = Cassandra::cluster();
187
188
        // Authentication
189 48
        $this->setConnectionOptions($cluster);
190
191 48
        $this->setDefaultQueryOptions($cluster);
192
193 48
        return $cluster->build();
194
    }
195
196
    /**
197
     * Disconnect from the underlying Cassandra connection.
198
     */
199 3
    public function disconnect()
200
    {
201 3
        $this->session->close();
202 3
        $this->session = null;
203 3
    }
204
205
    /**
206
     * Get the PDO driver name.
207
     *
208
     * @return string
209
     */
210 1
    public function getDriverName()
211
    {
212 1
        return 'cassandra';
213
    }
214
215
    /**
216
     * Run a select statement against the database.
217
     *
218
     * @param  string  $query
219
     * @param  array  $bindings
220
     * @param  bool  $useReadPdo
221
     * @param  array  $customOptions
222
     *
223
     * @return mixed
224
     */
225 48
    public function select($query, $bindings = [], $useReadPdo = true, array $customOptions = [])
226
    {
227 48
        return $this->statement($query, $bindings, $customOptions);
228
    }
229
230
    /**
231
     * Run an bulk insert statement against the database.
232
     *
233
     * @param  array  $queries
234
     * @param  array  $bindings
235
     * @param  int  $type
236
     * @param  array  $customOptions
237
     *
238
     * @return bool
239
     */
240 6
    public function insertBulk($queries = [], $bindings = [], $type = Cassandra::BATCH_LOGGED, array $customOptions = [])
241
    {
242 6
        return $this->batchStatement($queries, $bindings, $type, $customOptions);
243
    }
244
245
    /**
246
     * Execute a group of queries inside a batch statement against the database.
247
     *
248
     * @param  array  $queries
249
     * @param  array  $bindings
250
     * @param  int  $type
251
     * @param  array  $customOptions
252
     *
253
     * @return bool
254
     */
255
    public function batchStatement($queries = [], $bindings = [], $type = Cassandra::BATCH_LOGGED, array $customOptions = [])
256
    {
257 7
        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...
258 7
            if ($this->pretending()) {
259 1
                return [];
260
            }
261
262 6
            $batch = new BatchStatement($type);
263
264 6
            foreach ($queries as $k => $query) {
265 6
                $preparedStatement = $this->session->prepare($query);
266 6
                $batch->add($preparedStatement, $bindings[$k]);
267
            }
268
269 6
            return $this->session->execute($batch, $customOptions);
270 7
        });
271
    }
272
273
    /**
274
     * Execute an CQL statement and return the boolean result.
275
     *
276
     * @param  string  $query
277
     * @param  array   $bindings
278
     * @param  array  $customOptions
279
     *
280
     * @return mixed
281
     */
282 48
    public function statement($query, $bindings = [], array $customOptions = [])
283
    {
284 48
        return $this->runStatement($query, $bindings, $customOptions);
285
    }
286
287
    /**
288
     * Because Cassandra is an eventually consistent database, it's not possible to obtain
289
     * the affected count for statements so we're just going to return 0, based on the idea
290
     * that if the query fails somehow, an exception will be thrown
291
     *
292
     * @param  string  $query
293
     * @param  array   $bindings
294
     * @param  array  $customOptions
295
     *
296
     * @return int
297
     */
298 10
    public function affectingStatement($query, $bindings = [], array $customOptions = [])
299
    {
300 10
        return $this->runStatement($query, $bindings, $customOptions, 0, 1);
301
    }
302
303
    /**
304
     * @inheritdoc
305
     */
306 48
    protected function getDefaultPostProcessor()
307
    {
308 48
        return new Query\Processor();
309
    }
310
311
    /**
312
     * @inheritdoc
313
     */
314 48
    protected function getDefaultQueryGrammar()
315
    {
316 48
        return new Query\Grammar();
317
    }
318
319
    /**
320
     * @inheritdoc
321
     */
322 48
    protected function getDefaultSchemaGrammar()
323
    {
324
        //return new Schema\Grammar();
325 48
    }
326
327
    /**
328
     * Reconnect to the database if connection is missing.
329
     *
330
     * @return void
331
     */
332 48
    protected function reconnectIfMissingConnection()
333
    {
334 48
        if (is_null($this->session)) {
335 1
            $this->session = $this->createCluster()->connect($this->keyspace);
336
        }
337 48
    }
338
339
    /**
340
     * Dynamically pass methods to the connection.
341
     *
342
     * @param  string  $method
343
     * @param  array   $parameters
344
     * @return mixed
345
     */
346 1
    public function __call($method, $parameters)
347
    {
348 1
        return call_user_func_array([$this->session, $method], $parameters);
349
    }
350
351
    /**
352
     * Execute an CQL statement and return the boolean result.
353
     *
354
     * @param string $query
355
     * @param array $bindings
356
     * @param array $customOptions
357
     * @param mixed $defaultFailed
358
     * @param mixed $defaultSuccess
359
     *
360
     * @return mixed
361
     */
362
    protected function runStatement($query, $bindings = [], array $customOptions = [], $defaultFailed = [], $defaultSuccess = null)
363
    {
364 48
        return $this->run($query, $bindings, function ($query, $bindings) use ($customOptions, $defaultFailed, $defaultSuccess) {
365 48
            if ($this->pretending()) {
366 2
                return $defaultFailed;
367
            }
368
369 48
            $preparedStatement = $this->session->prepare($query);
370
371
            //Add bindings
372 48
            $customOptions['arguments'] = $bindings;
373
374 48
            $result = $this->session->execute($preparedStatement, $customOptions);
375
376 48
            return $defaultSuccess === null ? $result : $defaultSuccess;
377 48
        });
378
    }
379
380
    /**
381
     * @inheritDoc
382
     */
383 1
    public function transaction(\Closure $callback, $attempts = 1)
384
    {
385 1
        throw new CassandraNotSupportedException("Transactions is not supported by Cassandra database");
386
    }
387
388
    /**
389
     * @inheritDoc
390
     */
391 1
    public function beginTransaction()
392
    {
393 1
        throw new CassandraNotSupportedException("Transactions is not supported by Cassandra database");
394
    }
395
396
    /**
397
     * @inheritDoc
398
     */
399 1
    public function commit()
400
    {
401 1
        throw new CassandraNotSupportedException("Transactions is not supported by Cassandra database");
402
    }
403
404
    /**
405
     * @inheritDoc
406
     */
407 1
    public function rollBack()
408
    {
409 1
        throw new CassandraNotSupportedException("Transactions is not supported by Cassandra database");
410
    }
411
412
    /**
413
     * @inheritDoc
414
     */
415 1
    public function transactionLevel()
416
    {
417 1
        throw new CassandraNotSupportedException("Transactions is not supported by Cassandra database");
418
    }
419
420
    //TODO: override isDoctrineAvailable method
421
    //TODO: override getDoctrineColumn method
422
    //TODO: override getDoctrineSchemaManager method
423
    //TODO: override getDoctrineConnection method
424
    //TODO: override getPdo method
425
    //TODO: override getReadPdo method
426
    //TODO: override setPdo method
427
    //TODO: override setReadPdo method
428
    //TODO: override setReconnector method
429
    //TODO: override reconnect method
430
    //TODO: override query method
431
432
    //TODO: override bindValues method
433
    //TODO: override cursor method
434
    //TODO: override unprepared method
435
436
    //TODO: check prepareBindings method
437
438
    //TODO: provide interface for $this->session->executeAsync
439
    //TODO: provide interface for $this->session->prepareAsync
440
    //TODO: provide interface for $this->session->closeAsync
441
    //TODO: provide interface for $this->session->schema
442
}
443