Completed
Pull Request — master (#23)
by Damian
08:37
created

code/SQLite3SchemaManager.php (21 issues)

Upgrade to new PHP Analysis Engine

These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more

1
<?php
2
3
/**
4
 * SQLite schema manager class
5
 * 
6
 * @package SQLite3
7
 */
8
class SQLite3SchemaManager extends DBSchemaManager
0 ignored issues
show
Coding Style Compatibility introduced by
PSR1 recommends that each class must be in a namespace of at least one level to avoid collisions.

You can fix this by adding a namespace to your class:

namespace YourVendor;

class YourClass { }

When choosing a vendor namespace, try to pick something that is not too generic to avoid conflicts with other libraries.

Loading history...
9
{
10
11
    /**
12
     * Instance of the database controller this schema belongs to
13
     * 
14
     * @var SQLite3Database
15
     */
16
    protected $database = null;
17
18
    /**
19
     * Flag indicating whether or not the database has been checked and repaired
20
     *
21
     * @var boolean
22
     */
23
    protected static $checked_and_repaired = false;
24
25
    /**
26
     * Should schema be vacuumed during checkeAndRepairTable?
27
     *
28
     * @var boolean
29
     */
30
    public static $vacuum = true;
31
    
32
    public function createDatabase($name)
33
    {
34
        // Ensure that any existing database is cleared before connection
35
        $this->dropDatabase($name);
36
    }
37
38
    public function dropDatabase($name)
39
    {
40
        // No need to delete database files if operating purely within memory
41
        if ($this->database->getLivesInMemory()) {
42
            return;
43
        }
44
         
45
        // If using file based database ensure any existing file is removed
46
        $parameters = $this->database->getParameters();
47
        $fullpath = $parameters['path'] . '/' . $name;
48
        if (is_writable($fullpath)) {
49
            unlink($fullpath);
50
        }
51
    }
52
    
53
    public function databaseList()
54
    {
55
        $parameters = $this->database->getParameters();
56
        
57
        // If in-memory use the current database name only
58
        if ($this->database->getLivesInMemory()) {
59
            return array($parameters['database']);
60
        }
61
        
62
        // If using file based database enumerate files in the database directory
63
        $directory = $parameters['path'];
64
        $files = scandir($directory);
65
        
66
        // Filter each file in this directory
67
        $databases = array();
68
        if ($files !== false) {
69
            foreach ($files as $file) {
70
            
71
            // Filter non-files
72
            if (!is_file("$directory/$file")) {
73
                continue;
74
            }
75
            
76
            // Filter those with correct extension
77
            if (!SQLite3Database::is_valid_database_name($file)) {
78
                continue;
79
            }
80
            
81
                $databases[] = $file;
82
            }
83
        }
84
        return $databases;
85
    }
86
87
    public function databaseExists($name)
88
    {
89
        $databases = $this->databaseList();
90
        return in_array($name, $databases);
91
    }
92
    
93
    /**
94
     * Empties any cached enum values
95
     */
96
    public function flushCache()
97
    {
98
        $this->enum_map = array();
99
    }
100
    
101
    public function schemaUpdate($callback)
102
    {
103
        // Set locking mode
104
        $this->database->setPragma('locking_mode', 'EXCLUSIVE');
105
        $this->checkAndRepairTable();
106
        $this->flushCache();
107
        
108
        // Initiate schema update
109
        $error = null;
110
        try {
111
            parent::schemaUpdate($callback);
112
        } catch (Exception $ex) {
113
            $error = $ex;
114
        }
115
        
116
        // Revert locking mode
117
        $this->database->setPragma('locking_mode', SQLite3Database::$default_pragma['locking_mode']);
118
        
119
        if ($error) {
120
            throw $error;
121
        }
122
    }
123
124
    /**
125
     * Empty a specific table
126
     * 
127
     * @param string $table
128
     */
129
    public function clearTable($table)
130
    {
131
        if ($table != 'SQLiteEnums') {
132
            $this->dbConn->query("DELETE FROM \"$table\"");
0 ignored issues
show
The property dbConn does not exist. Did you maybe forget to declare it?

In PHP it is possible to write to properties without declaring them. For example, the following is perfectly valid PHP code:

class MyClass { }

$x = new MyClass();
$x->foo = true;

Generally, it is a good practice to explictly declare properties to avoid accidental typos and provide IDE auto-completion:

class MyClass {
    public $foo;
}

$x = new MyClass();
$x->foo = true;
Loading history...
133
        }
134
    }
135
136
    public function createTable($table, $fields = null, $indexes = null, $options = null, $advancedOptions = null)
137
    {
138
        if (!isset($fields['ID'])) {
139
            $fields['ID'] = $this->IdColumn();
140
        }
141
142
        $fieldSchemata = array();
143
        if ($fields) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $fields of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
144
            foreach ($fields as $k => $v) {
145
                $fieldSchemata[] = "\"$k\" $v";
146
            }
147
        }
148
        $fieldSchemas = implode(",\n", $fieldSchemata);
149
150
        // Switch to "CREATE TEMPORARY TABLE" for temporary tables
151
        $temporary = empty($options['temporary']) ? "" : "TEMPORARY";
152
        $this->query("CREATE $temporary TABLE \"$table\" (
153
			$fieldSchemas
154
		)");
155
156
        if ($indexes) {
157
            foreach ($indexes as $indexName => $indexDetails) {
158
                $this->createIndex($table, $indexName, $indexDetails);
159
            }
160
        }
161
162
        return $table;
163
    }
164
165
    public function alterTable($tableName, $newFields = null, $newIndexes = null, $alteredFields = null,
166
        $alteredIndexes = null, $alteredOptions = null, $advancedOptions = null
167
    ) {
168
        if ($newFields) {
169
            foreach ($newFields as $fieldName => $fieldSpec) {
170
                $this->createField($tableName, $fieldName, $fieldSpec);
171
            }
172
        }
173
174
        if ($alteredFields) {
175
            foreach ($alteredFields as $fieldName => $fieldSpec) {
176
                $this->alterField($tableName, $fieldName, $fieldSpec);
177
            }
178
        }
179
180
        if ($newIndexes) {
181
            foreach ($newIndexes as $indexName => $indexSpec) {
182
                $this->createIndex($tableName, $indexName, $indexSpec);
183
            }
184
        }
185
186
        if ($alteredIndexes) {
187
            foreach ($alteredIndexes as $indexName => $indexSpec) {
188
                $this->alterIndex($tableName, $indexName, $indexSpec);
189
            }
190
        }
191
    }
192
    
193
    public function renameTable($oldTableName, $newTableName)
194
    {
195
        $this->query("ALTER TABLE \"$oldTableName\" RENAME TO \"$newTableName\"");
196
    }
197
198
    public function checkAndRepairTable($tableName = null)
199
    {
200
        $ok = true;
201
202
        if (!SapphireTest::using_temp_db() && !self::$checked_and_repaired) {
203
            $this->alterationMessage("Checking database integrity", "repaired");
204
            
205
            // Check for any tables with failed integrity
206
            if ($messages = $this->query('PRAGMA integrity_check')) {
207
                foreach ($messages as $message) {
208
                    if ($message['integrity_check'] != 'ok') {
209
                        Debug::show($message['integrity_check']);
210
                        $ok = false;
211
                    }
212
                }
213
            }
214
            
215
            // If enabled vacuum (clean and rebuild) the database
216
            if (self::$vacuum) {
217
                $this->query('VACUUM', E_USER_NOTICE);
218
                $message = $this->database->getConnector()->getLastError();
219
                if (preg_match('/authoriz/', $message)) {
220
                    $this->alterationMessage("VACUUM | $message", "error");
221
                } else {
222
                    $this->alterationMessage("VACUUMing", "repaired");
223
                }
224
            }
225
            self::$checked_and_repaired = true;
226
        }
227
        
228
        return $ok;
229
    }
230
231
    public function createField($table, $field, $spec)
232
    {
233
        $this->query("ALTER TABLE \"$table\" ADD \"$field\" $spec");
234
    }
235
236
    /**
237
     * Change the database type of the given field.
238
     * @param string $tableName The name of the tbale the field is in.
239
     * @param string $fieldName The name of the field to change.
240
     * @param string $fieldSpec The new field specification
241
     */
242
    public function alterField($tableName, $fieldName, $fieldSpec)
243
    {
244
        $oldFieldList = $this->fieldList($tableName);
245
        $fieldNameList = '"' . implode('","', array_keys($oldFieldList)) . '"';
246
247
        if (!empty($_REQUEST['avoidConflict']) && Director::isDev()) {
248
            $fieldSpec = preg_replace('/\snot null\s/i', ' NOT NULL ON CONFLICT REPLACE ', $fieldSpec);
249
        }
250
251
        // Skip non-existing columns
252
        if (!array_key_exists($fieldName, $oldFieldList)) {
253
            return;
254
        }
255
256
        // Update field spec
257
        $newColsSpec = array();
258
        foreach ($oldFieldList as $name => $oldSpec) {
259
            $newColsSpec[] = "\"$name\" " . ($name == $fieldName ? $fieldSpec : $oldSpec);
260
        }
261
262
        $queries = array(
263
            "BEGIN TRANSACTION",
264
            "CREATE TABLE \"{$tableName}_alterfield_{$fieldName}\"(" . implode(',', $newColsSpec) . ")",
265
            "INSERT INTO \"{$tableName}_alterfield_{$fieldName}\" SELECT {$fieldNameList} FROM \"$tableName\"",
266
            "DROP TABLE \"$tableName\"",
267
            "ALTER TABLE \"{$tableName}_alterfield_{$fieldName}\" RENAME TO \"$tableName\"",
268
            "COMMIT"
269
        );
270
271
        // Remember original indexes
272
        $indexList = $this->indexList($tableName);
273
        
274
        // Then alter the table column
275
        foreach ($queries as $query) {
276
            $this->query($query.';');
277
        }
278
279
        // Recreate the indexes
280
        foreach ($indexList as $indexName => $indexSpec) {
281
            $this->createIndex($tableName, $indexName, $indexSpec);
282
        }
283
    }
284
285
    public function renameField($tableName, $oldName, $newName)
286
    {
287
        $oldFieldList = $this->fieldList($tableName);
288
289
        // Skip non-existing columns
290
        if (!array_key_exists($oldName, $oldFieldList)) {
291
            return;
292
        }
293
        
294
        // Determine column mappings
295
        $oldCols = array();
296
        $newColsSpec = array();
297
        foreach ($oldFieldList as $name => $spec) {
298
            $oldCols[] = "\"$name\"" . (($name == $oldName) ? " AS $newName" : '');
299
            $newColsSpec[] = "\"" . (($name == $oldName) ? $newName : $name) . "\" $spec";
300
        }
301
302
        // SQLite doesn't support direct renames through ALTER TABLE
303
        $queries = array(
304
            "BEGIN TRANSACTION",
305
            "CREATE TABLE \"{$tableName}_renamefield_{$oldName}\" (" . implode(',', $newColsSpec) . ")",
306
            "INSERT INTO \"{$tableName}_renamefield_{$oldName}\" SELECT " . implode(',', $oldCols) . " FROM \"$tableName\"",
307
            "DROP TABLE \"$tableName\"",
308
            "ALTER TABLE \"{$tableName}_renamefield_{$oldName}\" RENAME TO \"$tableName\"",
309
            "COMMIT"
310
        );
311
312
        // Remember original indexes
313
        $oldIndexList = $this->indexList($tableName);
314
315
        // Then alter the table column
316
        foreach ($queries as $query) {
317
            $this->query($query.';');
318
        }
319
320
        // Recreate the indexes
321
        foreach ($oldIndexList as $indexName => $indexSpec) {
322
            // Rename columns to new columns
323
            $indexSpec['value'] = preg_replace("/\"$oldName\"/i", "\"$newName\"", $indexSpec['value']);
324
            $this->createIndex($tableName, $indexName, $indexSpec);
325
        }
326
    }
327
328
    public function fieldList($table)
329
    {
330
        $sqlCreate = $this->preparedQuery(
331
            'SELECT sql FROM sqlite_master WHERE type = ? AND name = ?',
332
            array('table', $table)
333
        )->record();
334
        
335
        $fieldList = array();
336
        if ($sqlCreate && $sqlCreate['sql']) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $sqlCreate of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
337
            preg_match('/^[\s]*CREATE[\s]+TABLE[\s]+[\'"]?[a-zA-Z0-9_\\\]+[\'"]?[\s]*\((.+)\)[\s]*$/ims',
338
                $sqlCreate['sql'], $matches
339
            );
340
            $fields = isset($matches[1])
341
                ? preg_split('/,(?=(?:[^\'"]*$)|(?:[^\'"]*[\'"][^\'"]*[\'"][^\'"]*)*$)/x', $matches[1])
342
                : array();
343
            foreach ($fields as $field) {
344
                $details = preg_split('/\s/', trim($field));
345
                $name = array_shift($details);
346
                $name = str_replace('"', '', trim($name));
347
                $fieldList[$name] = implode(' ', $details);
348
            }
349
        }
350
        return $fieldList;
351
    }
