GitHub Access Token became invalid

It seems like the GitHub access token used for retrieving details about this repository from GitHub became invalid. This might prevent certain types of inspections from being run (in particular, everything related to pull requests).
Please ask an admin of your repository to re-new the access token on this website.

Connection::getDatabases()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 5
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 2
Bugs 0 Features 0
Metric Value
eloc 2
c 2
b 0
f 0
dl 0
loc 5
rs 10
cc 1
nc 1
nop 0
1
<?php
2
/**
3
 * This file is part of the O2System Framework package.
4
 *
5
 * For the full copyright and license information, please view the LICENSE
6
 * file that was distributed with this source code.
7
 *
8
 * @author         Steeve Andrian Salim
9
 * @copyright      Copyright (c) Steeve Andrian Salim
10
 */
11
12
// ------------------------------------------------------------------------
13
14
namespace O2System\Database\Sql\Drivers\Sqlite;
15
16
// ------------------------------------------------------------------------
17
18
use O2System\Database\DataStructures\Config;
19
use O2System\Database\Sql\Abstracts\AbstractConnection;
20
use O2System\Database\Sql\DataStructures\Query\Statement;
21
use O2System\Spl\DataStructures\SplArrayObject;
22
23
/**
24
 * Class Connection
25
 *
26
 * @package O2System\Database\Sql\Drivers\Sqlite
27
 */
