Completed
Push — master ( a45e07...0294bf )
by Agel_Nash
02:52
created

IlluminateDriver   D

Complexity

Total Complexity 58

Size/Duplication

Total Lines 371
Duplicated Lines 0 %

Test Coverage

Coverage 88.32%

Importance

Changes 0
Metric Value
wmc 58
dl 0
loc 371
ccs 121
cts 137
cp 0.8832
rs 4.8387
c 0
b 0
f 0

22 Methods

Rating   Name   Duplication   Size   Complexity  
B useEloquent() 0 20 5
B __construct() 0 39 5
A isResult() 0 3 1
A fieldName() 0 4 3
B getRow() 0 22 5
A getInsertId() 0 3 1
A getAffectedRows() 0 3 1
A getConnect() 0 10 3
A isConnected() 0 3 2
A disconnect() 0 9 2
A escape() 0 9 2
A getCapsule() 0 3 1
A connect() 0 23 3
D query() 0 27 11
A setCharset() 0 8 2
A numFields() 0 3 2
A getLastErrorNo() 0 5 2
A getVersion() 0 3 1
A getRecordCount() 0 3 2
A getLastError() 0 5 2
A hasConnectionName() 0 4 1
A selectDb() 0 5 1

How to fix   Complexity   

Complex Class

Complex classes like IlluminateDriver often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use IlluminateDriver, and based on these observations, apply Extract Interface, too.

1
<?php namespace AgelxNash\Modx\Evo\Database\Drivers;
2
3
use AgelxNash\Modx\Evo\Database\Exceptions;
4
use Illuminate\Database\Capsule\Manager as Capsule;
5
use Illuminate\Database\Connection;
6
use PDOStatement;
7
use Illuminate\Events\Dispatcher;
8
use Illuminate\Contracts\Events\Dispatcher as DispatcherContract;
9
use Illuminate\Container\Container;
10
use ReflectionClass;
11
use PDO;
12
13
/**
14
 * @property Connection $conn
15
 */
