Failed Conditions
Push — master ( 8b8169...80f782 )
by Marco
15s
created

ConvertDoctrine1Schema::convertRelations()   C

Complexity

Conditions 13
Paths 194

Size

Total Lines 56
Code Lines 37

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 29
CRAP Score 13.8509

Importance

Changes 0
Metric Value
dl 0
loc 56
ccs 29
cts 35
cp 0.8286
rs 6.0142
c 0
b 0
f 0
cc 13
eloc 37
nc 194
nop 3
crap 13.8509

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\ClassMetadataInfo;
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 2
    public function __construct($from)
63
    {
64 2
        $this->from = (array) $from;
65 2
    }
66
67
    /**
68
     * Gets an array of ClassMetadataInfo instances from the passed
69
     * Doctrine 1 schema.
70
     *
71
     * @return array An array of ClassMetadataInfo instances
72
     */
73 2
    public function getMetadata()
74
    {
75 2
        $schema = [];
76 2
        foreach ($this->from as $path) {
77 1
            if (is_dir($path)) {
78 1
                $files = glob($path . '/*.yml');
79 1
                foreach ($files as $file) {
80 1
                    $schema = array_merge($schema, (array) Yaml::parse(file_get_contents($file)));
81
                }
82
            } else {
83 1
                $schema = array_merge($schema, (array) Yaml::parse(file_get_contents($path)));
84
            }
85
        }
86
87 2
        $metadatas = [];
88 2
        foreach ($schema as $className => $mappingInformation) {
89 1
            $metadatas[] = $this->convertToClassMetadataInfo($className, $mappingInformation);
90
        }
91
92 2
        return $metadatas;
93
    }
94
95
    /**
96
     * @param string $className
97
     * @param array  $mappingInformation
98
     *
99
     * @return \Doctrine\ORM\Mapping\ClassMetadataInfo
100
     */
101 1
    private function convertToClassMetadataInfo($className, $mappingInformation)
102
    {
103 1
        $metadata = new ClassMetadataInfo($className);
104
105 1
        $this->convertTableName($className, $mappingInformation, $metadata);
106 1
        $this->convertColumns($className, $mappingInformation, $metadata);
107 1
        $this->convertIndexes($className, $mappingInformation, $metadata);
108 1
        $this->convertRelations($className, $mappingInformation, $metadata);
109
110 1
        return $metadata;
111
    }
112
113
    /**
114
     * @param string            $className
115
     * @param array             $model
116
     * @param ClassMetadataInfo $metadata
117
     *
118
     * @return void
119
     */
120 1
    private function convertTableName($className, array $model, ClassMetadataInfo $metadata)
0 ignored issues
show
Unused Code introduced by
The parameter $className is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
121
    {
122 1
        if (isset($model['tableName']) && $model['tableName']) {
123 1
            $e = explode('.', $model['tableName']);
124
125 1
            if (count($e) > 1) {
126
                $metadata->table['schema'] = $e[0];
127
                $metadata->table['name'] = $e[1];
128
            } else {
129 1
                $metadata->table['name'] = $e[0];
130
            }
131
        }
132 1
    }
133
134
    /**
135
     * @param string            $className
136
     * @param array             $model
137
     * @param ClassMetadataInfo $metadata
138
     *
139
     * @return void
140
     */
141 1
    private function convertColumns($className, array $model, ClassMetadataInfo $metadata)
142
    {
143 1
        $id = false;
144
145 1
        if (isset($model['columns']) && $model['columns']) {
146 1
            foreach ($model['columns'] as $name => $column) {
147 1
                $fieldMapping = $this->convertColumn($className, $name, $column, $metadata);
148
149 1
                if (isset($fieldMapping['id']) && $fieldMapping['id']) {
150 1
                    $id = true;
151
                }
152
            }
153
        }
154
155 1
        if ( ! $id) {
156
            $fieldMapping = [
157 1
                'fieldName' => 'id',
158
                'columnName' => 'id',
159
                'type' => 'integer',
160
                'id' => true
161
            ];
162 1
            $metadata->mapField($fieldMapping);
163 1
            $metadata->setIdGeneratorType(ClassMetadataInfo::GENERATOR_TYPE_AUTO);
164
        }
165 1
    }
166
167
    /**
168
     * @param string            $className
169
     * @param string            $name
170
     * @param string|array      $column
171
     * @param ClassMetadataInfo $metadata
172
     *
173
     * @return array
174
     *
175
     * @throws ToolsException
176
     */
177 1
    private function convertColumn($className, $name, $column, ClassMetadataInfo $metadata)
0 ignored issues
show
Unused Code introduced by
The parameter $className is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
178
    {
179 1
        if (is_string($column)) {
180 1
            $string = $column;
181 1
            $column = [];
182 1
            $column['type'] = $string;
183
        }
184
185 1
        if ( ! isset($column['name'])) {
186 1
            $column['name'] = $name;
187
        }
188
189
        // check if a column alias was used (column_name as field_name)
190 1 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 1
            $name = $matches[1];
192 1
            $column['name'] = $name;
193 1
            $column['alias'] = $matches[2];
194
        }
