Connection::getDefaultQueryGrammar()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 0
Metric Value
cc 1
eloc 2
nc 1
nop 0
dl 0
loc 4
rs 10
c 0
b 0
f 0
ccs 0
cts 0
cp 0
crap 2
1
<?php
2
/**
3
 * @author Donii Sergii <[email protected]>
4
 */
5
6
namespace sonrac\Arango;
7
8
use ArangoDBClient\CollectionHandler as ArangoDBCollectionHandler;
9
use ArangoDBClient\Connection as ArangoDBConnection;
10
use ArangoDBClient\ConnectionOptions as ArangoDBConnectionOptions;
11
use ArangoDBClient\Document;
12
use ArangoDBClient\Exception as ArangoException;
13
use ArangoDBClient\Statement;
14
use ArangoDBClient\UpdatePolicy as ArangoDBUpdatePolicy;
15
use Illuminate\Database\Connection as IlluminateConnection;
16
use sonrac\Arango\Query\Grammars\Grammar;
17
use sonrac\Arango\Query\Processors\Processor;
18
use sonrac\Arango\Query\QueryBuilder;
19
20
/**
21
 * Class Connection.
22
 * Arango connection.
23
 *
24
 * @author  Donii Sergii <[email protected]>
25
 */
26
class Connection extends IlluminateConnection
27
{
28
    /**
29
     * Arango.DB Query Builder
30
     *
31
     * @var
32
     *
33
     * @author Donii Sergii <[email protected]>
34
     */
35
    protected $db;
36
37
    protected $database = '_system';
38
39
    /**
40
     * Arango.DB connection
41
     *
42
     * @var \ArangoDBClient\Connection
43
     *
44
     * @author Donii Sergii <[email protected]>
45
     */
46
    protected $arangoConnection;
47
48
    /**
49
     * Connection constructor.
50 11
     *
51
     * @param array $config Connection options
52 11
     *
53
     * @throws ArangoException
54 11
     *
55
     * @author Donii Sergii <[email protected]>
56 11
     */
57 11
    public function __construct(array $config = [])
58
    {
59
        $this->config = $config;
60
61
        $this->arangoConnection = $this->createConnection();
62
63
        $this->db = new ArangoDBCollectionHandler($this->arangoConnection);
64
65
        // We need to initialize a query grammar and the query post processors
66 1
        // which are both very important parts of the database abstractions
67
        // so we initialize these to their default values while starting.
68 1
        $this->useDefaultQueryGrammar();
69
70
        $this->useDefaultPostProcessor();
71
    }
72
73
    /**
74
     * Send AQL request to ArangoDB and return response with flat array
75
     *
76
     * @param string $query
77
     * @param array $bindings
78 1
     * @param bool $useReadPdo
79
     * @return mixed
80 1
     */
81
    public function select($query, $bindings = [], $useReadPdo = true)
82
    {
83
        return $this->run($query, $bindings, function ($query, $bindings) use ($useReadPdo) {
84
            if ($this->pretending()) {
85
                return [];
86
            }
87
88
            $query = $this->prepareBindingsInQuery($query);
89
            $options = [
90
                'query' => $query,
91
                'count' => true,
92 11
                'batchSize' => 1000,
93
                'sanitize'  => true,
94 11
            ];
95
96 11
            if (count($bindings) > 0) {
97
                $options['bindVars'] = $this->prepareBindings($bindings);
98 11
                var_dump($options['bindVars']);
0 ignored issues
show
Security Debugging Code introduced by
var_dump($options['bindVars']); looks like debug code. Are you sure you do not want to remove it? This might expose sensitive data.
Loading history...
99
            }
100
101
            $statement = new Statement($this->getArangoClient(), $options);
102
103
            $cursor = $statement->execute();
104
105
            $resultingDocuments = [];
106
107
            foreach ($cursor as $key => $document) {
0 ignored issues
show
Bug introduced by
The expression $cursor of type object<ArangoDBClient\Cursor>|null is not guaranteed to be traversable. How about adding an additional type check?

There are different options of fixing this problem.

  1. If you want to be on the safe side, you can add an additional type-check:

    $collection = json_decode($data, true);
    if ( ! is_array($collection)) {
        throw new \RuntimeException('$collection must be an array.');
    }
    
    foreach ($collection as $item) { /** ... */ }
    
  2. If you are sure that the expression is traversable, you might want to add a doc comment cast to improve IDE auto-completion and static analysis:

    /** @var array $collection */
    $collection = json_decode($data, true);
    
    foreach ($collection as $item) { /** .. */ }
    
  3. Mark the issue as a false-positive: Just hover the remove button, in the top-right corner of this issue for more options.

Loading history...
108 11
                /* @var Document $document */
109
                $resultingDocuments[$key] = $document->getAll();
110 11
            }
111
112 11
            return $resultingDocuments;
113
        });
114
    }
115
116
    /**
117
     * {@inheritdoc}
118
     */
119
    public function query()
120
    {
121
        return new QueryBuilder(
122 11
            $this, $this->getQueryGrammar(), $this->getPostProcessor()
123
        );
124 11
    }
125
126
    /**
127
     * {@inheritdoc}
128
     */
129 View Code Duplication
    public function statement($query, $bindings = [])
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
130
    {
131
        return $this->run($query, $bindings, function ($query, $bindings) {
132
            if ($this->pretending()) {
133
                return true;
134 11
            }
135
136 11
            $query = $this->prepareBindingsInQuery($query);
137
            $options = [
138
                'query' => $query,
139
                'count' => true,
140
                'batchSize' => 1000,
141
                'sanitize'  => true,
142
            ];
143
144
            if (count($bindings) > 0) {
145
                $options['bindVars'] = $this->prepareBindings($bindings);
146 11
            }
147
148 11
            $statement = new Statement($this->getArangoClient(), $options);
149
150
            return $statement->execute();
151
        });
152
    }
153
154
    /**
155
     * {@inheritdoc}
156
     */
157 View Code Duplication
    public function affectingStatement($query, $bindings = [])
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
158 11
    {
159
        return $this->run($query, $bindings, function ($query, $bindings) {
160 11
            $query = $this->prepareBindingsInQuery($query);
161
162
            $options = [
163
                'query' => $query,
164
                'count' => true,
165
                'batchSize' => 1000,
166
                'sanitize'  => true,
167
            ];
168
169
            if (count($bindings) > 0) {
170 11
                $options['bindVars'] = $this->prepareBindings($bindings);
171
            }
172 11
173
            $statement = new Statement($this->getArangoClient(), $options);
174
175
            return $statement->execute();
176
        });
177
    }
178
179
    /**
180
     * Get Arango.DB
181
     *
182 11
     * @return mixed
183
     *
184 11
     * @author Donii Sergii <[email protected]>
185
     */
186
    public function getArangoDB()
187
    {
188
        return $this->db;
189
    }
190
191
    /**
192
     * Get Arango.DB client
193
     *
194 11
     * @return \ArangoDBClient\Connection
195
     *
196 11
     * @author Donii Sergii <[email protected]>
197
     */
198
    public function getArangoClient()
199
    {
200
        return $this->arangoConnection;
201
    }
202
203
    /**
204
     * Create new arango.db connection.
205
     *
206 11
     * @param array $config Config
207
     *
208 11
     * @return ArangoDBConnection
209
     *
210
     * @throws \ArangoDBClient\Exception
211
     *
212
     * @author Donii Sergii <[email protected]>
213
     */
214
    public function createConnection(array $config = [])
215
    {
216
        $config = $this->config + $config;
217
218 11
        ArangoException::enableLogging();
219
220 11
        return new ArangoDBConnection($this->getMainConnectionOption() + $config);
221
    }
222
223
    /**
224
     * Get database name.
225
     *
226
     * @return string
227
     *
228
     * @author Donii Sergii <[email protected]>
229
     */
230
    public function getDatabaseName()
231
    {
232
        $this->database = $this->getOption(ArangoDBConnectionOptions::OPTION_DATABASE, $this->database);
233 11
234
        return parent::getDatabaseName();
235 11
    }
236 11
237
    /**
238
     * Get arango.db endpoint.
239 11
     *
240
     * @return string
241
     *
242
     * @author Donii Sergii <[email protected]>
243
     */
244
    public function getEndPoint()
245
    {
246
        return $this->getOption(ArangoDBConnectionOptions::OPTION_ENDPOINT, 'tcp://127.0.0.1:8529');
247
    }
248
249 11
    /**
250
     * Get auth type
251
     *
252
     * @return string
253 11
     *
254
     * @author Donii Sergii <[email protected]>
255 11
     */
256
    public function getAuthType()
257 11
    {
258
        return $this->getOption(ArangoDBConnectionOptions::OPTION_AUTH_TYPE, 'Basic');
259 11
    }
260
261 11
    /**
262
     * Get auth type
263 11
     *
264
     * @return string
265 11
     *
266
     * @author Donii Sergii <[email protected]>
267 11
     */
268
    public function getAuthUser()
269 11
    {
270
        return $this->getOption(ArangoDBConnectionOptions::OPTION_AUTH_USER, 'root');
271 11
    }
272
273
    /**
274
     * Get auth type
275
     *
276
     * @return string
277
     *
278
     * @author Donii Sergii <[email protected]>
279
     */
280
    public function getAuthPassword()
281
    {
282
        return $this->getOption(ArangoDBConnectionOptions::OPTION_AUTH_PASSWD, '');
283
    }
284
285
    /**
286
     * Get connection option
287
     *
288
     * @return string
289
     *
290
     * @author Donii Sergii <[email protected]>
291
     */
292
    public function getConnectionOption()
293
    {
294
        return $this->getOption(ArangoDBConnectionOptions::OPTION_CONNECTION, 'Keep-Alive');
295
    }
296
297
    /**
298
     * Get timeout option
299
     *
300
     * @return int
301
     *
302
     * @author Donii Sergii <[email protected]>
303
     */
304
    public function getTimeout()
305
    {
306
        return $this->getOption(ArangoDBConnectionOptions::OPTION_TIMEOUT, 3);
307
    }
308
309
    /**
310
     * Get reconnect option
311
     *
312
     * @return bool
313
     *
314
     * @author Donii Sergii <[email protected]>
315
     */
316
    public function getReconnect()
317
    {
318
        return $this->getOption(ArangoDBConnectionOptions::OPTION_RECONNECT, true);
319
    }
320
321
    /**
322
     * Get create option
323
     *
324
     * @return mixed
325
     *
326
     * @author Donii Sergii <[email protected]>
327
     */
328
    public function getCreate()
329
    {
330
        return $this->getOption(ArangoDBConnectionOptions::OPTION_CREATE, true);
331
    }
332
333
    /**
334
     * Get update policy option
335
     *
336
     * @return string
337
     *
338
     * @author Donii Sergii <[email protected]>
339
     */
340
    public function getUpdatePolicy()
341
    {
342
        return $this->getOption(ArangoDBConnectionOptions::OPTION_UPDATE_POLICY, ArangoDBUpdatePolicy::LAST);
343
    }
344
345
    public function getDefaultQueryGrammar()
346
    {
347
        return new Grammar();
348
    }
349
350
    public function getDefaultPostProcessor()
351
    {
352
        return new Processor();
353
    }
354
355
    protected function prepareBindingsInQuery($query)
356
    {
357
        $query = explode('?', $query);
358
        $result = '';
359
        foreach ($query as $index => $part) {
360
            if ($index === count($query) - 1) {
361
                $result .= $part;
362
                continue;
363
            }
364
            $result .= $part.'@B'.($index + 1);
365
        }
366
        return $result;
367
    }
368
369
    /**
370
     * Reconnect to the database if a PDO connection is missing.
371
     *
372
     * @throws \ArangoDBClient\Exception
373
     * @return void
374
     */
375
    protected function reconnectIfMissingConnection()
376
    {
377
        if (is_null($this->arangoConnection)) {
378
            $this->arangoConnection = $this->createConnection();
379
        }
380
    }
381
382
    /**
383
     * Get option value
384
     *
385
     * @param string $optionName
386
     * @param mixed  $default
387
     *
388
     * @return mixed
389
     *
390
     * @author Donii Sergii <[email protected]>
391
     */
392
    private function getOption($optionName, $default)
393
    {
394
        if (!isset($this->config[$optionName])) {
395
            $this->config[$optionName] = $default;
396
        }
397
398
        return $this->config[$optionName];
399
    }
400
401
    /**
402
     * Get main connection option
403
     *
404
     * @return array
405
     *
406
     * @author Donii Sergii <[email protected]>
407
     */
408
    private function getMainConnectionOption()
409
    {
410
        return [
411
            // database name
412
            ArangoDBConnectionOptions::OPTION_DATABASE      => $this->getDatabaseName(),
413
            // server endpoint to connect to
414
            ArangoDBConnectionOptions::OPTION_ENDPOINT      => $this->getEndPoint(),
415
            // authorization type to use (currently supported: 'Basic')
416
            ArangoDBConnectionOptions::OPTION_AUTH_TYPE     => $this->getAuthType(),
417
            // user for basic authorization
418
            ArangoDBConnectionOptions::OPTION_AUTH_USER     => $this->getAuthUser(),
419
            // password for basic authorization
420
            ArangoDBConnectionOptions::OPTION_AUTH_PASSWD   => $this->getAuthPassword(),
421
            // connection persistence on server. can use either 'Close' (one-time connections) or 'Keep-Alive' (re-used connections)
422
            ArangoDBConnectionOptions::OPTION_CONNECTION    => $this->getConnectionOption(),
423
            // connect timeout in seconds
424
            ArangoDBConnectionOptions::OPTION_TIMEOUT       => $this->getTimeout(),
425
            // whether or not to reconnect when a keep-alive connection has timed out on server
426
            ArangoDBConnectionOptions::OPTION_RECONNECT     => $this->getReconnect(),
427
            // optionally create new collections when inserting documents
428
            ArangoDBConnectionOptions::OPTION_CREATE        => $this->getCreate(),
429
            // optionally create new collections when inserting documents
430
            ArangoDBConnectionOptions::OPTION_UPDATE_POLICY => $this->getUpdatePolicy(),
431
        ];
432
    }
433
}
434