Test Setup Failed
Push — testing ( cb849e...32e40e )
by Roman
02:52
created

Connection::beginTransaction()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

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