Completed
Push — master ( 30b471...767c34 )
by Todd
03:41
created

SqliteDb::fetchIndexesDb()   B

Complexity

Conditions 3
Paths 3

Size

Total Lines 25
Code Lines 16

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 16
CRAP Score 3

Importance

Changes 0
Metric Value
dl 0
loc 25
ccs 16
cts 16
cp 1
rs 8.8571
c 0
b 0
f 0
cc 3
eloc 16
nc 3
nop 1
crap 3
1
<?php
2
/**
3
 * @author Todd Burry <[email protected]>
4
 * @copyright 2009-2014 Vanilla Forums Inc.
5
 * @license MIT
6
 */
7
8
namespace Garden\Db\Drivers;
9
10
use Garden\Db\Db;
11
use Garden\Db\Identifier;
12
use Garden\Db\Literal;
13
use PDO;
14
15
/**
16
 * A {@link Db} class for connecting to SQLite.
17
 */
18
class SqliteDb extends MySqlDb {
19
    /**
20
     * {@inheritdoc}
21
     */
22 4
    protected function alterTableDb(array $alterDef, array $options = []) {
23 4
        $this->alterTableMigrate($alterDef, $options);
24 4
    }
25
26
    /**
27
     * Alter a table by creating a new table and copying the old table's data to it.
28
     *
29
     * @param array $alterDef The new definition.
30
     * @param array $options An array of options for the migration.
31
     */
32 4
    private function alterTableMigrate(array $alterDef, array $options = []) {
33 4
        $table = $alterDef['name'];
0 ignored issues
show
Coding Style introduced by
Equals sign not aligned with surrounding assignments; expected 6 spaces but found 1 space

This check looks for multiple assignments in successive lines of code. It will report an issue if the operators are not in a straight line.

To visualize

$a = "a";
$ab = "ab";
$abc = "abc";

will produce issues in the first and second line, while this second example

$a   = "a";
$ab  = "ab";
$abc = "abc";

will produce no issues.

Loading history...
34 4
        $currentDef = $this->fetchTableDef($table);
35
36
        // Merge the table definitions if we aren't dropping stuff.
37 4
        if (!self::val(Db::OPTION_DROP, $options)) {
38 3
            $tableDef = $this->mergeTableDefs($currentDef, $alterDef);
0 ignored issues
show
Bug introduced by
It seems like $currentDef defined by $this->fetchTableDef($table) on line 34 can also be of type null; however, Garden\Db\Drivers\SqliteDb::mergeTableDefs() does only seem to accept array, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
39 3
        } else {
40 1
            $tableDef = $alterDef['def'];
41
        }
42
43
        // Drop all of the indexes on the current table.
44 4
        foreach (self::val('indexes', $currentDef, []) as $indexDef) {
0 ignored issues
show
Bug introduced by
It seems like $currentDef defined by $this->fetchTableDef($table) on line 34 can also be of type null; however, Garden\Db\Db::val() does only seem to accept array|object, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
45 4
            if (self::val('type', $indexDef, Db::INDEX_IX) === Db::INDEX_IX) {
46 2
                $this->dropIndex($indexDef['name']);
47 2
            }
48 4
        }
49
50 4
        $tmpTable = $table.'_'.time();
51
52
        // Rename the current table.
53 4
        $this->renameTable($table, $tmpTable);
54
55
        // Create the new table.
56 4
        $this->createTableDb($tableDef, $options);
57
58
        // Figure out the columns that we can insert.
59 4
        $columns = array_keys(array_intersect_key($tableDef['columns'], $currentDef['columns']));
60
61
        // Build the insert/select statement.
62 4
        $sql = 'insert into '.$this->prefixTable($table)."\n".
63 4
            $this->bracketList($columns, '`')."\n".
64 4
            $this->buildSelect($tmpTable, [], ['columns' => $columns]);
65
66 4
        $this->queryDefine($sql);
67
68
        // Drop the temp table.
69 4
        $this->dropTable($tmpTable);
70 4
    }
71
72
    /**
73
     * Rename a table.
74
     *
75
     * @param string $old The old name of the table.
76
     * @param string $new The new name of the table.
77
     */
78 4
    private function renameTable($old, $new) {
79
        $renameSql = 'alter table '.
80 4
            $this->prefixTable($old).
81 4
            ' rename to '.
82 4
            $this->prefixTable($new);
83 4
        $this->queryDefine($renameSql);
84 4
    }
85
86
    /**
87
     * Merge a table def with its alter def so that no columns/indexes are lost in an alter.
88
     *
89
     * @param array $tableDef The table def.
90
     * @param array $alterDef The alter def.
91
     * @return array The new table def.
92
     */
93 3
    private function mergeTableDefs(array $tableDef, array $alterDef) {
94 3
        $result = $tableDef;
95
96 3
        if ($this->findPrimaryKeyIndex($alterDef['add']['indexes'])) {
97 2
            $remove = null;
98 2
            foreach ($result['indexes'] as $i => $index) {
99 2
                if ($index['type'] === Db::INDEX_PK) {
100 2
                    $remove = $i;
101 2
                }
102 2
            }
103 2
            if ($remove !== null) {
104 2
                unset($result['indexes'][$i]);
105 2
            }
106 2
        }
107
108 3
        $result['columns'] = array_merge($result['columns'], $alterDef['def']['columns']);
109 3
        $result['indexes'] = array_merge($result['indexes'], $alterDef['add']['indexes']);
110
111 3
        return $result;
112
    }
113
114
    /**
115
     * Drop an index.
116
     *
117
     * @param string $index The name of the index to drop.
118
     */
119 2
    protected function dropIndex($index) {
120
        $sql = 'drop index if exists '.
121 2
            $this->escape($index);
122 2
        $this->queryDefine($sql);
123 2
    }
124
125
    /**
126
     * {@inheritdoc}
127
     */
128 27
    protected function buildInsert($table, array $row, $options = []) {
129 27
        if (self::val(Db::OPTION_UPSERT, $options)) {
130
            throw new \Exception("Upsert is not supported.");
131 27
        } elseif (self::val(Db::OPTION_IGNORE, $options)) {
132 2
            $sql = 'insert or ignore into ';
133 27
        } elseif (self::val(Db::OPTION_REPLACE, $options)) {
134 2
            $sql = 'insert or replace into ';
135 2
        } else {
136 25
            $sql = 'insert into ';
137
        }
138 27
        $sql .= $this->prefixTable($table);
139
140
        // Add the list of values.
141
        $sql .=
142 27
            "\n".$this->bracketList(array_keys($row), '`').
143 27
            "\nvalues".$this->bracketList($row, "'");
144
145 27
        return $sql;
146
    }
147
148
    /**
149
     * {@inheritdoc}
150
     */
151
    protected function buildLike($column, $value) {
152
        return "$column like ".$this->quote($value)." escape '\\'";
153
    }
154
155
    /**
156
     * {@inheritdoc}
157
     */
158 4
    protected function buildUpdate($table, array $set, array $where, array $options = []) {
159
        $sql = 'update '.
160 4
            (self::val(Db::OPTION_IGNORE, $options) ? 'or ignore ' : '').
161 4
            $this->prefixTable($table).
162 4
            "\nset\n  ";
163
164 4
        $parts = [];
165 4
        foreach ($set as $key => $value) {
166 4
            $parts[] = $this->escape($key).' = '.$this->quote($value);
167 4
        }
168 4
        $sql .= implode(",\n  ", $parts);
169
170 4
        if (!empty($where)) {
171 4
            $sql .= "\nwhere ".$this->buildWhere($where, Db::OP_AND);
172 4
        }
173
174 4
        return $sql;
175
    }
176
177
    /**
178
     * Construct a column definition string from an array defintion.
179
     *
180
     * @param string $name The name of the column.
181
     * @param array $cdef The column definition.
182
     * @return string Returns a string representing the column definition.
183
     */
184 11
    protected function columnDefString($name, array $cdef) {
185
        $cdef += [
186 11
            'autoIncrement' => false,
187 11
            'primary' => false,
188
            'allowNull' => false
189 11
        ];
190
191
        // Auto-increments MUST be of type integer.
192 11
        if ($cdef['autoIncrement']) {
193 4
            $cdef['dbtype'] = 'integer';
194 4
        }
195
196 11
        $result = $this->escape($name).' '.$this->nativeDbType($cdef);
197
198 11
        if ($cdef['primary'] && $cdef['autoIncrement']) {
199
//            if (val('autoincrement', $def)) {
0 ignored issues
show
Unused Code Comprehensibility introduced by
65% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
200 4
                $result .= ' primary key autoincrement';
0 ignored issues
show
Coding Style introduced by
Equals sign not aligned with surrounding assignments; expected 9 spaces but found 1 space

This check looks for multiple assignments in successive lines of code. It will report an issue if the operators are not in a straight line.

To visualize

$a = "a";
$ab = "ab";
$abc = "abc";

will produce issues in the first and second line, while this second example

$a   = "a";
$ab  = "ab";
$abc = "abc";

will produce no issues.

Loading history...
201 4
                $cdef['primary'] = true;
202
//            }
203 4
        } else {
204 11
            if (!$cdef['allowNull']) {
205 10
                $result .= ' not null';
206 10
            }
207
208 11
            if (isset($cdef['default'])) {
209 8
                $result .= ' default '.$this->quote($cdef['default']);
210 8
            }
211
        }
212
213 11
        return $result;
214
    }
215
216
    /**
217
     * {@inheritdoc}
218
     */
219 11
    protected function nativeDbType(array $type) {
220 11
        static $translations = ['bool' => 'boolean', 'byte' => 'tinyint', 'short' => 'smallint', 'long' => 'bigint'];
221
222
        // Translate the dbtype to a MySQL native type.
223 11
        if (isset($translations[$type['dbtype']])) {
224 1
            $type['dbtype'] = $translations[$type['dbtype']];
225 1
        }
226
227 11
        if (!empty($type['autoIncrement'])) {
228 4
            $type['dbtype'] = 'integer';
229 4
        }
230
231
        // Unsigned is represented differently in MySQL.
232 11
        $unsigned = !empty($type['unsigned']) && empty($type['autoIncrement']);
233 11
        unset($type['unsigned']);
234
235 11
        $dbType = static::dbType($type).($unsigned ? ' unsigned' : '');
236
237 11
        return $dbType;
238
    }
239
240
    /**
241
     * {@inheritdoc}
242
     */
243 11
    protected function createTableDb(array $tableDef, array $options = []) {
244 11
        $table = $tableDef['name'];
245 11
        $parts = [];
246
247
        // Make sure the primary key columns are defined first and in order.
248 11
        $autoInc = false;
249 11
        if ($pkIndex = $this->findPrimaryKeyIndex($tableDef['indexes'])) {
250 8
            foreach ($pkIndex['columns'] as $column) {
251 8
                $cdef = $tableDef['columns'][$column];
0 ignored issues
show
Coding Style introduced by
Equals sign not aligned with surrounding assignments; expected 4 spaces but found 1 space

This check looks for multiple assignments in successive lines of code. It will report an issue if the operators are not in a straight line.

To visualize

$a = "a";
$ab = "ab";
$abc = "abc";

will produce issues in the first and second line, while this second example

$a   = "a";
$ab  = "ab";
$abc = "abc";

will produce no issues.

Loading history...
252 8
                $parts[] = $this->columnDefString($column, $cdef);
253 8
                $autoInc |= !empty($cdef['autoIncrement']);
254 8
                unset($tableDef['columns'][$column]);
255 8
            }
256 8
        }
257
258 11
        foreach ($tableDef['columns'] as $name => $cdef) {
259 10
            $parts[] = $this->columnDefString($name, $cdef);
260 11
        }
261
262
        // Add the primary key index.
263 11
        if (isset($pkIndex) && !$autoInc) {
264 4
            $parts[] = 'primary key '.$this->bracketList($pkIndex['columns'], '`');
265 4
        }
266
267 11
        $fullTableName = $this->prefixTable($table);
268 11
        $sql = "create table $fullTableName (\n  ".
0 ignored issues
show
Coding Style introduced by
Equals sign not aligned with surrounding assignments; expected 11 spaces but found 1 space

This check looks for multiple assignments in successive lines of code. It will report an issue if the operators are not in a straight line.

To visualize

$a = "a";
$ab = "ab";
$abc = "abc";

will produce issues in the first and second line, while this second example

$a   = "a";
$ab  = "ab";
$abc = "abc";

will produce no issues.

Loading history...
269 11
            implode(",\n  ", $parts).
270 11
            "\n)";
271
272 11
        $this->queryDefine($sql);
273
274
        // Add the rest of the indexes.
275 11
        foreach (self::val('indexes', $tableDef, []) as $index) {
276 11
            if (self::val('type', $index, Db::INDEX_IX) !== Db::INDEX_PK) {
277 7
                $this->createIndex($table, $index, $options);
278 7
            }
279 11
        }
280 11
    }
281
282
    /**
283
     * Create an index.
284
     *
285
     * @param string $table The name of the table to create the index on.
286
     * @param array $indexDef The index definition.
287
     * @param array $options Additional options for the index creation.
288
     */
289 7
    public function createIndex($table, array $indexDef, $options = []) {
290
        $sql = 'create '.
291 7
            (self::val('type', $indexDef) === Db::INDEX_UNIQUE ? 'unique ' : '').
292 7
            'index '.
293 7
            (self::val(Db::OPTION_IGNORE, $options) ? 'if not exists ' : '').
294 7
            $this->buildIndexName($table, $indexDef).
295 7
            ' on '.
296 7
            $this->prefixTable($table).
297 7
            $this->bracketList($indexDef['columns'], '`');
298
299 7
        $this->queryDefine($sql);
300 7
    }
301
302
    /**
303
     * Force a value into the appropriate php type based on its Sqlite type.
304
     *
305
     * @param mixed $value The value to force.
306
     * @param string $type The sqlite type name.
307
     * @return mixed Returns $value cast to the appropriate type.
308
     */
309 3
    protected function forceType($value, $type) {
310 3
        $type = strtolower($type);
311
312 3
        if ($type === 'null') {
313
            return null;
314 3
        } elseif (in_array($type, ['int', 'integer', 'tinyint', 'smallint',
315 3
            'mediumint', 'bigint', 'unsigned big int', 'int2', 'int8', 'boolean'])) {
316 3
            return (int)filter_var($value, FILTER_VALIDATE_INT);
317
        } elseif (in_array($type, ['real', 'double', 'double precision', 'float',
318
            'numeric', 'decimal(10,5)'])) {
319
            return filter_var($value, FILTER_VALIDATE_FLOAT);
320
        } else {
321
            return (string)$value;
322
        }
323
    }
324
325
    /**
326
     * Get the columns for a table..
327
     *
328
     * @param string $table The table to get the columns for.
329
     * @return array|null Returns an array of columns.
330
     */
331 4
    protected function fetchColumnDefsDb($table) {
332 4
        $cdefs = $this->query('pragma table_info('.$this->prefixTable($table, false).')')->fetchAll(PDO::FETCH_ASSOC);
333 4
        if (empty($cdefs)) {
334 3
            return null;
335
        }
336
337 4
        $columns = [];
338 4
        $pk = [];
0 ignored issues
show
Coding Style introduced by
Equals sign not aligned with surrounding assignments; expected 6 spaces but found 1 space

This check looks for multiple assignments in successive lines of code. It will report an issue if the operators are not in a straight line.

To visualize

$a = "a";
$ab = "ab";
$abc = "abc";

will produce issues in the first and second line, while this second example

$a   = "a";
$ab  = "ab";
$abc = "abc";

will produce no issues.

Loading history...
339 4
        foreach ($cdefs as $cdef) {
340 4
            $column = Db::typeDef($cdef['type']);
0 ignored issues
show
Unused Code introduced by
$column is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
341 4
            $column = Db::typeDef($cdef['type']);
342 4
            if ($column === null) {
343
                throw new \Exception("Unknown type '$columnType'.", 500);
344
            }
345 4
            $column['allowNull'] = !filter_var($cdef['notnull'], FILTER_VALIDATE_BOOLEAN);
346
347 4
            if ($cdef['pk']) {
348 2
                $pk[] = $cdef['name'];
349 2
                if (strcasecmp($cdef['type'], 'integer') === 0) {
350
                    $column['autoIncrement'] = true;
351
                } else {
352 2
                    $column['primary'] = true;
353
                }
354 2
            }
355 4
            if ($cdef['dflt_value'] !== null) {
356 3
                $column['default'] = $this->forceType($cdef['dflt_value'], $column['type']);
357 3
            }
358 4
            $columns[$cdef['name']] = $column;
359 4
        }
360
//        $tdef = ['columns' => $columns];
0 ignored issues
show
Unused Code Comprehensibility introduced by
53% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
361
//        if (!empty($pk)) {
362
//            $tdef['indexes'][Db::INDEX_PK] = [
363
//                'columns' => $pk,
364
//                'type' => Db::INDEX_PK
365
//            ];
366
//        }
367
//        $this->tables[$table] = $tdef;
368 4
        return $columns;
369
    }
370
371
    /**
372
     * Get the indexes for a table.
373
     *
374
     * @param string $table The name of the table to get the indexes for or an empty string to get all indexes.
375
     * @return array|null
376
     */
377 4
    protected function fetchIndexesDb($table = '') {
378 4
        $indexes = [];
379
380 4
        $indexInfos = $this->query('pragma index_list('.$this->prefixTable($table).')')->fetchAll(PDO::FETCH_ASSOC);
381 4
        foreach ($indexInfos as $row) {
382 4
            $indexName = $row['name'];
383 4
            if ($row['unique']) {
384 2
                $type = Db::INDEX_UNIQUE;
385 2
            } else {
386 2
                $type = Db::INDEX_IX;
387
            }
388
389
            // Query the columns in the index.
390 4
            $columns = $this->query('pragma index_info('.$this->quote($indexName).')')->fetchAll(PDO::FETCH_ASSOC);
391
392
            $index = [
0 ignored issues
show
Coding Style introduced by
Equals sign not aligned with surrounding assignments; expected 5 spaces but found 1 space

This check looks for multiple assignments in successive lines of code. It will report an issue if the operators are not in a straight line.

To visualize

$a = "a";
$ab = "ab";
$abc = "abc";

will produce issues in the first and second line, while this second example

$a   = "a";
$ab  = "ab";
$abc = "abc";

will produce no issues.

Loading history...
393 4
                'name' => $indexName,
394 4
                'columns' => array_column($columns, 'name'),
395
                'type' => $type
396 4
            ];
397 4
            $indexes[] = $index;
398 4
        }
399
400 4
        return $indexes;
401
    }
402
403
    /**
404
     * Get the primary or secondary keys from the given rows.
405
     *
406
     * @param string $table The name of the table.
407
     * @param array $row The row to examine.
408
     * @param bool $quick Whether or not to quickly look for <tablename>ID for the primary key.
409
     * @return array|null Returns the primary keys and values from {@link $rows} or null if the primary key isn't found.
410
     */
411 2
    private function getPKValue($table, array $row, $quick = false) {
412 2
        if ($quick && isset($row[$table.'ID'])) {
413 1
            return [$table.'ID' => $row[$table.'ID']];
414
        }
415
416 1
        $tdef = $this->fetchTableDef($table);
417 1
        $cols = [];
418 1
        foreach ($tdef['columns'] as $name => $cdef) {
419 1
            if (empty($cdef['primary'])) {
420 1
                break;
421
            }
422 1
            if (!array_key_exists($name, $row)) {
423
                return null;
424
            }
425
426 1
            $cols[$name] = $row[$name];
427 1
        }
428 1
        return $cols;
429
    }
430
431
    /**
432
     * Get the all of table names in the database.
433
     *
434
     * @return array Returns an array of table names.
435
     */
436
    protected function fetchTableNamesDb() {
437
        // Get the table names.
438
        $tables = $this->get(
439
            new Identifier('sqlite_master'),
440
            [
441
                'type' => 'table',
442
                'name' => [Db::OP_LIKE => $this->escapeLike($this->getPx()).'%']
443
            ],
444
            [
445
                'columns' => ['name']
446
            ]
447
        )->fetchAll(PDO::FETCH_COLUMN);
448
449
        // Remove internal tables.
450
        $tables = array_filter($tables, function ($name) {
451
            return substr($name, 0, 7) !== 'sqlite_';
452
        });
453
454
        return $tables;
455
    }
456
457
    /**
458
     * {@inheritdoc}
459
     */
460 7
    public function insert($table, array $row, array $options = []) {
461
        // Sqlite doesn't support upsert so do upserts manually.
462 7
        if (self::val(Db::OPTION_UPSERT, $options)) {
463 2
            unset($options[Db::OPTION_UPSERT]);
464
465 2
            $keys = $this->getPKValue($table, $row, true);
466 2
            if (empty($keys)) {
467
                throw new \Exception("Cannot upsert with no key.", 500);
468
            }
469
            // Try updating first.
470 2
            $updated = $this->update(
471 2
                $table,
472 2
                array_diff_key($row, $keys),
473 2
                $keys,
474
                $options
475 2
            );
476 2
            if ($updated) {
477
                // Updated.
478 2
                if (count($keys) === 1) {
479 1
                    return array_pop($keys);
480
                } else {
481 1
                    return true;
0 ignored issues
show
Bug Best Practice introduced by
The return type of return true; (boolean) is incompatible with the return type of the parent method Garden\Db\Drivers\MySqlDb::insert of type integer.

If you return a value from a function or method, it should be a sub-type of the type that is given by the parent type f.e. an interface, or abstract method. This is more formally defined by the Lizkov substitution principle, and guarantees that classes that depend on the parent type can use any instance of a child type interchangably. This principle also belongs to the SOLID principles for object oriented design.

Let’s take a look at an example:

class Author {
    private $name;

    public function __construct($name) {
        $this->name = $name;
    }

    public function getName() {
        return $this->name;
    }
}

abstract class Post {
    public function getAuthor() {
        return 'Johannes';
    }
}

class BlogPost extends Post {
    public function getAuthor() {
        return new Author('Johannes');
    }
}

class ForumPost extends Post { /* ... */ }

function my_function(Post $post) {
    echo strtoupper($post->getAuthor());
}

Our function my_function expects a Post object, and outputs the author of the post. The base class Post returns a simple string and outputting a simple string will work just fine. However, the child class BlogPost which is a sub-type of Post instead decided to return an object, and is therefore violating the SOLID principles. If a BlogPost were passed to my_function, PHP would not complain, but ultimately fail when executing the strtoupper call in its body.

Loading history...
482
                }
483
            }
484 1
        }
485
486 7
        $result = parent::insert($table, $row, $options);
487 7
        return $result;
488
    }
489
490
    /**
491
     * Optionally quote a where value.
492
     *
493
     * @param mixed $value The value to quote.
494
     * @param string $column The name of the column being operated on.
495
     * @return string Returns the value, optionally quoted.
496
     * @internal param bool $quote Whether or not to quote the value.
497
     */
498 34
    public function quote($value, $column = '') {
499 34
        if ($value instanceof Literal) {
500
            /* @var Literal $value */
501 20
            return $value->getValue($this, $column);
502 29
        } elseif (in_array(gettype($value), ['integer', 'double'])) {
503 29
            return (string)$value;
504 11
        } elseif ($value === true) {
505
            return '1';
506 11
        } elseif ($value === false) {
507 1
            return '0';
508
        } else {
509 11
            return $this->getPDO()->quote($value);
510
        }
511
    }
512
}
513