Completed
Pull Request — master (#6930)
by Daniel
09:37
created

MySQLSchemaManager   D

Complexity

Total Complexity 93

Size/Duplication

Total Lines 636
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 7

Importance

Changes 0
Metric Value
dl 0
loc 636
rs 4.7257
c 0
b 0
f 0
wmc 93
lcom 1
cbo 7

38 Methods

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

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. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.

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
8
/**
9
 * Represents schema management object for MySQL
10
 */
11
class MySQLSchemaManager extends DBSchemaManager
12
{
13
14
    /**
15
     * Identifier for this schema, used for configuring schema-specific table
16
     * creation options
17
     *
18
     * @skipUpgrade
19
     */
20
    const ID = 'MySQLDatabase';
21
22
    public function createTable($table, $fields = null, $indexes = null, $options = null, $advancedOptions = null)
23
    {
24
        $fieldSchemas = $indexSchemas = "";
25
26
        if (!empty($options[self::ID])) {
27
            $addOptions = $options[self::ID];
28
        } else {
29
            $addOptions = "ENGINE=InnoDB";
30
        }
31
32
        if (!isset($fields['ID'])) {
33
            $fields['ID'] = "int(11) not null auto_increment";
34
        }
35
        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...
36
            foreach ($fields as $k => $v) {
37
                $fieldSchemas .= "\"$k\" $v,\n";
38
            }
39
        }
40
        if ($indexes) {
41
            foreach ($indexes as $k => $v) {
42
                // force MyISAM if we have a fulltext index
43
                if ($v['type'] === 'fulltext') {
44
                    $addOptions = 'ENGINE=MyISAM';
45
                }
46
                $indexSchemas .= $this->getIndexSqlDefinition($k, $v) . ",\n";
47
            }
48
        }
49
50
        // Switch to "CREATE TEMPORARY TABLE" for temporary tables
51
        $temporary = empty($options['temporary'])
52
                ? ""
53
                : "TEMPORARY";
54
55
        $this->query("CREATE $temporary TABLE \"$table\" (
56
				$fieldSchemas
57
				$indexSchemas
58
				primary key (ID)
59
			) {$addOptions}");
60
61
        return $table;
62
    }
63
64
    public function alterTable(
65
        $tableName,
66
        $newFields = null,
67
        $newIndexes = null,
68
        $alteredFields = null,
69
        $alteredIndexes = null,
70
        $alteredOptions = null,
71
        $advancedOptions = null
72
    ) {
73
        if ($this->isView($tableName)) {
74
            $this->alterationMessage(
75
                sprintf("Table %s not changed as it is a view", $tableName),
76
                "changed"
77
            );
78
            return;
79
        }
80
        $alterList = array();
81
82
        if ($newFields) {
83
            foreach ($newFields as $k => $v) {
84
                $alterList[] .= "ADD \"$k\" $v";
85
            }
86
        }
87
        if ($newIndexes) {
88
            foreach ($newIndexes as $k => $v) {
89
                $alterList[] .= "ADD " . $this->getIndexSqlDefinition($k, $v);
90
            }
91
        }
92
        if ($alteredFields) {
93
            foreach ($alteredFields as $k => $v) {
94
                $alterList[] .= "CHANGE \"$k\" \"$k\" $v";
95
            }
96
        }
97
        if ($alteredIndexes) {
98
            foreach ($alteredIndexes as $k => $v) {
99
                $alterList[] .= "DROP INDEX \"$k\"";
100
                $alterList[] .= "ADD " . $this->getIndexSqlDefinition($k, $v);
101
            }
102
        }
103
104
        $dbID = self::ID;
105
        if ($alteredOptions && isset($alteredOptions[$dbID])) {
106
            $indexList = $this->indexList($tableName);
107
            $skip = false;
108
            foreach ($indexList as $index) {
109
                if ($index['type'] === 'fulltext') {
110
                    $skip = true;
111
                    break;
112
                }
113
            }
114
            if ($skip) {
115
                $this->alterationMessage(
116
                    sprintf(
117
                        "Table %s options not changed to %s due to fulltextsearch index",
118
                        $tableName,
119
                        $alteredOptions[$dbID]
120
                    ),
121
                    "changed"
122
                );
123
            } else {
124
                $this->query(sprintf("ALTER TABLE \"%s\" %s", $tableName, $alteredOptions[$dbID]));
125
                $this->alterationMessage(
126
                    sprintf("Table %s options changed: %s", $tableName, $alteredOptions[$dbID]),
127
                    "changed"
128
                );
129
            }
130
        }
131
132
        $alterations = implode(",\n", $alterList);
133
        $this->query("ALTER TABLE \"$tableName\" $alterations");
134
    }
135
136
    public function isView($tableName)
137
    {
138
        $info = $this->query("SHOW /*!50002 FULL*/ TABLES LIKE '$tableName'")->record();
139
        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...
140
    }
141
142
    public function renameTable($oldTableName, $newTableName)
143
    {
144
        $this->query("ALTER TABLE \"$oldTableName\" RENAME \"$newTableName\"");
145
    }
146
147
    public function checkAndRepairTable($tableName)
148
    {
149
        // Flag to ensure we only send the warning about PDO + native mode once
150
        static $pdo_warning_sent = false;
151
152
        // If running PDO and not in emulated mode, check table will fail
153
        if ($this->database->getConnector() instanceof PDOConnector && !PDOConnector::is_emulate_prepare()) {
154
            if (!$pdo_warning_sent) {
155
                $this->alterationMessage('CHECK TABLE command disabled for PDO in native mode', 'notice');
156
                $pdo_warning_sent = true;
157
            }
158
159
            return true;
160
        }
161
162
        // Perform check
163
        if ($this->runTableCheckCommand("CHECK TABLE \"$tableName\"")) {
164
            return true;
165
        }
166
        $this->alterationMessage(
167
            "Table $tableName: repaired",
168
            "repaired"
169
        );
170
        return $this->runTableCheckCommand("REPAIR TABLE \"$tableName\" USE_FRM");
171
    }
172
173
    /**
174
     * Helper function used by checkAndRepairTable.
175
     * @param string $sql Query to run.
176
     * @return boolean Returns if the query returns a successful result.
177
     */
178
    protected function runTableCheckCommand($sql)
179
    {
180
        $testResults = $this->query($sql);
181
        foreach ($testResults as $testRecord) {
182
            if (strtolower($testRecord['Msg_text']) != 'ok') {
183
                return false;
184
            }
185
        }
186
        return true;
187
    }
188
189
    public function hasTable($table)
190
    {
191
        // MySQLi doesn't like parameterised queries for some queries
192
        // underscores need to be escaped in a SHOW TABLES LIKE query
193
        $sqlTable = str_replace('_', '\\_', $this->database->quoteString($table));
194
        return (bool) ($this->query("SHOW TABLES LIKE $sqlTable")->value());
195
    }
196
197
    public function createField($tableName, $fieldName, $fieldSpec)
198
    {
199
        $this->query("ALTER TABLE \"$tableName\" ADD \"$fieldName\" $fieldSpec");
200
    }
201
202
    public function databaseList()
203
    {
204
        return $this->query("SHOW DATABASES")->column();
205
    }
206
207
    public function databaseExists($name)
208
    {
209
        // MySQLi doesn't like parameterised queries for some queries
210
        $sqlName = $this->database->quoteString($name);
211
        return !!($this->query("SHOW DATABASES LIKE $sqlName")->value());
212
    }
213
214
    public function createDatabase($name)
215
    {
216
        $charset = Config::inst()->get('SilverStripe\ORM\Connect\MySQLDatabase', 'charset');
217
        $collation = Config::inst()->get('SilverStripe\ORM\Connect\MySQLDatabase', 'collation');
218
        $this->query("CREATE DATABASE \"$name\" DEFAULT CHARACTER SET {$charset} DEFAULT COLLATE {$collation}");
219
    }
220
221
    public function dropDatabase($name)
222
    {
223
        $this->query("DROP DATABASE \"$name\"");
224
    }
225
226
    /**
227
     * Change the database type of the given field.
228
     * @param string $tableName The name of the tbale the field is in.
229
     * @param string $fieldName The name of the field to change.
230
     * @param string $fieldSpec The new field specification
231
     */
232
    public function alterField($tableName, $fieldName, $fieldSpec)
233
    {
234
        $this->query("ALTER TABLE \"$tableName\" CHANGE \"$fieldName\" \"$fieldName\" $fieldSpec");
235
    }
236
237
    /**
238
     * Change the database column name of the given field.
239
     *
240
     * @param string $tableName The name of the tbale the field is in.
241
     * @param string $oldName The name of the field to change.
242
     * @param string $newName The new name of the field
243
     */
244
    public function renameField($tableName, $oldName, $newName)
245
    {
246
        $fieldList = $this->fieldList($tableName);
247
        if (array_key_exists($oldName, $fieldList)) {
248
            $this->query("ALTER TABLE \"$tableName\" CHANGE \"$oldName\" \"$newName\" " . $fieldList[$oldName]);
249
        }
250
    }
251
252
    protected static $_cache_collation_info = array();
253
254
    public function fieldList($table)
255
    {
256
        $fields = $this->query("SHOW FULL FIELDS IN \"$table\"");
257
        $fieldList = array();
258
        foreach ($fields as $field) {
259
            $fieldSpec = $field['Type'];
260
            if (!$field['Null'] || $field['Null'] == 'NO') {
261
                $fieldSpec .= ' not null';
262
            }
263
264
            if ($field['Collation'] && $field['Collation'] != 'NULL') {
265
                // Cache collation info to cut down on database traffic
266
                if (!isset(self::$_cache_collation_info[$field['Collation']])) {
267
                    self::$_cache_collation_info[$field['Collation']]
268
                        = $this->query("SHOW COLLATION LIKE '{$field['Collation']}'")->record();
269
                }
270
                $collInfo = self::$_cache_collation_info[$field['Collation']];
271
                $fieldSpec .= " character set $collInfo[Charset] collate $field[Collation]";
272
            }
273
274
            if ($field['Default'] || $field['Default'] === "0") {
275
                $fieldSpec .= " default " . $this->database->quoteString($field['Default']);
276
            }
277
            if ($field['Extra']) {
278
                $fieldSpec .= " " . $field['Extra'];
279
            }
280
281
            $fieldList[$field['Field']] = $fieldSpec;
282
        }
283
        return $fieldList;
284
    }
285
286
    /**
287
     * Create an index on a table.
288
     *
289
     * @param string $tableName The name of the table.
290
     * @param string $indexName The name of the index.
291
     * @param string $indexSpec The specification of the index, see {@link SS_Database::requireIndex()} for more
292
     *                          details.
293
     */
294
    public function createIndex($tableName, $indexName, $indexSpec)
295
    {
296
        $this->query("ALTER TABLE \"$tableName\" ADD " . $this->getIndexSqlDefinition($indexName, $indexSpec));
297
    }
298
299
    /**
300
     * Generate SQL suitable for creating this index
301
     *
302
     * @param string $indexName
303
     * @param string|array $indexSpec See {@link requireTable()} for details
304
     * @return string MySQL compatible ALTER TABLE syntax
305
     */
306
    protected function getIndexSqlDefinition($indexName, $indexSpec)
307
    {
308
        if ($indexSpec['type'] == 'using') {
309
            return sprintf('index "%s" using (%s)', $indexName, $this->implodeColumnList($indexSpec['columns']));
310
        } else {
311
            return sprintf('%s "%s" (%s)', $indexSpec['type'], $indexName, $this->implodeColumnList($indexSpec['columns']));
312
        }
313
    }
314
315
    public function alterIndex($tableName, $indexName, $indexSpec)
316
    {
317
        $indexSpec = $this->parseIndexSpec($indexName, $indexSpec);
318
        $this->query(sprintf('ALTER TABLE "%s" DROP INDEX "%s"', $tableName, $indexName));
319
        $this->query(sprintf(
320
            'ALTER TABLE "%s" ADD %s "%s" %s',
321
            $tableName,
322
            $indexSpec['type'],
323
            $indexName,
324
            $this->implodeColumnList($indexSpec['columns'])
325
        ));
326
    }
327
328
    protected function indexKey($table, $index, $spec)
329
    {
330
        // MySQL simply uses the same index name as SilverStripe does internally
331
        return $index;
332
    }
333
334
    public function indexList($table)
335
    {
336
        $indexes = $this->query("SHOW INDEXES IN \"$table\"");
337
        $groupedIndexes = array();
338
        $indexList = array();
339
340
        foreach ($indexes as $index) {
341
            $groupedIndexes[$index['Key_name']]['fields'][$index['Seq_in_index']] = $index['Column_name'];
342
343
            if ($index['Index_type'] == 'FULLTEXT') {
344
                $groupedIndexes[$index['Key_name']]['type'] = 'fulltext';
345
            } elseif (!$index['Non_unique']) {
346
                $groupedIndexes[$index['Key_name']]['type'] = 'unique';
347
            } elseif ($index['Index_type'] == 'HASH') {
348
                $groupedIndexes[$index['Key_name']]['type'] = 'hash';
349
            } elseif ($index['Index_type'] == 'RTREE') {
350
                $groupedIndexes[$index['Key_name']]['type'] = 'rtree';
351
            } else {
352
                $groupedIndexes[$index['Key_name']]['type'] = 'index';
353
            }
354
        }
355
356
        if ($groupedIndexes) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $groupedIndexes 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...
357
            foreach ($groupedIndexes as $index => $details) {
358
                ksort($details['fields']);
359
                $indexList[$index] = array(
360
                    'name' => $index,
361
                    'columns' => $details['fields'],
362
                    'type' => $details['type'],
363
                );
364
            }
365
        }
366
367
        return $indexList;
368
    }
