Failed Conditions
Push — refactor/improve-static-analys... ( d71351...8065ea )
by Bas
05:41
created

Connection::reconnect()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 6

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 2
eloc 2
nc 2
nop 0
dl 0
loc 4
ccs 0
cts 0
cp 0
crap 6
rs 10
c 1
b 0
f 0
1
<?php
2
3
declare(strict_types=1);
4
5
namespace LaravelFreelancerNL\Aranguent;
6
7
use ArangoClient\ArangoClient;
8
use Illuminate\Database\Connection as IlluminateConnection;
9
use Illuminate\Database\Schema\Grammars\Grammar as IlluminateGrammar;
10
use LaravelFreelancerNL\Aranguent\Concerns\DetectsDeadlocks;
11
use LaravelFreelancerNL\Aranguent\Concerns\DetectsLostConnections;
12
use LaravelFreelancerNL\Aranguent\Concerns\HandlesArangoDb;
13
use LaravelFreelancerNL\Aranguent\Concerns\ManagesTransactions;
14
use LaravelFreelancerNL\Aranguent\Concerns\RunsQueries;
15
use LaravelFreelancerNL\Aranguent\Query\Grammar as QueryGrammar;
16
use LaravelFreelancerNL\Aranguent\Query\Processor;
17
use LaravelFreelancerNL\Aranguent\Schema\Builder as SchemaBuilder;
18
use LaravelFreelancerNL\FluentAQL\QueryBuilder as ArangoQueryBuilder;
19
use RuntimeException;
20
use Spatie\DataTransferObject\Exceptions\UnknownProperties;
21
22
class Connection extends IlluminateConnection
23
{
24
    use HandlesArangoDb;
25
    use DetectsDeadlocks;
26
    use DetectsLostConnections;
27
    use ManagesTransactions;
28
    use RunsQueries;
0 ignored issues
show
introduced by
The trait LaravelFreelancerNL\Aranguent\Concerns\RunsQueries requires some properties which are not provided by LaravelFreelancerNL\Aranguent\Connection: $binds, $query
Loading history...
29
30
    protected ?ArangoClient $arangoClient = null;
31
32
    protected $database;
33
34
    /**
35
     * The ArangoDB driver name.
36
     */
37
    protected string $driverName = 'arangodb';
38
39
    /**
40
     * Connection constructor.
41
     *
42
     * @param  array<mixed>  $config
43
     *
44 215
     * @throws UnknownProperties
45
     */
46 215
    public function __construct($config = [])
47
    {
48 215
        $this->config = $config;
49 215
50
        $this->database = (isset($this->config['database'])) ? $this->config['database'] : null;
51
        $this->tablePrefix = $this->config['tablePrefix'] ?? null;
52 215
53
        // activate and set the database client connection
54
        $this->arangoClient = new ArangoClient($this->config);
55
56
        // We need to initialize a query grammar and the query post processors
57 215
        // which are both very important parts of the database abstractions
58
        // so, we initialize these to their default values while starting.
59 215
        $this->useDefaultQueryGrammar();
60 215
61
        $this->useDefaultPostProcessor();
62
    }
63
64
    /**
65
     * Get a schema builder instance for the connection.
66
     */
67 163
    public function getSchemaBuilder(): SchemaBuilder
68
    {
69 163
        //        if (!isset($this->schemaGrammar)) {
70
        //            $this->useDefaultSchemaGrammar();
71
        //        }
72
73 163
        return new SchemaBuilder($this);
74
    }
75
76
    /**
77
     * Get the default query grammar instance.
78
     */
79
    //    protected function getDefaultQueryGrammar(): QueryGrammar
80
    //    {
81 215
    //        return new QueryGrammar();
82
    //    }
83 215
84
    /**
85
     * Get the default post processor instance.
86
     */
87
    protected function getDefaultPostProcessor(): Processor
88
    {
89
        return new Processor();
90
    }
91 215
92
    /**
93 215
     * Get the default query grammar instance.
94
     *
95
     * @return QueryGrammar
96
     */
97
    protected function getDefaultQueryGrammar()
98
    {
99
        ($grammar = new QueryGrammar())->setConnection($this);
100
101
        return $grammar;
102
    }
103
104
    /**
105
     * Get the schema grammar used by the connection.
106
     *
107
     * @return IlluminateGrammar
108
     */
109
    public function getSchemaGrammar()
110
    {
111 7
        return $this->schemaGrammar;
112
    }
113 7
114 7
    /**
115
     * Get the collection prefix for the connection.
116
     */
117
    public function getTablePrefix(): string
118
    {
119
        return $this->tablePrefix;
120
    }
121
122
    /**
123 3
     * Disconnect from the underlying ArangoDB connection.
124
     *
125 3
     * @return void
126 3
     */
127
    public function disconnect()
128 3
    {
129
        $this->arangoClient = null;
130 3
    }
131
132
    /**
133
     * Reconnect to the database.
134
     *
135
     * @throws \LogicException
136
     */
137
    public function reconnect()
138
    {
139
        if (is_callable($this->reconnector)) {
140
            return call_user_func($this->reconnector, $this);
141 174
        }
142
    }
143 174
144
    /**
145
     * Reconnect to the database if an ArangoDB connection is missing.
146 174
     *
147
     * @return void
148 175
     */
149
    public function reconnectIfMissingConnection()
150 175
    {
151
        if (is_null($this->arangoClient)) {
152
            $this->reconnect();
153
        }
154
    }
155
156 1
    public function getArangoClient(): ArangoClient|null
157
    {
158 1
        return $this->arangoClient;
159 1
    }
160 1
161
    /**
162 2
     * Set the name of the connected database.
163
     *
164 2
     * @param  string  $database
165
     * @return $this
166
     */
167 4
    public function setDatabaseName($database)
168
    {
169 4
        $this->database = $database;
170
171
        if ($this->arangoClient !== null) {
172
            $this->arangoClient->setDatabase($database);
173
        }
174
175
        return $this;
176
    }
177
178
    public function getDatabaseName(): string
179
    {
180
        return $this->database;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $this->database could return the type null which is incompatible with the type-hinted return string. Consider adding an additional type-check to rule them out.
Loading history...
181
    }
182
183
    public static function aqb(): ArangoQueryBuilder
184
    {
185
        return new ArangoQueryBuilder();
186
    }
187
188
    /**
189
     * Escape a binary value for safe SQL embedding.
190
     *
191
     * @param  string  $value
192
     * @return string
193
     */
194
    protected function escapeBinary($value)
195
    {
196
        if (mb_detect_encoding($value, ['UTF-8'])) {
197
            return $value;
198
        }
199
200
        return base64_encode($value);
201
    }
202
203
    /**
204
     * Escape a value for safe SQL embedding.
205
     *
206
     * @param  array<mixed>|string|float|int|bool|null  $value
207
     * @param  bool  $binary
208
     * @return string
209
     *
210
     * @SuppressWarnings(PHPMD.BooleanArgumentFlag)
211
     */
212
    public function escape($value, $binary = false)
213
    {
214
        if ($value === null) {
215
            return 'null';
216
        } elseif (is_string($value) && $binary === true) {
217
            return $this->escapeBinary($value);
218
        } elseif (is_int($value) || is_float($value)) {
219
            return (string) $value;
220
        } elseif (is_bool($value)) {
221
            return $this->escapeBool($value);
222
        } elseif (is_array($value)) {
223
            return $this->escapeArray($value);
224
        } else {
225
            if (str_contains($value, "\00")) {
226
                throw new RuntimeException('Strings with null bytes cannot be escaped. Use the binary escape option.');
227
            }
228
229
            if (preg_match('//u', $value) === false) {
230
                throw new RuntimeException('Strings with invalid UTF-8 byte sequences cannot be escaped.');
231
            }
232
233
            return $this->escapeString($value);
234
        }
235
    }
236
237
    /**
238
     * Escape an array value for safe SQL embedding.
239
     *
240
     * @param  array<mixed>  $array
241
     * @return string
242
     */
243
    protected function escapeArray(array $array): string
244
    {
245
        foreach($array as $key => $value) {
246
            $array[$key] = $this->escape($value);
247
        }
248
249
        if (array_is_list($array)) {
250
            return '[' . implode(', ', $array) . ']';
251
        }
252
253
        $grammar = $this->getDefaultQueryGrammar();
254
        return $grammar->generateAqlObject($array);
255
    }
256
257
    /**
258
     * Escape a boolean value for safe SQL embedding.
259
     *
260
     * @param  bool  $value
261
     * @return string
262
     */
263
    protected function escapeBool($value)
264
    {
265
        return $value ? 'true' : 'false';
266
    }
267
268
    /**
269
     * Escape a string value for safe SQL embedding.
270
     *
271
     * @param  string  $value
272
     * @return string
273
     */
274
    protected function escapeString($value)
275
    {
276
        return '"' . str_replace(
277
            ['\\', "\0", "\n", "\r", "'", '"', "\x1a"],
278
            ['\\\\', '\\0', '\\n', '\\r', "\\'", '\\"', '\\Z'],
279
            $value
280
        ) . '"';
281
    }
282
283
    /**
284
     * Get the elapsed time since a given starting point.
285
     *
286
     * @param  int|float  $start
287
     * @return float
288
     */
289
    protected function getElapsedTime($start)
290
    {
291
        return round((microtime(true) - $start) * 1000, 2);
292
    }
293
}
294