16
class IlluminateDriver extends AbstractDriver
17
{
18
    /**
19
     * @var string
20
     */
21
    protected $connection = 'default';
22
23
    /**
24
     * @var Capsule
25
     */
26
    protected $capsule;
27
28
    private $affectedRows = 0;
29
30
    /**
31
     * @var array
32
     */
33
    public $lastError;
34
35
    /**
36
     * @var string
37
     */
38
    public $lastErrorNo;
39
40
    protected $driver = 'mysql';
41
42
    /**
43
     * {@inheritDoc}
44
     */
45 24
    public function __construct(array $config = [], $connection = 'default')
46
    {
47 24
        $reflection = new ReflectionClass(Capsule::class);
48 24
        $property = $reflection->getProperty('instance');
49 24
        $property->setAccessible(true);
50
        /**
51
         * @var Capsule|null $capsule
52
         */
53 24
        $capsule = $property->getValue(Capsule::class);
0 ignored issues
show
Bug introduced by
Illuminate\Database\Capsule\Manager::class of type string is incompatible with the type object expected by parameter $object of ReflectionProperty::getValue(). ( Ignorable by Annotation )

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

53
        $capsule = $property->getValue(/** @scrutinizer ignore-type */ Capsule::class);
Loading history...
54 24
        if ($capsule === null) {
55 1
            $this->capsule = new Capsule;
56
57 1
            $this->getCapsule()->setAsGlobal();
58
        } else {
59 23
            $this->capsule = $capsule;
60
        }
61
62 24
        if ($this->hasConnectionName($connection)) {
63 23
            if (empty($config)) {
64 2
                $config = $this->getCapsule()->getConnection($connection)->getConfig();
65 2
                unset($config['name'], $config['driver']);
66
            } else {
67 21
                $diff = array_diff_assoc(
68 21
                    array_merge(['driver' => $this->driver], $config),
69 21
                    $this->getCapsule()->getConnection($connection)->getConfig()
70
                );
71 21
                if (array_intersect(['driver', 'host', 'database', 'password', 'username'], array_keys($diff))) {
72 1
                    throw new Exceptions\ConnectException(
73 1
                        sprintf('The connection name "%s" is already used', $connection)
74
                    );
75
                }
76
            }
77
        }
78
79 23
        $this->connection = $connection;
80
81 23
        $this->useEloquent();
82
83 23
        $this->config = $config;
84 23
    }
85
86
    /**
87
     * @param DispatcherContract|null $dispatcher
88
     * @return bool
89
     */
90 23
    public function useEloquent(DispatcherContract $dispatcher = null)
91
    {
92 23
        $out = false;
93 23
        if ($dispatcher === null) {
94 23
            $dispatcher = $this->getCapsule()->getEventDispatcher();
95
        }
96
97 23
        if ($dispatcher === null && class_exists(Dispatcher::class)) {
98 4
            $dispatcher = new Dispatcher(new Container);
99
        }
100
101 23
        if ($dispatcher !== null) {
102 23
            $this->getCapsule()->setEventDispatcher($dispatcher);
103
104 23
            $out = true;
105
        }
106
107 23
        $this->getCapsule()->bootEloquent();
108
109 23
        return $out;
110
    }
111
112
    /**
113
     * @return Capsule
114
     */
115 24
    public function getCapsule()
116
    {
117 24
        return $this->capsule;
118
    }
119
120
    /**
121
     * @return Connection
122
     * @throws Exceptions\Exception
123
     */
124 23
    public function getConnect()
125
    {
126 23
        if (! $this->isConnected()) {
127 23
            $this->connect();
128 23
            if (! $this->conn->getPdo() instanceof PDO) {
0 ignored issues
show
Bug introduced by
The method getPdo() does not exist on null. ( Ignorable by Annotation )

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

128
            if (! $this->conn->/** @scrutinizer ignore-call */ getPdo() instanceof PDO) {

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
introduced by
$this->conn->getPdo() is always a sub-type of PDO.
Loading history...
129 1
                $this->conn->reconnect();
130
            }
131
        }
132
133 23
        return $this->conn;
134
    }
135
136
    /**
137
     * @param $name
138
     * @return bool
139
     */
140 24
    public function hasConnectionName($name)
141
    {
142 24
        $connections = $this->getCapsule()->getDatabaseManager()->getConnections();
143 24
        return isset($connections[$name]);
144
    }
145
146
    /**
147
     * @return Connection
148
     * @throws Exceptions\Exception
149
     */
150 23
    public function connect()
151
    {
152
        try {
153 23
            if (! $this->hasConnectionName($this->connection)) {
154 1
                $this->getCapsule()->addConnection([
155 1
                    'driver'    => $this->driver,
156 1
                    'host'      => $this->config['host'],
157 1
                    'database'  => $this->config['database'],
158 1
                    'username'  => $this->config['username'],
159 1
                    'password'  => $this->config['password'],
160 1
                    'charset'   => $this->config['charset'],
161 1
                    'collation' => $this->config['collation'],
162 1
                    'prefix'    => $this->config['prefix'],
163 1
                ], $this->connection);
164
            }
165
166 23
            $this->conn = $this->getCapsule()->getConnection($this->connection);
167
        } catch (\Exception $exception) {
168
            $this->conn = null;
169
            throw new Exceptions\ConnectException($exception->getMessage(), $exception->getCode());
170
        }
171
172 23
        return $this->conn;
173
    }
174
175
    /**
176
     * {@inheritDoc}
177
     */
178 1
    public function disconnect()
179
    {
180 1
        if ($this->isConnected()) {
181 1
            $this->conn->disconnect();
182
        }
183
184 1
        $this->conn = null;
185
186 1
        return $this;
187
    }
188
189
    /**
190
     * @return bool
191
     */
192 23
    public function isConnected()
193
    {
194 23
        return ($this->conn instanceof Connection && $this->conn->getDatabaseName());
195
    }
196
197
    /**
198
     * @param $data
199
     * @return mixed
200
     * @throws Exceptions\Exception
201
     */
202 1
    public function escape($data)
203
    {
204
        /**
205
         * It's not secure
206
         * But need for backward compatibility
207
         */
208
209 1
        $quote = $this->getConnect()->getPdo()->quote($data);
210 1
        return strpos($quote, '\'') === 0 ? mb_substr($quote, 1, -1) : $quote;
211
    }
212
213
    /**
214
     * @return mixed
215
     * @throws Exceptions\Exception
216
     */
217 3
    public function getInsertId()
218
    {
219 3
        return $this->getConnect()->getPdo()->lastInsertId();
220
    }
221
222
    /**
223
     * @return int
224
     * @throws Exceptions\Exception
225
     */
226 8
    public function getAffectedRows()
227
    {
228 8
        return $this->affectedRows;
229
    }
230
231
    /**
232
     * @return string
233
     * @throws Exceptions\Exception
234
     */
235 4
    public function getVersion()
236
    {
237 4
        return $this->getConnect()->getPdo()->getAttribute(\PDO::ATTR_SERVER_VERSION);
238
    }
239
240
    /**
241
     * @param PDOStatement $result
242
     * @return int
243
     */
244 10
    public function getRecordCount($result)
245
    {
246 10
        return $this->isResult($result) ? $result->rowCount() : 0;
247
    }
248
249
    /**
250
     * {@inheritDoc}
251
     */
252 20
    public function setCharset($charset, $collation, $method = null)
253
    {
254 20
        if ($method === null) {
255
            $method = $this->config['method'];
256
        }
257 20
        $query = $method . ' ' . $charset . ' COLLATE ' . $collation;
258
259 20
        return (bool)$this->query($query);
260
    }
261
262
    /**
263
     * @param $result
264
     * @return bool
265
     */
266 20
    public function isResult($result)
267
    {
268 20
        return $result instanceof PDOStatement;
269
    }
270
271
    /**
272
     * @param PDOStatement $result
273
     * @return int
274
     */
275 1
    public function numFields($result)
276
    {
277 1
        return $this->isResult($result) ? $result->columnCount() : 0;
278
    }
279
280
    /**
281
     * @param PDOStatement $result
282
     * @param int $col
283
     * @return string|null
284
     */
285 1
    public function fieldName($result, $col = 0)
286
    {
287 1
        $field = $this->isResult($result) ? $result->getColumnMeta($col) : [];
288 1
        return isset($field['name']) ? $field['name'] : null;
289
    }
290
291
    /**
292
     * @param string $name
293
     * @return bool
294
     * @throws Exceptions\Exception
295
     */
296
    public function selectDb($name)
297
    {
298
        $this->getConnect()->setDatabaseName($name);
299
300
        return true;
301
    }
302
303
    /**
304
     * @param PDOStatement $result
305
     * @param string $mode
306
     * @return array|mixed|object|\stdClass
307
     * @throws Exceptions\Exception
308
     */
309 8
    public function getRow($result, $mode = 'assoc')
310
    {
311
        switch ($mode) {
312 8
            case 'assoc':
313 6
                $out = $result->fetch(\PDO::FETCH_ASSOC);
314 6
                break;
315 3
            case 'num':
316 3
                $out = $result->fetch(\PDO::FETCH_NUM);
317 3
                break;
318
            case 'object':
319
                $out = $result->fetchObject();
320
                break;
321
            case 'both':
322
                $out = $result->fetch(\PDO::FETCH_BOTH);
323
                break;
324
            default:
325
                throw new Exceptions\UnknownFetchTypeException(
326
                    "Unknown get type ($mode) specified for fetchRow - must be empty, 'assoc', 'num' or 'both'."
327
                );
328
        }
329
330 8
        return $out;
331
    }
332
333
    /**
334
     * @param string $query
335
     * @return mixed
336
     * @throws Exceptions\Exception
337
     */
338 20
    public function query($query)
339
    {
340 20
        $result = null;
0 ignored issues
show
Unused Code introduced by
The assignment to $result is dead and can be removed.
Loading history...
341
        try {
342 20
            $result = $this->getConnect()->getPdo()->prepare(
343 20
                $query,
344
                [
345 20
                    \PDO::ATTR_CURSOR => \PDO::CURSOR_SCROLL
346
                ]
347
            );
348 20
            $result->setFetchMode(\PDO::FETCH_ASSOC);
349 20
            if ($result->execute() === false) {
350
                $result = false;
351
            }
352 20
            $this->affectedRows = \is_bool($result) ? 0 : $result->rowCount();
353 20
            if ($this->affectedRows === 0 && $this->isResult($result) && 0 !== mb_stripos(trim($query), 'SELECT')) {
354 20
                $result = true;
355
            }
356 2
        } catch (\Exception $exception) {
357 2
            $this->lastError = $this->isResult($result) ? $result->errorInfo() : [];
358 2
            $code = $this->isResult($result) ? $result->errorCode() : '';
359 2
            $this->lastErrorNo = $this->isResult($result) ? (empty($code) ? $exception->getCode() : $code) : '';
360 2
            throw (new Exceptions\QueryException($exception->getMessage(), $exception->getCode()))
361 2
                ->setQuery($query);
362
        }
363
364 20
        return $result;
365
    }
366
367
    /**
368
     * @return string|null
369
     * @throws Exceptions\Exception
370
     */
371 1
    public function getLastError()
372
    {
373 1
        $pdo = $this->getConnect()->getPdo();
374 1
        $error = $pdo->errorInfo();
375 1
        return (string)(isset($error[2]) ? $error[2] : $this->lastError[2]);
376
    }
377
378
    /**
379
     * @return string|null
380
     * @throws Exceptions\Exception
381
     */
382 1
    public function getLastErrorNo()
383
    {
384 1
        $pdo = $this->getConnect()->getPdo();
385 1
        $error = $pdo->errorInfo();
386 1
        return (string)(isset($error[1]) ? $error[1] : $this->lastErrorNo);
387
    }
388
}
389