Commit 165abc3c authored by jwage's avatar jwage

[2.0] Work on mapping drivers, exporter drivers and reverse engineering of database schemas

parent c8362da4
This diff is collapsed.
......@@ -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
<?php
/*
* $Id$
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* This software consists of voluntary contributions made by many individuals
* and is licensed under the LGPL. For more information, see
* <http://www.doctrine-project.org>.
*/
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 <guilhermeblanco@hotmail.com>
* @author Jonathan Wage <jonwage@gmail.com>
* @author Roman Borschel <roman@code-factory.org>
*/
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
......@@ -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);
}
......
......@@ -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;
$type = $this->_determineSourceType($sourceArg);
$source = $this->_getSourceByType($type, $sourceArg);
$printer->writeln(sprintf('Adding %s mapping directory: "%s"', $type, $path), 'INFO');
$printer->writeln(sprintf('Adding "%s" mapping source', $sourceArg), 'INFO');
$cme->addMappingDir($path, $type);
$cme->addMappingSource($source, $type);
}
$exporter->setMetadatas($cme->getMetadatasForMappingDirectories());
$metadatas = $cme->getMetadatasForMappingSources();
}
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');
$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)
{
// If the --from=<VALUE> 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)
{
$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 --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
......@@ -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,40 +174,42 @@ class SchemaToolTask extends AbstractTask
$printer->writeln('No classes to process.', 'INFO');
return;
}
if ($isCreate) {
if ($isDrop) {
if (isset($args['dump-sql'])) {
foreach ($tool->getCreateSchemaSql($classes) as $sql) {
foreach ($tool->getDropSchemaSql($classes) as $sql) {
$printer->writeln($sql);
}
} else {
$printer->writeln('Creating database schema...', 'INFO');
$printer->writeln('Dropping database schema...', 'INFO');
try {
$tool->createSchema($classes);
$printer->writeln('Database schema created successfully.', 'INFO');
$tool->dropSchema($classes);
$printer->writeln('Database schema dropped successfully.', 'INFO');
} catch (\Exception $ex) {
throw new DoctrineException($ex);
}
}
} else if ($isDrop) {
}
if ($isCreate) {
if (isset($args['dump-sql'])) {
foreach ($tool->getDropSchemaSql($classes) as $sql) {
foreach ($tool->getCreateSchemaSql($classes) as $sql) {
$printer->writeln($sql);
}
} else {
$printer->writeln('Dropping database schema...', 'INFO');
$printer->writeln('Creating database schema...', 'INFO');
try {
$tool->dropSchema($classes);
$printer->writeln('Database schema dropped successfully.', 'INFO');
$tool->createSchema($classes);
$printer->writeln('Database schema created 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);
......
......@@ -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
......@@ -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'] . '"';
}
......
......@@ -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
......@@ -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) {
......
......@@ -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');
......
......@@ -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());
......
......@@ -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")
......
......@@ -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);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment