Passed
Push — tests-better-coverage ( b00e66...9c1c22 )
by Michael
23:49
created

_getPortableTableColumnDefinition()   F

Complexity

Conditions 31
Paths 6656

Size

Total Lines 102
Code Lines 78

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 71
CRAP Score 31.0197

Importance

Changes 0
Metric Value
dl 0
loc 102
ccs 71
cts 73
cp 0.9726
rs 2
c 0
b 0
f 0
cc 31
eloc 78
nc 6656
nop 1
crap 31.0197

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

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 8
    protected function _getPortableViewDefinition($view)
53
    {
54 8
        return new View($view['TABLE_NAME'], $view['VIEW_DEFINITION']);
55
    }
56
57
    /**
58
     * {@inheritdoc}
59
     */
60 574
    protected function _getPortableTableDefinition($table)
61
    {
62 574
        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 294
    protected function _getPortableTableIndexesList($tableIndexes, $tableName = null)
80
    {
81 294
        foreach ($tableIndexes as $k => $v) {
82 160
            $v = array_change_key_case($v, CASE_LOWER);
83 160
            if ($v['key_name'] === 'PRIMARY') {
84 128
                $v['primary'] = true;
85
            } else {
86 104
                $v['primary'] = false;
87
            }
88 160
            if (strpos($v['index_type'], 'FULLTEXT') !== false) {
89 24
                $v['flags'] = ['FULLTEXT'];
90 152
            } elseif (strpos($v['index_type'], 'SPATIAL') !== false) {
91 24
                $v['flags'] = ['SPATIAL'];
92
            }
93 160
            $tableIndexes[$k] = $v;
94
        }
95
96 294
        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 16
    protected function _getPortableDatabaseDefinition($database)
111
    {
112 16
        return $database['Database'];
113
    }
114
115
    /**
116
     * {@inheritdoc}
117
     */
118 358
    protected function _getPortableTableColumnDefinition($tableColumn)
119
    {
120 358
        $tableColumn = array_change_key_case($tableColumn, CASE_LOWER);
121
122 358
        $dbType = strtolower($tableColumn['type']);
123 358
        $dbType = strtok($dbType, '(), ');
124 358
        $length = $tableColumn['length'] ?? strtok('(), ');
125
126 358
        $fixed = null;
127
128 358
        if ( ! isset($tableColumn['name'])) {
129 358
            $tableColumn['name'] = '';
130
        }
131
132 358
        $scale     = null;
133 358
        $precision = null;
134
135 358
        $type = $this->_platform->getDoctrineTypeMapping($dbType);
136
137
        // In cases where not connected to a database DESCRIBE $table does not return 'Comment'
138 358
        if (isset($tableColumn['comment'])) {
139 358
            $type                   = $this->extractDoctrineTypeFromComment($tableColumn['comment'], $type);
140 358
            $tableColumn['comment'] = $this->removeDoctrineTypeFromComment($tableColumn['comment'], $type);
141
        }
142
143
        switch ($dbType) {
144 358
            case 'char':
145 342
            case 'binary':
146 56
                $fixed = true;
147 56
                break;
148 342
            case 'float':
149 342
            case 'double':
150 334
            case 'real':
151 334
            case 'numeric':
152 334
            case 'decimal':
153 56
                if (preg_match('([A-Za-z]+\(([0-9]+)\,([0-9]+)\))', $tableColumn['type'], $match)) {
154 48
                    $precision = $match[1];
155 48
                    $scale     = $match[2];
156 48
                    $length    = null;
157
                }
158 56
                break;
159 326
            case 'tinytext':
160 24
                $length = MySqlPlatform::LENGTH_LIMIT_TINYTEXT;
161 24
                break;
162 326
            case 'text':
163 24
                $length = MySqlPlatform::LENGTH_LIMIT_TEXT;
164 24
                break;
165 326
            case 'mediumtext':
166 24
                $length = MySqlPlatform::LENGTH_LIMIT_MEDIUMTEXT;
167 24
                break;
168 326
            case 'tinyblob':
169
                $length = MySqlPlatform::LENGTH_LIMIT_TINYBLOB;
170
                break;
171 326
            case 'blob':
172 24
                $length = MySqlPlatform::LENGTH_LIMIT_BLOB;
173 24
                break;
174 326
            case 'mediumblob':
175 24
                $length = MySqlPlatform::LENGTH_LIMIT_MEDIUMBLOB;
176 24
                break;
177 326
            case 'tinyint':
178 326
            case 'smallint':
179 326
            case 'mediumint':
180 326
            case 'int':
181 166
            case 'integer':
182 166
            case 'bigint':
183 166
            case 'year':
184 264
                $length = null;
185 264
                break;
186
        }
187
188 358
        if ($this->_platform instanceof MariaDb1027Platform) {
189 88
            $columnDefault = $this->getMariaDb1027ColumnDefault($this->_platform, $tableColumn['default']);
190
        } else {
191 270
            $columnDefault = $tableColumn['default'];
192
        }
193
194
        $options = [
195 358
            'length'        => $length !== null ? (int) $length : null,
196 358
            'unsigned'      => strpos($tableColumn['type'], 'unsigned') !== false,
197 358
            'fixed'         => (bool) $fixed,
198 358
            'default'       => $columnDefault,
199 358
            'notnull'       => $tableColumn['null'] !== 'YES',
200
            'scale'         => null,
201
            'precision'     => null,
202 358
            'autoincrement' => strpos($tableColumn['extra'], 'auto_increment') !== false,
203 358
            'comment'       => isset($tableColumn['comment']) && $tableColumn['comment'] !== ''
204 112
                ? $tableColumn['comment']
205
                : null,
206
        ];
207
208 358
        if ($scale !== null && $precision !== null) {
209 48
            $options['scale']     = (int) $scale;
210 48
            $options['precision'] = (int) $precision;
211
        }
212
213 358
        $column = new Column($tableColumn['field'], Type::getType($type), $options);
214
215 358
        if (isset($tableColumn['collation'])) {
216 160
            $column->setPlatformOption('collation', $tableColumn['collation']);
217
        }
218
219 358
        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 88
    private function getMariaDb1027ColumnDefault(MariaDb1027Platform $platform, ?string $columnDefault) : ?string
239
    {
240 88
        if ($columnDefault === 'NULL' || $columnDefault === null) {
241 80
            return null;
242
        }
243 20
        if ($columnDefault[0] === "'") {
244 16
            return stripslashes(
245 16
                str_replace("''", "'",
246 16
                    preg_replace('/^\'(.*)\'$/', '$1', $columnDefault)
247
                )
248
            );
249
        }
250
        switch ($columnDefault) {
251 12
            case 'current_timestamp()':
252 8
                return $platform->getCurrentTimestampSQL();
253 10
            case 'curdate()':
254 6
                return $platform->getCurrentDateSQL();
255 10
            case 'curtime()':
256 6
                return $platform->getCurrentTimeSQL();
257
        }
258 8
        return $columnDefault;
259
    }
260
261
    /**
262
     * {@inheritdoc}
263
     */
264 279
    protected function _getPortableTableForeignKeysList($tableForeignKeys)
265
    {
266 279
        $list = [];
267 279
        foreach ($tableForeignKeys as $value) {
268 73
            $value = array_change_key_case($value, CASE_LOWER);
269 73
            if ( ! isset($list[$value['constraint_name']])) {
270 73
                if ( ! isset($value['delete_rule']) || $value['delete_rule'] === "RESTRICT") {
271 65
                    $value['delete_rule'] = null;
272
                }
273 73
                if ( ! isset($value['update_rule']) || $value['update_rule'] === "RESTRICT") {
274 73
                    $value['update_rule'] = null;
275
                }
276
277 73
                $list[$value['constraint_name']] = [
278 73
                    'name' => $value['constraint_name'],
279
                    'local' => [],
280
                    'foreign' => [],
281 73
                    'foreignTable' => $value['referenced_table_name'],
282 73
                    'onDelete' => $value['delete_rule'],
283 73
                    'onUpdate' => $value['update_rule'],
284
                ];
285
            }
286 73
            $list[$value['constraint_name']]['local'][]   = $value['column_name'];
287 73
            $list[$value['constraint_name']]['foreign'][] = $value['referenced_column_name'];
288
        }
289
290 279
        $result = [];
291 279
        foreach ($list as $constraint) {
292 73
            $result[] = new ForeignKeyConstraint(
293 73
                array_values($constraint['local']),
294 73
                $constraint['foreignTable'],
295 73
                array_values($constraint['foreign']),
296 73
                $constraint['name'],
297
                [
298 73
                    'onDelete' => $constraint['onDelete'],
299 73
                    'onUpdate' => $constraint['onUpdate'],
300
                ]
301
            );
302
        }
303
304 279
        return $result;
305
    }
306
}
307