369
370
    public function tableList()
371
    {
372
        $tables = array();
373
        foreach ($this->query("SHOW TABLES") as $record) {
374
            $table = reset($record);
375
            $tables[strtolower($table)] = $table;
376
        }
377
        return $tables;
378
    }
379
380
    public function enumValuesForField($tableName, $fieldName)
381
    {
382
        // Get the enum of all page types from the SiteTree table
383
        $classnameinfo = $this->query("DESCRIBE \"$tableName\" \"$fieldName\"")->first();
384
        preg_match_all("/'[^,]+'/", $classnameinfo["Type"], $matches);
385
386
        $classes = array();
387
        foreach ($matches[0] as $value) {
388
            $classes[] = stripslashes(trim($value, "'"));
389
        }
390
        return $classes;
391
    }
392
393
    public function dbDataType($type)
394
    {
395
        $values = array(
396
            'unsigned integer' => 'UNSIGNED'
397
        );
398
399
        if (isset($values[$type])) {
400
            return $values[$type];
401
        } else {
402
            return '';
403
        }
404
    }
405
406
    /**
407
     * Return a boolean type-formatted string
408
     *
409
     * @param array $values Contains a tokenised list of info about this data type
410
     * @return string
411
     */
412
    public function boolean($values)
413
    {
414
        //For reference, this is what typically gets passed to this function:
415
        //$parts=Array('datatype'=>'tinyint', 'precision'=>1, 'sign'=>'unsigned', 'null'=>'not null',
0 ignored issues
show
Unused Code Comprehensibility introduced by
83% 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...
416
        //'default'=>$this->default);
0 ignored issues
show
Unused Code Comprehensibility introduced by
86% 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...
417
        //DB::requireField($this->tableName, $this->name, "tinyint(1) unsigned not null default
418
        //'{$this->defaultVal}'");
419
        return 'tinyint(1) unsigned not null' . $this->defaultClause($values);
420
    }
