From 165abc3ca4492ff3c9fd2934f6e848a82a43348c Mon Sep 17 00:00:00 2001 From: jwage Date: Wed, 7 Oct 2009 04:07:23 +0000 Subject: [PATCH] [2.0] Work on mapping drivers, exporter drivers and reverse engineering of database schemas --- lib/Doctrine/Common/Util/Inflector.php | 195 +----------------- lib/Doctrine/DBAL/Types/Type.php | 6 + .../ORM/Mapping/Driver/DatabaseDriver.php | 158 ++++++++++++++ .../ORM/Mapping/Driver/YamlDriver.php | 26 ++- .../Tools/Cli/Tasks/ConvertMappingTask.php | 82 ++++++-- .../ORM/Tools/Cli/Tasks/SchemaToolTask.php | 44 ++-- .../Tools/Export/ClassMetadataExporter.php | 61 +++--- .../Export/Driver/AnnotationExporter.php | 8 +- .../ORM/Tools/Export/Driver/XmlExporter.php | 54 ++++- .../ORM/Tools/Export/Driver/YamlExporter.php | 59 ++++-- .../ORM/Tools/ConvertDoctrine1SchemaTest.php | 18 +- .../Export/ClassMetadataExporterTest.php | 60 +++--- tools/sandbox/Entities/User.php | 4 +- tools/sandbox/cli-config.php | 6 +- 14 files changed, 452 insertions(+), 329 deletions(-) create mode 100644 lib/Doctrine/ORM/Mapping/Driver/DatabaseDriver.php diff --git a/lib/Doctrine/Common/Util/Inflector.php b/lib/Doctrine/Common/Util/Inflector.php index c0bbe5590..b62059cf8 100644 --- a/lib/Doctrine/Common/Util/Inflector.php +++ b/lib/Doctrine/Common/Util/Inflector.php @@ -72,198 +72,13 @@ class Inflector } /** - * Check if a string has utf7 characters in it + * Camelize a word. This uses the classify() method and turns the first character to lowercase * - * By bmorel at ssi dot fr - * - * @param string $string - * @return boolean $bool + * @param string $word + * @return string $word */ - public static function seemsUtf8($string) + public static function camelize($word) { - for ($i = 0; $i < strlen($string); $i++) { - if (ord($string[$i]) < 0x80) continue; # 0bbbbbbb - elseif ((ord($string[$i]) & 0xE0) == 0xC0) $n=1; # 110bbbbb - elseif ((ord($string[$i]) & 0xF0) == 0xE0) $n=2; # 1110bbbb - elseif ((ord($string[$i]) & 0xF8) == 0xF0) $n=3; # 11110bbb - elseif ((ord($string[$i]) & 0xFC) == 0xF8) $n=4; # 111110bb - elseif ((ord($string[$i]) & 0xFE) == 0xFC) $n=5; # 1111110b - else return false; # Does not match any model - for ($j=0; $j<$n; $j++) { # n bytes matching 10bbbbbb follow ? - if ((++$i == strlen($string)) || ((ord($string[$i]) & 0xC0) != 0x80)) - return false; - } - } - return true; - } - - /** - * Remove any illegal characters, accents, etc. - * - * @param string $string String to unaccent - * @return string $string Unaccented string - */ - public static function unaccent($string) - { - if ( ! preg_match('/[\x80-\xff]/', $string) ) { - return $string; - } - - if (self::seemsUtf8($string)) { - $chars = array( - // Decompositions for Latin-1 Supplement - chr(195).chr(128) => 'A', chr(195).chr(129) => 'A', - chr(195).chr(130) => 'A', chr(195).chr(131) => 'A', - chr(195).chr(132) => 'A', chr(195).chr(133) => 'A', - chr(195).chr(135) => 'C', chr(195).chr(136) => 'E', - chr(195).chr(137) => 'E', chr(195).chr(138) => 'E', - chr(195).chr(139) => 'E', chr(195).chr(140) => 'I', - chr(195).chr(141) => 'I', chr(195).chr(142) => 'I', - chr(195).chr(143) => 'I', chr(195).chr(145) => 'N', - chr(195).chr(146) => 'O', chr(195).chr(147) => 'O', - chr(195).chr(148) => 'O', chr(195).chr(149) => 'O', - chr(195).chr(150) => 'O', chr(195).chr(153) => 'U', - chr(195).chr(154) => 'U', chr(195).chr(155) => 'U', - chr(195).chr(156) => 'U', chr(195).chr(157) => 'Y', - chr(195).chr(159) => 's', chr(195).chr(160) => 'a', - chr(195).chr(161) => 'a', chr(195).chr(162) => 'a', - chr(195).chr(163) => 'a', chr(195).chr(164) => 'a', - chr(195).chr(165) => 'a', chr(195).chr(167) => 'c', - chr(195).chr(168) => 'e', chr(195).chr(169) => 'e', - chr(195).chr(170) => 'e', chr(195).chr(171) => 'e', - chr(195).chr(172) => 'i', chr(195).chr(173) => 'i', - chr(195).chr(174) => 'i', chr(195).chr(175) => 'i', - chr(195).chr(177) => 'n', chr(195).chr(178) => 'o', - chr(195).chr(179) => 'o', chr(195).chr(180) => 'o', - chr(195).chr(181) => 'o', chr(195).chr(182) => 'o', - chr(195).chr(182) => 'o', chr(195).chr(185) => 'u', - chr(195).chr(186) => 'u', chr(195).chr(187) => 'u', - chr(195).chr(188) => 'u', chr(195).chr(189) => 'y', - chr(195).chr(191) => 'y', - // Decompositions for Latin Extended-A - chr(196).chr(128) => 'A', chr(196).chr(129) => 'a', - chr(196).chr(130) => 'A', chr(196).chr(131) => 'a', - chr(196).chr(132) => 'A', chr(196).chr(133) => 'a', - chr(196).chr(134) => 'C', chr(196).chr(135) => 'c', - chr(196).chr(136) => 'C', chr(196).chr(137) => 'c', - chr(196).chr(138) => 'C', chr(196).chr(139) => 'c', - chr(196).chr(140) => 'C', chr(196).chr(141) => 'c', - chr(196).chr(142) => 'D', chr(196).chr(143) => 'd', - chr(196).chr(144) => 'D', chr(196).chr(145) => 'd', - chr(196).chr(146) => 'E', chr(196).chr(147) => 'e', - chr(196).chr(148) => 'E', chr(196).chr(149) => 'e', - chr(196).chr(150) => 'E', chr(196).chr(151) => 'e', - chr(196).chr(152) => 'E', chr(196).chr(153) => 'e', - chr(196).chr(154) => 'E', chr(196).chr(155) => 'e', - chr(196).chr(156) => 'G', chr(196).chr(157) => 'g', - chr(196).chr(158) => 'G', chr(196).chr(159) => 'g', - chr(196).chr(160) => 'G', chr(196).chr(161) => 'g', - chr(196).chr(162) => 'G', chr(196).chr(163) => 'g', - chr(196).chr(164) => 'H', chr(196).chr(165) => 'h', - chr(196).chr(166) => 'H', chr(196).chr(167) => 'h', - chr(196).chr(168) => 'I', chr(196).chr(169) => 'i', - chr(196).chr(170) => 'I', chr(196).chr(171) => 'i', - chr(196).chr(172) => 'I', chr(196).chr(173) => 'i', - chr(196).chr(174) => 'I', chr(196).chr(175) => 'i', - chr(196).chr(176) => 'I', chr(196).chr(177) => 'i', - chr(196).chr(178) => 'IJ',chr(196).chr(179) => 'ij', - chr(196).chr(180) => 'J', chr(196).chr(181) => 'j', - chr(196).chr(182) => 'K', chr(196).chr(183) => 'k', - chr(196).chr(184) => 'k', chr(196).chr(185) => 'L', - chr(196).chr(186) => 'l', chr(196).chr(187) => 'L', - chr(196).chr(188) => 'l', chr(196).chr(189) => 'L', - chr(196).chr(190) => 'l', chr(196).chr(191) => 'L', - chr(197).chr(128) => 'l', chr(197).chr(129) => 'L', - chr(197).chr(130) => 'l', chr(197).chr(131) => 'N', - chr(197).chr(132) => 'n', chr(197).chr(133) => 'N', - chr(197).chr(134) => 'n', chr(197).chr(135) => 'N', - chr(197).chr(136) => 'n', chr(197).chr(137) => 'N', - chr(197).chr(138) => 'n', chr(197).chr(139) => 'N', - chr(197).chr(140) => 'O', chr(197).chr(141) => 'o', - chr(197).chr(142) => 'O', chr(197).chr(143) => 'o', - chr(197).chr(144) => 'O', chr(197).chr(145) => 'o', - chr(197).chr(146) => 'OE',chr(197).chr(147) => 'oe', - chr(197).chr(148) => 'R', chr(197).chr(149) => 'r', - chr(197).chr(150) => 'R', chr(197).chr(151) => 'r', - chr(197).chr(152) => 'R', chr(197).chr(153) => 'r', - chr(197).chr(154) => 'S', chr(197).chr(155) => 's', - chr(197).chr(156) => 'S', chr(197).chr(157) => 's', - chr(197).chr(158) => 'S', chr(197).chr(159) => 's', - chr(197).chr(160) => 'S', chr(197).chr(161) => 's', - chr(197).chr(162) => 'T', chr(197).chr(163) => 't', - chr(197).chr(164) => 'T', chr(197).chr(165) => 't', - chr(197).chr(166) => 'T', chr(197).chr(167) => 't', - chr(197).chr(168) => 'U', chr(197).chr(169) => 'u', - chr(197).chr(170) => 'U', chr(197).chr(171) => 'u', - chr(197).chr(172) => 'U', chr(197).chr(173) => 'u', - chr(197).chr(174) => 'U', chr(197).chr(175) => 'u', - chr(197).chr(176) => 'U', chr(197).chr(177) => 'u', - chr(197).chr(178) => 'U', chr(197).chr(179) => 'u', - chr(197).chr(180) => 'W', chr(197).chr(181) => 'w', - chr(197).chr(182) => 'Y', chr(197).chr(183) => 'y', - chr(197).chr(184) => 'Y', chr(197).chr(185) => 'Z', - chr(197).chr(186) => 'z', chr(197).chr(187) => 'Z', - chr(197).chr(188) => 'z', chr(197).chr(189) => 'Z', - chr(197).chr(190) => 'z', chr(197).chr(191) => 's', - // Euro Sign - chr(226).chr(130).chr(172) => 'E', - // GBP (Pound) Sign - chr(194).chr(163) => '', - 'Ä' => 'Ae', 'ä' => 'ae', 'Ü' => 'Ue', 'ü' => 'ue', - 'Ö' => 'Oe', 'ö' => 'oe', 'ß' => 'ss'); - - $string = strtr($string, $chars); - } else { - // Assume ISO-8859-1 if not UTF-8 - $chars['in'] = chr(128).chr(131).chr(138).chr(142).chr(154).chr(158) - .chr(159).chr(162).chr(165).chr(181).chr(192).chr(193).chr(194) - .chr(195).chr(196).chr(197).chr(199).chr(200).chr(201).chr(202) - .chr(203).chr(204).chr(205).chr(206).chr(207).chr(209).chr(210) - .chr(211).chr(212).chr(213).chr(214).chr(216).chr(217).chr(218) - .chr(219).chr(220).chr(221).chr(224).chr(225).chr(226).chr(227) - .chr(228).chr(229).chr(231).chr(232).chr(233).chr(234).chr(235) - .chr(236).chr(237).chr(238).chr(239).chr(241).chr(242).chr(243) - .chr(244).chr(245).chr(246).chr(248).chr(249).chr(250).chr(251) - .chr(252).chr(253).chr(255); - - $chars['out'] = "EfSZszYcYuAAAAAACEEEEIIIINOOOOOOUUUUYaaaaaaceeeeiiiinoooooouuuuyy"; - - $string = strtr($string, $chars['in'], $chars['out']); - $doubleChars['in'] = array(chr(140), chr(156), chr(198), chr(208), chr(222), chr(223), chr(230), chr(240), chr(254)); - $doubleChars['out'] = array('OE', 'oe', 'AE', 'DH', 'TH', 'ss', 'ae', 'dh', 'th'); - $string = str_replace($doubleChars['in'], $doubleChars['out'], $string); - } - - return $string; - } - - /** - * Convert any passed string to a url friendly string. Converts 'My first blog post' to 'my-first-blog-post' - * - * @param string $text Text to urlize - * @return string $text Urlized text - */ - public static function urlize($text) - { - // Remove all non url friendly characters with the unaccent function - $text = self::unaccent($text); - - if (function_exists('mb_strtolower')) - { - $text = mb_strtolower($text); - } else { - $text = strtolower($text); - } - - // Remove all none word characters - $text = preg_replace('/\W/', ' ', $text); - - // More stripping. Replace spaces with dashes - $text = strtolower(preg_replace('/[^A-Z^a-z^0-9^\/]+/', '-', - preg_replace('/([a-z\d])([A-Z])/', '\1_\2', - preg_replace('/([A-Z]+)([A-Z][a-z])/', '\1_\2', - preg_replace('/::/', '/', $text))))); - - return trim($text, '-'); + return lcfirst(self::classify($word)); } } \ No newline at end of file diff --git a/lib/Doctrine/DBAL/Types/Type.php b/lib/Doctrine/DBAL/Types/Type.php index da3fe9ccf..4c5eac92a 100644 --- a/lib/Doctrine/DBAL/Types/Type.php +++ b/lib/Doctrine/DBAL/Types/Type.php @@ -177,4 +177,10 @@ abstract class Type self::$_typesMap[$name] = $className; } + + public function __toString() + { + $e = explode('\\', get_class($this)); + return str_replace('Type', '', end($e)); + } } \ No newline at end of file diff --git a/lib/Doctrine/ORM/Mapping/Driver/DatabaseDriver.php b/lib/Doctrine/ORM/Mapping/Driver/DatabaseDriver.php new file mode 100644 index 000000000..5d47a9ee1 --- /dev/null +++ b/lib/Doctrine/ORM/Mapping/Driver/DatabaseDriver.php @@ -0,0 +1,158 @@ +. + */ + +namespace Doctrine\ORM\Mapping\Driver; + +use Doctrine\Common\DoctrineException, + Doctrine\Common\Cache\ArrayCache, + Doctrine\Common\Annotations\AnnotationReader, + Doctrine\DBAL\Schema\AbstractSchemaManager, + Doctrine\ORM\Mapping\ClassMetadataInfo, + Doctrine\ORM\Mapping\MappingException, + Doctrine\Common\Util\Inflector; + +/** + * The DatabaseDriver reverse engineers the mapping metadata from a database + * + * @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 DatabaseDriver implements Driver +{ + /** The SchemaManager. */ + private $_sm; + + /** + * Initializes a new AnnotationDriver that uses the given AnnotationReader for reading + * docblock annotations. + * + * @param AnnotationReader $reader The AnnotationReader to use. + */ + public function __construct(AbstractSchemaManager $schemaManager) + { + $this->_sm = $schemaManager; + } + + /** + * {@inheritdoc} + */ + public function loadMetadataForClass($className, ClassMetadataInfo $metadata) + { + $tableName = $className; + $className = Inflector::classify($tableName); + + $metadata->name = $className; + $metadata->primaryTable['name'] = $tableName; + + $columns = $this->_sm->listTableColumns($tableName); + $foreignKeys = $this->_sm->listTableForeignKeys($tableName); + + $ids = array(); + $fieldMappings = array(); + foreach ($columns as $column) { + // Skip columns that are foreign keys + foreach ($foreignKeys as $foreignKey) { + if ($column['name'] == $foreignKey['local']) { + continue(2); + } + } + + $fieldMapping = array(); + if ($column['primary']) { + $fieldMapping['id'] = true; + } + + $fieldMapping['fieldName'] = Inflector::camelize($column['name']); + $fieldMapping['columnName'] = $column['name']; + $fieldMapping['type'] = strtolower((string) $column['type']); + $fieldMapping['length'] = $column['length']; + $fieldMapping['unsigned'] = $column['unsigned']; + $fieldMapping['fixed'] = $column['fixed']; + $fieldMapping['notnull'] = $column['notnull']; + $fieldMapping['default'] = $column['default']; + + if (isset($fieldMapping['id'])) { + $ids[] = $fieldMapping; + } else { + $fieldMappings[] = $fieldMapping; + } + } + + if ($ids) { + $metadata->setIdGeneratorType(ClassMetadataInfo::GENERATOR_TYPE_AUTO); + + foreach ($ids as $id) { + $metadata->mapField($id); + } + } + + foreach ($fieldMappings as $fieldMapping) { + $metadata->mapField($fieldMapping); + } + + foreach ($foreignKeys as $foreignKey) { + $associationMapping = array(); + $associationMapping['fieldName'] = Inflector::camelize(str_replace('_id', '', $foreignKey['local'])); + $associationMapping['columnName'] = $foreignKey['local']; + $associationMapping['targetEntity'] = Inflector::classify($foreignKey['table']); + $associationMapping['joinColumns'][] = array( + 'name' => $foreignKey['local'], + 'referencedColumnName' => $foreignKey['foreign'] + ); + + $metadata->mapManyToOne($associationMapping); + } + } + + /** + * Whether the class with the specified name should have its metadata loaded. + * This is only the case if it is either mapped as an Entity or a + * MappedSuperclass. + * + * @param string $className + * @return boolean + */ + public function isTransient($className) + { + return true; + } + + /** + * Preloads all mapping information found in any documents within the + * configured paths and returns a list of class names that have been preloaded. + * + * @return array The list of class names that have been preloaded. + */ + public function preload() + { + $tables = array(); + foreach ($this->_sm->listTables() as $table) { + $tables[] = $table; + } + + return $tables; + } +} \ No newline at end of file diff --git a/lib/Doctrine/ORM/Mapping/Driver/YamlDriver.php b/lib/Doctrine/ORM/Mapping/Driver/YamlDriver.php index 00db64940..8bce76fad 100644 --- a/lib/Doctrine/ORM/Mapping/Driver/YamlDriver.php +++ b/lib/Doctrine/ORM/Mapping/Driver/YamlDriver.php @@ -149,39 +149,49 @@ class YamlDriver extends AbstractFileDriver // Evaluate fields if (isset($element['fields'])) { foreach ($element['fields'] as $name => $fieldMapping) { + $e = explode('(', $fieldMapping['type']); + $fieldMapping['type'] = $e[0]; + if (isset($e[1])) { + $fieldMapping['length'] = substr($e[1], 0, strlen($e[1]) - 1); + } $mapping = array( 'fieldName' => $name, 'type' => $fieldMapping['type'] ); - + if (isset($fieldMapping['id'])) { + $mapping['id'] = true; + if (isset($fieldMapping['generator']['strategy'])) { + $metadata->setIdGeneratorType(constant('Doctrine\ORM\Mapping\ClassMetadata::GENERATOR_TYPE_' + . strtoupper($fieldMapping['generator']['strategy']))); + } + } + // Check for SequenceGenerator/TableGenerator definition + if (isset($fieldMapping['sequenceGenerator'])) { + $metadata->setSequenceGeneratorDefinition($fieldMapping['sequenceGenerator']); + } else if (isset($fieldMapping['tableGenerator'])) { + throw DoctrineException::tableIdGeneratorNotImplemented(); + } if (isset($fieldMapping['column'])) { $mapping['columnName'] = $fieldMapping['column']; } - if (isset($fieldMapping['length'])) { $mapping['length'] = $fieldMapping['length']; } - if (isset($fieldMapping['precision'])) { $mapping['precision'] = $fieldMapping['precision']; } - if (isset($fieldMapping['scale'])) { $mapping['scale'] = $fieldMapping['scale']; } - if (isset($fieldMapping['unique'])) { $mapping['unique'] = (bool)$fieldMapping['unique']; } - if (isset($fieldMapping['options'])) { $mapping['options'] = $fieldMapping['options']; } - if (isset($fieldMapping['notnull'])) { $mapping['notnull'] = $fieldMapping['notnull']; } - if (isset($fieldMapping['version']) && $fieldMapping['version']) { $metadata->setVersionMapping($mapping); } diff --git a/lib/Doctrine/ORM/Tools/Cli/Tasks/ConvertMappingTask.php b/lib/Doctrine/ORM/Tools/Cli/Tasks/ConvertMappingTask.php index f51bff28b..55111b850 100644 --- a/lib/Doctrine/ORM/Tools/Cli/Tasks/ConvertMappingTask.php +++ b/lib/Doctrine/ORM/Tools/Cli/Tasks/ConvertMappingTask.php @@ -101,6 +101,10 @@ class ConvertMappingTask extends AbstractTask $printer->writeln('You can only use the --extend argument when converting to annoations.'); return false; } + if ($args['from'][0] == 'database') { + $config = $this->_em->getConfiguration(); + $config->setMetadataDriverImpl(new \Doctrine\ORM\Mapping\Driver\DatabaseDriver($this->_em->getConnection()->getSchemaManager())); + } return true; } @@ -127,47 +131,83 @@ class ConvertMappingTask extends AbstractTask $printer->writeln('Converting Doctrine 1 schema to Doctrine 2 mapping files', 'INFO'); $converter = new \Doctrine\ORM\Tools\ConvertDoctrine1Schema($from); - $exporter->setMetadatas($converter->getMetadatasFromSchema()); + $metadatas = $converter->getMetadatasFromSchema(); } else { - foreach ($from as $path) { - $type = $this->_determinePathType($path); + foreach ($from as $source) { + $sourceArg = $source; - $printer->writeln(sprintf('Adding %s mapping directory: "%s"', $type, $path), 'INFO'); + $type = $this->_determineSourceType($sourceArg); + $source = $this->_getSourceByType($type, $sourceArg); - $cme->addMappingDir($path, $type); + $printer->writeln(sprintf('Adding "%s" mapping source', $sourceArg), 'INFO'); + + $cme->addMappingSource($source, $type); } - $exporter->setMetadatas($cme->getMetadatasForMappingDirectories()); + $metadatas = $cme->getMetadatasForMappingSources(); } - $printer->writeln(sprintf('Exporting %s mapping information to directory: "%s"', $args['to'], $args['dest']), 'INFO'); + foreach ($metadatas as $metadata) { + $printer->write('Processing entity "') + ->write($metadata->name, 'KEYWORD')->writeln('"'); + } + + $printer->writeln(sprintf('Exporting %s mapping information to directory "%s"', $args['to'], $args['dest']), 'INFO'); + + $exporter->setMetadatas($metadatas); $exporter->export(); } private function _isDoctrine1Schema(array $from) { - $files = glob($from[0] . '/*.yml'); + $files = glob(current($from) . '/*.yml'); if ($files) { $array = \sfYaml::load($files[0]); $first = current($array); + // We're dealing with a Doctrine 1 schema if you have + // a columns index in the first model array return isset($first['columns']); } else { return false; } } - private function _determinePathType($path) + private function _determineSourceType($source) { - $files = glob($path . '/*.*'); - if (!$files) - { - throw new \InvalidArgumentException(sprintf('No schema mapping files found in "%s"', $path)); - } - $contents = file_get_contents($files[0]); - if (preg_match("/class (.*)/", $contents)) { - return 'annotation'; - } else { - $info = pathinfo($files[0]); - return $info['extension']; - } + // If the --from= is a directory lets determine if it is + // annotations, yaml, xml, etc. + if (is_dir($source)) { + // Find the files in the directory + $files = glob($source . '/*.*'); + if ( ! $files) { + throw new \InvalidArgumentException(sprintf('No mapping files found in "%s"', $source)); + } + + // Get the contents of the first file + $contents = file_get_contents($files[0]); + + // Check if it has a class definition in it for annotations + if (preg_match("/class (.*)/", $contents)) { + return 'annotation'; + // Otherwise lets determine the type based on the extension of the + // first file in the directory (yml, xml, etc) + } else { + $info = pathinfo($files[0]); + return $info['extension']; + } + // Nothing special for database + } else if ($source == 'database') { + return 'database'; + } + } + + private function _getSourceByType($type, $source) + { + // If --from==database then the source is an instance of SchemaManager + // for the current EntityMAnager + if ($type == 'database') { + return $this->_em->getConnection()->getSchemaManager(); + } else { + return $source; + } } } \ No newline at end of file diff --git a/lib/Doctrine/ORM/Tools/Cli/Tasks/SchemaToolTask.php b/lib/Doctrine/ORM/Tools/Cli/Tasks/SchemaToolTask.php index 8f6929ecb..e81c7c46f 100644 --- a/lib/Doctrine/ORM/Tools/Cli/Tasks/SchemaToolTask.php +++ b/lib/Doctrine/ORM/Tools/Cli/Tasks/SchemaToolTask.php @@ -110,8 +110,8 @@ class SchemaToolTask extends AbstractTask $isDrop = isset($args['drop']); $isUpdate = isset($args['update']); - if ( ! ($isCreate ^ $isDrop ^ $isUpdate)) { - $printer->writeln("One of --create, --drop or --update required, and only one.", 'ERROR'); + if ($isUpdate && ($isCreate || $isDrop)) { + $printer->writeln("You can't use --update with --create or --drop", 'ERROR'); return false; } @@ -174,7 +174,24 @@ class SchemaToolTask extends AbstractTask $printer->writeln('No classes to process.', 'INFO'); return; } - + + if ($isDrop) { + if (isset($args['dump-sql'])) { + foreach ($tool->getDropSchemaSql($classes) as $sql) { + $printer->writeln($sql); + } + } else { + $printer->writeln('Dropping database schema...', 'INFO'); + + try { + $tool->dropSchema($classes); + $printer->writeln('Database schema dropped successfully.', 'INFO'); + } catch (\Exception $ex) { + throw new DoctrineException($ex); + } + } + } + if ($isCreate) { if (isset($args['dump-sql'])) { foreach ($tool->getCreateSchemaSql($classes) as $sql) { @@ -190,24 +207,9 @@ class SchemaToolTask extends AbstractTask throw new DoctrineException($ex); } } - } else if ($isDrop) { - if (isset($args['dump-sql'])) { - foreach ($tool->getDropSchemaSql($classes) as $sql) { - $printer->writeln($sql); - } - } else { - $printer->writeln('Dropping database schema...', 'INFO'); - - try { - $tool->dropSchema($classes); - $printer->writeln('Database schema dropped successfully.', 'INFO'); - } catch (\Exception $ex) { - throw new DoctrineException($ex); - } - } - } else if ($isUpdate) { - $printer->writeln("--update support is not yet fully implemented.", 'ERROR'); - + } + + if ($isUpdate) { if (isset($args['dump-sql'])) { foreach ($tool->getUpdateSchemaSql($classes) as $sql) { $printer->writeln($sql); diff --git a/lib/Doctrine/ORM/Tools/Export/ClassMetadataExporter.php b/lib/Doctrine/ORM/Tools/Export/ClassMetadataExporter.php index 41f5725f7..48190e6e0 100644 --- a/lib/Doctrine/ORM/Tools/Export/ClassMetadataExporter.php +++ b/lib/Doctrine/ORM/Tools/Export/ClassMetadataExporter.php @@ -35,14 +35,14 @@ use Doctrine\ORM\Mapping\ClassMetadata; * // and convert it to a single set of yaml files. * * $cme = new Doctrine\ORM\Tools\Export\ClassMetadataExporter(); - * $cme->addMappingDirectory(__DIR__ . '/Entities', 'php'); - * $cme->addMappingDirectory(__DIR__ . '/xml', 'xml'); - * $cme->addMappingDirectory(__DIR__ . '/yaml', 'yaml'); + * $cme->addMappingSource(__DIR__ . '/Entities', 'php'); + * $cme->addMappingSource(__DIR__ . '/xml', 'xml'); + * $cme->addMappingSource(__DIR__ . '/yaml', 'yaml'); * * $exporter = $cme->getExporter('yaml'); * $exporter->setOutputDir(__DIR__ . '/new_yaml'); * - * $exporter->setMetadatas($cme->getMetadatasForMappingDirectories()); + * $exporter->setMetadatas($cme->getMetadatasForMappingSources()); * $exporter->export(); * * @license http://www.opensource.org/licenses/lgpl-license.php LGPL @@ -65,10 +65,11 @@ class ClassMetadataExporter 'annotation' => 'Doctrine\ORM\Mapping\Driver\AnnotationDriver', 'yaml' => 'Doctrine\ORM\Mapping\Driver\YamlDriver', 'yml' => 'Doctrine\ORM\Mapping\Driver\YamlDriver', - 'xml' => 'Doctrine\ORM\Mapping\Driver\XmlDriver' + 'xml' => 'Doctrine\ORM\Mapping\Driver\XmlDriver', + 'database' => 'Doctrine\ORM\Mapping\Driver\DatabaseDriver' ); - private $_mappingDirectories = array(); + private $_mappingSources = array(); /** * Add a new mapping directory to the array of directories to convert and export @@ -76,23 +77,24 @@ class ClassMetadataExporter * * [php] * $cme = new Doctrine\ORM\Tools\Export\ClassMetadataExporter(); - * $cme->addMappingDirectory(__DIR__ . '/yaml', 'yaml'); + * $cme->addMappingSource(__DIR__ . '/yaml', 'yaml'); + * $cme->addMappingSource($schemaManager, 'database'); * - * @param string $dir The path to the mapping files + * @param string $source The source for the mapping * @param string $type The type of mapping files (yml, xml, etc.) * @return void */ - public function addMappingDirectory($dir, $type) + public function addMappingSource($source, $type) { if ($type === 'php') { - $this->_mappingDirectories[] = array($dir, $type); + $this->_mappingSources[] = array($source, $type); } else { if ( ! isset($this->_mappingDrivers[$type])) { throw DoctrineException::invalidMappingDriverType($type); } - $driver = $this->getMappingDriver($type, $dir); - $this->_mappingDirectories[] = array($dir, $driver); + $driver = $this->getMappingDriver($type, $source); + $this->_mappingSources[] = array($source, $driver); } } @@ -100,24 +102,26 @@ class ClassMetadataExporter * Get an instance of a mapping driver * * @param string $type The type of mapping driver (yaml, xml, annotation, etc.) - * @param string $dir The directory to configure the driver to look in. Only required for file drivers (yml, xml). + * @param string $source The source for the driver * @return AbstractDriver $driver */ - public function getMappingDriver($type, $dir = null) + public function getMappingDriver($type, $source = null) { if ( ! isset($this->_mappingDrivers[$type])) { return false; } $class = $this->_mappingDrivers[$type]; if (is_subclass_of($class, 'Doctrine\ORM\Mapping\Driver\AbstractFileDriver')) { - if (is_null($dir)) { + if (is_null($source)) { throw DoctrineException::fileMappingDriversRequireDirectoryPath(); } - $driver = new $class($dir, constant($class . '::PRELOAD')); - } else { + $driver = new $class($source, constant($class . '::PRELOAD')); + } else if ($class == 'Doctrine\ORM\Mapping\Driver\AnnotationDriver') { $reader = new \Doctrine\Common\Annotations\AnnotationReader(new \Doctrine\Common\Cache\ArrayCache); $reader->setDefaultAnnotationNamespace('Doctrine\ORM\Mapping\\'); - $driver = new $class($reader); + $driver = new \Doctrine\ORM\Mapping\Driver\AnnotationDriver($reader); + } else if ($class == 'Doctrine\ORM\Mapping\Driver\DatabaseDriver') { + $driver = new \Doctrine\ORM\Mapping\Driver\DatabaseDriver($source); } return $driver; } @@ -127,9 +131,9 @@ class ClassMetadataExporter * * @return array $mappingDirectories */ - public function getMappingDirectories() + public function getMappingSources() { - return $this->_mappingDirectories; + return $this->_mappingSources; } /** @@ -139,14 +143,14 @@ class ClassMetadataExporter * * @return array $classes */ - public function getMetadatasForMappingDirectories() + public function getMetadatasForMappingSources() { $classes = array(); - foreach ($this->_mappingDirectories as $d) { - list($dir, $driver) = $d; + foreach ($this->_mappingSources as $d) { + list($source, $driver) = $d; if ($driver == 'php') { - $iter = new \RecursiveIteratorIterator(new \RecursiveDirectoryIterator($dir), + $iter = new \RecursiveIteratorIterator(new \RecursiveDirectoryIterator($source), \RecursiveIteratorIterator::LEAVES_ONLY); foreach ($iter as $item) { @@ -164,7 +168,7 @@ class ClassMetadataExporter } } else { if ($driver instanceof \Doctrine\ORM\Mapping\Driver\AnnotationDriver) { - $iter = new \RecursiveIteratorIterator(new \RecursiveDirectoryIterator($dir), + $iter = new \RecursiveIteratorIterator(new \RecursiveDirectoryIterator($source), \RecursiveIteratorIterator::LEAVES_ONLY); $declared = get_declared_classes(); @@ -200,7 +204,6 @@ class ClassMetadataExporter unset($classes[$key]); } } - $classes = array_values($classes); return $classes; } @@ -208,16 +211,16 @@ class ClassMetadataExporter * Get a exporter driver instance * * @param string $type The type to get (yml, xml, etc.) - * @param string $dir The directory where the exporter will export to + * @param string $source The directory where the exporter will export to * @return AbstractExporter $exporter */ - public function getExporter($type, $dir = null) + public function getExporter($type, $source = null) { if ( ! isset($this->_exporterDrivers[$type])) { throw DoctrineException::invalidExporterDriverType($type); } $class = $this->_exporterDrivers[$type]; - return new $class($dir); + return new $class($source); } } \ No newline at end of file diff --git a/lib/Doctrine/ORM/Tools/Export/Driver/AnnotationExporter.php b/lib/Doctrine/ORM/Tools/Export/Driver/AnnotationExporter.php index 45c6afb75..a5465277b 100644 --- a/lib/Doctrine/ORM/Tools/Export/Driver/AnnotationExporter.php +++ b/lib/Doctrine/ORM/Tools/Export/Driver/AnnotationExporter.php @@ -250,7 +250,10 @@ class AnnotationExporter extends AbstractExporter $methods = array(); foreach ($metadata->fieldMappings as $fieldMapping) { - $this->_addMethod('set', $fieldMapping['fieldName'], $metadata, $methods); + if ( ! isset($fieldMapping['id']) || ! $fieldMapping['id']) { + $this->_addMethod('set', $fieldMapping['fieldName'], $metadata, $methods); + } + $this->_addMethod('get', $fieldMapping['fieldName'], $metadata, $methods); } @@ -302,6 +305,9 @@ class AnnotationExporter extends AbstractExporter $lines[] = str_repeat(' ', $this->_numSpaces) . '/**'; $column = array(); + if (isset($fieldMapping['columnName'])) { + $column[] = 'name="' . $fieldMapping['columnName'] . '"'; + } if (isset($fieldMapping['type'])) { $column[] = 'type="' . $fieldMapping['type'] . '"'; } diff --git a/lib/Doctrine/ORM/Tools/Export/Driver/XmlExporter.php b/lib/Doctrine/ORM/Tools/Export/Driver/XmlExporter.php index c2cf334c5..29464a4f8 100644 --- a/lib/Doctrine/ORM/Tools/Export/Driver/XmlExporter.php +++ b/lib/Doctrine/ORM/Tools/Export/Driver/XmlExporter.php @@ -145,11 +145,14 @@ class XmlExporter extends AbstractExporter if (isset($field['scale'])) { $fieldXml->addAttribute('scale', $field['scale']); } - if (isset($field['unique'])) { + if (isset($field['unique']) && $field['unique']) { $fieldXml->addAttribute('unique', $field['unique']); } if (isset($field['options'])) { - $fieldXml->addAttribute('options', $field['options']); + $optionsXml = $fieldXml->addChild('options'); + foreach ($field['options'] as $key => $value) { + $optionsXml->addAttribute($key, $value); + } } if (isset($field['version'])) { $fieldXml->addAttribute('version', $field['version']); @@ -225,6 +228,51 @@ class XmlExporter extends AbstractExporter } } - return $xml->asXml(); + return $this->_asXml($xml); + } + + /** + * Code originally taken from + * http://recurser.com/articles/2007/04/05/format-xml-with-php/ + * + * @param string $simpleXml + * @return string $xml + */ + private function _asXml($simpleXml) + { + $xml = $simpleXml->asXml(); + + // add marker linefeeds to aid the pretty-tokeniser (adds a linefeed between all tag-end boundaries) + $xml = preg_replace('/(>)(<)(\/*)/', "$1\n$2$3", $xml); + + // now indent the tags + $token = strtok($xml, "\n"); + $result = ''; // holds formatted version as it is built + $pad = 0; // initial indent + $matches = array(); // returns from preg_matches() + + // test for the various tag states + while ($token !== false) { + // 1. open and closing tags on same line - no change + if (preg_match('/.+<\/\w[^>]*>$/', $token, $matches)) { + $indent = 0; + // 2. closing tag - outdent now + } else if (preg_match('/^<\/\w/', $token, $matches)) { + $pad = $pad - 4; + // 3. opening tag - don't pad this one, only subsequent tags + } elseif (preg_match('/^<\w[^>]*[^\/]>.*$/', $token, $matches)) { + $indent = 4; + // 4. no indentation needed + } else { + $indent = 0; + } + + // pad the line with the required number of leading spaces + $line = str_pad($token, strlen($token)+$pad, ' ', STR_PAD_LEFT); + $result .= $line . "\n"; // add to the cumulative result, with linefeed + $token = strtok("\n"); // get the next token + $pad += $indent; // update the pad size for subsequent lines + } + return $result; } } \ 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 0d5c1a15d..cf07f8e2f 100644 --- a/lib/Doctrine/ORM/Tools/Export/Driver/YamlExporter.php +++ b/lib/Doctrine/ORM/Tools/Export/Driver/YamlExporter.php @@ -70,7 +70,10 @@ class YamlExporter extends AbstractExporter $array['schema'] = $metadata->primaryTable['schema']; } - $array['inheritanceType'] = $this->_getInheritanceTypeString($metadata->getInheritanceType()); + $inheritanceType = $metadata->getInheritanceType(); + if ($inheritanceType !== ClassMetadataInfo::INHERITANCE_TYPE_NONE) { + $array['inheritanceType'] = $this->_getInheritanceTypeString($inheritanceType); + } if ($column = $metadata->getDiscriminatorColumn()) { $array['discriminatorColumn'] = $column; @@ -80,7 +83,9 @@ class YamlExporter extends AbstractExporter $array['discriminatorMap'] = $map; } - $array['changeTrackingPolicy'] = $this->_getChangeTrackingPolicyString($metadata->changeTrackingPolicy); + if ($metadata->changeTrackingPolicy !== ClassMetadataInfo::CHANGETRACKING_DEFERRED_IMPLICIT) { + $array['changeTrackingPolicy'] = $this->_getChangeTrackingPolicyString($metadata->changeTrackingPolicy); + } if (isset($metadata->primaryTable['indexes'])) { $array['indexes'] = $metadata->primaryTable['indexes']; @@ -92,27 +97,48 @@ class YamlExporter extends AbstractExporter } } - $fields = $metadata->fieldMappings; + $fieldMappings = $metadata->fieldMappings; - $id = array(); - foreach ($fields as $name => $field) { - if (isset($field['id']) && $field['id']) { - $id[$name] = $field; - unset($fields[$name]); + $ids = array(); + foreach ($fieldMappings as $name => $fieldMapping) { + if (isset($fieldMapping['length'])) { + $fieldMapping['type'] = $fieldMapping['type'] . '(' . $fieldMapping['length'] . ')'; + unset($fieldMapping['length']); } + + unset($fieldMapping['fieldName']); + + if ($fieldMapping['columnName'] == $name) { + unset($fieldMapping['columnName']); + } + + if (isset($fieldMapping['id']) && $fieldMapping['id']) { + $ids[$name] = $fieldMapping; + unset($fieldMappings[$name]); + continue; + } + + $fieldMappings[$name] = $fieldMapping; } if ($idGeneratorType = $this->_getIdGeneratorTypeString($metadata->generatorType)) { - $id[$metadata->getSingleIdentifierFieldName()]['generator']['strategy'] = $this->_getIdGeneratorTypeString($metadata->generatorType); + $ids[$metadata->getSingleIdentifierFieldName()]['generator']['strategy'] = $this->_getIdGeneratorTypeString($metadata->generatorType); } - $array['id'] = $id; - $array['fields'] = $fields; + if ($ids) { + $array['fields'] = $ids; + } + + if ($fieldMappings) { + if ( ! isset($array['fields'])) { + $array['fields'] = array(); + } + $array['fields'] = array_merge($array['fields'], $fieldMappings); + } $associations = array(); foreach ($metadata->associationMappings as $name => $associationMapping) { $associationMappingArray = array( - 'fieldName' => $associationMapping->sourceFieldName, 'targetEntity' => $associationMapping->targetEntityName, 'cascade' => array( 'remove' => $associationMapping->isCascadeRemove, @@ -124,9 +150,14 @@ class YamlExporter extends AbstractExporter ); if ($associationMapping instanceof OneToOneMapping) { + $joinColumns = $associationMapping->joinColumns; + $newJoinColumns = array(); + foreach ($joinColumns as $joinColumn) { + $newJoinColumns[$joinColumn['name']]['referencedColumnName'] = $joinColumn['referencedColumnName']; + } $oneToOneMappingArray = array( 'mappedBy' => $associationMapping->mappedByFieldName, - 'joinColumns' => $associationMapping->joinColumns, + 'joinColumns' => $newJoinColumns, 'orphanRemoval' => $associationMapping->orphanRemoval, ); @@ -137,7 +168,7 @@ class YamlExporter extends AbstractExporter 'mappedBy' => $associationMapping->mappedByFieldName, 'orphanRemoval' => $associationMapping->orphanRemoval, ); - + $associationMappingArray = array_merge($associationMappingArray, $oneToManyMappingArray); $array['oneToMany'][$name] = $associationMappingArray; } else if ($associationMapping instanceof ManyToManyMapping) { diff --git a/tests/Doctrine/Tests/ORM/Tools/ConvertDoctrine1SchemaTest.php b/tests/Doctrine/Tests/ORM/Tools/ConvertDoctrine1SchemaTest.php index 5721e45fe..dc02f8527 100644 --- a/tests/Doctrine/Tests/ORM/Tools/ConvertDoctrine1SchemaTest.php +++ b/tests/Doctrine/Tests/ORM/Tools/ConvertDoctrine1SchemaTest.php @@ -50,19 +50,19 @@ class ConvertDoctrine1SchemaTest extends \Doctrine\Tests\OrmTestCase $this->assertTrue(file_exists(__DIR__ . '/convert/User.dcm.yml')); $this->assertTrue(file_exists(__DIR__ . '/convert/Profile.dcm.yml')); - $cme->addMappingDirectory(__DIR__ . '/convert', 'yml'); - $metadatas = $cme->getMetadatasForMappingDirectories(); + $cme->addMappingSource(__DIR__ . '/convert', 'yml'); + $metadatas = $cme->getMetadatasForMappingSources(); $this->assertEquals(2, count($metadatas)); - $this->assertEquals('Profile', $metadatas[0]->name); - $this->assertEquals('User', $metadatas[1]->name); - $this->assertEquals(4, count($metadatas[0]->fieldMappings)); - $this->assertEquals(3, count($metadatas[1]->fieldMappings)); + $this->assertEquals('Profile', $metadatas['Profile']->name); + $this->assertEquals('User', $metadatas['User']->name); + $this->assertEquals(4, count($metadatas['Profile']->fieldMappings)); + $this->assertEquals(3, count($metadatas['User']->fieldMappings)); - $this->assertEquals('Profile', $metadatas[0]->associationMappings['User']->sourceEntityName); - $this->assertEquals('\User', $metadatas[0]->associationMappings['User']->targetEntityName); + $this->assertEquals('Profile', $metadatas['Profile']->associationMappings['User']->sourceEntityName); + $this->assertEquals('\User', $metadatas['Profile']->associationMappings['User']->targetEntityName); - $this->assertEquals('username', $metadatas[1]->primaryTable['indexes']['username']['columns'][0]); + $this->assertEquals('username', $metadatas['User']->primaryTable['indexes']['username']['columns'][0]); unlink(__DIR__ . '/convert/User.dcm.yml'); unlink(__DIR__ . '/convert/Profile.dcm.yml'); diff --git a/tests/Doctrine/Tests/ORM/Tools/Export/ClassMetadataExporterTest.php b/tests/Doctrine/Tests/ORM/Tools/Export/ClassMetadataExporterTest.php index fe3e3b23a..660b4161d 100644 --- a/tests/Doctrine/Tests/ORM/Tools/Export/ClassMetadataExporterTest.php +++ b/tests/Doctrine/Tests/ORM/Tools/Export/ClassMetadataExporterTest.php @@ -61,25 +61,25 @@ class ClassMetadataExporterTest extends \Doctrine\Tests\OrmTestCase public function testAddMappingDirectory() { $cme = new ClassMetadataExporter(); - $cme->addMappingDirectory(__DIR__ . '/annotation', 'annotation'); - $cme->addMappingDirectory(__DIR__ . '/php', 'php'); - $cme->addMappingDirectory(__DIR__ . '/xml', 'xml'); - $cme->addMappingDirectory(__DIR__ . '/yml', 'yml'); + $cme->addMappingSource(__DIR__ . '/annotation', 'annotation'); + $cme->addMappingSource(__DIR__ . '/php', 'php'); + $cme->addMappingSource(__DIR__ . '/xml', 'xml'); + $cme->addMappingSource(__DIR__ . '/yml', 'yml'); - $mappingDirectories = $cme->getMappingDirectories(); - $this->assertEquals(4, count($mappingDirectories)); + $mappingSources = $cme->getMappingSources(); + $this->assertEquals(4, count($mappingSources)); - $this->assertEquals($mappingDirectories[0][0], __DIR__.'/annotation'); - $this->assertTrue($mappingDirectories[0][1] instanceof \Doctrine\ORM\Mapping\Driver\AnnotationDriver); + $this->assertEquals($mappingSources[0][0], __DIR__.'/annotation'); + $this->assertTrue($mappingSources[0][1] instanceof \Doctrine\ORM\Mapping\Driver\AnnotationDriver); - $this->assertEquals($mappingDirectories[1][0], __DIR__.'/php'); - $this->assertEquals('php', $mappingDirectories[1][1]); + $this->assertEquals($mappingSources[1][0], __DIR__.'/php'); + $this->assertEquals('php', $mappingSources[1][1]); - $this->assertEquals($mappingDirectories[2][0], __DIR__.'/xml'); - $this->assertTrue($mappingDirectories[2][1] instanceof \Doctrine\ORM\Mapping\Driver\XmlDriver); + $this->assertEquals($mappingSources[2][0], __DIR__.'/xml'); + $this->assertTrue($mappingSources[2][1] instanceof \Doctrine\ORM\Mapping\Driver\XmlDriver); - $this->assertEquals($mappingDirectories[3][0], __DIR__.'/yml'); - $this->assertTrue($mappingDirectories[3][1] instanceof \Doctrine\ORM\Mapping\Driver\YamlDriver); + $this->assertEquals($mappingSources[3][0], __DIR__.'/yml'); + $this->assertTrue($mappingSources[3][1] instanceof \Doctrine\ORM\Mapping\Driver\YamlDriver); } /** @@ -89,16 +89,16 @@ class ClassMetadataExporterTest extends \Doctrine\Tests\OrmTestCase public function testGetMetadataInstances() { $cme = new ClassMetadataExporter(); - $cme->addMappingDirectory(__DIR__ . '/php', 'php'); - $cme->addMappingDirectory(__DIR__ . '/xml', 'xml'); - $cme->addMappingDirectory(__DIR__ . '/yml', 'yml'); + $cme->addMappingSource(__DIR__ . '/php', 'php'); + $cme->addMappingSource(__DIR__ . '/xml', 'xml'); + $cme->addMappingSource(__DIR__ . '/yml', 'yml'); - $metadataInstances = $cme->getMetadatasForMappingDirectories(); + $metadataInstances = $cme->getMetadatasForMappingSources(); $this->assertEquals(3, count($metadataInstances)); - $this->assertEquals('PhpTest', $metadataInstances[0]->name); - $this->assertEquals('XmlTest', $metadataInstances[1]->name); - $this->assertEquals('YmlTest', $metadataInstances[2]->name); + $this->assertEquals('PhpTest', $metadataInstances['PhpTest']->name); + $this->assertEquals('XmlTest', $metadataInstances['XmlTest']->name); + $this->assertEquals('YmlTest', $metadataInstances['YmlTest']->name); } /** @@ -116,14 +116,14 @@ class ClassMetadataExporterTest extends \Doctrine\Tests\OrmTestCase $types = array('annotation', 'php', 'xml', 'yml'); $cme = new ClassMetadataExporter(); - $cme->addMappingDirectory(__DIR__ . '/php', 'php'); - $cme->addMappingDirectory(__DIR__ . '/xml', 'xml'); - $cme->addMappingDirectory(__DIR__ . '/yml', 'yml'); + $cme->addMappingSource(__DIR__ . '/php', 'php'); + $cme->addMappingSource(__DIR__ . '/xml', 'xml'); + $cme->addMappingSource(__DIR__ . '/yml', 'yml'); foreach ($types as $type) { // Export the above mapping directories to the type $exporter = $cme->getExporter($type, __DIR__ . '/export/' . $type); - $exporter->setMetadatas($cme->getMetadatasForMappingDirectories()); + $exporter->setMetadatas($cme->getMetadatasForMappingSources()); $exporter->export(); // Make sure the files were written @@ -133,12 +133,12 @@ class ClassMetadataExporterTest extends \Doctrine\Tests\OrmTestCase // Try and read back in the exported mapping files to make sure they are valid $cme2 = new ClassMetadataExporter(); - $cme2->addMappingDirectory(__DIR__ . '/export/' . $type, $type); - $metadataInstances = $cme2->getMetadatasForMappingDirectories(); + $cme2->addMappingSource(__DIR__ . '/export/' . $type, $type); + $metadataInstances = $cme2->getMetadatasForMappingSources(); $this->assertEquals(3, count($metadataInstances)); - $this->assertEquals('PhpTest', $metadataInstances[0]->name); - $this->assertEquals('XmlTest', $metadataInstances[1]->name); - $this->assertEquals('YmlTest', $metadataInstances[2]->name); + $this->assertEquals('PhpTest', $metadataInstances['PhpTest']->name); + $this->assertEquals('XmlTest', $metadataInstances['XmlTest']->name); + $this->assertEquals('YmlTest', $metadataInstances['YmlTest']->name); // Cleanup unlink(__DIR__ . '/export/' . $type . '/PhpTest'.$exporter->getExtension()); diff --git a/tools/sandbox/Entities/User.php b/tools/sandbox/Entities/User.php index 95487f570..cf44b4683 100644 --- a/tools/sandbox/Entities/User.php +++ b/tools/sandbox/Entities/User.php @@ -2,7 +2,7 @@ namespace Entities; -/** @Entity @Table(name="users") */ +/** @Entity @Table(name="users", indexes={@Index(name="name_idx", columns={"name", "test"})}) */ class User { /** * @Id @Column(type="integer") @@ -11,6 +11,8 @@ class User { private $id; /** @Column(type="string", length=50) */ private $name; + /** @Column(type="string", length=50) */ + private $test; /** * @OneToOne(targetEntity="Address") * @JoinColumn(name="address_id", referencedColumnName="id") diff --git a/tools/sandbox/cli-config.php b/tools/sandbox/cli-config.php index ff19f1b03..6434c9e74 100644 --- a/tools/sandbox/cli-config.php +++ b/tools/sandbox/cli-config.php @@ -23,8 +23,10 @@ $config = new \Doctrine\ORM\Configuration(); $config->setMetadataCacheImpl(new \Doctrine\Common\Cache\ArrayCache); $connectionOptions = array( - 'driver' => 'pdo_sqlite', - 'path' => 'database.sqlite' + 'driver' => 'pdo_mysql', + 'user' => 'root', + 'password' => '', + 'dbname' => 'doctrine2' ); $em = \Doctrine\ORM\EntityManager::create($connectionOptions, $config);