Failed Conditions
Pull Request — master (#3133)
by Michael
25:15 queued 21:18
created

MySqlSchemaManager::getMariaDb1027ColumnDefault()   B

Complexity

Conditions 7
Paths 6

Size

Total Lines 21
Code Lines 14

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 14
CRAP Score 7

Importance

Changes 0
Metric Value
dl 0
loc 21
ccs 14
cts 14
cp 1
rs 7.551
c 0
b 0
f 0
cc 7
eloc 14
nc 6
nop 2
crap 7
1
<?php
2
/*
3
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
4
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
5
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
6
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
7
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
8
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
9
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
10
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
11
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
12
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
13
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
14
 *
15
 * This software consists of voluntary contributions made by many individuals
16
 * and is licensed under the MIT license. For more information, see
17
 * <http://www.doctrine-project.org>.
18
 */
19
20
namespace Doctrine\DBAL\Schema;
21
22
use Doctrine\DBAL\Platforms\MariaDb1027Platform;
23
use Doctrine\DBAL\Platforms\MySqlPlatform;
24
use Doctrine\DBAL\Types\Type;
25
use const CASE_LOWER;
26
use function array_change_key_case;
27
use function array_shift;
28
use function array_values;
29
use function end;
30
use function preg_match;
31
use function preg_replace;
32
use function str_replace;
33
use function stripslashes;
34
use function strpos;
35
use function strtok;
36
use function strtolower;
37
38
/**
39
 * Schema manager for the MySql RDBMS.
40
 *
41
 * @author Konsta Vesterinen <[email protected]>
42
 * @author Lukas Smith <[email protected]> (PEAR MDB2 library)
43
 * @author Roman Borschel <[email protected]>
44
 * @author Benjamin Eberlei <[email protected]>
45
 * @since  2.0
46
 */
47
class MySqlSchemaManager extends AbstractSchemaManager
48
{
49
    /**
50
     * {@inheritdoc}
51
     */
52 9
    protected function _getPortableViewDefinition($view)
53
    {
54 9
        return new View($view['TABLE_NAME'], $view['VIEW_DEFINITION']);
55
    }
56
57
    /**
58
     * {@inheritdoc}
59
     */
60 645
    protected function _getPortableTableDefinition($table)
61
    {
62 645
        return array_shift($table);
63
    }
64
65
    /**
66
     * {@inheritdoc}
67
     */
68
    protected function _getPortableUserDefinition($user)
69
    {
70
        return [
71
            'user' => $user['User'],
72
            'password' => $user['Password'],
73
        ];
74
    }
75
76
    /**
77
     * {@inheritdoc}
78
     */
79 330
    protected function _getPortableTableIndexesList($tableIndexes, $tableName = null)
80
    {
81 330
        foreach ($tableIndexes as $k => $v) {
82 180
            $v = array_change_key_case($v, CASE_LOWER);
83 180
            if ($v['key_name'] === 'PRIMARY') {
84 144
                $v['primary'] = true;
85
            } else {
86 117
                $v['primary'] = false;
87
            }
88 180
            if (strpos($v['index_type'], 'FULLTEXT') !== false) {
89 27
                $v['flags'] = ['FULLTEXT'];
90 171
            } elseif (strpos($v['index_type'], 'SPATIAL') !== false) {
91 27
                $v['flags'] = ['SPATIAL'];
92
            }
93 180
            $tableIndexes[$k] = $v;
94
        }
95
96 330
        return parent::_getPortableTableIndexesList($tableIndexes, $tableName);
97
    }
98
99
    /**
100
     * {@inheritdoc}
101
     */
102
    protected function _getPortableSequenceDefinition($sequence)
103
    {
104
        return end($sequence);
105
    }
106
107
    /**
108
     * {@inheritdoc}
109
     */
110 18
    protected function _getPortableDatabaseDefinition($database)
111
    {
112 18
        return $database['Database'];
113
    }
114
115
    /**
116
     * {@inheritdoc}
117
     */
118 402
    protected function _getPortableTableColumnDefinition($tableColumn)
119
    {
120 402
        $tableColumn = array_change_key_case($tableColumn, CASE_LOWER);
121
122 402
        $dbType = strtolower($tableColumn['type']);
123 402
        $dbType = strtok($dbType, '(), ');
124 402
        $length = $tableColumn['length'] ?? strtok('(), ');
125
126 402
        $fixed = null;
127
128 402
        if ( ! isset($tableColumn['name'])) {
129 402
            $tableColumn['name'] = '';
130
        }
131
132 402
        $scale     = null;
133 402
        $precision = null;
134
135 402
        $type = $this->_platform->getDoctrineTypeMapping($dbType);
136
137
        // In cases where not connected to a database DESCRIBE $table does not return 'Comment'
138 402
        if (isset($tableColumn['comment'])) {
139 402
            $type                   = $this->extractDoctrineTypeFromComment($tableColumn['comment'], $type);
140 402
            $tableColumn['comment'] = $this->removeDoctrineTypeFromComment($tableColumn['comment'], $type);
141
        }
142
143
        switch ($dbType) {
144 402
            case 'char':
0 ignored issues
show
Coding Style introduced by
case statements should be defined using a colon.

As per the PSR-2 coding standard, case statements should not be wrapped in curly braces. There is no need for braces, since each case is terminated by the next break.

There is also the option to use a semicolon instead of a colon, this is discouraged because many programmers do not even know it works and the colon is universal between programming languages.

switch ($expr) {
    case "A": { //wrong
        doSomething();
        break;
    }
    case "B"; //wrong
        doSomething();
        break;
    case "C": //right
        doSomething();
        break;
}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
145 384
            case 'binary':
0 ignored issues
show
Coding Style introduced by
case statements should be defined using a colon.

As per the PSR-2 coding standard, case statements should not be wrapped in curly braces. There is no need for braces, since each case is terminated by the next break.

There is also the option to use a semicolon instead of a colon, this is discouraged because many programmers do not even know it works and the colon is universal between programming languages.

switch ($expr) {
    case "A": { //wrong
        doSomething();
        break;
    }
    case "B"; //wrong
        doSomething();
        break;
    case "C": //right
        doSomething();
        break;
}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
146 54
                $fixed = true;
147 54
                break;
148 384
            case 'float':
149 384
            case 'double':
150 375
            case 'real':
151 375
            case 'numeric':
152 375
            case 'decimal':
153 63
                if (preg_match('([A-Za-z]+\(([0-9]+)\,([0-9]+)\))', $tableColumn['type'], $match)) {
154 54
                    $precision = $match[1];
155 54
                    $scale     = $match[2];
156 54
                    $length    = null;
157
                }
158 63
                break;
159 366
            case 'tinytext':
160 27
                $length = MySqlPlatform::LENGTH_LIMIT_TINYTEXT;
161 27
                break;
162 366
            case 'text':
163 27
                $length = MySqlPlatform::LENGTH_LIMIT_TEXT;
164 27
                break;
165 366
            case 'mediumtext':
166 27
                $length = MySqlPlatform::LENGTH_LIMIT_MEDIUMTEXT;
167 27
                break;
168 366
            case 'tinyblob':
169
                $length = MySqlPlatform::LENGTH_LIMIT_TINYBLOB;
170
                break;
171 366
            case 'blob':
172 27
                $length = MySqlPlatform::LENGTH_LIMIT_BLOB;
173 27
                break;
174 366
            case 'mediumblob':
175 27
                $length = MySqlPlatform::LENGTH_LIMIT_MEDIUMBLOB;
176 27
                break;
177 366
            case 'tinyint':
178 366
            case 'smallint':
179 366
            case 'mediumint':
180 366
            case 'int':
181 195
            case 'integer':
182 195
            case 'bigint':
183 195
            case 'year':
184 297
                $length = null;
185 297
                break;
186
        }
187
188 402
        if ($this->_platform instanceof MariaDb1027Platform) {
189 132
            $columnDefault = $this->getMariaDb1027ColumnDefault($this->_platform, $tableColumn['default']);
190
        } else {
191 270
            $columnDefault = $tableColumn['default'];
192
        }
193
194
        $options = [
195 402
            'length'        => $length !== null ? (int) $length : null,
196 402
            'unsigned'      => strpos($tableColumn['type'], 'unsigned') !== false,
197 402
            'fixed'         => (bool) $fixed,
198 402
            'default'       => $columnDefault,
199 402
            'notnull'       => $tableColumn['null'] !== 'YES',
200
            'scale'         => null,
201
            'precision'     => null,
202 402
            'autoincrement' => strpos($tableColumn['extra'], 'auto_increment') !== false,
203 402
            'comment'       => isset($tableColumn['comment']) && $tableColumn['comment'] !== ''
204 126
                ? $tableColumn['comment']
205
                : null,
206
        ];
207
208 402
        if ($scale !== null && $precision !== null) {
209 54
            $options['scale']     = (int) $scale;
210 54
            $options['precision'] = (int) $precision;
211
        }
212
213 402
        $column = new Column($tableColumn['field'], Type::getType($type), $options);
214
215 402
        if (isset($tableColumn['collation'])) {
216 180
            $column->setPlatformOption('collation', $tableColumn['collation']);
217
        }
218
219 402
        return $column;
220
    }
221
222
    /**
223
     * Return Doctrine/Mysql-compatible column default values for MariaDB 10.2.7+ servers.
224
     *
225
     * - Since MariaDb 10.2.7 column defaults stored in information_schema are now quoted
226
     *   to distinguish them from expressions (see MDEV-10134).
227
     * - CURRENT_TIMESTAMP, CURRENT_TIME, CURRENT_DATE are stored in information_schema
228
     *   as current_timestamp(), currdate(), currtime()
229
     * - Quoted 'NULL' is not enforced by Maria, it is technically possible to have
230
     *   null in some circumstances (see https://jira.mariadb.org/browse/MDEV-14053)
231
     * - \' is always stored as '' in information_schema (normalized)
232
     *
233
     * @link https://mariadb.com/kb/en/library/information-schema-columns-table/
234
     * @link https://jira.mariadb.org/browse/MDEV-13132
235
     *
236
     * @param null|string $columnDefault default value as stored in information_schema for MariaDB >= 10.2.7
237
     */
238 132
    private function getMariaDb1027ColumnDefault(MariaDb1027Platform $platform, ?string $columnDefault) : ?string
239
    {
240 132
        if ($columnDefault === 'NULL' || $columnDefault === null) {
241 120
            return null;
242
        }
243 30
        if ($columnDefault[0] === "'") {
244 24
            return stripslashes(
245 24
                str_replace("''", "'",
246 24
                    preg_replace('/^\'(.*)\'$/', '$1', $columnDefault)
247
                )
248
            );
249
        }
250
        switch ($columnDefault) {
251 18
            case 'current_timestamp()':
0 ignored issues
show
Coding Style introduced by
case statements should be defined using a colon.

As per the PSR-2 coding standard, case statements should not be wrapped in curly braces. There is no need for braces, since each case is terminated by the next break.

There is also the option to use a semicolon instead of a colon, this is discouraged because many programmers do not even know it works and the colon is universal between programming languages.

switch ($expr) {
    case "A": { //wrong
        doSomething();
        break;
    }
    case "B"; //wrong
        doSomething();
        break;
    case "C": //right
        doSomething();
        break;
}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
252 12
                return $platform->getCurrentTimestampSQL();
253 15
            case 'curdate()':
254 9
                return $platform->getCurrentDateSQL();
255 15
            case 'curtime()':
256 9
                return $platform->getCurrentTimeSQL();
257
        }
258 12
        return $columnDefault;
259
    }
260
261
    /**
262
     * {@inheritdoc}
263
     */
264 313
    protected function _getPortableTableForeignKeysList($tableForeignKeys)
265
    {
266 313
        $list = [];
267 313
        foreach ($tableForeignKeys as $value) {
268 82
            $value = array_change_key_case($value, CASE_LOWER);
269 82
            if ( ! isset($list[$value['constraint_name']])) {
270 82
                if ( ! isset($value['delete_rule']) || $value['delete_rule'] === "RESTRICT") {
271 73
                    $value['delete_rule'] = null;
272
                }
273 82
                if ( ! isset($value['update_rule']) || $value['update_rule'] === "RESTRICT") {
274 82
                    $value['update_rule'] = null;
275
                }
276
277 82
                $list[$value['constraint_name']] = [
278 82
                    'name' => $value['constraint_name'],
279
                    'local' => [],
280
                    'foreign' => [],
281 82
                    'foreignTable' => $value['referenced_table_name'],
282 82
                    'onDelete' => $value['delete_rule'],
283 82
                    'onUpdate' => $value['update_rule'],
284
                ];
285
            }
286 82
            $list[$value['constraint_name']]['local'][]   = $value['column_name'];
287 82
            $list[$value['constraint_name']]['foreign'][] = $value['referenced_column_name'];
288
        }
289
290 313
        $result = [];
291 313
        foreach ($list as $constraint) {
292 82
            $result[] = new ForeignKeyConstraint(
293 82
                array_values($constraint['local']),
294 82
                $constraint['foreignTable'],
295 82
                array_values($constraint['foreign']),
296 82
                $constraint['name'],
297
                [
298 82
                    'onDelete' => $constraint['onDelete'],
299 82
                    'onUpdate' => $constraint['onUpdate'],
300
                ]
301
            );
302
        }
303
304 313
        return $result;
305
    }
306
}
307