|
0
|
1 |
<?php |
|
|
2 |
/* |
|
|
3 |
* $Id$ |
|
|
4 |
* |
|
|
5 |
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
|
|
6 |
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
|
|
7 |
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
|
|
8 |
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
|
|
9 |
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
|
|
10 |
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
|
|
11 |
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
|
|
12 |
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
|
|
13 |
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
|
|
14 |
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
|
|
15 |
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
|
|
16 |
* |
|
|
17 |
* This software consists of voluntary contributions made by many individuals |
|
|
18 |
* and is licensed under the LGPL. For more information, see |
|
|
19 |
* <http://www.doctrine-project.org>. |
|
|
20 |
*/ |
|
|
21 |
|
|
|
22 |
namespace Doctrine\ORM\Tools; |
|
|
23 |
|
|
|
24 |
use Doctrine\ORM\Mapping\ClassMetadataInfo, |
|
|
25 |
Doctrine\ORM\Tools\Export\Driver\AbstractExporter, |
|
|
26 |
Doctrine\Common\Util\Inflector; |
|
|
27 |
|
|
|
28 |
/** |
|
|
29 |
* Class to help with converting Doctrine 1 schema files to Doctrine 2 mapping files |
|
|
30 |
* |
|
|
31 |
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL |
|
|
32 |
* @link www.doctrine-project.org |
|
|
33 |
* @since 2.0 |
|
|
34 |
* @version $Revision$ |
|
|
35 |
* @author Guilherme Blanco <guilhermeblanco@hotmail.com> |
|
|
36 |
* @author Jonathan Wage <jonwage@gmail.com> |
|
|
37 |
* @author Roman Borschel <roman@code-factory.org> |
|
|
38 |
*/ |
|
|
39 |
class ConvertDoctrine1Schema |
|
|
40 |
{ |
|
|
41 |
private $_legacyTypeMap = array( |
|
|
42 |
// TODO: This list may need to be updated |
|
|
43 |
'clob' => 'text', |
|
|
44 |
'timestamp' => 'datetime', |
|
|
45 |
'enum' => 'string' |
|
|
46 |
); |
|
|
47 |
|
|
|
48 |
/** |
|
|
49 |
* Constructor passes the directory or array of directories |
|
|
50 |
* to convert the Doctrine 1 schema files from |
|
|
51 |
* |
|
|
52 |
* @param array $from |
|
|
53 |
* @author Jonathan Wage |
|
|
54 |
*/ |
|
|
55 |
public function __construct($from) |
|
|
56 |
{ |
|
|
57 |
$this->_from = (array) $from; |
|
|
58 |
} |
|
|
59 |
|
|
|
60 |
/** |
|
|
61 |
* Get an array of ClassMetadataInfo instances from the passed |
|
|
62 |
* Doctrine 1 schema |
|
|
63 |
* |
|
|
64 |
* @return array $metadatas An array of ClassMetadataInfo instances |
|
|
65 |
*/ |
|
|
66 |
public function getMetadata() |
|
|
67 |
{ |
|
|
68 |
$schema = array(); |
|
|
69 |
foreach ($this->_from as $path) { |
|
|
70 |
if (is_dir($path)) { |
|
|
71 |
$files = glob($path . '/*.yml'); |
|
|
72 |
foreach ($files as $file) { |
|
|
73 |
$schema = array_merge($schema, (array) \Symfony\Component\Yaml\Yaml::parse($file)); |
|
|
74 |
} |
|
|
75 |
} else { |
|
|
76 |
$schema = array_merge($schema, (array) \Symfony\Component\Yaml\Yaml::parse($path)); |
|
|
77 |
} |
|
|
78 |
} |
|
|
79 |
|
|
|
80 |
$metadatas = array(); |
|
|
81 |
foreach ($schema as $className => $mappingInformation) { |
|
|
82 |
$metadatas[] = $this->_convertToClassMetadataInfo($className, $mappingInformation); |
|
|
83 |
} |
|
|
84 |
|
|
|
85 |
return $metadatas; |
|
|
86 |
} |
|
|
87 |
|
|
|
88 |
private function _convertToClassMetadataInfo($className, $mappingInformation) |
|
|
89 |
{ |
|
|
90 |
$metadata = new ClassMetadataInfo($className); |
|
|
91 |
|
|
|
92 |
$this->_convertTableName($className, $mappingInformation, $metadata); |
|
|
93 |
$this->_convertColumns($className, $mappingInformation, $metadata); |
|
|
94 |
$this->_convertIndexes($className, $mappingInformation, $metadata); |
|
|
95 |
$this->_convertRelations($className, $mappingInformation, $metadata); |
|
|
96 |
|
|
|
97 |
return $metadata; |
|
|
98 |
} |
|
|
99 |
|
|
|
100 |
private function _convertTableName($className, array $model, ClassMetadataInfo $metadata) |
|
|
101 |
{ |
|
|
102 |
if (isset($model['tableName']) && $model['tableName']) { |
|
|
103 |
$e = explode('.', $model['tableName']); |
|
|
104 |
if (count($e) > 1) { |
|
|
105 |
$metadata->table['schema'] = $e[0]; |
|
|
106 |
$metadata->table['name'] = $e[1]; |
|
|
107 |
} else { |
|
|
108 |
$metadata->table['name'] = $e[0]; |
|
|
109 |
} |
|
|
110 |
} |
|
|
111 |
} |
|
|
112 |
|
|
|
113 |
private function _convertColumns($className, array $model, ClassMetadataInfo $metadata) |
|
|
114 |
{ |
|
|
115 |
$id = false; |
|
|
116 |
|
|
|
117 |
if (isset($model['columns']) && $model['columns']) { |
|
|
118 |
foreach ($model['columns'] as $name => $column) { |
|
|
119 |
$fieldMapping = $this->_convertColumn($className, $name, $column, $metadata); |
|
|
120 |
|
|
|
121 |
if (isset($fieldMapping['id']) && $fieldMapping['id']) { |
|
|
122 |
$id = true; |
|
|
123 |
} |
|
|
124 |
} |
|
|
125 |
} |
|
|
126 |
|
|
|
127 |
if ( ! $id) { |
|
|
128 |
$fieldMapping = array( |
|
|
129 |
'fieldName' => 'id', |
|
|
130 |
'columnName' => 'id', |
|
|
131 |
'type' => 'integer', |
|
|
132 |
'id' => true |
|
|
133 |
); |
|
|
134 |
$metadata->mapField($fieldMapping); |
|
|
135 |
$metadata->setIdGeneratorType(ClassMetadataInfo::GENERATOR_TYPE_AUTO); |
|
|
136 |
} |
|
|
137 |
} |
|
|
138 |
|
|
|
139 |
private function _convertColumn($className, $name, $column, ClassMetadataInfo $metadata) |
|
|
140 |
{ |
|
|
141 |
if (is_string($column)) { |
|
|
142 |
$string = $column; |
|
|
143 |
$column = array(); |
|
|
144 |
$column['type'] = $string; |
|
|
145 |
} |
|
|
146 |
if ( ! isset($column['name'])) { |
|
|
147 |
$column['name'] = $name; |
|
|
148 |
} |
|
|
149 |
// check if a column alias was used (column_name as field_name) |
|
|
150 |
if (preg_match("/(\w+)\sas\s(\w+)/i", $column['name'], $matches)) { |
|
|
151 |
$name = $matches[1]; |
|
|
152 |
$column['name'] = $name; |
|
|
153 |
$column['alias'] = $matches[2]; |
|
|
154 |
} |
|
|
155 |
if (preg_match("/([a-zA-Z]+)\(([0-9]+)\)/", $column['type'], $matches)) { |
|
|
156 |
$column['type'] = $matches[1]; |
|
|
157 |
$column['length'] = $matches[2]; |
|
|
158 |
} |
|
|
159 |
$column['type'] = strtolower($column['type']); |
|
|
160 |
// check if legacy column type (1.x) needs to be mapped to a 2.0 one |
|
|
161 |
if (isset($this->_legacyTypeMap[$column['type']])) { |
|
|
162 |
$column['type'] = $this->_legacyTypeMap[$column['type']]; |
|
|
163 |
} |
|
|
164 |
if ( ! \Doctrine\DBAL\Types\Type::hasType($column['type'])) { |
|
|
165 |
throw ToolsException::couldNotMapDoctrine1Type($column['type']); |
|
|
166 |
} |
|
|
167 |
|
|
|
168 |
$fieldMapping = array(); |
|
|
169 |
if (isset($column['primary'])) { |
|
|
170 |
$fieldMapping['id'] = true; |
|
|
171 |
} |
|
|
172 |
$fieldMapping['fieldName'] = isset($column['alias']) ? $column['alias'] : $name; |
|
|
173 |
$fieldMapping['columnName'] = $column['name']; |
|
|
174 |
$fieldMapping['type'] = $column['type']; |
|
|
175 |
if (isset($column['length'])) { |
|
|
176 |
$fieldMapping['length'] = $column['length']; |
|
|
177 |
} |
|
|
178 |
$allowed = array('precision', 'scale', 'unique', 'options', 'notnull', 'version'); |
|
|
179 |
foreach ($column as $key => $value) { |
|
|
180 |
if (in_array($key, $allowed)) { |
|
|
181 |
$fieldMapping[$key] = $value; |
|
|
182 |
} |
|
|
183 |
} |
|
|
184 |
|
|
|
185 |
$metadata->mapField($fieldMapping); |
|
|
186 |
|
|
|
187 |
if (isset($column['autoincrement'])) { |
|
|
188 |
$metadata->setIdGeneratorType(ClassMetadataInfo::GENERATOR_TYPE_AUTO); |
|
|
189 |
} else if (isset($column['sequence'])) { |
|
|
190 |
$metadata->setIdGeneratorType(ClassMetadataInfo::GENERATOR_TYPE_SEQUENCE); |
|
|
191 |
$definition = array( |
|
|
192 |
'sequenceName' => is_array($column['sequence']) ? $column['sequence']['name']:$column['sequence'] |
|
|
193 |
); |
|
|
194 |
if (isset($column['sequence']['size'])) { |
|
|
195 |
$definition['allocationSize'] = $column['sequence']['size']; |
|
|
196 |
} |
|
|
197 |
if (isset($column['sequence']['value'])) { |
|
|
198 |
$definition['initialValue'] = $column['sequence']['value']; |
|
|
199 |
} |
|
|
200 |
$metadata->setSequenceGeneratorDefinition($definition); |
|
|
201 |
} |
|
|
202 |
return $fieldMapping; |
|
|
203 |
} |
|
|
204 |
|
|
|
205 |
private function _convertIndexes($className, array $model, ClassMetadataInfo $metadata) |
|
|
206 |
{ |
|
|
207 |
if (isset($model['indexes']) && $model['indexes']) { |
|
|
208 |
foreach ($model['indexes'] as $name => $index) { |
|
|
209 |
$type = (isset($index['type']) && $index['type'] == 'unique') |
|
|
210 |
? 'uniqueConstraints' : 'indexes'; |
|
|
211 |
|
|
|
212 |
$metadata->table[$type][$name] = array( |
|
|
213 |
'columns' => $index['fields'] |
|
|
214 |
); |
|
|
215 |
} |
|
|
216 |
} |
|
|
217 |
} |
|
|
218 |
|
|
|
219 |
private function _convertRelations($className, array $model, ClassMetadataInfo $metadata) |
|
|
220 |
{ |
|
|
221 |
if (isset($model['relations']) && $model['relations']) { |
|
|
222 |
foreach ($model['relations'] as $name => $relation) { |
|
|
223 |
if ( ! isset($relation['alias'])) { |
|
|
224 |
$relation['alias'] = $name; |
|
|
225 |
} |
|
|
226 |
if ( ! isset($relation['class'])) { |
|
|
227 |
$relation['class'] = $name; |
|
|
228 |
} |
|
|
229 |
if ( ! isset($relation['local'])) { |
|
|
230 |
$relation['local'] = Inflector::tableize($relation['class']); |
|
|
231 |
} |
|
|
232 |
if ( ! isset($relation['foreign'])) { |
|
|
233 |
$relation['foreign'] = 'id'; |
|
|
234 |
} |
|
|
235 |
if ( ! isset($relation['foreignAlias'])) { |
|
|
236 |
$relation['foreignAlias'] = $className; |
|
|
237 |
} |
|
|
238 |
|
|
|
239 |
if (isset($relation['refClass'])) { |
|
|
240 |
$type = 'many'; |
|
|
241 |
$foreignType = 'many'; |
|
|
242 |
$joinColumns = array(); |
|
|
243 |
} else { |
|
|
244 |
$type = isset($relation['type']) ? $relation['type'] : 'one'; |
|
|
245 |
$foreignType = isset($relation['foreignType']) ? $relation['foreignType'] : 'many'; |
|
|
246 |
$joinColumns = array( |
|
|
247 |
array( |
|
|
248 |
'name' => $relation['local'], |
|
|
249 |
'referencedColumnName' => $relation['foreign'], |
|
|
250 |
'onDelete' => isset($relation['onDelete']) ? $relation['onDelete'] : null, |
|
|
251 |
'onUpdate' => isset($relation['onUpdate']) ? $relation['onUpdate'] : null, |
|
|
252 |
) |
|
|
253 |
); |
|
|
254 |
} |
|
|
255 |
|
|
|
256 |
if ($type == 'one' && $foreignType == 'one') { |
|
|
257 |
$method = 'mapOneToOne'; |
|
|
258 |
} else if ($type == 'many' && $foreignType == 'many') { |
|
|
259 |
$method = 'mapManyToMany'; |
|
|
260 |
} else { |
|
|
261 |
$method = 'mapOneToMany'; |
|
|
262 |
} |
|
|
263 |
|
|
|
264 |
$associationMapping = array(); |
|
|
265 |
$associationMapping['fieldName'] = $relation['alias']; |
|
|
266 |
$associationMapping['targetEntity'] = $relation['class']; |
|
|
267 |
$associationMapping['mappedBy'] = $relation['foreignAlias']; |
|
|
268 |
$associationMapping['joinColumns'] = $joinColumns; |
|
|
269 |
|
|
|
270 |
$metadata->$method($associationMapping); |
|
|
271 |
} |
|
|
272 |
} |
|
|
273 |
} |
|
|
274 |
} |