Completed
Push — master ( 6e0700...30b471 )
by Todd
02:33
created

SqliteDb::mergeTableDefs()   B

Complexity

Conditions 5
Paths 3

Size

Total Lines 20
Code Lines 12

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 16
CRAP Score 5

Importance

Changes 0
Metric Value
dl 0
loc 20
ccs 16
cts 16
cp 1
rs 8.8571
c 0
b 0
f 0
cc 5
eloc 12
nc 3
nop 2
crap 5
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;
9
10
use PDO;
11
12
/**
13
 * A {@link Db} class for connecting to SQLite.
14
 */
15
class SqliteDb extends MySqlDb {
16
    /**
17
     * {@inheritdoc}
18
     */
19 4
    protected function alterTableDb(array $alterDef, array $options = []) {
20 4
        $tablename = $alterDef['name'];
21 4
        $this->alterTableMigrate($tablename, $alterDef, $options);
22 4
    }
23
24
    /**
25
     * Alter a table by creating a new table and copying the old table's data to it.
26
     *
27
     * @param string $tablename The table to alter.
28
     * @param array $alterDef The new definition.
29
     * @param array $options An array of options for the migration.
30
     */
31 4
    private function alterTableMigrate($tablename, array $alterDef, array $options = []) {
32 4
        $currentDef = $this->fetchTableDef($tablename);
33
34
        // Merge the table definitions if we aren't dropping stuff.
35 4
        if (!self::val(Db::OPTION_DROP, $options)) {
36 3
            $tableDef = $this->mergeTableDefs($currentDef, $alterDef);
0 ignored issues
show
Bug introduced by
It seems like $currentDef defined by $this->fetchTableDef($tablename) on line 32 can also be of type null; however, Garden\Db\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...
37 3
        } else {
38 1
            $tableDef = $alterDef['def'];
39
        }
40
41
        // Drop all of the indexes on the current table.
42 4
        foreach (self::val('indexes', $currentDef, []) as $indexDef) {
0 ignored issues
show
Bug introduced by
It seems like $currentDef defined by $this->fetchTableDef($tablename) on line 32 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...
43 4
            if (self::val('type', $indexDef, Db::INDEX_IX) === Db::INDEX_IX) {
44 2
                $this->dropIndex($indexDef['name']);
45 2
            }
46 4
        }
47
48 4
        $tmpTablename = $tablename.'_'.time();
49
50
        // Rename the current table.
51 4
        $this->renameTable($tablename, $tmpTablename);
52
53
        // Create the new table.
54 4
        $this->createTableDb($tableDef, $options);
55
56
        // Figure out the columns that we can insert.
57 4
        $columns = array_keys(array_intersect_key($tableDef['columns'], $currentDef['columns']));
58
59
        // Build the insert/select statement.
60 4
        $sql = 'insert into '.$this->prefixTable($tablename)."\n".
61 4
            $this->bracketList($columns, '`')."\n".
62 4
            $this->buildSelect($tmpTablename, [], ['columns' => $columns]);
63
64 4
        $this->queryDefine($sql);
65
66
        // Drop the temp table.
67 4
        $this->dropTable($tmpTablename);
68 4
    }
69
70
    /**
71
     * Rename a table.
72
     *
73
     * @param string $oldname The old name of the table.
74
     * @param string $newname The new name of the table.
75
     */
76 4
    private function renameTable($oldname, $newname) {
77
        $renameSql = 'alter table '.
78 4
            $this->prefixTable($oldname).
79 4
            ' rename to '.
80 4
            $this->prefixTable($newname);
81 4
        $this->queryDefine($renameSql);
82 4
    }
83
84
    /**
85
     * Merge a table def with its alter def so that no columns/indexes are lost in an alter.
86
     *
87
     * @param array $tableDef The table def.
88
     * @param array $alterDef The alter def.
89
     * @return array The new table def.
90
     */
91 3
    private function mergeTableDefs(array $tableDef, array $alterDef) {
92 3
        $result = $tableDef;
93
94 3
        if ($this->findPrimaryKeyIndex($alterDef['add']['indexes'])) {
95 2
            $remove = null;
96 2
            foreach ($result['indexes'] as $i => $index) {
97 2
                if ($index['type'] === Db::INDEX_PK) {
98 2
                    $remove = $i;
99 2
                }
100 2
            }
101 2
            if ($remove !== null) {
102 2
                unset($result['indexes'][$i]);
103 2
            }
104 2
        }
105
106 3
        $result['columns'] = array_merge($result['columns'], $alterDef['def']['columns']);
107 3
        $result['indexes'] = array_merge($result['indexes'], $alterDef['add']['indexes']);
108
109 3
        return $result;
110
    }
111
112
    /**
113
     * Drop an index.
114
     *
115
     * @param string $indexName The name of the index to drop.
116
     */
117 2
    protected function dropIndex($indexName) {
118
        $sql = 'drop index if exists '.
119 2
            $this->escape($indexName);
120 2
        $this->queryDefine($sql);
121 2
    }
122
123
    /**
124
     * {@inheritdoc}
125
     */
126 27
    protected function buildInsert($tableName, array $row, $options = []) {
127 27
        if (self::val(Db::OPTION_UPSERT, $options)) {
128
            throw new \Exception("Upsert is not supported.");
129 27
        } elseif (self::val(Db::OPTION_IGNORE, $options)) {
130 2
            $sql = 'insert or ignore into ';
131 27
        } elseif (self::val(Db::OPTION_REPLACE, $options)) {
132 2
            $sql = 'insert or replace into ';
133 2
        } else {
134 25
            $sql = 'insert into ';
135
        }
136 27
        $sql .= $this->prefixTable($tableName);
137
138
        // Add the list of values.
139
        $sql .=
140 27
            "\n".$this->bracketList(array_keys($row), '`').
141 27
            "\nvalues".$this->bracketList($row, "'");
142
143 27
        return $sql;
144
    }
145
146
    /**
147
     * {@inheritdoc}
148
     */
149
    protected function buildLike($column, $value) {
150
        return "$column like ".$this->quote($value)." escape '\\'";
151
    }
152
153
    /**
154
     * {@inheritdoc}
155
     */
156 4
    protected function buildUpdate($tableName, array $set, array $where, array $options = []) {
157
        $sql = 'update '.
158 4
            (self::val(Db::OPTION_IGNORE, $options) ? 'or ignore ' : '').
159 4
            $this->prefixTable($tableName).
160 4
            "\nset\n  ";
161
162 4
        $parts = [];
163 4
        foreach ($set as $key => $value) {
164 4
            $parts[] = $this->escape($key).' = '.$this->quote($value);
165 4
        }
166 4
        $sql .= implode(",\n  ", $parts);
167
168 4
        if (!empty($where)) {
169 4
            $sql .= "\nwhere ".$this->buildWhere($where, Db::OP_AND);
170 4
        }
171
172 4
        return $sql;
173
    }
174
175
    /**
176
     * Construct a column definition string from an array defintion.
177
     *
178
     * @param string $name The name of the column.
179
     * @param array $cdef The column definition.
180
     * @return string Returns a string representing the column definition.
181
     */
182 11
    protected function columnDefString($name, array $cdef) {
183
        $cdef += [
184 11
            'autoIncrement' => false,
185 11
            'primary' => false,
186
            'allowNull' => false
187 11
        ];
188
189
        // Auto-increments MUST be of type integer.
190 11
        if ($cdef['autoIncrement']) {
191 4
            $cdef['dbtype'] = 'integer';
192 4
        }
193
194 11
        $result = $this->escape($name).' '.$this->nativeDbType($cdef);
195
196 11
        if ($cdef['primary'] && $cdef['autoIncrement']) {
197
//            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...
198 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...
199 4
                $cdef['primary'] = true;
200
//            }
201 4
        } else {
202 11
            if (!$cdef['allowNull']) {
203 10
                $result .= ' not null';
204 10
            }
205
206 11
            if (isset($cdef['default'])) {
207 8
                $result .= ' default '.$this->quote($cdef['default']);
208 8
            }
209
        }
210
211 11
        return $result;
212
    }
213
214
    /**
215
     * {@inheritdoc}
216
     */
217 11
    protected function nativeDbType(array $type) {
218 11
        static $translations = ['bool' => 'boolean', 'byte' => 'tinyint', 'short' => 'smallint', 'long' => 'bigint'];
219
220
        // Translate the dbtype to a MySQL native type.
221 11
        if (isset($translations[$type['dbtype']])) {
222 1
            $type['dbtype'] = $translations[$type['dbtype']];
223 1
        }
224
225 11
        if (!empty($type['autoIncrement'])) {
226 4
            $type['dbtype'] = 'integer';
227 4
        }
228
229
        // Unsigned is represented differently in MySQL.
230 11
        $unsigned = !empty($type['unsigned']) && empty($type['autoIncrement']);
231 11
        unset($type['unsigned']);
232
233 11
        $dbType = static::dbType($type).($unsigned ? ' unsigned' : '');
234
235 11
        return $dbType;
236
    }
237
238
    /**
239
     * {@inheritdoc}
240
     */
241 11
    protected function createTableDb(array $tableDef, array $options = []) {
242 11
        $tablename = $tableDef['name'];
243 11
        $parts = [];
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...
244
245
        // Make sure the primary key columns are defined first and in order.
246 11
        $autoInc = false;
247 11
        if ($pkIndex = $this->findPrimaryKeyIndex($tableDef['indexes'])) {
248 8
            foreach ($pkIndex['columns'] as $column) {
249 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...
250 8
                $parts[] = $this->columnDefString($column, $cdef);
251 8
                $autoInc |= !empty($cdef['autoIncrement']);
252 8
                unset($tableDef['columns'][$column]);
253 8
            }
254 8
        }
255
256 11
        foreach ($tableDef['columns'] as $name => $cdef) {
257 10
            $parts[] = $this->columnDefString($name, $cdef);
258 11
        }
259
260
        // Add the primary key index.
261 11
        if (isset($pkIndex) && !$autoInc) {
262 4
            $parts[] = 'primary key '.$this->bracketList($pkIndex['columns'], '`');
263 4
        }
264
265 11
        $fullTablename = $this->prefixTable($tablename);
266 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...
267 11
            implode(",\n  ", $parts).
268 11
            "\n)";
269
270 11
        $this->queryDefine($sql);
271
272
        // Add the rest of the indexes.
273 11
        foreach (self::val('indexes', $tableDef, []) as $index) {
274 11
            if (self::val('type', $index, Db::INDEX_IX) !== Db::INDEX_PK) {
275 7
                $this->createIndex($tablename, $index, $options);
276 7
            }
277 11
        }
278 11
    }
279
280
    /**
281
     * Create an index.
282
     *
283
     * @param string $tablename The name of the table to create the index on.
284
     * @param array $indexDef The index definition.
285
     * @param array $options Additional options for the index creation.
286
     */
287 7
    public function createIndex($tablename, array $indexDef, $options = []) {
288
        $sql = 'create '.
289 7
            (self::val('type', $indexDef) === Db::INDEX_UNIQUE ? 'unique ' : '').
290 7
            'index '.
291 7
            (self::val(Db::OPTION_IGNORE, $options) ? 'if not exists ' : '').
292 7
            $this->buildIndexName($tablename, $indexDef).
293 7
            ' on '.
294 7
            $this->prefixTable($tablename).
295 7
            $this->bracketList($indexDef['columns'], '`');
296
297 7
        $this->queryDefine($sql);
298 7
    }
299
300
    /**
301
     * Force a value into the appropriate php type based on its Sqlite type.
302
     *
303
     * @param mixed $value The value to force.
304
     * @param string $type The sqlite type name.
305
     * @return mixed Returns $value cast to the appropriate type.
306
     */
307 3
    protected function forceType($value, $type) {
308 3
        $type = strtolower($type);
309
310 3
        if ($type === 'null') {
311
            return null;
312 3
        } elseif (in_array($type, ['int', 'integer', 'tinyint', 'smallint',
313 3
            'mediumint', 'bigint', 'unsigned big int', 'int2', 'int8', 'boolean'])) {
314 3
            return (int)filter_var($value, FILTER_VALIDATE_INT);
315
        } elseif (in_array($type, ['real', 'double', 'double precision', 'float',
316
            'numeric', 'decimal(10,5)'])) {
317
            return filter_var($value, FILTER_VALIDATE_FLOAT);
318
        } else {
319
            return (string)$value;
320
        }
321
    }
322
323
    /**
324
     * Get the columns for a table..
325
     *
326
     * @param string $table The table to get the columns for.
327
     * @return array|null Returns an array of columns.
328
     */
329 4
    protected function fetchColumnDefsDb($table) {
330 4
        $cdefs = $this->query('pragma table_info('.$this->prefixTable($table, false).')')->fetchAll(PDO::FETCH_ASSOC);
331 4
        if (empty($cdefs)) {
332 3
            return null;
333
        }
334
335 4
        $columns = [];
336 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...
337 4
        foreach ($cdefs as $cdef) {
338 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...
339 4
            $column = Db::typeDef($cdef['type']);
340 4
            if ($column === null) {
341
                throw new \Exception("Unknown type '$columnType'.", 500);
342
            }
343 4
            $column['allowNull'] = !filter_var($cdef['notnull'], FILTER_VALIDATE_BOOLEAN);
344
345 4
            if ($cdef['pk']) {
346 2
                $pk[] = $cdef['name'];
347 2
                if (strcasecmp($cdef['type'], 'integer') === 0) {
348
                    $column['autoIncrement'] = true;
349
                } else {
350 2
                    $column['primary'] = true;
351
                }
352 2
            }
353 4
            if ($cdef['dflt_value'] !== null) {
354 3
                $column['default'] = $this->forceType($cdef['dflt_value'], $column['type']);
355 3
            }
356 4
            $columns[$cdef['name']] = $column;
357 4
        }
358
//        $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...
359
//        if (!empty($pk)) {
360
//            $tdef['indexes'][Db::INDEX_PK] = [
361
//                'columns' => $pk,
362
//                'type' => Db::INDEX_PK
363
//            ];
364
//        }
365
//        $this->tables[$table] = $tdef;
366 4
        return $columns;
367
    }
368
369
    /**
370
     * Get the indexes for a table.
371
     *
372
     * @param string $table The name of the table to get the indexes for or an empty string to get all indexes.
373
     * @return array|null
374
     */
375 4
    protected function fetchIndexesDb($table = '') {
376 4
        $indexes = [];
377
378 4
        $indexInfos = $this->query('pragma index_list('.$this->prefixTable($table).')')->fetchAll(PDO::FETCH_ASSOC);
379 4
        foreach ($indexInfos as $row) {
380 4
            $indexName = $row['name'];
381 4
            if ($row['unique']) {
382 2
                $type = Db::INDEX_UNIQUE;
383 2
            } else {
384 2
                $type = Db::INDEX_IX;
385
            }
386
387
            // Query the columns in the index.
388 4
            $columns = $this->query('pragma index_info('.$this->quote($indexName).')')->fetchAll(PDO::FETCH_ASSOC);
389
390
            $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...
391 4
                'name' => $indexName,
392 4
                'columns' => array_column($columns, 'name'),
393
                'type' => $type
394 4
            ];
395 4
            $indexes[] = $index;
396 4
        }
397
398 4
        return $indexes;
399
    }