195
196 1 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 1
            $column['type'] = $matches[1];
198 1
            $column['length'] = $matches[2];
199
        }
200
201 1
        $column['type'] = strtolower($column['type']);
202
        // check if legacy column type (1.x) needs to be mapped to a 2.0 one
203 1
        if (isset($this->legacyTypeMap[$column['type']])) {
204 1
            $column['type'] = $this->legacyTypeMap[$column['type']];
205
        }
206
207 1
        if ( ! Type::hasType($column['type'])) {
208
            throw ToolsException::couldNotMapDoctrine1Type($column['type']);
209
        }
210
211 1
        $fieldMapping = [];
212
213 1
        if (isset($column['primary'])) {
214
            $fieldMapping['id'] = true;
215
        }
216
217 1
        $fieldMapping['fieldName'] = $column['alias'] ?? $name;
218 1
        $fieldMapping['columnName'] = $column['name'];
219 1
        $fieldMapping['type'] = $column['type'];
220
221 1
        if (isset($column['length'])) {
222 1
            $fieldMapping['length'] = $column['length'];
223
        }
224
225 1
        $allowed = ['precision', 'scale', 'unique', 'options', 'notnull', 'version'];
226
227 1
        foreach ($column as $key => $value) {
228 1
            if (in_array($key, $allowed)) {
229 1
                $fieldMapping[$key] = $value;
230
            }
231
        }
232
233 1
        $metadata->mapField($fieldMapping);
234
235 1
        if (isset($column['autoincrement'])) {
236
            $metadata->setIdGeneratorType(ClassMetadataInfo::GENERATOR_TYPE_AUTO);
237 1
        } elseif (isset($column['sequence'])) {
238
            $metadata->setIdGeneratorType(ClassMetadataInfo::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 1
        return $fieldMapping;
256
    }
257
258
    /**
259
     * @param string            $className
260
     * @param array             $model
261
     * @param ClassMetadataInfo $metadata
262
     *
263
     * @return void
264
     */
265 1
    private function convertIndexes($className, array $model, ClassMetadataInfo $metadata)
0 ignored issues
show
Unused Code introduced by
The parameter $className is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
266
    {
267 1
        if (empty($model['indexes'])) {
268 1
            return;
269
        }
270
271 1
        foreach ($model['indexes'] as $name => $index) {
272 1
            $type = (isset($index['type']) && $index['type'] == 'unique')
273 1
                ? 'uniqueConstraints' : 'indexes';
274
275 1
            $metadata->table[$type][$name] = [
276 1
                'columns' => $index['fields']
277
            ];
278
        }
279 1
    }
280
281
    /**
282
     * @param string            $className
283
     * @param array             $model
284
     * @param ClassMetadataInfo $metadata
285
     *
286
     * @return void
287
     */
288 1
    private function convertRelations($className, array $model, ClassMetadataInfo $metadata)
289
    {
290 1
        if (empty($model['relations'])) {
291 1
            return;
292
        }
293
294 1
        foreach ($model['relations'] as $name => $relation) {
295 1
            if ( ! isset($relation['alias'])) {
296 1
                $relation['alias'] = $name;
297
            }
298 1
            if ( ! isset($relation['class'])) {
299 1
                $relation['class'] = $name;
300
            }
301 1
            if ( ! isset($relation['local'])) {
302 1
                $relation['local'] = Inflector::tableize($relation['class']);
303
            }
304 1
            if ( ! isset($relation['foreign'])) {
305 1
                $relation['foreign'] = 'id';
306
            }
307 1
            if ( ! isset($relation['foreignAlias'])) {
308 1
                $relation['foreignAlias'] = $className;
309
            }
310
311 1
            if (isset($relation['refClass'])) {
312
                $type = 'many';
313
                $foreignType = 'many';
314
                $joinColumns = [];
315
            } else {
316 1
                $type = $relation['type'] ?? 'one';
317 1
                $foreignType = $relation['foreignType'] ?? 'many';
318
                $joinColumns = [
319
                    [
320 1
                        'name' => $relation['local'],
321 1
                        'referencedColumnName' => $relation['foreign'],
322 1
                        'onDelete' => $relation['onDelete'] ?? null,
323
                    ]
324
                ];
325
            }
326
327 1
            if ($type == 'one' && $foreignType == 'one') {
328 1
                $method = 'mapOneToOne';
329
            } elseif ($type == 'many' && $foreignType == 'many') {
330
                $method = 'mapManyToMany';
331
            } else {
332
                $method = 'mapOneToMany';
333
            }
334
335 1
            $associationMapping = [];
336 1
            $associationMapping['fieldName'] = $relation['alias'];
337 1
            $associationMapping['targetEntity'] = $relation['class'];
338 1
            $associationMapping['mappedBy'] = $relation['foreignAlias'];
339 1
            $associationMapping['joinColumns'] = $joinColumns;
340
341 1
            $metadata->$method($associationMapping);
342
        }
343 1
    }
344
}
345