MySQLSchemaManager   F
last analyzed

Complexity

Total Complexity 95

Size/Duplication

Total Lines 649
Duplicated Lines 0 %

Importance

Changes 0
Metric Value
eloc 215
dl 0
loc 649
rs 2
c 0
b 0
f 0
wmc 95

38 Methods

Rating   Name   Duplication   Size   Complexity  
A checkAndRepairTable() 0 24 5
C alterTable() 0 70 15
A databaseList() 0 3 1
A createIndex() 0 3 1
A isView() 0 4 2
A databaseExists() 0 5 1
A createDatabase() 0 5 1
A createField() 0 3 1
A alterField() 0 3 1
A renameTable() 0 7 2
B createTable() 0 40 9
A hasTable() 0 6 1
A renameField() 0 5 2
A runTableCheckCommand() 0 9 3
A dropDatabase() 0 3 1
A enum() 0 11 1
A alterIndex() 0 9 1
A indexKey() 0 4 1
A text() 0 8 1
A IdColumn() 0 3 1
A time() 0 6 1
A boolean() 0 8 1
A float() 0 6 1
A int() 0 6 1
A year() 0 3 1
A defaultClause() 0 6 2
A enumValuesForField() 0 11 2
A getIndexSqlDefinition() 0 10 2
A tableList() 0 8 2
A set() 0 11 1
A decimal() 0 23 5
A dbDataType() 0 10 2
B indexList() 0 34 8
A varchar() 0 11 1
A date() 0 6 1
A bigint() 0 9 1
A datetime() 0 6 1
B fieldList() 0 30 11

How to fix   Complexity   

Complex Class

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

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

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

1
<?php
2
3
namespace SilverStripe\ORM\Connect;
4
5
use SilverStripe\Core\Config\Config;
6
use SilverStripe\Core\Convert;
7
use LogicException;
8
9
/**
10
 * Represents schema management object for MySQL
11
 */