352
353
    /**
354
     * Create an index on a table.
355
     * 
356
     * @param string $tableName The name of the table.
357
     * @param string $indexName The name of the index.
358
     * @param array $indexSpec The specification of the index, see Database::requireIndex() for more details.
359
     */
360
    public function createIndex($tableName, $indexName, $indexSpec)
361
    {
362
        $parsedSpec = $this->parseIndexSpec($indexName, $indexSpec);
363
        $sqliteName = $this->buildSQLiteIndexName($tableName, $indexName);
364
        $columns = $parsedSpec['value'];
365
        $unique = ($parsedSpec['type'] == 'unique') ? 'UNIQUE' : '';
366
        $this->query("CREATE $unique INDEX IF NOT EXISTS \"$sqliteName\" ON \"$tableName\" ($columns)");
367
    }
368
369
    public function alterIndex($tableName, $indexName, $indexSpec)
370
    {
371
        // Drop existing index
372
        $sqliteName = $this->buildSQLiteIndexName($tableName, $indexName);
373
        $this->query("DROP INDEX IF EXISTS \"$sqliteName\"");
374
        
375
        // Create the index
376
        $this->createIndex($tableName, $indexName, $indexSpec);
0 ignored issues
show
$indexSpec is of type string, but the function expects a array.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
377
    }
