From e6131d11ac8c3ec68e800e60620b71c497c988e0 Mon Sep 17 00:00:00 2001 From: jwage Date: Wed, 30 Sep 2009 04:35:43 +0000 Subject: [PATCH] [2.0] More work on ClassmetadataExporter and ConvertMappingTask for converting mapping information between various formats --- .../ORM/Mapping/ClassMetadataFactory.php | 2 +- lib/Doctrine/ORM/Mapping/Driver/XmlDriver.php | 9 +- .../ORM/Mapping/Driver/YamlDriver.php | 4 +- lib/Doctrine/ORM/Tools/Cli.php | 11 +- .../Tools/Cli/Tasks/ConvertMappingTask.php | 131 +++++++++++++ .../ORM/Tools/Cli/Tasks/CreateMappingTask.php | 14 -- .../Tools/Export/ClassmetadataExporter.php | 92 +++++---- .../Tools/Export/Driver/AbstractExporter.php | 22 +-- .../Export/Driver/AnnotationExporter.php | 163 ++++++++++++++++ .../ORM/Tools/Export/Driver/PhpExporter.php | 103 +++++++++- .../ORM/Tools/Export/Driver/XmlExporter.php | 176 ++++++++++++++++++ .../ORM/Tools/Export/Driver/YamlExporter.php | 25 +-- .../Tools/Export/Driver/annotation.tpl.php | 26 +++ 13 files changed, 691 insertions(+), 87 deletions(-) create mode 100644 lib/Doctrine/ORM/Tools/Cli/Tasks/ConvertMappingTask.php create mode 100644 lib/Doctrine/ORM/Tools/Export/Driver/AnnotationExporter.php create mode 100644 lib/Doctrine/ORM/Tools/Export/Driver/annotation.tpl.php diff --git a/lib/Doctrine/ORM/Mapping/ClassMetadataFactory.php b/lib/Doctrine/ORM/Mapping/ClassMetadataFactory.php index e0ef2e40f..005bcfd57 100644 --- a/lib/Doctrine/ORM/Mapping/ClassMetadataFactory.php +++ b/lib/Doctrine/ORM/Mapping/ClassMetadataFactory.php @@ -195,7 +195,7 @@ class ClassMetadataFactory if ( ! $class->identifier && ! $class->isMappedSuperclass) { throw MappingException::identifierRequired($className); } - if ($parent) { + if ($parent && ! $parent->isMappedSuperclass) { if ($parent->isIdGeneratorSequence()) { $class->setSequenceGeneratorDefinition($parent->getSequenceGeneratorDefinition()); } else if ($parent->isIdGeneratorTable()) { diff --git a/lib/Doctrine/ORM/Mapping/Driver/XmlDriver.php b/lib/Doctrine/ORM/Mapping/Driver/XmlDriver.php index acff179bf..7104628c8 100644 --- a/lib/Doctrine/ORM/Mapping/Driver/XmlDriver.php +++ b/lib/Doctrine/ORM/Mapping/Driver/XmlDriver.php @@ -77,9 +77,9 @@ class XmlDriver extends AbstractFileDriver if (isset($xmlRoot->{'discriminator-column'})) { $discrColumn = $xmlRoot->{'discriminator-column'}; $metadata->setDiscriminatorColumn(array( - 'name' => (string)$discrColumn->name, - 'type' => (string)$discrColumn->type, - 'length' => (string)$discrColumn->length + 'name' => (string)$discrColumn['name'], + 'type' => (string)$discrColumn['type'], + 'length' => (string)$discrColumn['length'] )); } @@ -90,7 +90,8 @@ class XmlDriver extends AbstractFileDriver // Evaluate if (isset($xmlRoot->{'change-tracking-policy'})) { - $metadata->setChangeTrackingPolicy((array)$xmlRoot->{'change-tracking-policy'}); + $metadata->setChangeTrackingPolicy(constant('Doctrine\ORM\Mapping\ClassMetadata::CHANGETRACKING_' + . strtoupper((string)$xmlRoot->{'change-tracking-policy'}))); } // Evaluate diff --git a/lib/Doctrine/ORM/Mapping/Driver/YamlDriver.php b/lib/Doctrine/ORM/Mapping/Driver/YamlDriver.php index de62940d9..c0c0e964e 100644 --- a/lib/Doctrine/ORM/Mapping/Driver/YamlDriver.php +++ b/lib/Doctrine/ORM/Mapping/Driver/YamlDriver.php @@ -73,7 +73,7 @@ class YamlDriver extends AbstractFileDriver } if (isset($element['inheritanceType'])) { - $metadata->setInheritanceType(constant('Doctrine\ORM\Mapping\ClassMetadata::INHERITANCE_TYPE_' . $element['inheritanceType'])); + $metadata->setInheritanceType(constant('Doctrine\ORM\Mapping\ClassMetadata::INHERITANCE_TYPE_' . strtoupper($element['inheritanceType']))); } // Evaluate discriminatorColumn @@ -94,7 +94,7 @@ class YamlDriver extends AbstractFileDriver // Evaluate changeTrackingPolicy if (isset($element['changeTrackingPolicy'])) { $metadata->setChangeTrackingPolicy(constant('Doctrine\ORM\Mapping\ClassMetadata::CHANGETRACKING_' - . $element['changeTrackingPolicy'])); + . strtoupper($element['changeTrackingPolicy']))); } // Evaluate indexes diff --git a/lib/Doctrine/ORM/Tools/Cli.php b/lib/Doctrine/ORM/Tools/Cli.php index 7f0f383b6..74c44f476 100644 --- a/lib/Doctrine/ORM/Tools/Cli.php +++ b/lib/Doctrine/ORM/Tools/Cli.php @@ -84,11 +84,12 @@ class Cli $ns = 'Doctrine\ORM\Tools\Cli\Tasks'; $this->addTasks(array( - 'help' => $ns . '\HelpTask', - 'version' => $ns . '\VersionTask', - 'schema-tool' => $ns . '\SchemaToolTask', - 'run-sql' => $ns . '\RunSqlTask', - 'run-dql' => $ns . '\RunDqlTask', + 'help' => $ns . '\HelpTask', + 'version' => $ns . '\VersionTask', + 'schema-tool' => $ns . '\SchemaToolTask', + 'run-sql' => $ns . '\RunSqlTask', + 'run-dql' => $ns . '\RunDqlTask', + 'convert-mapping' => $ns . '\ConvertMappingTask', )); } diff --git a/lib/Doctrine/ORM/Tools/Cli/Tasks/ConvertMappingTask.php b/lib/Doctrine/ORM/Tools/Cli/Tasks/ConvertMappingTask.php new file mode 100644 index 000000000..2c10a988e --- /dev/null +++ b/lib/Doctrine/ORM/Tools/Cli/Tasks/ConvertMappingTask.php @@ -0,0 +1,131 @@ +. + */ + +namespace Doctrine\ORM\Tools\Cli\Tasks; + +use Doctrine\ORM\Tools\Export\ClassmetadataExporter; + +/** + * CLI Task to convert your mapping information between the various formats + * + * @license http://www.opensource.org/licenses/lgpl-license.php LGPL + * @link www.doctrine-project.org + * @since 2.0 + * @version $Revision$ + * @author Guilherme Blanco + * @author Jonathan Wage + * @author Roman Borschel + */ +class ConvertMappingTask extends AbstractTask +{ + /** + * @inheritdoc + */ + public function extendedHelp() + { + $printer = $this->getPrinter(); + + $printer->write('Task: ')->writeln('convert-mapping', 'KEYWORD') + ->write('Synopsis: '); + $this->_writeSynopsis($printer); + + $printer->writeln('Description: Convert mapping information between supported formats.') + ->writeln('Options:') + ->write('--from=', 'REQ_ARG') + ->writeln("\tThe path to the mapping information you are converting from.") + ->write('--to=', 'REQ_ARG') + ->writeln("\tThe format to convert to.") + ->write(PHP_EOL) + ->write('--dest=', 'REQ_ARG') + ->writeln("\tThe path to write the converted mapping information."); + } + + /** + * @inheritdoc + */ + public function basicHelp() + { + $this->_writeSynopsis($this->getPrinter()); + } + + private function _writeSynopsis($printer) + { + $printer->write('convert-mapping', 'KEYWORD') + ->write(' --from=', 'REQ_ARG') + ->write(' --to=', 'REQ_ARG') + ->writeln(' --dest=', 'REQ_ARG'); + } + + /** + * @inheritdoc + */ + public function validate() + { + if ( ! parent::validate()) { + return false; + } + + $args = $this->getArguments(); + $printer = $this->getPrinter(); + + if (!(isset($args['from']) && isset($args['to']) && isset($args['dest']))) + { + $printer->writeln('You must include a value for all four options: --from, --to and --dest', 'ERROR'); + return false; + } + + return true; + } + + public function run() + { + $printer = $this->getPrinter(); + $args = $this->getArguments(); + + $cme = new ClassmetadataExporter(); + $from = (array) $args['from']; + foreach ($from as $path) { + $type = $this->_determinePathType($path); + + $printer->writeln(sprintf('Adding %s mapping directory: "%s"', $type, $path), 'INFO'); + + $cme->addMappingDir($path, $type); + } + + $exporter = $cme->getExporter($args['to']); + $exporter->setOutputDir($args['dest']); + + $printer->writeln(sprintf('Exporting %s mapping information to directory: "%s"', $args['to'], $args['dest']), 'INFO'); + + $exporter->export(); + } + + protected function _determinePathType($path) + { + $files = glob($path . '/*.*'); + if (!$files) + { + throw new \InvalidArgumentException(sprintf('No schema mapping files found in "%s"', $path)); + } + $info = pathinfo($files[0]); + return $info['extension']; + } +} \ No newline at end of file diff --git a/lib/Doctrine/ORM/Tools/Cli/Tasks/CreateMappingTask.php b/lib/Doctrine/ORM/Tools/Cli/Tasks/CreateMappingTask.php index 2c8fda7a3..e69de29bb 100644 --- a/lib/Doctrine/ORM/Tools/Cli/Tasks/CreateMappingTask.php +++ b/lib/Doctrine/ORM/Tools/Cli/Tasks/CreateMappingTask.php @@ -1,14 +0,0 @@ - 'Doctrine\ORM\Tools\Export\Driver\XmlExporter', - 'yaml' => 'Doctrine\ORM\Tools\Export\Driver\YamlExporter', - 'php' => 'Doctrine\ORM\Tools\Export\Driver\PhpExporter' + 'xml' => 'Doctrine\ORM\Tools\Export\Driver\XmlExporter', + 'yaml' => 'Doctrine\ORM\Tools\Export\Driver\YamlExporter', + 'yml' => 'Doctrine\ORM\Tools\Export\Driver\YamlExporter', + 'php' => 'Doctrine\ORM\Tools\Export\Driver\PhpExporter', + 'annotation' => 'Doctrine\ORM\Tools\Export\Driver\AnnotationExporter' ); private $_mappingDrivers = array( - 'php' => 'Doctrine\ORM\Mapping\Driver\AnnotationDriver', + 'annotation' => 'Doctrine\ORM\Mapping\Driver\AnnotationDriver', 'yaml' => 'Doctrine\ORM\Mapping\Driver\YamlDriver', + 'yml' => 'Doctrine\ORM\Mapping\Driver\YamlDriver', 'xml' => 'Doctrine\ORM\Mapping\Driver\XmlDriver' ); - private $_mappingDriverInstances = array(); + private $_mappingDirectories = array(); public function addMappingDir($dir, $type) { - if ( ! isset($this->_mappingDrivers[$type])) { - throw DoctrineException::invalidMappingDriverType($type); - } - - $class = $this->_mappingDrivers[$type]; - if (is_subclass_of($class, 'Doctrine\ORM\Mapping\Driver\AbstractFileDriver')) { - $driver = new $class($dir, constant($class . '::PRELOAD')); + if ($type === 'php') { + $this->_mappingDirectories[] = array($dir, $type); } else { - $reader = new \Doctrine\Common\Annotations\AnnotationReader(new \Doctrine\Common\Cache\ArrayCache); - $reader->setDefaultAnnotationNamespace('Doctrine\ORM\Mapping\\'); - $driver = new $class($reader); + if ( ! isset($this->_mappingDrivers[$type])) { + throw DoctrineException::invalidMappingDriverType($type); + } + + $class = $this->_mappingDrivers[$type]; + if (is_subclass_of($class, 'Doctrine\ORM\Mapping\Driver\AbstractFileDriver')) { + $driver = new $class($dir, constant($class . '::PRELOAD')); + } else { + $reader = new \Doctrine\Common\Annotations\AnnotationReader(new \Doctrine\Common\Cache\ArrayCache); + $reader->setDefaultAnnotationNamespace('Doctrine\ORM\Mapping\\'); + $driver = new $class($reader); + } + $this->_mappingDirectories[] = array($dir, $driver); } - $this->_mappingDriverInstances[] = array($dir, $driver); } private function _getMetadataInstances() { $classes = array(); - foreach ($this->_mappingDriverInstances as $d) { + foreach ($this->_mappingDirectories as $d) { list($dir, $driver) = $d; - // TODO: This code exists in the SchemaToolTask.php - // Should we pull it out somewhere common? I can see the need to have - // a way to retrieve an array of entity names found in some directories - if ($driver instanceof \Doctrine\ORM\Mapping\Driver\AnnotationDriver) { + if ($driver == 'php') { $iter = new \FilesystemIterator($dir); - $declared = get_declared_classes(); foreach ($iter as $item) { - $baseName = $item->getBaseName(); - if ($baseName[0] == '.') { - continue; + include $item->getPathName(); + $vars = get_defined_vars(); + foreach ($vars as $var) { + if ($var instanceof \Doctrine\ORM\Mapping\ClassMetadata) { + $classes[] = $var; + } } - require_once $item->getPathName(); } - $declared = array_diff(get_declared_classes(), $declared); + $classes = array_unique($classes); + $classes = array_values($classes); + } else { + if ($driver instanceof \Doctrine\ORM\Mapping\Driver\AnnotationDriver) { + $iter = new \FilesystemIterator($dir); - foreach ($declared as $className) { - if ( ! $driver->isTransient($className)) { + $declared = get_declared_classes(); + foreach ($iter as $item) { + $baseName = $item->getBaseName(); + if ($baseName[0] == '.') { + continue; + } + require_once $item->getPathName(); + } + $declared = array_diff(get_declared_classes(), $declared); + + foreach ($declared as $className) { + if ( ! $driver->isTransient($className)) { + $metadata = new ClassMetadata($className); + $driver->loadMetadataForClass($className, $metadata); + $classes[] = $metadata; + } + } + } else { + $preloadedClasses = $driver->preload(true); + foreach ($preloadedClasses as $className) { $metadata = new ClassMetadata($className); $driver->loadMetadataForClass($className, $metadata); $classes[] = $metadata; } } - } else { - $preloadedClasses = $driver->preload(true); - foreach ($preloadedClasses as $className) { - $metadata = new ClassMetadata($className); - $driver->loadMetadataForClass($className, $metadata); - $classes[] = $metadata; - } } } diff --git a/lib/Doctrine/ORM/Tools/Export/Driver/AbstractExporter.php b/lib/Doctrine/ORM/Tools/Export/Driver/AbstractExporter.php index 0c0922f67..5373e56af 100644 --- a/lib/Doctrine/ORM/Tools/Export/Driver/AbstractExporter.php +++ b/lib/Doctrine/ORM/Tools/Export/Driver/AbstractExporter.php @@ -110,19 +110,19 @@ abstract class AbstractExporter { switch ($type) { - case Classmetadata::INHERITANCE_TYPE_NONE: + case ClassMetadata::INHERITANCE_TYPE_NONE: return 'NONE'; break; - case Classmetadata::INHERITANCE_TYPE_JOINED: + case ClassMetadata::INHERITANCE_TYPE_JOINED: return 'JOINED'; break; - case Classmetadata::INHERITANCE_TYPE_SINGLE_TABLE: + case ClassMetadata::INHERITANCE_TYPE_SINGLE_TABLE: return 'SINGLE_TABLE'; break; - case Classmetadata::INHERITANCE_TYPE_TABLE_PER_CLASS: + case ClassMetadata::INHERITANCE_TYPE_TABLE_PER_CLASS: return 'PER_CLASS'; break; } @@ -132,15 +132,15 @@ abstract class AbstractExporter { switch ($policy) { - case Classmetadata::CHANGETRACKING_DEFERRED_IMPLICIT: + case ClassMetadata::CHANGETRACKING_DEFERRED_IMPLICIT: return 'DEFERRED_IMPLICIT'; break; - case Classmetadata::CHANGETRACKING_DEFERRED_EXPLICIT: + case ClassMetadata::CHANGETRACKING_DEFERRED_EXPLICIT: return 'DEFERRED_EXPLICIT'; break; - case Classmetadata::CHANGETRACKING_NOTIFY: + case ClassMetadata::CHANGETRACKING_NOTIFY: return 'NOTIFY'; break; } @@ -150,19 +150,19 @@ abstract class AbstractExporter { switch ($type) { - case Classmetadata::GENERATOR_TYPE_AUTO: + case ClassMetadata::GENERATOR_TYPE_AUTO: return 'AUTO'; break; - case Classmetadata::GENERATOR_TYPE_SEQUENCE: + case ClassMetadata::GENERATOR_TYPE_SEQUENCE: return 'SEQUENCE'; break; - case Classmetadata::GENERATOR_TYPE_TABLE: + case ClassMetadata::GENERATOR_TYPE_TABLE: return 'TABLE'; break; - case Classmetadata::GENERATOR_TYPE_IDENTITY: + case ClassMetadata::GENERATOR_TYPE_IDENTITY: return 'IDENTITY'; break; } diff --git a/lib/Doctrine/ORM/Tools/Export/Driver/AnnotationExporter.php b/lib/Doctrine/ORM/Tools/Export/Driver/AnnotationExporter.php new file mode 100644 index 000000000..290f57b23 --- /dev/null +++ b/lib/Doctrine/ORM/Tools/Export/Driver/AnnotationExporter.php @@ -0,0 +1,163 @@ +. + */ + +namespace Doctrine\ORM\Tools\Export\Driver; + +use Doctrine\ORM\Mapping\ClassMetadata, + Doctrine\ORM\Mapping\AssociationMapping; + +/** + * ClassMetadata exporter for PHP classes with annotations + * + * @license http://www.opensource.org/licenses/lgpl-license.php LGPL + * @link www.doctrine-project.org + * @since 2.0 + * @version $Revision$ + * @author Jonathan Wage + */ +class AnnotationExporter extends AbstractExporter +{ + protected $_extension = '.php'; + + /** + * Converts a single ClassMetadata instance to the exported format + * and returns it + * + * @param ClassMetadata $metadata + * @return mixed $exported + */ + public function exportClassMetadata(ClassMetadata $metadata) + { + ob_start(); + include('annotation.tpl.php'); + $code = ob_get_contents(); + ob_end_clean(); + + $code = str_replace(array('[?php', '?]'), array(''), $code); + return $code; + } + + private function _getTableAnnotation($metadata) + { + $table = array(); + $table[] = 'name=' . $metadata->primaryTable['name']; + if (isset($metadata->primaryTable['schema'])) { + $table[] = 'schema=' . $metadata->primaryTable['schema']; + } + return '@Table(' . implode(', ', $table) . ')'; + } + + private function _getAssociationMappingAnnotation(AssociationMapping $associationMapping, ClassMetadata $metadata) + { + // TODO: This function still needs to be written :) + $lines = array(); + $lines[] = ' /**'; + $lines[] = ' *'; + $lines[] = ' */'; + + return implode("\n", $lines); + } + + private function _getFieldMappingAnnotation(array $fieldMapping, ClassMetadata $metadata) + { + $lines = array(); + $lines[] = ' /**'; + + $column = array(); + if (isset($fieldMapping['type'])) { + $column[] = 'type="' . $fieldMapping['type'] . '"'; + } + if (isset($fieldMapping['length'])) { + $column[] = 'length=' . $fieldMapping['length']; + } + if (isset($fieldMapping['precision'])) { + $column[] = 'precision=' . $fieldMapping['precision']; + } + if (isset($fieldMapping['scale'])) { + $column[] = 'scale=' . $fieldMapping['scale']; + } + if (isset($fieldMapping['nullable'])) { + $column[] = 'nullable=' . var_export($fieldMapping['nullable'], true); + } + if (isset($fieldMapping['options'])) { + $options = array(); + foreach ($fieldMapping['options'] as $key => $value) { + $value = var_export($value, true); + $value = str_replace("'", '"', $value); + $options[] = ! is_numeric($key) ? $key . '=' . $value:$value; + } + $column[] = 'options={' . implode(', ', $options) . '}'; + } + if (isset($fieldMapping['unique'])) { + $column[] = 'unique=' . var_export($fieldMapping['unique'], true); + } + $lines[] = ' * @Column(' . implode(', ', $column) . ')'; + if (isset($fieldMapping['id']) && $fieldMapping['id']) { + $lines[] = ' * @Id'; + if ($generatorType = $this->_getIdGeneratorTypeString($metadata->generatorType)) { + $lines[] = ' * @GeneratedValue(strategy="' . $generatorType . '")'; + } + if ($metadata->sequenceGeneratorDefinition) { + $sequenceGenerator = array(); + if (isset($metadata->sequenceGeneratorDefinition['sequenceName'])) { + $sequenceGenerator[] = 'sequenceName="' . $metadata->sequenceGeneratorDefinition['sequenceName'] . '"'; + } + if (isset($metadata->sequenceGeneratorDefinition['allocationSize'])) { + $sequenceGenerator[] = 'allocationSize="' . $metadata->sequenceGeneratorDefinition['allocationSize'] . '"'; + } + if (isset($metadata->sequenceGeneratorDefinition['initialValue'])) { + $sequenceGenerator[] = 'initialValue="' . $metadata->sequenceGeneratorDefinition['initialValue'] . '"'; + } + $lines[] = ' * @SequenceGenerator(' . implode(', ', $sequenceGenerator) . ')'; + } + } + if (isset($fieldMapping['version']) && $fieldMapping['version']) { + $lines[] = ' * @Version'; + } + $lines[] = ' */'; + + return implode("\n", $lines); + } + + /** + * Export each ClassMetadata instance to a single Doctrine Mapping file + * named after the entity + * + * @return void + */ + public function export() + { + if ( ! is_dir($this->_outputDir)) { + mkdir($this->_outputDir, 0777); + } + + foreach ($this->_metadatas as $metadata) { + $outputPath = $this->_outputDir . '/' . str_replace('\\', DIRECTORY_SEPARATOR, $metadata->name) . $this->_extension; + $outputDir = dirname($outputPath); + if ( ! is_dir($outputDir)) { + mkdir($outputDir, 0777, true); + } + $output = $this->exportClassMetadata($metadata); + file_put_contents($outputPath, $output); + } + } +} \ No newline at end of file diff --git a/lib/Doctrine/ORM/Tools/Export/Driver/PhpExporter.php b/lib/Doctrine/ORM/Tools/Export/Driver/PhpExporter.php index 6ff47963c..51c484ee7 100644 --- a/lib/Doctrine/ORM/Tools/Export/Driver/PhpExporter.php +++ b/lib/Doctrine/ORM/Tools/Export/Driver/PhpExporter.php @@ -25,7 +25,7 @@ namespace Doctrine\ORM\Tools\Export\Driver; use Doctrine\ORM\Mapping\ClassMetadata; /** - * ClassMetadata exporter for PHP classes with annotations + * ClassMetadata exporter for PHP code * * @license http://www.opensource.org/licenses/lgpl-license.php LGPL * @link www.doctrine-project.org @@ -46,6 +46,105 @@ class PhpExporter extends AbstractExporter */ public function exportClassMetadata(ClassMetadata $metadata) { - + $lines = array(); + $lines[] = 'name . "');"; + + if ($metadata->isMappedSuperclass) { + $lines[] = '$metadata->isMappedSuperclass = true;'; + } + + if ($metadata->inheritanceType) { + $lines[] = '$metadata->setInheritanceType(ClassMetadata::INHERITANCE_TYPE_' . $this->_getInheritanceTypeString($metadata->inheritanceType) . ');'; + } + + if ($metadata->customRepositoryClassName) { + $lines[] = "\$metadata->customRepositoryClassName = '" . $metadata->customRepositoryClassName . "';"; + } + + if ($metadata->primaryTable) { + $lines[] = '$metadata->setPrimaryTable(' . $this->_varExport($metadata->primaryTable) . ');'; + } + + if ($metadata->discriminatorColumn) { + $lines[] = '$metadata->setDiscriminatorColumn(' . $this->_varExport($metadata->discriminatorColumn) . ');'; + } + + if ($metadata->discriminatorMap) { + $lines[] = '$metadata->setDiscriminatorMap(' . $this->_varExport($metadata->discriminatorMap) . ');'; + } + + if ($metadata->changeTrackingPolicy) { + $lines[] = '$metadata->setChangeTrackingPolicy(ClassMetadata::CHANGETRACKING_' . $this->_getChangeTrackingPolicyString($metadata->changeTrackingPolicy) . ');'; + } + + foreach ($metadata->fieldMappings as $fieldMapping) { + $lines[] = '$metadata->mapField(' . $this->_varExport($fieldMapping) . ');'; + } + + if ($generatorType = $this->_getIdGeneratorTypeString($metadata->generatorType)) { + $lines[] = '$metadata->setIdGeneratorType(ClassMetadata::GENERATOR_TYPE_' . $generatorType . ');'; + } + + foreach ($metadata->associationMappings as $associationMapping) { + $associationMappingArray = array( + 'fieldName' => $associationMapping->sourceFieldName, + 'targetEntity' => $associationMapping->targetEntityName, + 'cascade' => array( + 'remove' => $associationMapping->isCascadeRemove, + 'persist' => $associationMapping->isCascadePersist, + 'refresh' => $associationMapping->isCascadeRefresh, + 'merge' => $associationMapping->isCascadeMerge, + 'detach' => $associationMapping->isCascadeDetach, + ), + ); + + if ($associationMapping instanceof \Doctrine\ORM\Mapping\OneToOneMapping) { + $method = 'mapOneToOne'; + $oneToOneMappingArray = array( + 'mappedBy' => $associationMapping->mappedByFieldName, + 'joinColumns' => $associationMapping->joinColumns, + 'orphanRemoval' => $associationMapping->orphanRemoval, + ); + + $associationMappingArray = array_merge($associationMappingArray, $oneToOneMappingArray); + } else if ($associationMapping instanceof \Doctrine\ORM\Mapping\OneToManyMapping) { + $method = 'mapOneToMany'; + $oneToManyMappingArray = array( + 'mappedBy' => $associationMapping->mappedByFieldName, + 'orphanRemoval' => $associationMapping->orphanRemoval, + ); + + $associationMappingArray = array_merge($associationMappingArray, $oneToManyMappingArray); + } else if ($associationMapping instanceof \Doctrine\ORM\Mapping\ManyToManyMapping) { + $method = 'mapManyToMany'; + $manyToManyMappingArray = array( + 'mappedBy' => $associationMapping->mappedByFieldName, + 'joinTable' => $associationMapping->joinTable, + ); + + $associationMappingArray = array_merge($associationMappingArray, $manyToManyMappingArray); + } + $lines[] = '$metadata->' . $method . '(' . $this->_varExport($associationMappingArray) . ');'; + } + + return implode("\n", $lines); + } + + protected function _varExport($var) + { + $export = var_export($var, true); + $export = str_replace("\n", PHP_EOL . str_repeat(' ', 8), $export); + $export = str_replace(' ', ' ', $export); + $export = str_replace('array (', 'array(', $export); + $export = str_replace('array( ', 'array(', $export); + $export = str_replace(',)', ')', $export); + $export = str_replace(', )', ')', $export); + $export = str_replace(' ', ' ', $export); + + return $export; } } \ No newline at end of file diff --git a/lib/Doctrine/ORM/Tools/Export/Driver/XmlExporter.php b/lib/Doctrine/ORM/Tools/Export/Driver/XmlExporter.php index 753257974..b962b5639 100644 --- a/lib/Doctrine/ORM/Tools/Export/Driver/XmlExporter.php +++ b/lib/Doctrine/ORM/Tools/Export/Driver/XmlExporter.php @@ -46,6 +46,182 @@ class XmlExporter extends AbstractExporter */ public function exportClassMetadata(ClassMetadata $metadata) { + $xml = new \SimpleXmlElement(""); + + $xml->addAttribute('xmlns', 'http://doctrine-project.org/schemas/orm/doctrine-mapping'); + $xml->addAttribute('xmlns:xsi', 'http://www.w3.org/2001/XMLSchema-instance'); + $xml->addAttribute('xsi:schemaLocation', 'http://doctrine-project.org/schemas/orm/doctrine-mapping.xsd'); + + if ($metadata->isMappedSuperclass) { + $root = $xml->addChild('mapped-superclass'); + } else { + $root = $xml->addChild('entity'); + } + + if ($metadata->customRepositoryClassName) { + $root->addAttribute('repository-class', $metadata->customRepositoryClassName); + } + + $root->addAttribute('name', $metadata->name); + + if (isset($metadata->primaryTable['name'])) { + $root->addAttribute('table', $metadata->primaryTable['name']); + } + + if (isset($metadata->primaryTable['schema'])) { + $root->addAttribute('schema', $metadata->primaryTable['schema']); + } + + if (isset($metadata->primaryTable['inheritance-type'])) { + $root->addAttribute('inheritance-type', $metadata->primaryTable['inheritance-type']); + } + + if ($metadata->discriminatorColumn) { + $discriminatorColumnXml = $root->addChild('discriminiator-column'); + $discriminatorColumnXml->addAttribute('name', $metadata->discriminatorColumn['name']); + $discriminatorColumnXml->addAttribute('type', $metadata->discriminatorColumn['type']); + $discriminatorColumnXml->addAttribute('length', $metadata->discriminatorColumn['length']); + } + + if ($metadata->discriminatorMap) { + $discriminatorMapXml = $root->addChild('discriminator-map'); + foreach ($metadata->discriminatorMap as $value => $className) { + $discriminatorMappingXml = $discriminatorMapXml->addChild('discriminator-mapping'); + $discriminatorMappingXml->addAttribute('value', $value); + $discriminatorMappingXml->addAttribute('class', $className); + } + } + + $root->addChild('change-tracking-policy', $this->_getChangeTrackingPolicyString($metadata->changeTrackingPolicy)); + + if (isset($metadata->primaryTable['indexes'])) { + $indexesXml = $root->addChild('indexes'); + foreach ($metadata->primaryTable['indexes'] as $name => $index) { + $indexXml = $root->addChild('index'); + $indexXml->addAttribute('name', $name); + $indexXml->addAttribute('columns', implode(',', $index['fields'])); + } + } + + if (isset($metadata->primaryTable['uniqueConstraints'])) { + $uniqueConstraintsXml = $root->addChild('unique-constraints'); + foreach ($metadata->primaryTable['uniqueConstraints'] as $uniqueConstraint) { + $uniqueConstraintXml = $uniqueConstraintsXml->addChild('unique-constraint'); + $uniqueConstraintXml->addAttribute('columns', $uniqueConstraint['fields']); + } + } + + $fields = $metadata->fieldMappings; + $id = array(); + foreach ($fields as $name => $field) { + if (isset($field['id']) && $field['id']) { + $id[$name] = $field; + unset($fields[$name]); + } + } + + if ($idGeneratorType = $this->_getIdGeneratorTypeString($metadata->getIdGeneratorType())) { + $id[$metadata->getSingleIdentifierFieldName()]['generator']['strategy'] = $idGeneratorType; + } + + if ($fields) { + foreach ($fields as $field) { + $fieldXml = $root->addChild('field'); + $fieldXml->addAttribute('name', $field['fieldName']); + $fieldXml->addAttribute('type', $field['type']); + if (isset($field['columnName'])) { + $fieldXml->addAttribute('column', $field['columnName']); + } + if (isset($field['length'])) { + $fieldXml->addAttribute('length', $field['length']); + } + if (isset($field['precision'])) { + $fieldXml->addAttribute('precision', $field['precision']); + } + if (isset($field['scale'])) { + $fieldXml->addAttribute('scale', $field['scale']); + } + if (isset($field['unique'])) { + $fieldXml->addAttribute('unique', $field['unique']); + } + if (isset($field['options'])) { + $fieldXml->addAttribute('options', $field['options']); + } + if (isset($field['version'])) { + $fieldXml->addAttribute('version', $field['version']); + } + } + } + + if ($id) { + foreach ($id as $field) { + $idXml = $root->addChild('id'); + $idXml->addAttribute('name', $field['fieldName']); + $idXml->addAttribute('type', $field['type']); + if (isset($field['columnName'])) { + $idXml->addAttribute('column', $field['columnName']); + } + if ($idGeneratorType = $this->_getIdGeneratorTypeString($metadata->generatorType)) { + $generatorXml = $idXml->addChild('generator'); + $generatorXml->addAttribute('strategy', $idGeneratorType); + } + } + } + + foreach ($metadata->associationMappings as $name => $associationMapping) { + if ($associationMapping instanceof \Doctrine\ORM\Mapping\OneToOneMapping) { + $associationMappingXml = $root->addChild('one-to-one'); + } else if ($associationMapping instanceof \Doctrine\ORM\Mapping\OneToManyMapping) { + $associationMappingXml = $root->addChild('one-to-many'); + } else if ($associationMapping instanceof \Doctrine\ORM\Mapping\ManyToManyMapping) { + $associationMappingXml = $root->addChild('many-to-many'); + } + + $associationMappingXml->addAttribute('field', $associationMapping->sourceFieldName); + $associationMappingXml->addAttribute('target-entity', $associationMapping->targetEntityName); + + if (isset($associationMapping->mappedByFieldName)) { + $associationMappingXml->addAttribute('mapped-by', $associationMapping->mappedByFieldName); + } + if (isset($associationMapping->orphanRemoval)) { + $associationMappingXml->addAttribute('orphan-removal', $associationMapping->orphanRemoval); + } + if (isset($associationMapping->joinTable) && $associationMapping->joinTable) { + $joinTableXml = $associationMappingXml->addChild('join-table'); + $joinTableXml->addAttribute('name', $associationMapping->joinTable['name']); + $joinColumnsXml = $joinTableXml->addChild('join-columns'); + foreach ($associationMapping->joinTable['joinColumns'] as $joinColumn) { + $joinColumnXml = $joinColumnsXml->addChild('join-column'); + $joinColumnXml->addAttribute('name', $joinColumn['name']); + $joinColumnXml->addAttribute('referenced-column-name', $joinColumn['referencedColumnName']); + } + } + + $cascade = array(); + if ($associationMapping->isCascadeRemove) { + $cascade[] = 'remove'; + } + if ($associationMapping->isCascadePersist) { + $cascade[] = 'persist'; + } + if ($associationMapping->isCascadeRefresh) { + $cascade[] = 'refresh'; + } + if ($associationMapping->isCascadeMerge) { + $cascade[] = 'merge'; + } + if ($associationMapping->isCascadeDetach) { + $cascade[] = 'detach'; + } + if ($cascade) { + $cascadeXml = $associationMappingXml->addChild('cascade'); + foreach ($cascade as $type) { + $cascadeXml->addChild($type); + } + } + } + + return $xml->asXml(); } } \ No newline at end of file diff --git a/lib/Doctrine/ORM/Tools/Export/Driver/YamlExporter.php b/lib/Doctrine/ORM/Tools/Export/Driver/YamlExporter.php index 767bf2f9b..5991e5289 100644 --- a/lib/Doctrine/ORM/Tools/Export/Driver/YamlExporter.php +++ b/lib/Doctrine/ORM/Tools/Export/Driver/YamlExporter.php @@ -52,7 +52,11 @@ class YamlExporter extends AbstractExporter public function exportClassMetadata(ClassMetadata $metadata) { $array = array(); - $array['type'] = 'entity'; + if ($metadata->isMappedSuperclass) { + $array['type'] = 'mappedSuperclass'; + } else { + $array['type'] = 'entity'; + } $array['table'] = $metadata->primaryTable['name']; if (isset($metadata->primaryTable['schema'])) { @@ -79,7 +83,7 @@ class YamlExporter extends AbstractExporter $array['uniqueConstraints'] = $metadata->primaryTable['uniqueConstraints']; } - $fields = $metadata->getFieldMappings(); + $fields = $metadata->fieldMappings; $id = array(); foreach ($fields as $name => $field) { @@ -89,8 +93,8 @@ class YamlExporter extends AbstractExporter } } - if ($idGeneratorType = $this->_getIdGeneratorTypeString($metadata->getIdGeneratorType())) { - $id[$metadata->getSingleIdentifierFieldName()]['generator']['strategy'] = $idGeneratorType; + if ($idGeneratorType = $this->_getIdGeneratorTypeString($metadata->generatorType)) { + $id[$metadata->getSingleIdentifierFieldName()]['generator']['strategy'] = $this->_getIdGeneratorTypeString($metadata->generatorType); } $array['id'] = $id; @@ -100,10 +104,8 @@ class YamlExporter extends AbstractExporter foreach ($metadata->associationMappings as $name => $associationMapping) { $associationMappingArray = array( 'fieldName' => $associationMapping->sourceFieldName, - 'sourceEntity' => $associationMapping->sourceEntityName, 'targetEntity' => $associationMapping->targetEntityName, - 'optional' => $associationMapping->isOptional, - 'cascades' => array( + 'cascade' => array( 'remove' => $associationMapping->isCascadeRemove, 'persist' => $associationMapping->isCascadePersist, 'refresh' => $associationMapping->isCascadeRefresh, @@ -112,8 +114,7 @@ class YamlExporter extends AbstractExporter ), ); - if ($associationMapping instanceof OneToOneMapping) { - // TODO: We may need to re-include the quotes if quote = true in names of joinColumns + if ($associationMapping instanceof \Doctrine\ORM\Mapping\OneToOneMapping) { $oneToOneMappingArray = array( 'mappedBy' => $associationMapping->mappedByFieldName, 'joinColumns' => $associationMapping->joinColumns, @@ -121,16 +122,16 @@ class YamlExporter extends AbstractExporter ); $associationMappingArray = array_merge($associationMappingArray, $oneToOneMappingArray); - } else if ($associationMapping instanceof OneToManyMapping) { + } else if ($associationMapping instanceof \Doctrine\ORM\Mapping\OneToManyMapping) { $oneToManyMappingArray = array( 'mappedBy' => $associationMapping->mappedByFieldName, 'orphanRemoval' => $associationMapping->orphanRemoval, ); $associationMappingArray = array_merge($associationMappingArray, $oneToManyMappingArray); - } else if ($associationMapping instanceof ManyToManyMapping) { - // TODO: We may need to re-include the quotes if quote = true in name of joinTable + } else if ($associationMapping instanceof \Doctrine\ORM\Mapping\ManyToManyMapping) { $manyToManyMappingArray = array( + 'mappedBy' => $associationMapping->mappedByFieldName, 'joinTable' => $associationMapping->joinTable, ); diff --git a/lib/Doctrine/ORM/Tools/Export/Driver/annotation.tpl.php b/lib/Doctrine/ORM/Tools/Export/Driver/annotation.tpl.php new file mode 100644 index 000000000..4c2908aea --- /dev/null +++ b/lib/Doctrine/ORM/Tools/Export/Driver/annotation.tpl.php @@ -0,0 +1,26 @@ +[?php + +namespace namespace ?>; + +/** +isMappedSuperclass): ?> + * @MappedSuperclass + + * @Entity + + * _getTableAnnotation($metadata)."\n" ?> + */ +class getReflectionClass()->getShortName()."\n" ?> +{ +fieldMappings as $fieldMapping): ?> +_getFieldMappingAnnotation($fieldMapping, $metadata)."\n" ?> + private $; + + +associationMappings as $associationMapping): ?> +_getAssociationMappingAnnotation($associationMapping, $metadata)."\n" ?> + private $sourceFieldName ?>; + + + +} \ No newline at end of file