12
class MySQLSchemaManager extends DBSchemaManager
13
{
14
15
    /**
16
     * Identifier for this schema, used for configuring schema-specific table
17
     * creation options
18
     *
19
     * @skipUpgrade
20
     */
21
    const ID = 'MySQLDatabase';
22
23
    public function createTable($table, $fields = null, $indexes = null, $options = null, $advancedOptions = null)
24
    {
25
        $fieldSchemas = $indexSchemas = "";
26
27
        if (!empty($options[self::ID])) {
28
            $addOptions = $options[self::ID];
29
        } else {
30
            $addOptions = "ENGINE=InnoDB";
31
        }
32
33
        if (!isset($fields['ID'])) {
34
            $fields['ID'] = "int(11) not null auto_increment";
35
        }
36
        if ($fields) {
37
            foreach ($fields as $k => $v) {
38
                $fieldSchemas .= "\"$k\" $v,\n";
39
            }
40
        }
41
        if ($indexes) {
42
            foreach ($indexes as $k => $v) {
43
                // force MyISAM if we have a fulltext index
44
                if ($v['type'] === 'fulltext') {
45
                    $addOptions = 'ENGINE=MyISAM';
46
                }
47
                $indexSchemas .= $this->getIndexSqlDefinition($k, $v) . ",\n";
48
            }
49
        }
50
51
        // Switch to "CREATE TEMPORARY TABLE" for temporary tables
52
        $temporary = empty($options['temporary'])
53
                ? ""
54
                : "TEMPORARY";
55
56
        $this->query("CREATE $temporary TABLE \"$table\" (
57
				$fieldSchemas
58
				$indexSchemas
59
				primary key (ID)
60
			) {$addOptions}");
61
62
        return $table;
63
    }
64
65
    public function alterTable(
66
        $tableName,
67
        $newFields = null,
68
        $newIndexes = null,
69
        $alteredFields = null,
70
        $alteredIndexes = null,
71
        $alteredOptions = null,
72
        $advancedOptions = null
73
    ) {
74
        if ($this->isView($tableName)) {
75
            $this->alterationMessage(
76
                sprintf("Table %s not changed as it is a view", $tableName),
77
                "changed"
78
            );
79
            return;
80
        }
81
        $alterList = array();
82
83
        if ($newFields) {
84
            foreach ($newFields as $k => $v) {
85
                $alterList[] = "ADD \"$k\" $v";
86
            }
87
        }
88
        if ($newIndexes) {
89
            foreach ($newIndexes as $k => $v) {
90
                $alterList[] = "ADD " . $this->getIndexSqlDefinition($k, $v);
91
            }
92
        }
93
        if ($alteredFields) {
94
            foreach ($alteredFields as $k => $v) {
95
                $alterList[] = "CHANGE \"$k\" \"$k\" $v";
96
            }
97
        }
98
        if ($alteredIndexes) {
99
            foreach ($alteredIndexes as $k => $v) {
100
                $alterList[] = "DROP INDEX \"$k\"";
101
                $alterList[] = "ADD " . $this->getIndexSqlDefinition($k, $v);
102
            }
103
        }
104
105
        $dbID = self::ID;
106
        if ($alteredOptions && isset($alteredOptions[$dbID])) {
107
            $indexList = $this->indexList($tableName);
108
            $skip = false;
109
            foreach ($indexList as $index) {
110
                if ($index['type'] === 'fulltext') {
111
                    $skip = true;
112
                    break;
113
                }
114
            }
115
            if ($skip) {
116
                $this->alterationMessage(
117
                    sprintf(
118
                        "Table %s options not changed to %s due to fulltextsearch index",
119
                        $tableName,
120
                        $alteredOptions[$dbID]
121
                    ),
122
                    "changed"
123
                );
124
            } else {
125
                $this->query(sprintf("ALTER TABLE \"%s\" %s", $tableName, $alteredOptions[$dbID]));
126
                $this->alterationMessage(
127
                    sprintf("Table %s options changed: %s", $tableName, $alteredOptions[$dbID]),
128
                    "changed"
129
                );
130
            }
131
        }
132
133
        $alterations = implode(",\n", $alterList);
134
        $this->query("ALTER TABLE \"$tableName\" $alterations");
135
    }
136
137
    public function isView($tableName)
138
    {
139
        $info = $this->query("SHOW /*!50002 FULL*/ TABLES LIKE '$tableName'")->record();
140
        return $info && strtoupper($info['Table_type']) == 'VIEW';
0 ignored issues
show
Bug Best Practice introduced by
The expression $info 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...
141
    }
142
143
    /**
144
     * Renames a table
145
     *
146
     * @param string $oldTableName
147
     * @param string $newTableName
148
     * @throws LogicException
149
     * @return Query
150
     */
151
    public function renameTable($oldTableName, $newTableName)
152
    {
153
        if (!$this->hasTable($oldTableName)) {
154
            throw new LogicException('Table ' . $oldTableName . ' does not exist.');
155
        }
156
157
        return $this->query("ALTER TABLE \"$oldTableName\" RENAME \"$newTableName\"");
158
    }
159
160
    public function checkAndRepairTable($tableName)
161
    {
162
        // Flag to ensure we only send the warning about PDO + native mode once
163
        static $pdo_warning_sent = false;
164
165
        // If running PDO and not in emulated mode, check table will fail
166
        if ($this->database->getConnector() instanceof PDOConnector && !PDOConnector::is_emulate_prepare()) {
167
            if (!$pdo_warning_sent) {
168
                $this->alterationMessage('CHECK TABLE command disabled for PDO in native mode', 'notice');
169
                $pdo_warning_sent = true;
170
            }
171
172
            return true;
173
        }
174
175
        // Perform check
176
        if ($this->runTableCheckCommand("CHECK TABLE \"$tableName\"")) {
177
            return true;
178
        }
179
        $this->alterationMessage(
180
            "Table $tableName: repaired",
181
            "repaired"
182
        );
183
        return $this->runTableCheckCommand("REPAIR TABLE \"$tableName\"");
184
    }
185
186
    /**
187
     * Helper function used by checkAndRepairTable.
188
     * @param string $sql Query to run.
189
     * @return boolean Returns if the query returns a successful result.
190
     */
191
    protected function runTableCheckCommand($sql)
192
    {
193
        $testResults = $this->query($sql);
194
        foreach ($testResults as $testRecord) {
195
            if (strtolower($testRecord['Msg_text']) != 'ok') {
196
                return false;
197
            }
198
        }
199
        return true;
200
    }
201
202
    public function hasTable($table)
203
    {
204
        // MySQLi doesn't like parameterised queries for some queries
205
        // underscores need to be escaped in a SHOW TABLES LIKE query
206
        $sqlTable = str_replace('_', '\\_', $this->database->quoteString($table));
207
        return (bool) ($this->query("SHOW TABLES LIKE $sqlTable")->value());
208
    }
209
210
    public function createField($tableName, $fieldName, $fieldSpec)
211
    {
212
        $this->query("ALTER TABLE \"$tableName\" ADD \"$fieldName\" $fieldSpec");
213
    }
214
215
    public function databaseList()
216
    {
217
        return $this->query("SHOW DATABASES")->column();
218
    }
219
220
    public function databaseExists($name)
221
    {
222
        // MySQLi doesn't like parameterised queries for some queries
223
        $sqlName = addcslashes($this->database->quoteString($name), '%_');
224
        return !!($this->query("SHOW DATABASES LIKE $sqlName")->value());
225
    }
226
227
    public function createDatabase($name)
228
    {
229
        $charset = Config::inst()->get('SilverStripe\ORM\Connect\MySQLDatabase', 'charset');
230
        $collation = Config::inst()->get('SilverStripe\ORM\Connect\MySQLDatabase', 'collation');
231
        $this->query("CREATE DATABASE \"$name\" DEFAULT CHARACTER SET {$charset} DEFAULT COLLATE {$collation}");
232
    }
233
234
    public function dropDatabase($name)
235
    {
236
        $this->query("DROP DATABASE \"$name\"");
237
    }
238
239
    /**
240
     * Change the database type of the given field.
241
     * @param string $tableName The name of the tbale the field is in.
242
     * @param string $fieldName The name of the field to change.
243
     * @param string $fieldSpec The new field specification
244
     */
245
    public function alterField($tableName, $fieldName, $fieldSpec)
246
    {
247
        $this->query("ALTER TABLE \"$tableName\" CHANGE \"$fieldName\" \"$fieldName\" $fieldSpec");
248
    }
249
250
    /**
251
     * Change the database column name of the given field.
252
     *
253
     * @param string $tableName The name of the tbale the field is in.
254
     * @param string $oldName The name of the field to change.
255
     * @param string $newName The new name of the field
256
     */
257
    public function renameField($tableName, $oldName, $newName)
258
    {
259
        $fieldList = $this->fieldList($tableName);
260
        if (array_key_exists($oldName, $fieldList)) {
261
            $this->query("ALTER TABLE \"$tableName\" CHANGE \"$oldName\" \"$newName\" " . $fieldList[$oldName]);
262
        }
263
    }
264
265
    protected static $_cache_collation_info = array();
266
267
    public function fieldList($table)
268
    {
269
        $fields = $this->query("SHOW FULL FIELDS IN \"$table\"");
270
        $fieldList = array();
271
        foreach ($fields as $field) {
272
            $fieldSpec = $field['Type'];
273
            if (!$field['Null'] || $field['Null'] == 'NO') {
274
                $fieldSpec .= ' not null';
275
            }
276
277
            if ($field['Collation'] && $field['Collation'] != 'NULL') {
278
                // Cache collation info to cut down on database traffic
279
                if (!isset(self::$_cache_collation_info[$field['Collation']])) {
280
                    self::$_cache_collation_info[$field['Collation']]
281
                        = $this->query("SHOW COLLATION LIKE '{$field['Collation']}'")->record();
282
                }
283
                $collInfo = self::$_cache_collation_info[$field['Collation']];
284
                $fieldSpec .= " character set $collInfo[Charset] collate $field[Collation]";
285
            }
286
287
            if ($field['Default'] || $field['Default'] === "0" || $field['Default'] === '') {
288
                $fieldSpec .= " default " . $this->database->quoteString($field['Default']);
289
            }
290
            if ($field['Extra']) {
291
                $fieldSpec .= " " . $field['Extra'];
292
            }
293
294
            $fieldList[$field['Field']] = $fieldSpec;
295
        }
296
        return $fieldList;
297
    }
298
299
    /**
300
     * Create an index on a table.
301
     *
302
     * @param string $tableName The name of the table.
303
     * @param string $indexName The name of the index.
304
     * @param string $indexSpec The specification of the index, see {@link SS_Database::requireIndex()} for more
305
     *                          details.
306
     */
307
    public function createIndex($tableName, $indexName, $indexSpec)
308
    {
309
        $this->query("ALTER TABLE \"$tableName\" ADD " . $this->getIndexSqlDefinition($indexName, $indexSpec));
310
    }
311
312
    /**
313
     * Generate SQL suitable for creating this index
314
     *
315
     * @param string $indexName
316
     * @param string|array $indexSpec See {@link requireTable()} for details
317
     * @return string MySQL compatible ALTER TABLE syntax
318
     */
319
    protected function getIndexSqlDefinition($indexName, $indexSpec)
320
    {
321
        if ($indexSpec['type'] == 'using') {
322
            return sprintf('index "%s" using (%s)', $indexName, $this->implodeColumnList($indexSpec['columns']));
323
        }
324
        return sprintf(
325
            '%s "%s" (%s)',
326
            $indexSpec['type'],
327
            $indexName,
328
            $this->implodeColumnList($indexSpec['columns'])
329
        );
330
    }
331
332
    public function alterIndex($tableName, $indexName, $indexSpec)
333
    {
334
        $this->query(sprintf('ALTER TABLE "%s" DROP INDEX "%s"', $tableName, $indexName));
335
        $this->query(sprintf(
336
            'ALTER TABLE "%s" ADD %s "%s" %s',
337
            $tableName,
338
            $indexSpec['type'],
339
            $indexName,
340
            $this->implodeColumnList($indexSpec['columns'])
341
        ));
342
    }
343
344
    protected function indexKey($table, $index, $spec)
345
    {
346
        // MySQL simply uses the same index name as SilverStripe does internally
347
        return $index;
348
    }
349
350
    public function indexList($table)
351
    {
352
        $indexes = $this->query("SHOW INDEXES IN \"$table\"");
353
        $groupedIndexes = array();
354
        $indexList = array();
355
356
        foreach ($indexes as $index) {
357
            $groupedIndexes[$index['Key_name']]['fields'][$index['Seq_in_index']] = $index['Column_name'];
358
359
            if ($index['Index_type'] == 'FULLTEXT') {
360
                $groupedIndexes[$index['Key_name']]['type'] = 'fulltext';
361
            } elseif (!$index['Non_unique']) {
362
                $groupedIndexes[$index['Key_name']]['type'] = 'unique';
363
            } elseif ($index['Index_type'] == 'HASH') {
364
                $groupedIndexes[$index['Key_name']]['type'] = 'hash';
365
            } elseif ($index['Index_type'] == 'RTREE') {
366
                $groupedIndexes[$index['Key_name']]['type'] = 'rtree';
367
            } else {
368
                $groupedIndexes[$index['Key_name']]['type'] = 'index';
369
            }
370
        }
371
372
        if ($groupedIndexes) {
373
            foreach ($groupedIndexes as $index => $details) {
374
                ksort($details['fields']);
375
                $indexList[$index] = array(
376
                    'name' => $index,
377
                    'columns' => $details['fields'],
378
                    'type' => $details['type'],
379
                );
380
            }
381
        }
382
383
        return $indexList;
384
    }
385
386
    public function tableList()
387
    {
388
        $tables = array();
389
        foreach ($this->query("SHOW FULL TABLES WHERE Table_Type != 'VIEW'") as $record) {
390
            $table = reset($record);
391
            $tables[strtolower($table)] = $table;
392
        }
393
        return $tables;
394
    }
395
396
    public function enumValuesForField($tableName, $fieldName)
397
    {
398
        // Get the enum of all page types from the SiteTree table
399
        $classnameinfo = $this->query("DESCRIBE \"$tableName\" \"$fieldName\"")->first();
0 ignored issues
show
Deprecated Code introduced by
The function SilverStripe\ORM\Connect\Query::first() has been deprecated: Use record() instead ( Ignorable by Annotation )

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

399
        $classnameinfo = /** @scrutinizer ignore-deprecated */ $this->query("DESCRIBE \"$tableName\" \"$fieldName\"")->first();

This function has been deprecated. The supplier of the function has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead.

Loading history...
400
        preg_match_all("/'[^,]+'/", $classnameinfo["Type"], $matches);
401
402
        $classes = array();
403
        foreach ($matches[0] as $value) {
404
            $classes[] = stripslashes(trim($value, "'"));
405
        }
406
        return $classes;
407
    }
408
409
    public function dbDataType($type)
410
    {
411
        $values = array(
412
            'unsigned integer' => 'UNSIGNED'
413
        );
414
415
        if (isset($values[$type])) {
416
            return $values[$type];
417
        } else {
418
            return '';
419
        }
420
    }
421
422
    /**
423
     * Return a boolean type-formatted string
424
     *
425
     * @param array $values Contains a tokenised list of info about this data type
426
     * @return string
427
     */
428
    public function boolean($values)
429
    {
430
        //For reference, this is what typically gets passed to this function:
431
        //$parts=Array('datatype'=>'tinyint', 'precision'=>1, 'sign'=>'unsigned', 'null'=>'not null',
432
        //'default'=>$this->default);
433
        //DB::requireField($this->tableName, $this->name, "tinyint(1) unsigned not null default
434
        //'{$this->defaultVal}'");
435
        return 'tinyint(1) unsigned not null' . $this->defaultClause($values);
436
    }
437
438
    /**
439
     * Return a date type-formatted string
440
     * For MySQL, we simply return the word 'date', no other parameters are necessary
441
     *
442
     * @param array $values Contains a tokenised list of info about this data type
443
     * @return string
444
     */
445
    public function date($values)
446
    {
447
        //For reference, this is what typically gets passed to this function:
448
        //$parts=Array('datatype'=>'date');
449
        //DB::requireField($this->tableName, $this->name, "date");
450
        return 'date';
451
    }
452
453
    /**
454
     * Return a decimal type-formatted string
455
     *
456
     * @param array $values Contains a tokenised list of info about this data type
457
     * @return string
458
     */
459
    public function decimal($values)
460
    {
461
        //For reference, this is what typically gets passed to this function:
462
        //$parts=Array('datatype'=>'decimal', 'precision'=>"$this->wholeSize,$this->decimalSize");
463
        //DB::requireField($this->tableName, $this->name, "decimal($this->wholeSize,$this->decimalSize)");
464
        // Avoid empty strings being put in the db
465
        if ($values['precision'] == '') {
466
            $precision = 1;
467
        } else {
468
            $precision = $values['precision'];
469
        }
470
471
        // Fix format of default value to match precision
472
        if (isset($values['default']) && is_numeric($values['default'])) {
473
            $decs = strpos($precision, ',') !== false
474
                    ? (int) substr($precision, strpos($precision, ',') + 1)
475
                    : 0;
476
            $values['default'] = number_format($values['default'], $decs, '.', '');
477
        } else {
478
            unset($values['default']);
479
        }
480
481
        return "decimal($precision) not null" . $this->defaultClause($values);
482
    }
483
484
    /**
485
     * Return a enum type-formatted string
486
     *
487
     * @param array $values Contains a tokenised list of info about this data type
488
     * @return string
489
     */
490
    public function enum($values)
491
    {
492
        //For reference, this is what typically gets passed to this function:
493
        //$parts=Array('datatype'=>'enum', 'enums'=>$this->enum, 'character set'=>'utf8', 'collate'=>
494
        // 'utf8_general_ci', 'default'=>$this->default);
495
        //DB::requireField($this->tableName, $this->name, "enum('" . implode("','", $this->enum) . "') character set
496
        // utf8 collate utf8_general_ci default '{$this->default}'");
497
        $valuesString = implode(",", Convert::raw2sql($values['enums'], true));
0 ignored issues
show
Bug introduced by
It seems like SilverStripe\Core\Conver...$values['enums'], true) can also be of type string; however, parameter $pieces of implode() does only seem to accept array, maybe add an additional type check? ( Ignorable by Annotation )

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

497
        $valuesString = implode(",", /** @scrutinizer ignore-type */ Convert::raw2sql($values['enums'], true));
Loading history...
498
        $charset = Config::inst()->get('SilverStripe\ORM\Connect\MySQLDatabase', 'charset');
499
        $collation = Config::inst()->get('SilverStripe\ORM\Connect\MySQLDatabase', 'collation');
500
        return "enum($valuesString) character set {$charset} collate {$collation}" . $this->defaultClause($values);
501
    }
