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.
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>.
20 namespace Doctrine\ORM\Tools\Export\Driver;
22 use Doctrine\ORM\Mapping\ClassMetadataInfo;
25 * ClassMetadata exporter for Doctrine XML mapping files
28 * @link www.doctrine-project.org
30 * @author Jonathan Wage <jonwage@gmail.com>
32 class XmlExporter extends AbstractExporter
34 protected $_extension = '.dcm.xml';
37 * Converts a single ClassMetadata instance to the exported format
40 * @param ClassMetadataInfo $metadata
41 * @return mixed $exported
43 public function exportClassMetadata(ClassMetadataInfo $metadata)
45 $xml = new \SimpleXmlElement("<?xml version=\"1.0\" encoding=\"utf-8\"?><doctrine-mapping ".
46 "xmlns=\"http://doctrine-project.org/schemas/orm/doctrine-mapping\" " .
47 "xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" ".
48 "xsi:schemaLocation=\"http://doctrine-project.org/schemas/orm/doctrine-mapping http://doctrine-project.org/schemas/orm/doctrine-mapping.xsd\" />");
50 /*$xml->addAttribute('xmlns', 'http://doctrine-project.org/schemas/orm/doctrine-mapping');
51 $xml->addAttribute('xmlns:xsi', 'http://www.w3.org/2001/XMLSchema-instance');
52 $xml->addAttribute('xsi:schemaLocation', 'http://doctrine-project.org/schemas/orm/doctrine-mapping http://doctrine-project.org/schemas/orm/doctrine-mapping.xsd');*/
54 if ($metadata->isMappedSuperclass) {
55 $root = $xml->addChild('mapped-superclass');
57 $root = $xml->addChild('entity');
60 if ($metadata->customRepositoryClassName) {
61 $root->addAttribute('repository-class', $metadata->customRepositoryClassName);
64 $root->addAttribute('name', $metadata->name);
66 if (isset($metadata->table['name'])) {
67 $root->addAttribute('table', $metadata->table['name']);
70 if (isset($metadata->table['schema'])) {
71 $root->addAttribute('schema', $metadata->table['schema']);
74 if (isset($metadata->table['inheritance-type'])) {
75 $root->addAttribute('inheritance-type', $metadata->table['inheritance-type']);
78 if ($metadata->discriminatorColumn) {
79 $discriminatorColumnXml = $root->addChild('discriminiator-column');
80 $discriminatorColumnXml->addAttribute('name', $metadata->discriminatorColumn['name']);
81 $discriminatorColumnXml->addAttribute('type', $metadata->discriminatorColumn['type']);
82 $discriminatorColumnXml->addAttribute('length', $metadata->discriminatorColumn['length']);
85 if ($metadata->discriminatorMap) {
86 $discriminatorMapXml = $root->addChild('discriminator-map');
87 foreach ($metadata->discriminatorMap as $value => $className) {
88 $discriminatorMappingXml = $discriminatorMapXml->addChild('discriminator-mapping');
89 $discriminatorMappingXml->addAttribute('value', $value);
90 $discriminatorMappingXml->addAttribute('class', $className);
94 $trackingPolicy = $this->_getChangeTrackingPolicyString($metadata->changeTrackingPolicy);
95 if ( $trackingPolicy != 'DEFERRED_IMPLICIT') {
96 $root->addChild('change-tracking-policy', $trackingPolicy);
99 if (isset($metadata->table['indexes'])) {
100 $indexesXml = $root->addChild('indexes');
102 foreach ($metadata->table['indexes'] as $name => $index) {
103 $indexXml = $indexesXml->addChild('index');
104 $indexXml->addAttribute('name', $name);
105 $indexXml->addAttribute('columns', implode(',', $index['columns']));
109 if (isset($metadata->table['uniqueConstraints'])) {
110 $uniqueConstraintsXml = $root->addChild('unique-constraints');
112 foreach ($metadata->table['uniqueConstraints'] as $unique) {
113 $uniqueConstraintXml = $uniqueConstraintsXml->addChild('unique-constraint');
114 $uniqueConstraintXml->addAttribute('name', $unique['name']);
115 $uniqueConstraintXml->addAttribute('columns', implode(',', $unique['columns']));
119 $fields = $metadata->fieldMappings;
122 foreach ($fields as $name => $field) {
123 if (isset($field['id']) && $field['id']) {
125 unset($fields[$name]);
129 if ( ! $metadata->isIdentifierComposite && $idGeneratorType = $this->_getIdGeneratorTypeString($metadata->generatorType)) {
130 $id[$metadata->getSingleIdentifierFieldName()]['generator']['strategy'] = $idGeneratorType;
134 foreach ($id as $field) {
135 $idXml = $root->addChild('id');
136 $idXml->addAttribute('name', $field['fieldName']);
137 $idXml->addAttribute('type', $field['type']);
138 if (isset($field['columnName'])) {
139 $idXml->addAttribute('column', $field['columnName']);
141 if (isset($field['associationKey']) && $field['associationKey']) {
142 $idXml->addAttribute('association-key', 'true');
144 if ($idGeneratorType = $this->_getIdGeneratorTypeString($metadata->generatorType)) {
145 $generatorXml = $idXml->addChild('generator');
146 $generatorXml->addAttribute('strategy', $idGeneratorType);
152 foreach ($fields as $field) {
153 $fieldXml = $root->addChild('field');
154 $fieldXml->addAttribute('name', $field['fieldName']);
155 $fieldXml->addAttribute('type', $field['type']);
156 if (isset($field['columnName'])) {
157 $fieldXml->addAttribute('column', $field['columnName']);
159 if (isset($field['length'])) {
160 $fieldXml->addAttribute('length', $field['length']);
162 if (isset($field['precision'])) {
163 $fieldXml->addAttribute('precision', $field['precision']);
165 if (isset($field['scale'])) {
166 $fieldXml->addAttribute('scale', $field['scale']);
168 if (isset($field['unique']) && $field['unique']) {
169 $fieldXml->addAttribute('unique', $field['unique']);
171 if (isset($field['options'])) {
172 $optionsXml = $fieldXml->addChild('options');
173 foreach ($field['options'] as $key => $value) {
174 $optionsXml->addAttribute($key, $value);
177 if (isset($field['version'])) {
178 $fieldXml->addAttribute('version', $field['version']);
180 if (isset($field['columnDefinition'])) {
181 $fieldXml->addAttribute('column-definition', $field['columnDefinition']);
183 if (isset($field['nullable'])) {
184 $fieldXml->addAttribute('nullable', $field['nullable'] ? 'true' : 'false');
189 ClassMetadataInfo::ONE_TO_ONE,
190 ClassMetadataInfo::ONE_TO_MANY,
191 ClassMetadataInfo::MANY_TO_ONE,
192 ClassMetadataInfo::MANY_TO_MANY,
194 uasort($metadata->associationMappings, function($m1, $m2)use(&$orderMap){
195 $a1 = array_search($m1['type'],$orderMap);
196 $a2 = array_search($m2['type'],$orderMap);
197 return strcmp($a1, $a2);
199 foreach ($metadata->associationMappings as $name => $associationMapping) {
200 if ($associationMapping['type'] == ClassMetadataInfo::ONE_TO_ONE) {
201 $associationMappingXml = $root->addChild('one-to-one');
202 } else if ($associationMapping['type'] == ClassMetadataInfo::MANY_TO_ONE) {
203 $associationMappingXml = $root->addChild('many-to-one');
204 } else if ($associationMapping['type'] == ClassMetadataInfo::ONE_TO_MANY) {
205 $associationMappingXml = $root->addChild('one-to-many');
206 } else if ($associationMapping['type'] == ClassMetadataInfo::MANY_TO_MANY) {
207 $associationMappingXml = $root->addChild('many-to-many');
210 $associationMappingXml->addAttribute('field', $associationMapping['fieldName']);
211 $associationMappingXml->addAttribute('target-entity', $associationMapping['targetEntity']);
213 if (isset($associationMapping['mappedBy'])) {
214 $associationMappingXml->addAttribute('mapped-by', $associationMapping['mappedBy']);
216 if (isset($associationMapping['inversedBy'])) {
217 $associationMappingXml->addAttribute('inversed-by', $associationMapping['inversedBy']);
219 if (isset($associationMapping['indexBy'])) {
220 $associationMappingXml->addAttribute('index-by', $associationMapping['indexBy']);
222 if (isset($associationMapping['orphanRemoval']) && $associationMapping['orphanRemoval']!==false) {
223 $associationMappingXml->addAttribute('orphan-removal', 'true');
225 if (isset($associationMapping['joinTable']) && $associationMapping['joinTable']) {
226 $joinTableXml = $associationMappingXml->addChild('join-table');
227 $joinTableXml->addAttribute('name', $associationMapping['joinTable']['name']);
228 $joinColumnsXml = $joinTableXml->addChild('join-columns');
229 foreach ($associationMapping['joinTable']['joinColumns'] as $joinColumn) {
230 $joinColumnXml = $joinColumnsXml->addChild('join-column');
231 $joinColumnXml->addAttribute('name', $joinColumn['name']);
232 $joinColumnXml->addAttribute('referenced-column-name', $joinColumn['referencedColumnName']);
233 if (isset($joinColumn['onDelete'])) {
234 $joinColumnXml->addAttribute('on-delete', $joinColumn['onDelete']);
237 $inverseJoinColumnsXml = $joinTableXml->addChild('inverse-join-columns');
238 foreach ($associationMapping['joinTable']['inverseJoinColumns'] as $inverseJoinColumn) {
239 $inverseJoinColumnXml = $inverseJoinColumnsXml->addChild('join-column');
240 $inverseJoinColumnXml->addAttribute('name', $inverseJoinColumn['name']);
241 $inverseJoinColumnXml->addAttribute('referenced-column-name', $inverseJoinColumn['referencedColumnName']);
242 if (isset($inverseJoinColumn['onDelete'])) {
243 $inverseJoinColumnXml->addAttribute('on-delete', $inverseJoinColumn['onDelete']);
245 if (isset($inverseJoinColumn['columnDefinition'])) {
246 $inverseJoinColumnXml->addAttribute('column-definition', $inverseJoinColumn['columnDefinition']);
248 if (isset($inverseJoinColumn['nullable'])) {
249 $inverseJoinColumnXml->addAttribute('nullable', $inverseJoinColumn['nullable']);
251 if (isset($inverseJoinColumn['orderBy'])) {
252 $inverseJoinColumnXml->addAttribute('order-by', $inverseJoinColumn['orderBy']);
256 if (isset($associationMapping['joinColumns'])) {
257 $joinColumnsXml = $associationMappingXml->addChild('join-columns');
258 foreach ($associationMapping['joinColumns'] as $joinColumn) {
259 $joinColumnXml = $joinColumnsXml->addChild('join-column');
260 $joinColumnXml->addAttribute('name', $joinColumn['name']);
261 $joinColumnXml->addAttribute('referenced-column-name', $joinColumn['referencedColumnName']);
262 if (isset($joinColumn['onDelete'])) {
263 $joinColumnXml->addAttribute('on-delete', $joinColumn['onDelete']);
265 if (isset($joinColumn['columnDefinition'])) {
266 $joinColumnXml->addAttribute('column-definition', $joinColumn['columnDefinition']);
268 if (isset($joinColumn['nullable'])) {
269 $joinColumnXml->addAttribute('nullable', $joinColumn['nullable']);
273 if (isset($associationMapping['orderBy'])) {
274 $orderByXml = $associationMappingXml->addChild('order-by');
275 foreach ($associationMapping['orderBy'] as $name => $direction) {
276 $orderByFieldXml = $orderByXml->addChild('order-by-field');
277 $orderByFieldXml->addAttribute('name', $name);
278 $orderByFieldXml->addAttribute('direction', $direction);
282 if ($associationMapping['isCascadeRemove']) {
283 $cascade[] = 'cascade-remove';
285 if ($associationMapping['isCascadePersist']) {
286 $cascade[] = 'cascade-persist';
288 if ($associationMapping['isCascadeRefresh']) {
289 $cascade[] = 'cascade-refresh';
291 if ($associationMapping['isCascadeMerge']) {
292 $cascade[] = 'cascade-merge';
294 if ($associationMapping['isCascadeDetach']) {
295 $cascade[] = 'cascade-detach';
297 if (count($cascade) === 5) {
298 $cascade = array('cascade-all');
301 $cascadeXml = $associationMappingXml->addChild('cascade');
302 foreach ($cascade as $type) {
303 $cascadeXml->addChild($type);
308 if (isset($metadata->lifecycleCallbacks) && count($metadata->lifecycleCallbacks)>0) {
309 $lifecycleCallbacksXml = $root->addChild('lifecycle-callbacks');
310 foreach ($metadata->lifecycleCallbacks as $name => $methods) {
311 foreach ($methods as $method) {
312 $lifecycleCallbackXml = $lifecycleCallbacksXml->addChild('lifecycle-callback');
313 $lifecycleCallbackXml->addAttribute('type', $name);
314 $lifecycleCallbackXml->addAttribute('method', $method);
319 return $this->_asXml($xml);
323 * @param \SimpleXMLElement $simpleXml
324 * @return string $xml
326 private function _asXml($simpleXml)
328 $dom = new \DOMDocument('1.0', 'UTF-8');
329 $dom->loadXML($simpleXml->asXML());
330 $dom->formatOutput = true;
332 $result = $dom->saveXML();