421
422
    /**
423
     * Return a date type-formatted string
424
     * For MySQL, we simply return the word 'date', no other parameters are necessary
425
     *
426
     * @param array $values Contains a tokenised list of info about this data type
427
     * @return string
428
     */
429
    public function date($values)
430
    {
431
        //For reference, this is what typically gets passed to this function:
432
        //$parts=Array('datatype'=>'date');
0 ignored issues
show
Unused Code Comprehensibility introduced by
89% 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...
433
        //DB::requireField($this->tableName, $this->name, "date");
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...
434
        return 'date';
435
    }
436
437
    /**
438
     * Return a decimal type-formatted string
439
     *
440
     * @param array $values Contains a tokenised list of info about this data type
441
     * @return string
442
     */
443
    public function decimal($values)
444
    {
445
        //For reference, this is what typically gets passed to this function:
446
        //$parts=Array('datatype'=>'decimal', 'precision'=>"$this->wholeSize,$this->decimalSize");
0 ignored issues
show
Unused Code Comprehensibility introduced by
86% 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...
447
        //DB::requireField($this->tableName, $this->name, "decimal($this->wholeSize,$this->decimalSize)");
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...
448
        // Avoid empty strings being put in the db
449
        if ($values['precision'] == '') {
450
            $precision = 1;
451
        } else {
452
            $precision = $values['precision'];
453
        }
454
455
        // Fix format of default value to match precision
456
        if (isset($values['default']) && is_numeric($values['default'])) {
457
            $decs = strpos($precision, ',') !== false
458
                    ? (int) substr($precision, strpos($precision, ',') + 1)
459
                    : 0;
460
            $values['default'] = number_format($values['default'], $decs, '.', '');
461
        } else {
462
            unset($values['default']);
463
        }
464
465
        return "decimal($precision) not null" . $this->defaultClause($values);
466
    }