400
401
    /**
402
     * Get the primary or secondary keys from the given rows.
403
     *
404
     * @param string $tablename The name of the table.
405
     * @param array $row The row to examine.
406
     * @param bool $quick Whether or not to quickly look for <tablename>ID for the primary key.
407
     * @return array|null Returns the primary keys and values from {@link $rows} or null if the primary key isn't found.
408
     */
409 2
    private function getPKValue($tablename, array $row, $quick = false) {
410 2
        if ($quick && isset($row[$tablename.'ID'])) {
411 1
            return [$tablename.'ID' => $row[$tablename.'ID']];
412
        }
413
414 1
        $tdef = $this->fetchTableDef($tablename);
415 1
        $cols = [];
416 1
        foreach ($tdef['columns'] as $name => $cdef) {
417 1
            if (empty($cdef['primary'])) {
418 1
                break;
419
            }
420 1
            if (!array_key_exists($name, $row)) {
421
                return null;
422
            }
423
424 1
            $cols[$name] = $row[$name];
425 1
        }
426 1
        return $cols;
427
    }
428
429
    /**
430
     * Get the all of table names in the database.
431
     *
432
     * @return array Returns an array of table names.
433
     */
434
    protected function fetchTableNamesDb() {
435
        // Get the table names.
436
        $tables = $this->get(
437
            new Identifier('sqlite_master'),
438
            [
439
                'type' => 'table',
440
                'name' => [Db::OP_LIKE => $this->escapeLike($this->getPx()).'%']
441
            ],
442
            [
443
                'columns' => ['name']
444
            ]
445
        )->fetchAll(PDO::FETCH_COLUMN);
446
447
        // Remove internal tables.
448
        $tables = array_filter($tables, function ($name) {
449
            return substr($name, 0, 7) !== 'sqlite_';
450
        });
451
452
        return $tables;
453
    }