502
503
    /**
504
     * Return a set type-formatted string
505
     *
506
     * @param array $values Contains a tokenised list of info about this data type
507
     * @return string
508
     */
509
    public function set($values)
510
    {
511
        //For reference, this is what typically gets passed to this function:
512
        //$parts=Array('datatype'=>'enum', 'enums'=>$this->enum, 'character set'=>'utf8', 'collate'=>
513
        // 'utf8_general_ci', 'default'=>$this->default);
514
        //DB::requireField($this->tableName, $this->name, "enum('" . implode("','", $this->enum) . "') character set
515
        //utf8 collate utf8_general_ci default '{$this->default}'");
516
        $valuesString = implode(",", Convert::raw2sql($values['enums'], true));
0 ignored issues
show
Bug introduced by
It seems like SilverStripe\Core\Conver...$values['enums'], true) can also be of type string; however, parameter $pieces of implode() does only seem to accept array, maybe add an additional type check? ( Ignorable by Annotation )

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

516
        $valuesString = implode(",", /** @scrutinizer ignore-type */ Convert::raw2sql($values['enums'], true));
Loading history...
517
        $charset = Config::inst()->get('SilverStripe\ORM\Connect\MySQLDatabase', 'charset');
518
        $collation = Config::inst()->get('SilverStripe\ORM\Connect\MySQLDatabase', 'collation');