467
468
    /**
469
     * Return a enum type-formatted string
470
     *
471
     * @param array $values Contains a tokenised list of info about this data type
472
     * @return string
473
     */
474
    public function enum($values)
475
    {
476
        //For reference, this is what typically gets passed to this function:
477
        //$parts=Array('datatype'=>'enum', 'enums'=>$this->enum, 'character set'=>'utf8', 'collate'=>
0 ignored issues
show
Unused Code Comprehensibility introduced by
79% 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...
478
        // 'utf8_general_ci', 'default'=>$this->default);
0 ignored issues
show
Unused Code Comprehensibility introduced by
73% 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...
479
        //DB::requireField($this->tableName, $this->name, "enum('" . implode("','", $this->enum) . "') character set
480
        // utf8 collate utf8_general_ci default '{$this->default}'");
481
        $valuesString = implode(",", Convert::raw2sql($values['enums'], true));
482
        $charset = Config::inst()->get('SilverStripe\ORM\Connect\MySQLDatabase', 'charset');
483
        $collation = Config::inst()->get('SilverStripe\ORM\Connect\MySQLDatabase', 'collation');
484
        return "enum($valuesString) character set {$charset} collate {$collation}" . $this->defaultClause($values);
485
    }
486
487
    /**
488
     * Return a set type-formatted string
489
     *
490
     * @param array $values Contains a tokenised list of info about this data type
491
     * @return string
492
     */