454
455
    /**
456
     * {@inheritdoc}
457
     */
458 7
    public function insert($table, array $row, array $options = []) {
459
        // Sqlite doesn't support upsert so do upserts manually.
460 7
        if (self::val(Db::OPTION_UPSERT, $options)) {
461 2
            unset($options[Db::OPTION_UPSERT]);
462
463 2
            $keys = $this->getPKValue($table, $row, true);
464 2
            if (empty($keys)) {
465
                throw new \Exception("Cannot upsert with no key.", 500);
466
            }
467
            // Try updating first.
468 2
            $updated = $this->update(
469 2
                $table,
470 2
                array_diff_key($row, $keys),
471 2
                $keys,
472
                $options
473 2
            );
474 2
            if ($updated) {
475
                // Updated.
476 2
                if (count($keys) === 1) {
477 1
                    return array_pop($keys);
478
                } else {
479 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\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...
480
                }
481
            }
482 1
        }
483
484 7
        $result = parent::insert($table, $row, $options);
485 7
        return $result;
486
    }
487
488
    /**
489
     * Optionally quote a where value.
490
     *
491
     * @param mixed $value The value to quote.
492
     * @param string $column The name of the column being operated on.
493
     * @return string Returns the value, optionally quoted.
494
     * @internal param bool $quote Whether or not to quote the value.
495
     */
496 34
    public function quote($value, $column = '') {
497 34
        if ($value instanceof Literal) {
498
            /* @var Literal $value */
499 20
            return $value->getValue($this, $column);
500 29
        } elseif (in_array(gettype($value), ['integer', 'double'])) {
501 29
            return (string)$value;
502 11
        } elseif ($value === true) {
503
            return '1';
504 11
        } elseif ($value === false) {
505 1
            return '0';
506
        } else {
507 11
            return $this->getPDO()->quote($value);
508
        }
509
    }
510
}
511