378
    
379
    /**
380
     * Builds the internal SQLLite index name given the silverstripe table and index name.
381
     * 
382
     * The name is built using the table and index name in order to prevent name collisions
383
     * between indexes of the same name across multiple tables
384
     * 
385
     * @param string $tableName
386
     * @param string $indexName
387
     * @return string The SQLite3 name of the index
388
     */
389
    protected function buildSQLiteIndexName($tableName, $indexName)
390
    {
391
        return "{$tableName}_{$indexName}";
392
    }
393
    
394
    protected function parseIndexSpec($name, $spec)
395
    {
396
        $spec = parent::parseIndexSpec($name, $spec);
397
        
398
        // Only allow index / unique index types
399
        if (!in_array($spec['type'], array('index', 'unique'))) {
400
            $spec['type'] = 'index';
401
        }
402
        
403
        return $spec;
404
    }
405
    
406
    public function indexKey($table, $index, $spec)
407
    {
408
        return $this->buildSQLiteIndexName($table, $index);
409
    }
410
411
    public function indexList($table)
412
    {
413
        $indexList = array();
414
        
415
        // Enumerate each index and related fields
416
        foreach ($this->query("PRAGMA index_list(\"$table\")") as $index) {
417
            
418
            // The SQLite internal index name, not the actual Silverstripe name
419
            $indexName = $index["name"];
420
            $indexType = $index['unique'] ? 'unique' : 'index';
421
            
422
            // Determine a clean list of column names within this index
423
            $list = array();
424
            foreach ($this->query("PRAGMA index_info(\"$indexName\")") as $details) {
425
                $list[] = preg_replace('/^"?(.*)"?$/', '$1', $details['name']);
426
            }
427
            
428
            // Safely encode this spec
429
            $indexList[$indexName] = $this->parseIndexSpec($indexName, array(
430
                'name' => $indexName,
431
                'value' => $this->implodeColumnList($list),
432
                'type' => $indexType
433
            ));
434
        }
435
436
        return $indexList;
437
    }