519
        return "set($valuesString) character set {$charset} collate {$collation}" . $this->defaultClause($values);
520
    }
521
522
    /**
523
     * Return a float type-formatted string
524
     * For MySQL, we simply return the word 'date', no other parameters are necessary
525
     *
526
     * @param array $values Contains a tokenised list of info about this data type
527
     * @return string
528
     */
529
    public function float($values)
530
    {
531
        //For reference, this is what typically gets passed to this function:
532
        //$parts=Array('datatype'=>'float');
533
        //DB::requireField($this->tableName, $this->name, "float");
534
        return "float not null" . $this->defaultClause($values);
535
    }
536
537
    /**
538
     * Return a int type-formatted string
539
     *
540
     * @param array $values Contains a tokenised list of info about this data type
541
     * @return string
542
     */
543
    public function int($values)
544
    {
545
        //For reference, this is what typically gets passed to this function:
546
        //$parts=Array('datatype'=>'int', 'precision'=>11, 'null'=>'not null', 'default'=>(int)$this->default);
547
        //DB::requireField($this->tableName, $this->name, "int(11) not null default '{$this->defaultVal}'");
548
        return "int(11) not null" . $this->defaultClause($values);
549
    }
550
551
    /**
552
     * Return a bigint type-formatted string
553
     *
554
     * @param array $values Contains a tokenised list of info about this data type
555
     * @return string
556
     */
