1
0
mirror of synced 2025-01-06 00:57:10 +03:00

[2.0] DDC-186 - Fixed DatabaseDriver to work with new Schema abstraction, added functional test-cases for database to yaml convertion.

This commit is contained in:
beberlei 2009-12-04 21:40:03 +00:00
parent 466e96b491
commit 556f8699ee
9 changed files with 232 additions and 34 deletions

View File

@ -44,6 +44,16 @@ use Doctrine\DBAL\DBALException,
*/ */
abstract class AbstractPlatform abstract class AbstractPlatform
{ {
/**
* @var int
*/
const CREATE_INDEXES = 1;
/**
* @var int
*/
const CREATE_FOREIGNKEYS = 2;
/** /**
* Constructor. * Constructor.
*/ */
@ -530,29 +540,34 @@ abstract class AbstractPlatform
* on this platform. * on this platform.
* *
* @param string $table The name of the table. * @param string $table The name of the table.
* @param array $columns The column definitions for the table. * @param int $createFlags
* @param array $options The table constraints.
* @return array The sequence of SQL statements. * @return array The sequence of SQL statements.
*/ */
public function getCreateTableSql(Table $table) public function getCreateTableSql(Table $table, $createFlags=self::CREATE_INDEXES)
{ {
if (!is_int($createFlags)) {
throw new \InvalidArgumentException("Second argument of AbstractPlatform::getCreateTableSql() has to be integer.");
}
$tableName = $table->getName(); $tableName = $table->getName();
$options = $table->getOptions(); $options = $table->getOptions();
$options['uniqueConstraints'] = array(); $options['uniqueConstraints'] = array();
$options['indexes'] = array(); $options['indexes'] = array();
$options['primary'] = array(); $options['primary'] = array();
foreach($table->getIndexes() AS $index) { if (($createFlags&self::CREATE_INDEXES) > 0) {
/* @var $index Index */ foreach ($table->getIndexes() AS $index) {
if($index->isPrimary()) { /* @var $index Index */
$options['primary'] = $index->getColumns(); if ($index->isPrimary()) {
} else { $options['primary'] = $index->getColumns();
$options['indexes'][$index->getName()] = $index; } else {
$options['indexes'][$index->getName()] = $index;
}
} }
} }
$columns = array(); $columns = array();
foreach($table->getColumns() AS $column) { foreach ($table->getColumns() AS $column) {
/* @var \Doctrine\DBAL\Schema\Column $column */ /* @var \Doctrine\DBAL\Schema\Column $column */
$columnData = array(); $columnData = array();
$columnData['name'] = $column->getName(); $columnData['name'] = $column->getName();
@ -580,16 +595,23 @@ abstract class AbstractPlatform
$columns[$columnData['name']] = $columnData; $columns[$columnData['name']] = $columnData;
} }
if (($createFlags&self::CREATE_FOREIGNKEYS) > 0) {
$options['foreignKeys'] = array();
foreach ($table->getForeignKeys() AS $fkConstraint) {
$options['foreignKeys'][] = $fkConstraint;
}
}
return $this->_getCreateTableSql($tableName, $columns, $options); return $this->_getCreateTableSql($tableName, $columns, $options);
} }
/** /**
* @param string $table * @param string $tableName
* @param array $columns * @param array $columns
* @param array $options * @param array $options
* @return array * @return array
*/ */
protected function _getCreateTableSql($table, array $columns, array $options = array()) protected function _getCreateTableSql($tableName, array $columns, array $options = array())
{ {
$columnListSql = $this->getColumnDeclarationListSql($columns); $columnListSql = $this->getColumnDeclarationListSql($columns);
@ -609,7 +631,7 @@ abstract class AbstractPlatform
} }
} }
$query = 'CREATE TABLE ' . $table . ' (' . $columnListSql; $query = 'CREATE TABLE ' . $tableName . ' (' . $columnListSql;
$check = $this->getCheckDeclarationSql($columns); $check = $this->getCheckDeclarationSql($columns);
if ( ! empty($check)) { if ( ! empty($check)) {
@ -621,7 +643,7 @@ abstract class AbstractPlatform
if (isset($options['foreignKeys'])) { if (isset($options['foreignKeys'])) {
foreach ((array) $options['foreignKeys'] AS $definition) { foreach ((array) $options['foreignKeys'] AS $definition) {
$sql[] = $this->getCreateForeignKeySql($definition, $name); $sql[] = $this->getCreateForeignKeySql($definition, $tableName);
} }
} }

View File

@ -24,6 +24,7 @@ namespace Doctrine\DBAL\Schema;
use \Doctrine\DBAL\Types; use \Doctrine\DBAL\Types;
use \Doctrine\Common\DoctrineException; use \Doctrine\Common\DoctrineException;
use \Doctrine\DBAL\DBALException; use \Doctrine\DBAL\DBALException;
use \Doctrine\DBAL\Platforms\AbstractPlatform;
/** /**
* Base class for schema managers. Schema managers are used to inspect and/or * Base class for schema managers. Schema managers are used to inspect and/or
@ -65,6 +66,16 @@ abstract class AbstractSchemaManager
$this->_platform = $this->_conn->getDatabasePlatform(); $this->_platform = $this->_conn->getDatabasePlatform();
} }
/**
* Return associated platform.
*
* @return \Doctrine\DBAL\Platform\AbstractPlatform
*/
public function getDatabasePlatform()
{
return $this->_platform;
}
/** /**
* Try any method on the schema manager. Normally a method throws an * Try any method on the schema manager. Normally a method throws an
* exception when your DBMS doesn't support it or if an error occurs. * exception when your DBMS doesn't support it or if an error occurs.
@ -410,10 +421,12 @@ abstract class AbstractSchemaManager
* Create a new table. * Create a new table.
* *
* @param Table $table * @param Table $table
* @param int $createFlags
*/ */
public function createTable(Table $table) public function createTable(Table $table)
{ {
$this->_execSql($this->_platform->getCreateTableSql($table)); $createFlags = AbstractPlatform::CREATE_INDEXES|AbstractPlatform::CREATE_FOREIGNKEYS;
$this->_execSql($this->_platform->getCreateTableSql($table, $createFlags));
} }
/** /**

View File

@ -68,35 +68,42 @@ class DatabaseDriver implements Driver
$metadata->primaryTable['name'] = $tableName; $metadata->primaryTable['name'] = $tableName;
$columns = $this->_sm->listTableColumns($tableName); $columns = $this->_sm->listTableColumns($tableName);
try {
if($this->_sm->getDatabasePlatform()->supportsForeignKeyConstraints()) {
$foreignKeys = $this->_sm->listTableForeignKeys($tableName); $foreignKeys = $this->_sm->listTableForeignKeys($tableName);
} catch (\Doctrine\Common\DoctrineException $e) { } else {
$foreignKeys = array(); $foreignKeys = array();
} }
$indexes = $this->_sm->listTableIndexes($tableName);
$ids = array(); $ids = array();
$fieldMappings = array(); $fieldMappings = array();
foreach ($columns as $column) { foreach ($columns as $column) {
// Skip columns that are foreign keys // Skip columns that are foreign keys
foreach ($foreignKeys as $foreignKey) { foreach ($foreignKeys as $foreignKey) {
if ($column['name'] == $foreignKey['local']) { if (in_array($column->getName(), $foreignKey->getColumns())) {
continue(2); continue(2);
} }
} }
$fieldMapping = array(); $fieldMapping = array();
if ($column['primary']) { if (in_array($column->getName(), $indexes['primary']->getColumns())) {
$fieldMapping['id'] = true; $fieldMapping['id'] = true;
} }
$fieldMapping['fieldName'] = Inflector::camelize($column['name']); $fieldMapping['fieldName'] = Inflector::camelize($column->getName());
$fieldMapping['columnName'] = $column['name']; $fieldMapping['columnName'] = $column->getName();
$fieldMapping['type'] = strtolower((string) $column['type']); $fieldMapping['type'] = strtolower((string) $column->getType());
$fieldMapping['length'] = $column['length'];
$fieldMapping['unsigned'] = $column['unsigned']; if ($column->getType() instanceof \Doctrine\DBAL\Types\StringType) {
$fieldMapping['fixed'] = $column['fixed']; $fieldMapping['length'] = $column->getLength();
$fieldMapping['notnull'] = $column['notnull']; $fieldMapping['fixed'] = $column->getFixed();
$fieldMapping['default'] = $column['default']; } else if ($column->getType() instanceof \Doctrine\DBAL\Types\IntegerType) {
$fieldMapping['unsigned'] = $column->getUnsigned();
}
$fieldMapping['notnull'] = $column->getNotNull();
$fieldMapping['default'] = $column->getDefault();
if (isset($fieldMapping['id'])) { if (isset($fieldMapping['id'])) {
$ids[] = $fieldMapping; $ids[] = $fieldMapping;
@ -120,13 +127,27 @@ class DatabaseDriver implements Driver
} }
foreach ($foreignKeys as $foreignKey) { foreach ($foreignKeys as $foreignKey) {
if (count($foreignKey->getColumns()) != 1) {
throw new MappingException(
"Cannot generate mapping for table '".$tableName."' with foreign keys with multiple local columns."
);
}
$localColumn = current($foreignKey->getColumns());
if (count($foreignKey->getForeignColumns()) != 1) {
throw new MappingException(
"Cannot generate mapping for table '".$tableName."' with foreign keys with multiple foreign columns."
);
}
$foreignColumn = current($foreignKey->getForeignColumns());
$associationMapping = array(); $associationMapping = array();
$associationMapping['fieldName'] = Inflector::camelize(str_replace('_id', '', $foreignKey['local'])); $associationMapping['fieldName'] = Inflector::camelize(str_replace('_id', '', $localColumn));
$associationMapping['columnName'] = $foreignKey['local']; $associationMapping['columnName'] = $localColumn;
$associationMapping['targetEntity'] = Inflector::classify($foreignKey['table']); $associationMapping['targetEntity'] = Inflector::classify($foreignKey->getForeignTableName());
$associationMapping['joinColumns'][] = array( $associationMapping['joinColumns'][] = array(
'name' => $foreignKey['local'], 'name' => $localColumn,
'referencedColumnName' => $foreignKey['foreign'] 'referencedColumnName' => $foreignColumn
); );
$metadata->mapManyToOne($associationMapping); $metadata->mapManyToOne($associationMapping);
@ -156,7 +177,7 @@ class DatabaseDriver implements Driver
{ {
$tables = array(); $tables = array();
foreach ($this->_sm->listTables() as $table) { foreach ($this->_sm->listTables() as $table) {
$tables[] = $table; $tables[] = $table->getName();
} }
return $tables; return $tables;

View File

@ -2,7 +2,8 @@
namespace Doctrine\Tests\DBAL\Functional\Schema; namespace Doctrine\Tests\DBAL\Functional\Schema;
use Doctrine\DBAL\Types\Type; use Doctrine\DBAL\Types\Type,
Doctrine\DBAL\Schema\AbstractSchemaManager;
require_once __DIR__ . '/../../../TestInit.php'; require_once __DIR__ . '/../../../TestInit.php';
@ -197,6 +198,31 @@ class SchemaManagerFunctionalTestCase extends \Doctrine\Tests\DbalFunctionalTest
$this->assertFalse($tableIndexes['test']->isPrimary()); $this->assertFalse($tableIndexes['test']->isPrimary());
} }
public function testCreateTableWithForeignKeys()
{
if(!$this->_sm->getDatabasePlatform()->supportsForeignKeyConstraints()) {
$this->markTestSkipped('Platform does not support foreign keys.');
}
$tableB = $this->getTestTable('test_foreign');
$this->_sm->dropAndCreateTable($tableB);
$tableA = $this->getTestTable('test_create_fk');
$tableA->addForeignKeyConstraint('test_foreign', array('foreign_key_test'), array('id'));
$this->_sm->dropAndCreateTable($tableA);
$fkConstraints = $this->_sm->listTableForeignKeys('test_create_fk');
$this->assertEquals(1, count($fkConstraints));
$fkConstraint = current($fkConstraints);
$fkConstraint->setCaseMode("lower");
$this->assertEquals('test_foreign', $fkConstraint->getForeignTableName());
$this->assertEquals(array('foreign_key_test'), $fkConstraint->getColumns());
$this->assertEquals(array('id'), $fkConstraint->getForeignColumns());
}
public function testListForeignKeys() public function testListForeignKeys()
{ {
if(!$this->_conn->getDatabasePlatform()->supportsForeignKeyConstraints()) { if(!$this->_conn->getDatabasePlatform()->supportsForeignKeyConstraints()) {

View File

@ -45,6 +45,7 @@ class AllTests
$suite->addTestSuite('Doctrine\Tests\ORM\Functional\MappedSuperclassTest'); $suite->addTestSuite('Doctrine\Tests\ORM\Functional\MappedSuperclassTest');
$suite->addTestSuite('Doctrine\Tests\ORM\Functional\EntityRepositoryTest'); $suite->addTestSuite('Doctrine\Tests\ORM\Functional\EntityRepositoryTest');
$suite->addTestSuite('Doctrine\Tests\ORM\Functional\IdentityMapTest'); $suite->addTestSuite('Doctrine\Tests\ORM\Functional\IdentityMapTest');
$suite->addTestSuite('Doctrine\Tests\ORM\Functional\DatabaseDriverTest');
$suite->addTest(Locking\AllTests::suite()); $suite->addTest(Locking\AllTests::suite());
$suite->addTest(SchemaTool\AllTests::suite()); $suite->addTest(SchemaTool\AllTests::suite());

View File

@ -0,0 +1,26 @@
DbdriverBaz:
type: entity
table: dbdriver_baz
fields:
id:
id: true
type: integer
unsigned: false
notnull: true
default: null
generator:
strategy: AUTO
oneToOne:
bar:
targetEntity: DbdriverBar
cascade:
remove: false
persist: false
refresh: false
merge: false
detach: false
mappedBy: null
joinColumns:
bar_id:
referencedColumnName: id
orphanRemoval: false

View File

@ -0,0 +1,17 @@
DbdriverFoo:
type: entity
table: dbdriver_foo
fields:
id:
id: true
type: integer
unsigned: false
notnull: true
default: null
generator:
strategy: AUTO
bar:
type: string(200)
fixed: false
notnull: true
default: null

View File

@ -0,0 +1,68 @@
<?php
namespace Doctrine\Tests\ORM\Functional;
require_once __DIR__ . '/../../TestInit.php';
use Doctrine\ORM\Tools\Export\ClassMetadataExporter;
class DatabaseDriverTest extends \Doctrine\Tests\OrmFunctionalTestCase
{
protected $_sm = null;
public function testCreateSimpleYamlFromDatabase()
{
$table = new \Doctrine\DBAL\Schema\Table("dbdriver_foo");
$table->createColumn('id', 'integer');
$table->setPrimaryKey(array('id'));
$table->createColumn('bar', 'string', array('length' => 200));
$this->_sm = $this->_em->getConnection()->getSchemaManager();
$this->_sm->dropAndCreateTable($table);
$this->assertClassMetadataYamlEqualsFile(__DIR__."/DatabaseDriver/simpleYaml.yml", "DbdriverFoo");
}
protected function assertClassMetadataYamlEqualsFile($file, $className)
{
$cm = new ClassMetadataExporter();
$cm->addMappingSource($this->_sm, 'database');
$exporter = $cm->getExporter('yaml');
$metadatas = $cm->getMetadatasForMappingSources();
$output = false;
foreach ($metadatas AS $metadata) {
if ($metadata->name == $className) {
$output = $exporter->exportClassMetadata($metadata);
}
}
$this->assertTrue($output!==false, "No class matching the name '".$className."' was found!");
$this->assertEquals(strtolower(trim(file_get_contents($file))), strtolower(trim($output)));
}
public function testCreateYamlWithForeignKeyFromDatabase()
{
if (!$this->_em->getConnection()->getDatabasePlatform()->supportsForeignKeyConstraints()) {
$this->markTestSkipped('Platform does not support foreign keys.');
}
$tableB = new \Doctrine\DBAL\Schema\Table("dbdriver_bar");
$tableB->createColumn('id', 'integer');
$tableB->setPrimaryKey(array('id'));
$sm = $this->_em->getConnection()->getSchemaManager();
$sm->dropAndCreateTable($tableB);
$tableA = new \Doctrine\DBAL\Schema\Table("dbdriver_baz");
$tableA->createColumn('id', 'integer');
$tableA->setPrimaryKey(array('id'));
$tableA->createColumn('bar_id', 'integer');
$tableA->addForeignKeyConstraint('dbdriver_bar', array('bar_id'), array('id'));
$this->_sm = $this->_em->getConnection()->getSchemaManager();
$this->_sm->dropAndCreateTable($tableA);
$this->assertClassMetadataYamlEqualsFile(__DIR__."/DatabaseDriver/fkYaml.yml", "DbdriverBaz");
}
}

View File

@ -209,6 +209,10 @@ class OrmFunctionalTestCase extends OrmTestCase
protected function onNotSuccessfulTest(\Exception $e) protected function onNotSuccessfulTest(\Exception $e)
{ {
if ($e instanceof \PHPUnit_Framework_ExpectationFailedException) {
throw $e;
}
if($this->_sqlLoggerStack->queries !== null && count($this->_sqlLoggerStack->queries)) { if($this->_sqlLoggerStack->queries !== null && count($this->_sqlLoggerStack->queries)) {
$queries = ""; $queries = "";
for($i = 0; $i < count($this->_sqlLoggerStack->queries); $i++) { for($i = 0; $i < count($this->_sqlLoggerStack->queries); $i++) {