493
    public function set($values)
494
    {
495
        //For reference, this is what typically gets passed to this function:
496
        //$parts=Array('datatype'=>'enum', 'enums'=>$this->enum, 'character set'=>'utf8', 'collate'=>
0 ignored issues
show
Unused Code Comprehensibility introduced by
79% 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...
497
        // 'utf8_general_ci', 'default'=>$this->default);
0 ignored issues
show
Unused Code Comprehensibility introduced by
73% 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...
498
        //DB::requireField($this->tableName, $this->name, "enum('" . implode("','", $this->enum) . "') character set
499
        //utf8 collate utf8_general_ci default '{$this->default}'");
500
        $valuesString = implode(",", Convert::raw2sql($values['enums'], true));
501
        $charset = Config::inst()->get('SilverStripe\ORM\Connect\MySQLDatabase', 'charset');
502
        $collation = Config::inst()->get('SilverStripe\ORM\Connect\MySQLDatabase', 'collation');
503
        return "set($valuesString) character set {$charset} collate {$collation}" . $this->defaultClause($values);
504
    }
505
506
    /**
507
     * Return a float type-formatted string
508
     * For MySQL, we simply return the word 'date', no other parameters are necessary
509
     *
510
     * @param array $values Contains a tokenised list of info about this data type
511
     * @return string
512
     */
513
    public function float($values)
514
    {
515
        //For reference, this is what typically gets passed to this function:
516
        //$parts=Array('datatype'=>'float');
0 ignored issues
show
Unused Code Comprehensibility introduced by
89% 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...
517
        //DB::requireField($this->tableName, $this->name, "float");
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...
518
        return "float not null" . $this->defaultClause($values);
519
    }
520
521
    /**
522
     * Return a int type-formatted string
523
     *
524
     * @param array $values Contains a tokenised list of info about this data type
525
     * @return string
526
     */
527
    public function int($values)
528
    {
529
        //For reference, this is what typically gets passed to this function:
530
        //$parts=Array('datatype'=>'int', 'precision'=>11, 'null'=>'not null', 'default'=>(int)$this->default);
0 ignored issues
show
Unused Code Comprehensibility introduced by
82% 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...
531
        //DB::requireField($this->tableName, $this->name, "int(11) not null default '{$this->defaultVal}'");
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...
532
        return "int(11) not null" . $this->defaultClause($values);
533
    }
534
535
    /**
536
     * Return a bigint type-formatted string
537
     *
538
     * @param array $values Contains a tokenised list of info about this data type
539
     * @return string
540
     */
541
    public function bigint($values)