557
    public function bigint($values)
558
    {
559
        //For reference, this is what typically gets passed to this function:
560
        //$parts=Array('datatype'=>'bigint', 'precision'=>20, 'null'=>'not null', 'default'=>$this->defaultVal,
561
        //             'arrayValue'=>$this->arrayValue);
562
        //$values=Array('type'=>'bigint', 'parts'=>$parts);
563
        //DB::requireField($this->tableName, $this->name, $values);
564
565
        return 'bigint(20) not null' . $this->defaultClause($values);
566
    }
567
568
    /**
569
     * Return a datetime type-formatted string
570
     * For MySQL, we simply return the word 'datetime', no other parameters are necessary
571
     *
572
     * @param array $values Contains a tokenised list of info about this data type
573
     * @return string
574
     */
575
    public function datetime($values)
576
    {
577
        //For reference, this is what typically gets passed to this function:
578
        //$parts=Array('datatype'=>'datetime');
579
        //DB::requireField($this->tableName, $this->name, $values);
580
        return 'datetime';
581
    }
582
583
    /**
584
     * Return a text type-formatted string
585
     *
586
     * @param array $values Contains a tokenised list of info about this data type
587
     * @return string
588
     */
589
    public function text($values)
590
    {
591
        //For reference, this is what typically gets passed to this function:
592
        //$parts=Array('datatype'=>'mediumtext', 'character set'=>'utf8', 'collate'=>'utf8_general_ci');
593
        //DB::requireField($this->tableName, $this->name, "mediumtext character set utf8 collate utf8_general_ci");
594
        $charset = Config::inst()->get('SilverStripe\ORM\Connect\MySQLDatabase', 'charset');
595
        $collation = Config::inst()->get('SilverStripe\ORM\Connect\MySQLDatabase', 'collation');
596
        return 'mediumtext character set ' . $charset . ' collate ' . $collation . $this->defaultClause($values);
597
    }
