Completed
Push — master ( 89deac...cf3c32 )
by Bas
02:49
created

Connection::getArangoConnection()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 1
c 1
b 0
f 0
dl 0
loc 3
rs 10
cc 1
nc 1
nop 0
1
<?php
2
3
namespace LaravelFreelancerNL\Aranguent;
4
5
use ArangoDBClient\Exception;
6
use ArangoDBClient\Statement;
7
use ArangoDBClient\Connection as ArangoConnection;
8
use ArangoDBClient\GraphHandler as ArangoGraphHandler;
9
use ArangoDBClient\UserHandler as ArangoUserHandler;
10
use Illuminate\Database\Connection as IlluminateConnection;
11
use ArangoDBClient\DocumentHandler as ArangoDocumentHandler;
12
use Iterator;
13
use LaravelFreelancerNL\Aranguent\Concerns\DetectsDeadlocks;
14
use LaravelFreelancerNL\Aranguent\Query\Processor;
15
use LaravelFreelancerNL\Aranguent\Concerns\ManagesTransactions;
16
use ArangoDBClient\CollectionHandler as ArangoCollectionHandler;
17
use ArangoDBClient\ConnectionOptions as ArangoConnectionOptions;
18
use ArangoDBClient\ViewHandler as ArangoViewHandler;
19
use LaravelFreelancerNL\Aranguent\Query\Builder as QueryBuilder;
20
use LaravelFreelancerNL\Aranguent\Concerns\DetectsLostConnections;
21
use LaravelFreelancerNL\Aranguent\Schema\Builder as SchemaBuilder;
22
use LaravelFreelancerNL\Aranguent\Query\Grammar as QueryGrammar;
23
use LaravelFreelancerNL\FluentAQL\QueryBuilder as FluentAQL;
24
25
class Connection extends IlluminateConnection
26
{
27
    use DetectsDeadlocks,
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...
28
        DetectsLostConnections,
29
        ManagesTransactions;
30
31
    /**
32
     * {@inheritdoc}
33
     *
34
     * @var array
35
     */
36
    protected $defaultConfig = [
37
        ArangoConnectionOptions::OPTION_ENDPOINT => 'tcp://localhost:8529',
38
        ArangoConnectionOptions::OPTION_CONNECTION  => 'Keep-Alive',
39
        ArangoConnectionOptions::OPTION_AUTH_USER => null,
40
        ArangoConnectionOptions::OPTION_AUTH_PASSWD => null,
41
        'tablePrefix' => '',
42
    ];
43
44
    protected $config;
45
46
    protected $arangoConnection;
47
48
    protected $readArangoConnection;
49
50
    protected $reconnector;
51
52
    protected $database;
53
54
    protected $schemaGrammar;
55
56
    protected $queryGrammar;
57
58
    protected $pretending;
59
60
    protected $recordsModified;
61
62
    protected $loggingQueries;
63
64
    protected $queryLog;
65
66
    protected $collectionHandler;
67
68
    protected $viewHandler;
69
70
    protected $documentHandler;
71
72
    protected $graphHandler;
73
74
    protected $userHandler;
75
76
    /**
77
     * The ArangoDB driver name.
78
     *
79
     * @var string
80
     */
81
    protected $driverName = 'arangodb';
82
83
    /**
84
     * Connection constructor.
85
     *
86
     * @param array $config
87
     * @throws Exception
88
     */
89
    public function __construct($config = [])
90
    {
91
        $this->config = array_merge($this->defaultConfig, $config);
92
93
        if (isset($this->config ['database'])) {
94
            $this->database = $this->config ['database'];
95
        }
96
97
        $this->tablePrefix = $this->config['tablePrefix'];
98
99
        // activate and set the database client connection
100
        $this->arangoConnection = new ArangoConnection($this->config);
101
102
        // We need to initialize a query grammar and the query post processors
103
        // which are both very important parts of the database abstractions
104
        // so we initialize these to their default values while starting.
105
        $this->useDefaultQueryGrammar();
106
107
        $this->useDefaultPostProcessor();
108
    }
109
110
    /**
111
     * Get a schema builder instance for the connection.
112
     *
113
     * @return \LaravelFreelancerNL\Aranguent\Schema\Builder
114
     */
115
    public function getSchemaBuilder()
116
    {
117
        if (is_null($this->schemaGrammar)) {
118
            $this->useDefaultSchemaGrammar();
119
        }
120
121
        return new SchemaBuilder($this);
122
    }
123
124
    /**
125
     * Get the default query grammar instance.
126
     *
127
     * @return QueryGrammar
128
     */
129
    protected function getDefaultQueryGrammar()
130
    {
131
        return new QueryGrammar;
132
    }
133
134
    /**
135
     * Get the default post processor instance.
136
     *
137
     * @return Processor
138
     */
139
    protected function getDefaultPostProcessor()
140
    {
141
        return new Processor;
142
    }
143
144
    /**
145
     * Run a select statement against the database and returns a generator.
146
     * ($useReadPdo is a dummy to adhere to the interface).
147
     *
148
     * @param string $query
149
     * @param array $bindings
150
     * @param bool $useReadPdo
151
     * @param array|null $transactionCollections
152
     * @return Iterator|null
153
     * @throws Exception
154
     */
155
    public function cursor($query, $bindings = [], $useReadPdo = null, $transactionCollections = null)
156
    {
157
        return $this->run($query, $bindings, function ($query, $bindings) use ($transactionCollections) {
158
            if ($this->pretending()) {
159
                return [];
160
            }
161
            if ($this->transactionLevel() > 0) {
162
                $this->addQueryToTransaction($query, $bindings, $transactionCollections);
163
164
                return [];
165
            }
166
167
            $statement = $this->newArangoStatement($query, $bindings);
168
            return $statement->execute();
169
170
        });
171
    }
172
173
    /**
174
     * Execute an AQL statement and return the boolean result.
175
     *
176
     * @param  string|FluentAQL  $query
177
     * @param  array   $bindings
178
     * @param  array|null   $transactionCollections
179
     * @return bool
180
     */
181
    public function statement($query, $bindings = [], $transactionCollections = null)
182
    {
183
        if ($query instanceof FluentAQL) {
184
            $bindings = $query->binds;
185
            $transactionCollections = $query->collections;
186
            $query = $query->query;
187
        }
188
189
        return $this->run($query, $bindings, function ($query, $bindings) use ($transactionCollections) {
190
            if ($this->pretending()) {
191
                return true;
192
            }
193
            if ($this->transactionLevel() > 0) {
194
                $this->addQueryToTransaction($query, $bindings, $transactionCollections);
195
196
                return true;
197
            }
198
199
            $statement = $this->newArangoStatement($query, $bindings);
200
201
            $cursor = $statement->execute();
202
203
            $affectedDocumentCount = $cursor->getWritesExecuted();
204
            $this->recordsHaveBeenModified($changed = $affectedDocumentCount > 0);
205
206
            return $changed;
207
        });
208
    }
209
210
    /**
211
     * Run an AQL statement and get the number of rows affected.
212
     *
213
     * @param  string|FluentAQL  $query
214
     * @param  array   $bindings
215
     * @param  array|null   $transactionCollections
216
     * @return int
217
     */
218
    public function affectingStatement($query, $bindings = [], $transactionCollections = null)
219
    {
220
        if ($query instanceof FluentAQL) {
221
            $bindings = $query->binds;
222
            $transactionCollections = $query->collections;
223
            $query = $query->query;
224
        }
225
226
        return $this->run($query, $bindings, function ($query, $bindings) use ($transactionCollections) {
227
            if ($this->pretending()) {
228
                return 0;
229
            }
230
            if ($this->transactionLevel() > 0) {
231
                $this->addQueryToTransaction($query, $bindings, $transactionCollections);
232
233
                return 0;
234
            }
235
236
            // For update or delete statements, we want to get the number of rows affected
237
            // by the statement and return that back to the developer. We'll first need
238
            // to execute the statement and get the executed writes from the extra.
239
            $statement = $this->newArangoStatement($query, $bindings);
240
241
            $cursor = $statement->execute();
242
243
            $affectedDocumentCount = $cursor->getWritesExecuted();
244
245
            $this->recordsHaveBeenModified($affectedDocumentCount > 0);
246
247
            return $affectedDocumentCount;
248
        });
249
    }
250
251
    /**
252
     * Run a raw, unprepared query against the connection.
253
     *
254
     * @param string $query
255
     * @param array|null $collections
256
     * @return bool
257
     * @throws Exception
258
     */
259
    public function unprepared($query)
260
    {
261
        return $this->run($query, [], function ($query) {
262
            if ($this->pretending()) {
263
                return true;
264
            }
265
            if ($this->transactionLevel() > 0) {
266
                $this->addQueryToTransaction($query);
267
268
                return [];
269
            }
270
271
            $statement = $this->newArangoStatement($query, []);
272
273
            $cursor = $statement->execute();
274
275
            $affectedDocumentCount = $cursor->getWritesExecuted();
276
277
            $change = $affectedDocumentCount > 0;
278
279
            $this->recordsHaveBeenModified($change);
280
281
            return $change;
282
        });
283
    }
284
285
    /**
286
     * Returns the query execution plan. The query will not be executed.
287
     *
288
     * @param string $query
289
     * @param array $bindings
290
     * @return array
291
     * @throws Exception
292
     */
293
    public function explain($query, $bindings = [])
294
    {
295
        $statement = $this->newArangoStatement($query, $bindings);
296
297
        return $statement->explain();
298
    }
299
300
    /**
301
     * Run a select statement against the database.
302
     *
303
     * @param string|FluentAQL $query
304
     * @param array $bindings
305
     * @param bool $useReadPdo
306
     * @param null|array $transactionCollections
307
     * @return array
308
     */
309
    public function select($query, $bindings = [], $useReadPdo = true, $transactionCollections = null)
310
    {
311
        return $this->execute($query, $bindings, $useReadPdo, $transactionCollections);
312
    }
313
314
    /**
315
     * Run an AQL query against the database and return the results.
316
     *
317
     * @param string|FluentAQL $query
318
     * @param array $bindings
319
     * @param bool $useReadPdo
320
     * @param null|array $transactionCollections
321
     * @return array
322
     */
323
    public function execute($query, $bindings = [], $useReadPdo = true, $transactionCollections = null)
0 ignored issues
show
Unused Code introduced by
The parameter $transactionCollections is not used and could be removed. ( Ignorable by Annotation )

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

323
    public function execute($query, $bindings = [], $useReadPdo = true, /** @scrutinizer ignore-unused */ $transactionCollections = null)

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Unused Code introduced by
The parameter $useReadPdo is not used and could be removed. ( Ignorable by Annotation )

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

323
    public function execute($query, $bindings = [], /** @scrutinizer ignore-unused */ $useReadPdo = true, $transactionCollections = null)

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
324
    {
325
        if ($query instanceof FluentAQL) {
326
            $bindings = $query->binds;
327
            $transactionCollections = $query->collections;
0 ignored issues
show
Unused Code introduced by
The assignment to $transactionCollections is dead and can be removed.
Loading history...
328
            $query = $query->query;
329
        }
330
331
        return $this->run($query, $bindings, function ($query, $bindings, $transactionCollections= null) {
332
            if ($this->pretending()) {
333
                return [];
334
            }
335
            if ($this->transactionLevel() > 0) {
336
                $this->addQueryToTransaction($query, $bindings, $transactionCollections);
337
338
                return [];
339
            }
340
341
            $statement = $this->newArangoStatement($query, $bindings);
342
            $cursor = $statement->execute();
343
344
            return $cursor->getAll();
345
        });
346
    }
347
348
    /**
349
     * Run an insert statement against the database.
350
     *
351
     * @param  string|FluentAQL  $query
352
     * @param  array   $bindings
353
     * @param  array|null   $transactionCollections
354
     * @return bool
355
     */
356
    public function insert($query, $bindings = [], $transactionCollections = null)
357
    {
358
        return $this->statement($query, $bindings, $transactionCollections);
359
    }
360
361
    /**
362
     * Run an update statement against the database.
363
     *
364
     * @param  string|FluentAQL  $query
365
     * @param  array   $bindings
366
     * @param  array|null   $transactionCollections
367
     * @return int
368
     */
369
    public function update($query, $bindings = [], $transactionCollections = null)
370
    {
371
372
        return $this->affectingStatement($query, $bindings, $transactionCollections);
373
    }
374
375
    /**
376
     * Run a delete statement against the database.
377
     *
378
     * @param  string  $query
379
     * @param  array   $bindings
380
     * @param  array|null   $transactionCollections
381
     * @return int
382
     */
383
    public function delete($query, $bindings = [], $transactionCollections = null)
384
    {
385
        return $this->affectingStatement($query, $bindings, $transactionCollections);
386
    }
387
388
    /**
389
     * Get a new query builder instance.
390
     *
391
     * @return QueryBuilder
392
     */
393
    public function query()
394
    {
395
        return new QueryBuilder(
396
            $this, $this->getQueryGrammar(), $this->getPostProcessor()
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

396
            $this, /** @scrutinizer ignore-type */ $this->getQueryGrammar(), $this->getPostProcessor()
Loading history...
397
        );
398
    }
399
400
    /**
401
     * Get the collection prefix for the connection.
402
     *
403
     * @return string
404
     */
405
    public function getTablePrefix()
406
    {
407
        return $this->tablePrefix;
408
    }
409
410
    /**
411
     * Disconnect from the underlying ArangoDB connection.
412
     *
413
     * @return void
414
     */
415
    public function disconnect()
416
    {
417
        $this->transactions = 0;
418
419
        $this->arangoConnection = null;
420
    }
421
422
    /**
423
     * Reconnect to the database if a Arango connection is missing.
424
     *
425
     * @return void
426
     */
427
    protected function reconnectIfMissingConnection()
428
    {
429
        if (is_null($this->arangoConnection)) {
430
            $this->reconnect();
431
        }
432
    }
433
434
    public function getArangoConnection()
435
    {
436
        return $this->arangoConnection;
437
    }
438
439
    /**
440
     * @param $query
441
     * @param $bindings
442
     * @param $connection
443
     * @return Statement
444
     * @throws Exception
445
     */
446
    function newArangoStatement($query, $bindings): Statement
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
447
    {
448
        $statement = new Statement($this->arangoConnection, ['query' => $query, 'bindVars' => $bindings]);
449
        $statement->setDocumentClass(Document::class);
450
        return $statement;
451
    }
452
453
    public function getCollectionHandler()
454
    {
455
        if (!isset($this->collectionHandler)) {
456
            $this->collectionHandler = new ArangoCollectionHandler($this->arangoConnection);
457
            $this->collectionHandler->setDocumentClass(Document::class);
458
        }
459
460
        return $this->collectionHandler;
461
    }
462
463
    public function getDocumentHandler()
464
    {
465
        if (!isset($this->documentHandler)) {
466
            $this->documentHandler = new ArangoDocumentHandler($this->arangoConnection);
467
            $this->documentHandler->setDocumentClass(Document::class);
468
        }
469
        return $this->documentHandler;
470
    }
471
472
    public function getUserHandler()
473
    {
474
        if (!isset($this->userHandler)) {
475
            $this->userHandler = new ArangoUserHandler($this->arangoConnection);
476
            $this->userHandler->setDocumentClass(Document::class);
477
        }
478
        return $this->userHandler;
479
    }
480
481
    public function getGraphHandler()
482
    {
483
        if (!isset($this->graphHandler)) {
484
            $this->graphHandler = new ArangoGraphHandler($this->arangoConnection);
485
            $this->graphHandler->setDocumentClass(Document::class);
486
        }
487
        return $this->graphHandler;
488
    }
489
490
    public function getViewHandler()
491
    {
492
        if (!isset($this->viewHandler)) {
493
            $this->viewHandler = new ArangoViewHandler($this->arangoConnection);
494
            $this->viewHandler->setDocumentClass(Document::class);
495
496
        }
497
        return $this->viewHandler;
498
    }
499
500
    public function setDatabase($database)
501
    {
502
        $this->database = $database;
503
    }
504
505
    public function getDatabase()
506
    {
507
        return $this->database;
508
    }
509
}
510