542
    {
543
        //For reference, this is what typically gets passed to this function:
544
        //$parts=Array('datatype'=>'bigint', 'precision'=>20, 'null'=>'not null', 'default'=>$this->defaultVal,
0 ignored issues
show
Unused Code Comprehensibility introduced by
80% 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...
545
        //             'arrayValue'=>$this->arrayValue);
0 ignored issues
show
Unused Code Comprehensibility introduced by
75% 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...
546
        //$values=Array('type'=>'bigint', 'parts'=>$parts);
0 ignored issues
show
Unused Code Comprehensibility introduced by
86% 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...
547
        //DB::requireField($this->tableName, $this->name, $values);
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...
548
549
        return 'bigint(20) not null' . $this->defaultClause($values);
550
    }
551
552
    /**
553
     * Return a datetime type-formatted string
554
     * For MySQL, we simply return the word 'datetime', no other parameters are necessary
555
     *
556
     * @param array $values Contains a tokenised list of info about this data type
557
     * @return string
558
     */
559
    public function datetime($values)
560
    {
561
        //For reference, this is what typically gets passed to this function:
562
        //$parts=Array('datatype'=>'datetime');
0 ignored issues
show
Unused Code Comprehensibility introduced by
89% 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...
563
        //DB::requireField($this->tableName, $this->name, $values);
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...
564
        return 'datetime';
565
    }
566
567
    /**
568
     * Return a text type-formatted string
569
     *
570
     * @param array $values Contains a tokenised list of info about this data type
571
     * @return string
572
     */
573
    public function text($values)
574
    {
575
        //For reference, this is what typically gets passed to this function:
576
        //$parts=Array('datatype'=>'mediumtext', 'character set'=>'utf8', 'collate'=>'utf8_general_ci');
0 ignored issues
show
Unused Code Comprehensibility introduced by
85% 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...
577
        //DB::requireField($this->tableName, $this->name, "mediumtext character set utf8 collate utf8_general_ci");
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...
578
        $charset = Config::inst()->get('SilverStripe\ORM\Connect\MySQLDatabase', 'charset');
579
        $collation = Config::inst()->get('SilverStripe\ORM\Connect\MySQLDatabase', 'collation');
580
        return 'mediumtext character set ' . $charset . ' collate ' . $collation . $this->defaultClause($values);
581
    }
582
583
    /**
584
     * Return a time type-formatted string
585
     * For MySQL, we simply return the word 'time', no other parameters are necessary
586
     *
587
     * @param array $values Contains a tokenised list of info about this data type
588
     * @return string
589
     */
590
    public function time($values)
591
    {
592
        //For reference, this is what typically gets passed to this function:
593
        //$parts=Array('datatype'=>'time');
0 ignored issues
show
Unused Code Comprehensibility introduced by
89% 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...
594
        //DB::requireField($this->tableName, $this->name, "time");
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...
595
        return 'time';
596
    }
597
598
    /**
599
     * Return a varchar type-formatted string
600
     *
601
     * @param array $values Contains a tokenised list of info about this data type
602
     * @return string
603
     */
604
    public function varchar($values)
605
    {
606
        //For reference, this is what typically gets passed to this function:
607
        //$parts=Array('datatype'=>'varchar', 'precision'=>$this->size, 'character set'=>'utf8', 'collate'=>
0 ignored issues
show
Unused Code Comprehensibility introduced by
79% 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...
608
        //'utf8_general_ci');
609
        //DB::requireField($this->tableName, $this->name, "varchar($this->size) character set utf8 collate
610
        // utf8_general_ci");
611
        $default = $this->defaultClause($values);
612
        $charset = Config::inst()->get('SilverStripe\ORM\Connect\MySQLDatabase', 'charset');
613
        $collation = Config::inst()->get('SilverStripe\ORM\Connect\MySQLDatabase', 'collation');
614
        return "varchar({$values['precision']}) character set {$charset} collate {$collation}{$default}";
615
    }
616
617
    /*
618
	 * Return the MySQL-proprietary 'Year' datatype
619
	 *
620
	 * @param array $values Contains a tokenised list of info about this data type
621
	 * @return string
622
	 */
623
    public function year($values)
624
    {
625
        return 'year(4)';
626
    }
627
628
    public function IdColumn($asDbValue = false, $hasAutoIncPK = true)
629
    {
630
        return 'int(11) not null auto_increment';
631
    }
632
633
    /**
634
     * Parses and escapes the default values for a specification
635
     *
636
     * @param array $values Contains a tokenised list of info about this data type
637
     * @return string Default clause
638
     */
639
    protected function defaultClause($values)
640
    {
641
        if (isset($values['default'])) {
642
            return ' default ' . $this->database->quoteString($values['default']);
643
        }
644
        return '';
645
    }
646
}
647