438
439
    public function tableList()
440
    {
441
        $tables = array();
442
        $result = $this->preparedQuery('SELECT name FROM sqlite_master WHERE type = ?', array('table'));
443
        foreach ($result as $record) {
444
            $table = reset($record);
445
            $tables[strtolower($table)] = $table;
446
        }
447
        return $tables;
448
    }
449
    
450
    /**
451
     * Return a boolean type-formatted string
452
     * 
453
     * @params array $values Contains a tokenised list of info about this data type
454
     * @return string
455
     */
456
    public function boolean($values)
457
    {
458
        $default = empty($values['default']) ? 0 : (int)$values['default'];
459
        return "BOOL NOT NULL DEFAULT $default";
460
    }
461
462
    /**
463
     * Return a date type-formatted string
464
     * 
465
     * @params array $values Contains a tokenised list of info about this data type
466
     * @return string
467
     */
468
    public function date($values)
0 ignored issues
show
The parameter $values is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
469
    {
470
        return "TEXT";
471
    }
472
473
    /**
474
     * Return a decimal type-formatted string
475
     * 
476
     * @params array $values Contains a tokenised list of info about this data type
477
     * @return string
478
     */
479
    public function decimal($values, $asDbValue = false)
0 ignored issues
show
The parameter $asDbValue is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
480
    {
481
        $default = isset($values['default']) && is_numeric($values['default']) ? $values['default'] : 0;
482
        return "NUMERIC NOT NULL DEFAULT $default";
483
    }