598
599
    /**
600
     * Return a time type-formatted string
601
     * For MySQL, we simply return the word 'time', no other parameters are necessary
602
     *
603
     * @param array $values Contains a tokenised list of info about this data type
604
     * @return string
605
     */
606
    public function time($values)
607
    {
608
        //For reference, this is what typically gets passed to this function:
609
        //$parts=Array('datatype'=>'time');
610
        //DB::requireField($this->tableName, $this->name, "time");
611
        return 'time';
612
    }
613
614
    /**
615
     * Return a varchar type-formatted string
616
     *
617
     * @param array $values Contains a tokenised list of info about this data type
618
     * @return string
619
     */
620
    public function varchar($values)
621
    {
622
        //For reference, this is what typically gets passed to this function:
623
        //$parts=Array('datatype'=>'varchar', 'precision'=>$this->size, 'character set'=>'utf8', 'collate'=>
624
        //'utf8_general_ci');
625
        //DB::requireField($this->tableName, $this->name, "varchar($this->size) character set utf8 collate
626
        // utf8_general_ci");
627
        $default = $this->defaultClause($values);
628
        $charset = Config::inst()->get('SilverStripe\ORM\Connect\MySQLDatabase', 'charset');
629
        $collation = Config::inst()->get('SilverStripe\ORM\Connect\MySQLDatabase', 'collation');
630
        return "varchar({$values['precision']}) character set {$charset} collate {$collation}{$default}";
631
    }
632
633
    /*
634
     * Return the MySQL-proprietary 'Year' datatype
635
     *
636
     * @param array $values Contains a tokenised list of info about this data type
637
     * @return string
638
     */
639
    public function year($values)
640
    {
641
        return 'year(4)';
642
    }
643
644
    public function IdColumn($asDbValue = false, $hasAutoIncPK = true)
645
    {
646
        return 'int(11) not null auto_increment';
647
    }
648
649
    /**
650
     * Parses and escapes the default values for a specification
651
     *
652
     * @param array $values Contains a tokenised list of info about this data type
653
     * @return string Default clause
654
     */
655
    protected function defaultClause($values)
656
    {
657
        if (isset($values['default'])) {
658
            return ' default ' . $this->database->quoteString($values['default']);
659
        }
660
        return '';
661
    }
662
}
663