Failed Conditions
Push — master ( 11c8ec...b620eb )
by Bas
05:48 queued 10s
created

Connection::__construct()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 19
Code Lines 7

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 7
CRAP Score 2.0078

Importance

Changes 2
Bugs 0 Features 0
Metric Value
cc 2
eloc 7
nc 2
nop 1
dl 0
loc 19
ccs 7
cts 8
cp 0.875
crap 2.0078
rs 10
c 2
b 0
f 0
1
<?php
2
3
namespace LaravelFreelancerNL\Aranguent;
4
5
use ArangoDBClient\Connection as ArangoConnection;
6
use ArangoDBClient\ConnectionOptions as ArangoConnectionOptions;
7
use ArangoDBClient\Exception;
8
use ArangoDBClient\Statement;
9
use Illuminate\Database\Connection as IlluminateConnection;
10
use Iterator;
11
use LaravelFreelancerNL\Aranguent\Concerns\DetectsDeadlocks;
12
use LaravelFreelancerNL\Aranguent\Concerns\DetectsLostConnections;
13
use LaravelFreelancerNL\Aranguent\Concerns\HandlesArangoDb;
14
use LaravelFreelancerNL\Aranguent\Concerns\ManagesTransactions;
15
use LaravelFreelancerNL\Aranguent\Query\Builder as QueryBuilder;
16
use LaravelFreelancerNL\Aranguent\Query\Grammar as QueryGrammar;
17
use LaravelFreelancerNL\Aranguent\Query\Processor;
18
use LaravelFreelancerNL\Aranguent\Schema\Builder as SchemaBuilder;
19
use LaravelFreelancerNL\FluentAQL\QueryBuilder as FluentAQL;
20
21
class Connection extends IlluminateConnection
22
{
23
    use HandlesArangoDb;
24
    use DetectsDeadlocks;
25
    use DetectsLostConnections;
26
    use ManagesTransactions;
0 ignored issues
show
Bug introduced by
The trait LaravelFreelancerNL\Aran...rns\ManagesTransactions requires the property $collections which is not provided by LaravelFreelancerNL\Aranguent\Connection.
Loading history...
27
28
    /**
29
     * {@inheritdoc}
30
     *
31
     * @var array
32
     */
33
    protected $defaultConfig = [
34
        ArangoConnectionOptions::OPTION_ENDPOINT    => 'tcp://localhost:8529',
35
        ArangoConnectionOptions::OPTION_CONNECTION  => 'Keep-Alive',
36
        ArangoConnectionOptions::OPTION_AUTH_USER   => null,
37
        ArangoConnectionOptions::OPTION_AUTH_PASSWD => null,
38
        'tablePrefix'                               => '',
39
    ];
40
41
    protected $config;
42
43
    protected $arangoConnection;
44
45
    protected $reconnector;
46
47
    protected $database;
48
49
    protected $schemaGrammar;
50
51
    protected $queryGrammar;
52
53
    protected $pretending;
54
55
    protected $recordsModified;
56
57
    protected $loggingQueries;
58
59
    protected $queryLog;
60
61
    /**
62
     * The ArangoDB driver name.
63
     *
64
     * @var string
65
     */
66
    protected $driverName = 'arangodb';
67
68
    /**
69
     * Connection constructor.
70
     *
71
     * @param array $config
72
     *
73
     * @throws Exception
74
     */
75 121
    public function __construct($config = [])
76
    {
77 121
        $this->config = array_merge($this->defaultConfig, $config);
78
79 121
        if (isset($this->config['database'])) {
80
            $this->database = $this->config['database'];
81
        }
82
83 121
        $this->tablePrefix = $this->config['tablePrefix'];
84
85
        // activate and set the database client connection
86 121
        $this->arangoConnection = new ArangoConnection($this->config);
87
88
        // We need to initialize a query grammar and the query post processors
89
        // which are both very important parts of the database abstractions
90
        // so we initialize these to their default values while starting.
91 121
        $this->useDefaultQueryGrammar();
92
93 121
        $this->useDefaultPostProcessor();
94 121
    }
95
96
    /**
97
     * Get a schema builder instance for the connection.
98
     *
99
     * @return SchemaBuilder
100
     */
101 121
    public function getSchemaBuilder()
102
    {
103 121
        if (is_null($this->schemaGrammar)) {
104
            $this->useDefaultSchemaGrammar();
105
        }
106
107 121
        return new SchemaBuilder($this);
108
    }
109
110
    /**
111
     * Get the default query grammar instance.
112
     *
113
     * @return QueryGrammar
114
     */
115 121
    protected function getDefaultQueryGrammar()
116
    {
117 121
        return new QueryGrammar();
118
    }
119
120
    /**
121
     * Get the default post processor instance.
122
     *
123
     * @return Processor
124
     */
125 121
    protected function getDefaultPostProcessor()
126
    {
127 121
        return new Processor();
128
    }
129
130
    /**
131
     * Run a select statement against the database and returns a generator.
132
     * ($useReadPdo is a dummy to adhere to the interface).
133
     *
134
     * @param string     $query
135
     * @param array      $bindings
136
     * @param bool       $useReadPdo
137
     * @param array|null $transactionCollections
138
     *
139
     * @throws Exception
140
     *
141
     * @return Iterator|null
142
     */
143
    public function cursor($query, $bindings = [], $useReadPdo = null, $transactionCollections = [])
144
    {
145
        // Usage of a separate DB to read date isn't supported at this time
146
        $useReadPdo = null;
0 ignored issues
show
Unused Code introduced by
The assignment to $useReadPdo is dead and can be removed.
Loading history...
147
148
        return $this->run($query, $bindings, function ($query, $bindings) use ($transactionCollections) {
149
            if ($this->pretending()) {
150
                return [];
151
            }
152
            if ($this->transactionLevel() > 0) {
153
                $this->addQueryToTransaction($query, $bindings, $transactionCollections);
154
155
                return [];
156
            }
157
158
            $statement = $this->newArangoStatement($query, $bindings);
159
160
            return $statement->execute();
161
        });
162
    }
163
164
    /**
165
     * Execute an AQL statement and return the boolean result.
166
     *
167
     * @param string|FluentAQL $query
168
     * @param array            $bindings
169
     * @param array|null       $transactionCollections
170
     *
171
     * @return bool
172
     */
173 121
    public function statement($query, $bindings = [], $transactionCollections = [])
174
    {
175 121
        if ($query instanceof FluentAQL) {
176 57
            $bindings = $query->binds;
177 57
            $transactionCollections = $query->collections;
178 57
            $query = $query->query;
179
        }
180
181 121
        return $this->run($query, $bindings, function ($query, $bindings) use ($transactionCollections) {
182 121
            if ($this->pretending()) {
183
                return true;
184
            }
185
186 121
            if ($this->transactionLevel() > 0) {
187
                $this->addQueryToTransaction($query, $bindings, $transactionCollections);
188
189
                return true;
190
            }
191
192 121
            $statement = $this->newArangoStatement($query, $bindings);
193
194 121
            $cursor = $statement->execute();
195
196 121
            $affectedDocumentCount = $cursor->getWritesExecuted();
197 121
            $this->recordsHaveBeenModified($changed = $affectedDocumentCount > 0);
198
199 121
            return $changed;
200 121
        });
201
    }
202
203
    /**
204
     * Run an AQL statement and get the number of rows affected.
205
     *
206
     * @param string|FluentAQL $query
207
     * @param array            $bindings
208
     * @param array|null       $transactionCollections
209
     *
210
     * @return int
211
     */
212 16
    public function affectingStatement($query, $bindings = [], $transactionCollections = [])
213
    {
214 16
        [$query, $bindings, $transactionCollections] = $this->handleQueryBuilder(
215 16
            $query,
216
            $bindings,
217
            $transactionCollections
218
        );
219
220 16
        return $this->run($query, $bindings, function () use ($query, $bindings, $transactionCollections) {
221 16
            if ($this->pretending()) {
222
                return 0;
223
            }
224
225 16
            if ($this->transactionLevel() > 0) {
226
                $this->addQueryToTransaction($query, $bindings, $transactionCollections);
227
228
                return 0;
229
            }
230
231
            // For update or delete statements, we want to get the number of rows affected
232
            // by the statement and return that back to the developer. We'll first need
233
            // to execute the statement and get the executed writes from the extra.
234 16
            $statement = $this->newArangoStatement($query, $bindings);
235
236 16
            $cursor = $statement->execute();
237
238 16
            $affectedDocumentCount = $cursor->getWritesExecuted();
239
240 16
            $this->recordsHaveBeenModified($affectedDocumentCount > 0);
241
242 16
            return $affectedDocumentCount;
243 16
        });
244
    }
245
246
    /**
247
     * Run a raw, unprepared query against the connection.
248
     *
249
     * @param string $query
250
     *
251
     * @return bool
252
     */
253
    public function unprepared($query)
254
    {
255
        return $this->run($query, [], function ($query) {
256
            if ($this->pretending()) {
257
                return true;
258
            }
259
            if ($this->transactionLevel() > 0) {
260
                $this->addQueryToTransaction($query);
261
262
                return [];
263
            }
264
265
            $statement = $this->newArangoStatement($query, []);
266
267
            $cursor = $statement->execute();
268
269
            $affectedDocumentCount = $cursor->getWritesExecuted();
270
271
            $change = $affectedDocumentCount > 0;
272
273
            $this->recordsHaveBeenModified($change);
274
275
            return $change;
276
        });
277
    }
278
279
    /**
280
     * Returns the query execution plan. The query will not be executed.
281
     *
282
     * @param string $query
283
     * @param array  $bindings
284
     *
285
     * @throws Exception
286
     *
287
     * @return array
288
     */
289 1
    public function explain($query, $bindings = [])
290
    {
291 1
        $statement = $this->newArangoStatement($query, $bindings);
292
293 1
        return $statement->explain();
294
    }
295
296
    /**
297
     * Run a select statement against the database.
298
     *
299
     * @SuppressWarnings(PHPMD.BooleanArgumentFlag)
300
     *
301
     * @param string|FluentAQL $query
302
     * @param array            $bindings
303
     * @param bool             $useReadPdo
304
     * @param null|array       $transactionCollections
305
     *
306
     * @return array
307
     */
308 121
    public function select($query, $bindings = [], $useReadPdo = true, $transactionCollections = [])
309
    {
310 121
        return $this->execute($query, $bindings, $useReadPdo, $transactionCollections);
311
    }
312
313
    /**
314
     * Run an AQL query against the database and return the results.
315
     *
316
     * @SuppressWarnings(PHPMD.BooleanArgumentFlag)
317
     *
318
     * @param string|FluentAQL $query
319
     * @param array            $bindings
320
     * @param bool             $useReadPdo
321
     * @param null|array       $transactionCollections
322
     *
323
     * @return array
324
     */
325 121
    public function execute($query, $bindings = [], $useReadPdo = true, $transactionCollections = [])
326
    {
327
        // Usage of a separate DB to read date isn't supported at this time
328 121
        $useReadPdo = null;
0 ignored issues
show
Unused Code introduced by
The assignment to $useReadPdo is dead and can be removed.
Loading history...
329
330 121
        if ($query instanceof FluentAQL) {
331 48
            $bindings = $query->binds;
332
//            $transactionCollections = $query->collections;
333 48
            $query = $query->query;
334
        }
335
336 121
        return $this->run($query, $bindings, function () use ($query, $bindings, $transactionCollections) {
337 121
            if ($this->pretending()) {
338
                return [];
339
            }
340 121
            if ($this->transactionLevel() > 0) {
341
                $this->addQueryToTransaction($query, $bindings, $transactionCollections);
342
343
                return [];
344
            }
345
346 121
            $statement = $this->newArangoStatement($query, $bindings);
347 121
            $cursor = $statement->execute();
348
349 121
            return $cursor->getAll();
350 121
        });
351
    }
352
353
    /**
354
     * Run an insert statement against the database.
355
     *
356
     * @param string|FluentAQL $query
357
     * @param array            $bindings
358
     * @param array|null       $transactionCollections
359
     *
360
     * @return bool
361
     */
362 121
    public function insert($query, $bindings = [], $transactionCollections = [])
363
    {
364 121
        return $this->statement($query, $bindings, $transactionCollections);
365
    }
366
367
    /**
368
     * Run an update statement against the database.
369
     *
370
     * @param string|FluentAQL $query
371
     * @param array            $bindings
372
     * @param array|null       $transactionCollections
373
     *
374
     * @return int
375
     */
376 12
    public function update($query, $bindings = [], $transactionCollections = [])
377
    {
378 12
        return $this->affectingStatement($query, $bindings, $transactionCollections);
379
    }
380
381
    /**
382
     * Run a delete statement against the database.
383
     *
384
     * @param string     $query
385
     * @param array      $bindings
386
     * @param array|null $transactionCollections
387
     *
388
     * @return int
389
     */
390 6
    public function delete($query, $bindings = [], $transactionCollections = [])
391
    {
392 6
        return $this->affectingStatement($query, $bindings, $transactionCollections);
393
    }
394
395
    /**
396
     * Get a new query builder instance.
397
     *
398
     * @return QueryBuilder
399
     */
400 58
    public function query()
401
    {
402 58
        return new QueryBuilder(
403 58
            $this,
404 58
            $this->getQueryGrammar(),
0 ignored issues
show
Bug introduced by
$this->getQueryGrammar() of type Illuminate\Database\Query\Grammars\Grammar is incompatible with the type LaravelFreelancerNL\Aranguent\Query\Grammar|null expected by parameter $grammar of LaravelFreelancerNL\Aran...\Builder::__construct(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

404
            /** @scrutinizer ignore-type */ $this->getQueryGrammar(),
Loading history...
405 58
            $this->getPostProcessor()
406
        );
407
    }
408
409
    /**
410
     * Get the collection prefix for the connection.
411
     *
412
     * @return string
413
     */
414
    public function getTablePrefix()
415
    {
416
        return $this->tablePrefix;
417
    }
418
419
    /**
420
     * Disconnect from the underlying ArangoDB connection.
421
     *
422
     * @return void
423
     */
424
    public function disconnect()
425
    {
426
        $this->transactions = 0;
427
428
        $this->arangoConnection = null;
429
    }
430
431
    /**
432
     * Reconnect to the database if a Arango connection is missing.
433
     *
434
     * @return void
435
     */
436 121
    protected function reconnectIfMissingConnection()
437
    {
438 121
        if (is_null($this->arangoConnection)) {
439
            $this->reconnect();
440
        }
441 121
    }
442
443 121
    public function getArangoConnection()
444
    {
445 121
        return $this->arangoConnection;
446
    }
447
448
    /**
449
     * @param $query
450
     * @param $bindings
451
     * @return Statement
452
     * @throws Exception
453
     */
454 121
    protected function newArangoStatement($query, $bindings): Statement
455
    {
456 121
        $statement = new Statement($this->arangoConnection, ['query' => $query, 'bindVars' => $bindings]);
457 121
        $statement->setDocumentClass(Document::class);
458
459 121
        return $statement;
460
    }
461
462
463 121
    public function setDatabaseName($database)
464
    {
465 121
        $this->database = $database;
466 121
        $this->arangoConnection->setDatabase($database);
467 121
    }
468
469 1
    public function getDatabaseName()
470
    {
471 1
        return $this->database;
472
    }
473
474
    /**
475
     * @param  FluentAQL|string  $query
476
     * @param  array  $bindings
477
     * @param  array|null  $transactionCollections
478
     * @return array
479
     */
480 17
    private function handleQueryBuilder($query, array $bindings, ?array $transactionCollections)
481
    {
482 17
        if ($query instanceof FluentAQL) {
483 15
            $bindings = $query->binds;
484 15
            $transactionCollections = $query->collections;
485 15
            $query = $query->query;
486
        }
487 17
        return [$query, $bindings, $transactionCollections];
488
    }
489
}
490