484
485
    /**
486
     * Cached list of enum values indexed by table.column
487
     *
488
     * @var array
489
     */
490
    protected $enum_map = array();
491
    
492
    /**
493
     * Return a enum type-formatted string
494
     *
495
     * enums are not supported. as a workaround to store allowed values we creates an additional table
496
     * 
497
     * @params array $values Contains a tokenised list of info about this data type
498
     * @return string
499
     */
500
    public function enum($values)
501
    {
502
        $tablefield = $values['table'] . '.' . $values['name'];
503
        $enumValues = implode(',', $values['enums']);
504
        
505
        // Ensure the cache table exists
506
        if (empty($this->enum_map)) {
507
            $this->query("CREATE TABLE IF NOT EXISTS \"SQLiteEnums\" (\"TableColumn\" TEXT PRIMARY KEY, \"EnumList\" TEXT)");
508
        }
509
        
510
        // Ensure the table row exists
511
        if (empty($this->enum_map[$tablefield]) || $this->enum_map[$tablefield] != $enumValues) {
512
            $this->preparedQuery(
513
                "REPLACE INTO SQLiteEnums (TableColumn, EnumList) VALUES (?, ?)",
514
                array($tablefield, $enumValues)
515
            );
516
            $this->enum_map[$tablefield] = $enumValues;
517
        }
518
        
519
        // Set default
520
        if (!empty($values['default'])) {
521
            $default = str_replace(array('"', "'", "\\", "\0"), "", $values['default']);
522
            return "TEXT DEFAULT '$default'";
523
        } else {
524
            return 'TEXT';
525
        }
526
    }
527
    
528
    /**
529
     * Return a set type-formatted string
530
     * This type doesn't exist in SQLite either
531
     * 
532
     * @see SQLite3SchemaManager::enum()
533
     * 
534
     * @params array $values Contains a tokenised list of info about this data type
535
     * @return string
536
     */
537
    public function set($values)
538
    {
539
        return $this->enum($values);
540
    }
541
542
    /**
543
     * Return a float type-formatted string
544
     * 
545
     * @params array $values Contains a tokenised list of info about this data type
546
     * @return string
547
     */
548
    public function float($values, $asDbValue = false)
0 ignored issues
show
The parameter $values is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
The parameter $asDbValue is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
549
    {
550
        return "REAL";
551
    }
552
553
    /**
554
     * Return a Double type-formatted string
555
     * 
556
     * @params array $values Contains a tokenised list of info about this data type
557
     * @return string
558
     */
559
    public function double($values, $asDbValue = false)
0 ignored issues
show
The parameter $values is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
The parameter $asDbValue is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
560
    {
561
        return "REAL";
562
    }
563
564
    /**
565
     * Return a int type-formatted string
566
     * 
567
     * @params array $values Contains a tokenised list of info about this data type
568
     * @return string
569
     */
