Failed Conditions
Pull Request — master (#6886)
by Grégoire
09:16
created

ConvertDoctrine1Schema::convertColumn()   F

Complexity

Conditions 16
Paths 3872

Size

Total Lines 79
Code Lines 43

Duplication

Lines 9
Ratio 11.39 %

Code Coverage

Tests 0
CRAP Score 272

Importance

Changes 0
Metric Value
cc 16
eloc 43
nc 3872
nop 4
dl 9
loc 79
ccs 0
cts 43
cp 0
crap 272
rs 2.1424
c 0
b 0
f 0

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\ORM\Tools;
21
22
use Doctrine\ORM\Mapping\ClassMetadata;
23
use Doctrine\Common\Util\Inflector;
24
use Doctrine\DBAL\Types\Type;
25
use Symfony\Component\Yaml\Yaml;
26
27
/**
28
 * Class to help with converting Doctrine 1 schema files to Doctrine 2 mapping files
29
 *
30
 *
31
 * @link    www.doctrine-project.org
32
 * @since   2.0
33
 * @author  Guilherme Blanco <[email protected]>
34
 * @author  Jonathan Wage <[email protected]>
35
 * @author  Roman Borschel <[email protected]>
36
 */
37
class ConvertDoctrine1Schema
38
{
39
    /**
40
     * @var array
41
     */
42
    private $from;
43
44
    /**
45
     * @var array
46
     */
47
    private $legacyTypeMap = [
48
        // TODO: This list may need to be updated
49
        'clob' => 'text',
50
        'timestamp' => 'datetime',
51
        'enum' => 'string'
52
    ];
53
54
    /**
55
     * Constructor passes the directory or array of directories
56
     * to convert the Doctrine 1 schema files from.
57
     *
58
     * @param array $from
59
     *
60
     * @author Jonathan Wage
61
     */
62 1
    public function __construct($from)
63
    {
64 1
        $this->from = (array) $from;
65 1
    }
66
67
    /**
68
     * Gets an array of ClassMetadata instances from the passed
69
     * Doctrine 1 schema.
70
     *
71
     * @return array An array of ClassMetadata instances
72
     */
73 1
    public function getMetadata()
74
    {
75 1
        $schema = [];
76 1
        foreach ($this->from as $path) {
77
            if (is_dir($path)) {
78
                $files = glob($path . '/*.yml');
79
                foreach ($files as $file) {
80
                    $schema = array_merge($schema, (array) Yaml::parse(file_get_contents($file)));
0 ignored issues
show
Bug introduced by
It seems like file_get_contents($file) can also be of type false; however, parameter $input of Symfony\Component\Yaml\Yaml::parse() does only seem to accept string, 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

80
                    $schema = array_merge($schema, (array) Yaml::parse(/** @scrutinizer ignore-type */ file_get_contents($file)));
Loading history...
81
                }
82
            } else {
83
                $schema = array_merge($schema, (array) Yaml::parse(file_get_contents($path)));
84
            }
85
        }
86
87 1
        $metadatas = [];
88 1
        foreach ($schema as $className => $mapping) {
89
            $metadatas[] = $this->convertToClassMetadata($className, $mappingInformation);
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $mappingInformation seems to be never defined.
Loading history...
90
        }
91
92 1
        return $metadatas;
93
    }
94
95
    /**
96
     * @param string $className
97
     * @param array  $mappingInformation
98
     *
99
     * @return \Doctrine\ORM\Mapping\ClassMetadata
100
     */
101
    private function convertToClassMetadata($className, $mappingInformation)
102
    {
103
        $metadata = new ClassMetadata($className);
104
105
        $this->convertTableName($className, $mappingInformation, $metadata);
106
        $this->convertColumns($className, $mappingInformation, $metadata);
107
        $this->convertIndexes($className, $mappingInformation, $metadata);
108
        $this->convertRelations($className, $mappingInformation, $metadata);
109
110
        return $metadata;
111
    }
112
113
    /**
114
     * @param string            $className
115
     * @param array             $model
116
     * @param ClassMetadata $metadata
117
     *
118
     * @return void
119
     */
120
    private function convertTableName($className, array $model, ClassMetadata $metadata)
121
    {
122
        if (isset($model['tableName']) && $model['tableName']) {
123
            $e = explode('.', $model['tableName']);
124
125
            if (count($e) > 1) {
126
                $metadata->table['schema'] = $e[0];
127
                $metadata->table['name'] = $e[1];
128
            } else {
129
                $metadata->table['name'] = $e[0];
130
            }
131
        }
132
    }
133
134
    /**
135
     * @param string            $className
136
     * @param array             $model
137
     * @param ClassMetadata $metadata
138
     *
139
     * @return void
140
     */
141
    private function convertColumns($className, array $model, ClassMetadata $metadata)
142
    {
143
        $id = false;
144
145
        if (isset($model['columns']) && $model['columns']) {
146
            foreach ($model['columns'] as $name => $column) {
147
                $fieldMapping = $this->convertColumn($className, $name, $column, $metadata);
148
149
                if (isset($fieldMapping['id']) && $fieldMapping['id']) {
150
                    $id = true;
151
                }
152
            }
153
        }
154
155
        if ( ! $id) {
156
            $fieldMapping = [
157
                'fieldName' => 'id',
158
                'columnName' => 'id',
159
                'type' => 'integer',
160
                'id' => true
161
            ];
162
            $metadata->mapField($fieldMapping);
163
            $metadata->setIdGeneratorType(ClassMetadata::GENERATOR_TYPE_AUTO);
164
        }
165
    }
166
167
    /**
168
     * @param string            $className
169
     * @param string            $name
170
     * @param string|array      $column
171
     * @param ClassMetadata $metadata
172
     *
173
     * @return array
174
     *
175
     * @throws ToolsException
176
     */
177
    private function convertColumn($className, $name, $column, ClassMetadata $metadata)
178
    {
179
        if (is_string($column)) {
180
            $string = $column;
181
            $column = [];
182
            $column['type'] = $string;
183
        }
184
185
        if ( ! isset($column['name'])) {
186
            $column['name'] = $name;
187
        }
188
189
        // check if a column alias was used (column_name as field_name)
190 View Code Duplication
        if (preg_match("/(\w+)\sas\s(\w+)/i", $column['name'], $matches)) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
191
            $name = $matches[1];
192
            $column['name'] = $name;
193
            $column['alias'] = $matches[2];
194
        }
195
196 View Code Duplication
        if (preg_match("/([a-zA-Z]+)\(([0-9]+)\)/", $column['type'], $matches)) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
197
            $column['type'] = $matches[1];
198
            $column['length'] = $matches[2];
199
        }
200
201
        $column['type'] = strtolower($column['type']);
202
        // check if legacy column type (1.x) needs to be mapped to a 2.0 one
203
        if (isset($this->legacyTypeMap[$column['type']])) {
204
            $column['type'] = $this->legacyTypeMap[$column['type']];
205
        }
206
207
        if ( ! Type::hasType($column['type'])) {
208
            throw ToolsException::couldNotMapDoctrine1Type($column['type']);
209
        }
210
211
        $fieldMapping = [];
212
213
        if (isset($column['primary'])) {
214
            $fieldMapping['id'] = true;
215
        }
216
217
        $fieldMapping['fieldName'] = $column['alias'] ?? $name;
218
        $fieldMapping['columnName'] = $column['name'];
219
        $fieldMapping['type'] = $column['type'];
220
221
        if (isset($column['length'])) {
222
            $fieldMapping['length'] = $column['length'];
223
        }
224
225
        $allowed = ['precision', 'scale', 'unique', 'options', 'notnull', 'version'];
226
227
        foreach ($column as $key => $value) {
228
            if (in_array($key, $allowed)) {
229
                $fieldMapping[$key] = $value;
230
            }
231
        }
232
233
        $metadata->mapField($fieldMapping);
234
235
        if (isset($column['autoincrement'])) {
236
            $metadata->setIdGeneratorType(ClassMetadata::GENERATOR_TYPE_AUTO);
237
        } elseif (isset($column['sequence'])) {
238
            $metadata->setIdGeneratorType(ClassMetadata::GENERATOR_TYPE_SEQUENCE);
239
240
            $definition = [
241
                'sequenceName' => is_array($column['sequence']) ? $column['sequence']['name']:$column['sequence']
242
            ];
243
244
            if (isset($column['sequence']['size'])) {
245
                $definition['allocationSize'] = $column['sequence']['size'];
246
            }
247
248
            if (isset($column['sequence']['value'])) {
249
                $definition['initialValue'] = $column['sequence']['value'];
250
            }
251
252
            $metadata->setSequenceGeneratorDefinition($definition);
253
        }
254
255
        return $fieldMapping;
256
    }
