Completed
Branch testing (0dbbaf)
by Roman
08:13
created

Connection::runStatement()   A

Complexity

Conditions 3
Paths 1

Size

Total Lines 17

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 17
rs 9.7
c 0
b 0
f 0
cc 3
nc 1
nop 5
1
<?php
2
3
namespace lroman242\LaravelCassandra;
4
5
use Cassandra;
6
use Cassandra\BatchStatement;
7
8
class Connection extends \Illuminate\Database\Connection
9
{
10
    const DEFAULT_PAGE_SIZE = 5000;
11
    
12
    /**
13
     * The Cassandra keyspace
14
     *
15
     * @var string
16
     */
17
    protected $keyspace;
18
19
    /**
20
     * The Cassandra cluster
21
     *
22
     * @var \Cassandra\Cluster
23
     */
24
    protected $cluster;
25
26
    /**
27
     * The Cassandra connection handler.
28
     *
29
     * @var \Cassandra\Session
30
     */
31
    protected $session;
32
33
    /**
34
     * The config
35
     *
36
     * @var array
37
     */
38
    protected $config;
39
40
    /**
41
     * Create a new database connection instance.
42
     *
43
     * @param  array   $config
44
     */
45
    public function __construct(array $config)
46
    {
47
        $this->config = $config;
48
        if (empty($this->config['page_size'])) {
49
            $this->config['page_size'] = self::DEFAULT_PAGE_SIZE;
50
        }
51
52
        // You can pass options directly to the Cassandra constructor
53
        $options = array_get($config, 'options', []);
54
55
        // Create the connection
56
        $this->cluster = $this->createCluster($config, $options);
57
58
        if (isset($options['database']) || isset($config['keyspace'])) {
59
            $keyspaceName = isset($options['database']) ? $options['database'] : $config['keyspace'];
60
61
            $this->keyspace = $keyspaceName;
62
            $this->session = $this->cluster->connect($keyspaceName);
63
        }
64
65
        $this->useDefaultPostProcessor();
66
67
        $this->useDefaultSchemaGrammar();
68
69
        $this->setQueryGrammar($this->getDefaultQueryGrammar());
70
    }
71
72
    /**
73
     * Begin a fluent query against a database table.
74
     *
75
     * @param  string  $table
76
     * @return Query\Builder
77
     */
78
    public function table($table)
79
    {
80
        $processor = $this->getPostProcessor();
81
82
        $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...
83
84
        return $query->from($table);
85
    }
86
87
    /**
88
     * return Cassandra cluster.
89
     *
90
     * @return \Cassandra\Cluster
91
     */
92
    public function getCassandraCluster()
93
    {
94
        return $this->cluster;
95
    }
96
97
    /**
98
     * return Cassandra Session.
99
     *
100
     * @return \Cassandra\Session
101
     */
102
    public function getCassandraSession()
103
    {
104
        return $this->session;
105
    }
106
107
    /**
108
     * Return the Cassandra keyspace
109
     *
110
     * @return string
111
     */
112
    public function getKeyspace()
113
    {
114
        return $this->keyspace;
115
    }
116
117
    /**
118
     * Create a new Cassandra cluster object.
119
     *
120
     * @param  array   $config
121
     * @param  array   $options
122
     * @return \Cassandra\Cluster
123
     */
124
    protected function createCluster(array $config, array $options)
125
    {
126
        $cluster = Cassandra::cluster();
127
128
        // Check if the credentials are not already set in the options
129 View Code Duplication
        if (!isset($options['username']) && !empty($config['username'])) {
130
            $options['username'] = $config['username'];
131
        }
132 View Code Duplication
        if (!isset($options['password']) && !empty($config['password'])) {
133
            $options['password'] = $config['password'];
134
        }
135
136
        // Authentication
137
        if (isset($options['username']) && isset($options['password'])) {
138
            $cluster->withCredentials($options['username'], $options['password']);
139
        }
140
141
        // Contact Points/Host
142
        if (isset($options['contactpoints']) || (isset($config['host']) && !empty($config['host']))) {
143
            $contactPoints = $config['host'];
144
145
            if (isset($options['contactpoints'])) {
146
                $contactPoints = $options['contactpoints'];
147
            }
148
149
            if (is_array($contactPoints)) {
150
                $contactPoints = implode(',', $contactPoints);
151
            }
152
153
            $contactPoints = !empty($contactPoints) ? $contactPoints : '127.0.0.1';
154
155
            $cluster->withContactPoints($contactPoints);
156
        }
157
158
        if (!isset($options['port']) && !empty($config['port'])) {
159
            $cluster->withPort((int) $config['port']);
160
        }
161
162
        if (array_key_exists('page_size', $config) && !empty($config['page_size'])) {
163
            $cluster->withDefaultPageSize(intval($config['page_size'] ?? self::DEFAULT_PAGE_SIZE));
164
        }
165
166
        if (array_key_exists('consistency', $config) && in_array(strtoupper($config['consistency']), [
167
                Cassandra::CONSISTENCY_ANY, Cassandra::CONSISTENCY_ONE, Cassandra::CONSISTENCY_TWO,
168
                Cassandra::CONSISTENCY_THREE, Cassandra::CONSISTENCY_QUORUM, Cassandra::CONSISTENCY_ALL,
169
                Cassandra::CONSISTENCY_SERIAL, Cassandra::CONSISTENCY_QUORUM, Cassandra::CONSISTENCY_LOCAL_QUORUM,
170
                Cassandra::CONSISTENCY_EACH_QUORUM, Cassandra::CONSISTENCY_LOCAL_SERIAL, Cassandra::CONSISTENCY_LOCAL_ONE,
171
            ])) {
172
            $cluster->withDefaultConsistency($config['consistency']);
173
        }
174
175
        if (array_key_exists('timeout', $config) && !empty($config['timeout'])) {
176
            $cluster->withDefaultTimeout(intval($config['timeout']));
177
        }
178
179
        if (array_key_exists('connect_timeout', $config) && !empty($config['connect_timeout'])) {
180
            $cluster->withConnectTimeout(floatval($config['connect_timeout']));
181
        }
182
183
        if (array_key_exists('request_timeout', $config) && !empty($config['request_timeout'])) {
184
            $cluster->withRequestTimeout(floatval($config['request_timeout']));
185
        }
186
187
        return $cluster->build();
188
    }
189
190
    /**
191
     * Disconnect from the underlying Cassandra connection.
192
     */
193
    public function disconnect()
194
    {
195
        unset($this->connection);
196
    }
197
198
    /**
199
     * Get the PDO driver name.
200
     *
201
     * @return string
202
     */
203
    public function getDriverName()
204
    {
205
        return 'cassandra';
206
    }
207
208
    /**
209
     * Run a select statement against the database.
210
     *
211
     * @param  string  $query
212
     * @param  array  $bindings
213
     * @param  bool  $useReadPdo
214
     * @param  array  $customOptions
215
     *
216
     * @return array
217
     */
218
    public function select($query, $bindings = [], $useReadPdo = true, array $customOptions = [])
219
    {
220
        return $this->runStatement($query, $bindings, $customOptions);
221
    }
222
223
    /**
224
     * Run an bulk insert 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 insertBulk($queries = [], $bindings = [], $type = Cassandra::BATCH_LOGGED, array $customOptions = [])
234
    {
235
        return $this->batchStatement($queries, $bindings, $type, $customOptions);
236
    }
237
238
    /**
239
     * Execute a group of queries inside a batch statement against the database.
240
     *
241
     * @param  array  $queries
242
     * @param  array  $bindings
243
     * @param  int  $type
244
     * @param  array  $customOptions
245
     *
246
     * @return bool
247
     */
248
    public function batchStatement($queries = [], $bindings = [], $type = Cassandra::BATCH_LOGGED, array $customOptions = [])
249
    {
250
        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...
251
            if ($this->pretending()) {
252
                return [];
253
            }
254
255
            $batch = new BatchStatement($type);
256
257
            foreach ($queries as $k => $query) {
258
                $preparedStatement = $this->session->prepare($query);
259
                $batch->add($preparedStatement, $bindings[$k]);
260
            }
261
262
            return $this->session->execute($batch, $customOptions);
263
        });