570
    public function int($values, $asDbValue = false)
0 ignored issues
show
The parameter $asDbValue is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
571
    {
572
        return "INTEGER({$values['precision']}) " . strtoupper($values['null']) . " DEFAULT " . (int)$values['default'];
573
    }
574
575
    /**
576
     * Return a bigint type-formatted string
577
     *
578
     * @params array $values Contains a tokenised list of info about this data type
579
     * @return string
580
     */
581
    public function bigint($values, $asDbValue = false)
582
    {
583
        return $this->int($values, $asDbValue);
584
    }
585
586
    /**
587
     * Return a datetime type-formatted string
588
     * For SQLite3, we simply return the word 'TEXT', no other parameters are necessary
589
     * 
590
     * @params array $values Contains a tokenised list of info about this data type
591
     * @return string
592
     */
593
    public function ss_datetime($values, $asDbValue = false)
0 ignored issues
show
The parameter $values is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
The parameter $asDbValue is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
594
    {
595
        return "DATETIME";
596
    }
597
598
    /**
599
     * Return a text type-formatted string
600
     * 
601
     * @params array $values Contains a tokenised list of info about this data type
602
     * @return string
603
     */
604
    public function text($values, $asDbValue = false)
0 ignored issues
show
The parameter $values is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
The parameter $asDbValue is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
605
    {
606
        return 'TEXT';
607
    }
608
609
    /**
610
     * Return a time type-formatted string
611
     * 
612
     * @params array $values Contains a tokenised list of info about this data type
613
     * @return string
614
     */
615
    public function time($values)
0 ignored issues
show
The parameter $values is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
616
    {
617
        return "TEXT";
618
    }
619
620
    /**
621
     * Return a varchar type-formatted string
622
     * 
623
     * @params array $values Contains a tokenised list of info about this data type
624
     * @return string
625
     */
626
    public function varchar($values, $asDbValue = false)
0 ignored issues
show
The parameter $asDbValue is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
627
    {
628
        return "VARCHAR({$values['precision']}) COLLATE NOCASE";
629
    }
630
631
    /*
632
     * Return a 4 digit numeric type.  MySQL has a proprietary 'Year' type.
633
     * For SQLite3 we use TEXT
634
     */
635
    public function year($values, $asDbValue = false)
0 ignored issues
show
The parameter $values is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
The parameter $asDbValue is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
636
    {
637
        return "TEXT";
638
    }
639
640
    public function IdColumn($asDbValue = false, $hasAutoIncPK = true)
641
    {
642
        return 'INTEGER PRIMARY KEY AUTOINCREMENT';
643
    }
644
645
    public function hasTable($tableName)
646
    {
647
        return (bool)$this->preparedQuery(
648
            'SELECT name FROM sqlite_master WHERE type = ? AND name = ?',
649
            array('table', $tableName)
650
        )->first();
651
    }
652
653
    /**
654
     * Return enum values for the given field
655
     * 
656
     * @return array
657
     */
658
    public function enumValuesForField($tableName, $fieldName)
659
    {
660
        $tablefield = "$tableName.$fieldName";
661
        
662
        // Check already cached values for this field
663
        if (!empty($this->enum_map[$tablefield])) {
664
            return explode(',', $this->enum_map[$tablefield]);
665
        }
666
        
667
        // Retrieve and cache these details from the database
668
        $classnameinfo = $this->preparedQuery(
669
            "SELECT EnumList FROM SQLiteEnums WHERE TableColumn = ?",
670
            array($tablefield)
671
        )->first();
672
        if ($classnameinfo) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $classnameinfo of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
673
            $valueList = $classnameinfo['EnumList'];
674
            $this->enum_map[$tablefield] = $valueList;
675
            return explode(',', $valueList);
676
        }
677
        
678
        // Fallback to empty list
679
        return array();
680
    }
681
    
682
    public function dbDataType($type)
683
    {
684
        $values = array(
685
            'unsigned integer' => 'INT'
686
        );
687
        
688
        if (isset($values[$type])) {
689
            return $values[$type];
690
        } else {
691
            return '';
692
        }
693
    }
694
}
695