257
258
    /**
259
     * @param string            $className
260
     * @param array             $model
261
     * @param ClassMetadata $metadata
262
     *
263
     * @return void
264
     */
265
    private function convertIndexes($className, array $model, ClassMetadata $metadata)
266
    {
267
        if (empty($model['indexes'])) {
268
            return;
269
        }
270
271
        foreach ($model['indexes'] as $name => $index) {
272
            $type = (isset($index['type']) && $index['type'] == 'unique')
273
                ? 'uniqueConstraints' : 'indexes';
274
275
            $metadata->table[$type][$name] = [
276
                'columns' => $index['fields']
277
            ];
278
        }
279
    }
280
281
    /**
282
     * @param string            $className
283
     * @param array             $model
284
     * @param ClassMetadata $metadata
285
     *
286
     * @return void
287
     */
288
    private function convertRelations($className, array $model, ClassMetadata $metadata)
289
    {
290
        if (empty($model['relations'])) {
291
            return;
292
        }
293
294
        foreach ($model['relations'] as $name => $relation) {
295
            if ( ! isset($relation['alias'])) {
296
                $relation['alias'] = $name;
297
            }
298
            if ( ! isset($relation['class'])) {
299
                $relation['class'] = $name;
300
            }
301
            if ( ! isset($relation['local'])) {
302
                $relation['local'] = Inflector::tableize($relation['class']);
303
            }
304
            if ( ! isset($relation['foreign'])) {
305
                $relation['foreign'] = 'id';
306
            }
307
            if ( ! isset($relation['foreignAlias'])) {
308
                $relation['foreignAlias'] = $className;
309
            }
310
311
            if (isset($relation['refClass'])) {
312
                $type = 'many';
313
                $foreignType = 'many';
314
                $joinColumns = [];
315
            } else {
316
                $type = $relation['type'] ?? 'one';
317
                $foreignType = $relation['foreignType'] ?? 'many';
318
                $joinColumns = [
319
                    [
320
                        'name' => $relation['local'],
321
                        'referencedColumnName' => $relation['foreign'],
322
                        'onDelete' => $relation['onDelete'] ?? null,
323
                    ]
324
                ];
325
            }
326
327
            if ($type == 'one' && $foreignType == 'one') {
328
                $method = 'mapOneToOne';
329
            } elseif ($type == 'many' && $foreignType == 'many') {
330
                $method = 'mapManyToMany';
331
            } else {
332
                $method = 'mapOneToMany';
333
            }
334
335
            $associationMapping = [];
336
            $associationMapping['fieldName'] = $relation['alias'];
337
            $associationMapping['targetEntity'] = $relation['class'];
338
            $associationMapping['mappedBy'] = $relation['foreignAlias'];
339
            $associationMapping['joinColumns'] = $joinColumns;
340
341
            $metadata->$method($associationMapping);
342
        }
343
    }
344
}
345