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) |
|
|
|
|
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) |
|
|
|
|
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)) { |
|
|
|
|
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)) { |
|
|
|
|
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) |
|
|
|
|
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
|
|
|
|
This check looks from parameters that have been defined for a function or method, but which are not used in the method body.