264
    }
265
266
    /**
267
     * Execute an CQL statement and return the boolean result.
268
     *
269
     * @param  string  $query
270
     * @param  array   $bindings
271
     * @param  array  $customOptions
272
     *
273
     * @return bool
274
     */
275
    public function statement($query, $bindings = [], array $customOptions = [])
276
    {
277
        return $this->runStatement($query, $bindings, $customOptions);
278
    }
279
280
    /**
281
     * Because Cassandra is an eventually consistent database, it's not possible to obtain
282
     * the affected count for statements so we're just going to return 0, based on the idea
283
     * that if the query fails somehow, an exception will be thrown
284
     *
285
     * @param  string  $query
286
     * @param  array   $bindings
287
     * @param  array  $customOptions
288
     *
289
     * @return int
290
     */
291
    public function affectingStatement($query, $bindings = [], array $customOptions = [])
292
    {
293
        return $this->runStatement($query, $bindings, $customOptions, 0, 1);
294
    }
295
296
    /**
297
     * @inheritdoc
298
     */
299
    protected function getDefaultPostProcessor()
300
    {
301
        return new Query\Processor();
302
    }
303
304
    /**
305
     * @inheritdoc
306
     */
307
    protected function getDefaultQueryGrammar()
308
    {
309
        return new Query\Grammar();
310
    }
311
312
    /**
313
     * @inheritdoc
314
     */
315
    protected function getDefaultSchemaGrammar()
316
    {
317
        //return new Schema\Grammar();
318
    }
319
320
    /**
321
     * Reconnect to the database if connection is missing.
322
     *
323
     * @return void
324
     */
325
    protected function reconnectIfMissingConnection()
326
    {
327
        if (is_null($this->session)) {
328
            $this->session = $this->createCluster($this->config, [])->connect($this->keyspace);
329
        }
330
    }
331
332
    /**
333
     * Dynamically pass methods to the connection.
334
     *
335
     * @param  string  $method
336
     * @param  array   $parameters
337
     * @return mixed
338
     */
339
    public function __call($method, $parameters)
340
    {
341
        return call_user_func_array([$this->cluster, $method], $parameters);
342
    }
343
344
    /**
345
     * Execute an CQL statement and return the boolean result.
346
     *
347
     * @param string $query
348
     * @param array $bindings
349
     * @param array $customOptions
350
     * @param mixed $defaultFailed
351
     * @param mixed $defaultSuccess
352
     *
353
     * @return mixed
354
     */
355
    protected function runStatement($query, $bindings = [], array $customOptions = [], $defaultFailed = [], $defaultSuccess = null)
356
    {
357
        return $this->run($query, $bindings, function ($query, $bindings) use ($defaultFailed, $customOptions, $defaultFailed, $defaultSuccess) {
358
            if ($this->pretending()) {
359
                return $defaultFailed;
360
            }
361
362
            $preparedStatement = $this->session->prepare($query);
363
364
            //Add bindings
365
            $customOptions['arguments'] = $bindings;
366
367
            $result = $this->session->execute($preparedStatement, $customOptions);
368
369
            return $defaultSuccess === null ? $result : $defaultSuccess;
370
        });
371
    }
372
}
373