28
class Connection extends AbstractConnection
29
{
30
    /**
31
     * Connection::$isDeleteHack
32
     *
33
     * DELETE hack flag
34
     *
35
     * Whether to use the Sqlite3 "delete hack" which allows the number
36
     * of affected rows to be shown. Uses a preg_replace when enabled,
37
     * adding a bit more processing to all queries.
38
     *
39
     * @var    bool
40
     */
41
    public $isDeleteHack = false;
42
43
    /**
44
     * Connection::$platform
45
     *
46
     * Database driver platform name.
47
     *
48
     * @var string
49
     */
50
    protected $platform = 'Sqlite3';
51
52
    /**
53
     * Connection::$config
54
     *
55
     * Connection configurations.
56
     *
57
     * @var Config
58
     */
59
    protected $config
60
        = [
61
            'escapeCharacter'     => '`',
62
            'reservedIdentifiers' => ['*'],
63
            'likeEscapeStatement' => ' ESCAPE \'%s\' ',
64
            'likeEscapeCharacter' => '!',
65
        ];
66
67
    /**
68
     * Connection::$handle
69
     *
70
     * Sqlite Connection Instance.
71
     *
72
     * @var \Sqlite3
73
     */
74
    protected $handle;
75
76
    // ------------------------------------------------------------------------
77
78
    /**
79
     * Connection::isSupported
80
     *
81
     * Check if the platform is supported.
82
     *
83
     * @return bool
84
     */
85
    public function isSupported()
86
    {
87
        return extension_loaded('Sqlite3');
88
    }
89
90
    // ------------------------------------------------------------------------
91
92
    /**
93
     * Connection::setDatabase
94
     *
95
     * Set a specific database table to use.
96
     *
97
     * @param string $database Database name.
98
     *
99
     * @return static
100
     */
101
    public function setDatabase($database)
102
    {
103
        $database = empty($database)
104
            ? $this->database
105
            : $database;
106
107
        if (is_file($database)) {
108
            $this->handle->open($database);
109
            $this->database = $database;
110
        }
111
112
        return $this;
113
    }
114
115
    // ------------------------------------------------------------------------
116
117
    /**
118
     * AbstractConnection::getDatabases
119
     *
120
     * Get list of current connection databases.
121
     *
122
     * @return array Returns an array.
123
     */
124
    public function getDatabases()
125
    {
126
        $this->queriesResultCache[ 'databaseNames' ][] = pathinfo($this->database, PATHINFO_FILENAME);
127
128
        return $this->queriesResultCache[ 'databaseNames' ];
129
    }
130
131
    // ------------------------------------------------------------------------
132
133
    /**
134
     * Connection::getTables
135
     *
136
     * Get list of current database tables.
137
     *
138
     * @param bool $prefixLimit If sets TRUE the query will be limit using database table prefix.
139
     *
140
     * @return array Returns an array
141
     * @throws \O2System\Spl\Exceptions\RuntimeException
142
     * @throws \Psr\Cache\InvalidArgumentException
143
     */
144
    public function getTables($prefixLimit = false)
145
    {
146
        if (empty($this->queriesResultCache[ 'tableNames' ])) {
147
148
            $sqlStatement = 'SELECT "NAME" FROM "SQLITE_MASTER" WHERE "TYPE" = \'table\'';
149
150
            if ($prefixLimit !== false && $this->config[ 'tablePrefix' ] !== '') {
151
                $sqlStatement .= ' AND "NAME" LIKE \'' . $this->escapeLikeString($this->config[ 'tablePrefix' ]) . "%' ";
0 ignored issues
show
Bug introduced by
Are you sure $this->escapeLikeString(...>config['tablePrefix']) of type array|string can be used in concatenation? ( Ignorable by Annotation )

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

151
                $sqlStatement .= ' AND "NAME" LIKE \'' . /** @scrutinizer ignore-type */ $this->escapeLikeString($this->config[ 'tablePrefix' ]) . "%' ";
Loading history...
152
            }
153
154
            $result = $this->query($sqlStatement);
155
156
            if ($result->count()) {
157
                foreach ($result as $row) {
158
                    // Do we know from which column to get the table name?
159
                    if ( ! isset($key)) {
160
                        if (isset($row[ 'table_name' ])) {
161
                            $key = 'table_name';
162
                        } elseif (isset($row[ 'TABLE_NAME' ])) {
163
                            $key = 'TABLE_NAME';
164
                        } else {
165
                            /* We have no other choice but to just get the first element's key.
166
                             * Due to array_shift() accepting its argument by reference, if
167
                             * E_STRICT is on, this would trigger a warning. So we'll have to
168
                             * assign it first.
169
                             */
170
                            $key = array_keys($row->getArrayCopy());
171
                            $key = array_shift($key);
172
                        }
173
                    }
174
175
                    $this->queriesResultCache[ 'tableNames' ][] = $row->offsetGet($key);
176
                }
177
            }
178
        }
179
180
        return $this->queriesResultCache[ 'tableNames' ];
181
    }
182
183
    // ------------------------------------------------------------------------
184
185
    /**
186
     * AbstractConnection::getColumns
187
     *
188
     * @param string $table The database table name.
189
     *
190
     * @return array
191
     * @throws \O2System\Spl\Exceptions\RuntimeException
192
     * @throws \Psr\Cache\InvalidArgumentException
193
     */
194
    public function getColumns($table)
195
    {
196
        $table = $this->prefixTable($table);
197
198
        if (empty($this->queriesResultCache[ 'tableColumns' ][ $table ])) {
199
            $result = $this->query('PRAGMA TABLE_INFO(' . $this->protectIdentifiers($table, true, null, false) . ')');
200
201
            if ($result->count()) {
202
                foreach ($result as $row) {
203
                    // Do we know from where to get the column's name?
204
                    if ( ! isset($key)) {
205
                        if (isset($row[ 'name' ])) {
206
                            $key = 'name';
207
                        }
208
                    }
209
210
                    $this->queriesResultCache[ 'tableColumns' ][ $table ][ $row->offsetGet($key) ] = $row;
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $key does not seem to be defined for all execution paths leading up to this point.
Loading history...
211
                }
212
            }
213
        }
214
215
        return $this->queriesResultCache[ 'tableColumns' ][ $table ];
216
    }
217
218
    // ------------------------------------------------------------------------
219
220
    /**
221
     * Connection::getAffectedRows
222
     *
223
     * Get the total number of affected rows from the last query execution.
224
     *
225
     * @return int  Returns total number of affected rows
226
     */
227
    public function getAffectedRows()
228
    {
229
        return $this->handle->changes();
230
    }
231
232
    // ------------------------------------------------------------------------
233
234
    /**
235
     * Connection::getLastInsertId
236
     *
237
     * Get last insert id from the last insert query execution.
238
     *
239
     * @return int  Returns total number of affected rows
240
     */
241
    public function getLastInsertId()
242
    {
243
        return $this->handle->lastInsertRowID();
244
    }
245
246
    //--------------------------------------------------------------------
247
248
    /**
249
     * Connection::platformGetPlatformVersionHandler
250
     *
251
     * Platform getting version handler.
252
     *
253
     * @return SplArrayObject
254
     */
255
    protected function platformGetPlatformInfoHandler()
256
    {
257
        return new SplArrayObject(\Sqlite3::version());
258
    }
259
260
    // ------------------------------------------------------------------------
261
262
    /**
263
     * Connection::platformConnectHandler
264
     *
265
     * Establish the connection.
266
     *
267
     * @param Config $config
268
     *
269
     * @return void
270
     */
271
    protected function platformConnectHandler(Config $config)
272
    {
273
        $this->database = $config->database;
0 ignored issues
show
Bug Best Practice introduced by
The property database does not exist on O2System\Database\DataStructures\Config. Since you implemented __get, consider adding a @property annotation.
Loading history...
274
275
        if ($config->readOnly === true) {
0 ignored issues
show
Bug Best Practice introduced by
The property readOnly does not exist on O2System\Database\DataStructures\Config. Since you implemented __get, consider adding a @property annotation.
Loading history...
276
            $this->handle = new \Sqlite3($config->database, SQLITE3_OPEN_READONLY);
277
        } else {
278
            $this->handle = new \Sqlite3($config->database, SQLITE3_OPEN_READWRITE | SQLITE3_OPEN_CREATE);
279
        }
280
281
        // Enable throwing exceptions
282
        $this->handle->enableExceptions(true);
283
284
        // Set busy timeout
285
        if ($config->offsetExists('busyTimeout')) {
286
            if ($config->busyTimeout != 0) {
0 ignored issues
show
Bug Best Practice introduced by
The property busyTimeout does not exist on O2System\Database\DataStructures\Config. Since you implemented __get, consider adding a @property annotation.
Loading history...
287
                $this->handle->busyTimeout($config->busyTimeout);
288
            }
289
        }
290
    }
291
292
    // ------------------------------------------------------------------------
293
294
    /**
295
     * Connection::executeHandler
296
     *
297
     * Driver dependent way method for execute the Sql statement.
298
     *
299
     * @param Statement $statement Query object.
300
     *
301
     * @return bool
302
     */
303
    protected function platformExecuteHandler(Statement &$statement)
304
    {
305
        if (false !== $this->handle->exec($statement->getSqlFinalStatement())) {
306
            return true;
307
        }
308
309
        // Set query error information
310
        $statement->addError($this->handle->lastErrorCode(), $this->handle->lastErrorMsg());
311
312
        return false;
313
314
    }
315
316
    // ------------------------------------------------------------------------
317
318
    /**
319
     * Connection::platformQueryHandler
320
     *
321
     * Driver dependent way method for execute the Sql statement.
322
     *
323
     * @param Statement $statement Query object.
324
     *
325
     * @return array
326
     */
327
    protected function platformQueryHandler(Statement &$statement)
328
    {
329
        $rows = [];
330
331
        if (false !== ($result = $this->handle->query($statement->getSqlFinalStatement()))) {
332
            $i = 0;
333
            while ($row = $result->fetchArray(SQLITE3_ASSOC)) {
334
                $rows[ $i ] = $row;
335
                $i++;
336
            }
337
        } else {
338
            $statement->addError($this->handle->lastErrorCode(), $this->handle->lastErrorMsg());
339
        }
340
341
        return $rows;
342
    }
343
344
    // ------------------------------------------------------------------------
345
346
    /**
347
     * Connection::disconnectHandler
348
     *
349
     * Driver dependent way method for closing the connection.
350
     *
351
     * @return mixed
352
     */
353
    protected function platformDisconnectHandler()
354
    {
355
        $this->handle->close();
356
    }
357
358
    // ------------------------------------------------------------------------
359
360
    /**
361
     * Connection::platformTransactionBeginHandler
362
     *
363
     * Platform beginning a transaction handler.
364
     *
365
     * @return bool
366
     */
367
    protected function platformTransactionBeginHandler()
368
    {
369
        $this->transactionInProgress = true;
370
371
        return $this->handle->exec('BEGIN;');
372
    }
373
374
    // ------------------------------------------------------------------------
375
376
    /**
377
     * Connection::platformTransactionCommitHandler
378
     *
379
     * Platform committing a transaction handler.
380
     *
381
     * @return bool
382
     */
383
    protected function platformTransactionCommitHandler()
384
    {
385
        if ($this->handle->exec('COMMIT;')) {
386
            $this->transactionInProgress = false;
387
388
            return true;
389
        }
390
391
        return false;
392
    }
393
394
    // ------------------------------------------------------------------------
395
396
    /**
397
     * Connection::platformTransactionRollBackHandler
398
     *
399
     * Platform rolling back a transaction handler.
400
     *
401
     * @return bool
402
     */
403
    protected function platformTransactionRollBackHandler()
404
    {
405
        if ($this->handle->exec('ROLLBACK;')) {
406
            $this->transactionInProgress = false;
407
408
            return true;
409
        }
410
411
        return false;
412
    }
413
414
    // ------------------------------------------------------------------------
415
416
    /**
417
     * Connection::prepareSqlStatement
418
     *
419
     * Platform preparing a Sql statement.
420
     *
421
     * @param string $sqlStatement Sql Statement to be prepared.
422
     * @param array  $options      Preparing Sql statement options.
423
     *
424
     * @return string
425
     */
426
    protected function platformPrepareSqlStatement($sqlStatement, array $options = [])
427
    {
428
        // Sqlite3::changes() returns 0 for "DELETE FROM TABLE" queries. This hack
429
        // modifies the query so that it a proper number of affected rows is returned.
430
        if ($this->isDeleteHack === true && preg_match('/^\s*DELETE\s+FROM\s+(\S+)\s*$/i', $sqlStatement)) {
431
            return trim($sqlStatement) . ' WHERE 1=1';
432
        }
433
434
        return $sqlStatement;
435
    }
436
437
    // ------------------------------------------------------------------------
438
439
    /**
440
     * Connection::platformEscapeStringHandler
441
     *
442
     * Platform escape string handler.
443
     *
444
     * @param string $string
445
     *
446
     * @return string
447
     */
448
    protected function platformEscapeStringHandler($string)
449
    {
450
451
        return \Sqlite3::escapeString($string);
452
    }
453
}
454