1
0
Fork 0
mirror of synced 2025-04-01 12:26:11 +03:00

DDC-853, DDC-629 - Fix drop schema always dropping everything at the cost of potential failures when dropping due to foreign keys. Added a full-database drop mode that resembles the old behavior.

This commit is contained in:
Benjamin Eberlei 2010-11-16 21:31:54 +01:00
parent 85a579febc
commit ae76b2ab8d
6 changed files with 95 additions and 52 deletions

View file

@ -60,6 +60,10 @@ class DropCommand extends AbstractCommand
'force', null, InputOption::PARAMETER_NONE,
"Don't ask for the deletion of the database, but force the operation to run."
),
new InputOption(
'full-database', null, InputOption::PARAMETER_NONE,
'Instead of using the Class Metadata to detect the database table schema, drop ALL assets that the database contains.'
),
))
->setHelp(<<<EOT
Processes the schema and either drop the database schema of EntityManager Storage Connection or generate the SQL output.
@ -70,17 +74,31 @@ EOT
protected function executeSchemaCommand(InputInterface $input, OutputInterface $output, SchemaTool $schemaTool, array $metadatas)
{
$isFullDatabaseDrop = ($input->getOption('full-database'));
if ($input->getOption('dump-sql') === true) {
$sqls = $schemaTool->getDropSchemaSql($metadatas);
if ($isFullDatabaseDrop) {
$sqls = $schemaTool->getDropDatabaseSQL();
} else {
$sqls = $schemaTool->getDropSchemaSQL($metadatas);
}
$output->write(implode(';' . PHP_EOL, $sqls) . PHP_EOL);
} else if ($input->getOption('force') === true) {
$output->write('Dropping database schema...' . PHP_EOL);
$schemaTool->dropSchema($metadatas);
if ($isFullDatabaseDrop) {
$schemaTool->dropDatabase();
} else {
$schemaTool->dropSchema($metadatas);
}
$output->write('Database schema dropped successfully!' . PHP_EOL);
} else {
$output->write('ATTENTION: This operation should not be executed in an production enviroment.' . PHP_EOL . PHP_EOL);
$sqls = $schemaTool->getDropSchemaSql($metadatas);
if ($isFullDatabaseDrop) {
$sqls = $schemaTool->getDropDatabaseSQL();
} else {
$sqls = $schemaTool->getDropSchemaSQL($metadatas);
}
if (count($sqls)) {
$output->write('Schema-Tool would execute ' . count($sqls) . ' queries to drop the database.' . PHP_EOL);

View file

@ -509,12 +509,26 @@ class SchemaTool
}
/**
* Gets the SQL needed to drop the database schema for the given classes.
* Drops all elements in the database of the current connection.
*
* @return void
*/
public function dropDatabase()
{
$dropSchemaSql = $this->getDropDatabaseSQL();
$conn = $this->_em->getConnection();
foreach ($dropSchemaSql as $sql) {
$conn->executeQuery($sql);
}
}
/**
* Gets the SQL needed to drop the database schema for the connections database.
*
* @param array $classes
* @return array
*/
public function getDropSchemaSql(array $classes)
public function getDropDatabaseSQL()
{
$sm = $this->_em->getConnection()->getSchemaManager();
$schema = $sm->createSchema();
@ -526,39 +540,31 @@ class SchemaTool
}
/**
* Drop all tables of the database connection.
*
* @param array $classes
* @return array
*/
private function _getDropSchemaTablesDatabaseMode($classes)
public function getDropSchemaSQL(array $classes)
{
$conn = $this->_em->getConnection();
$sm = $this->_em->getConnection()->getSchemaManager();
$sql = array();
$orderedTables = array();
$sm = $conn->getSchemaManager();
/* @var $sm \Doctrine\DBAL\Schema\AbstractSchemaManager */
$allTables = $sm->listTables();
$orderedTables = $this->_getDropSchemaTablesMetadataMode($classes);
foreach($allTables AS $tableName) {
if(!in_array($tableName, $orderedTables)) {
$orderedTables[] = $tableName;
foreach ($classes AS $class) {
if ($class->isIdGeneratorSequence() && $class->name == $class->rootEntityName && $this->_platform->supportsSequences()) {
$sql[] = $this->_platform->getDropSequenceSQL($class->sequenceGeneratorDefinition['sequenceName']);
}
}
return $orderedTables;
}
private function _getDropSchemaTablesMetadataMode(array $classes)
{
$orderedTables = array();
$commitOrder = $this->_getCommitOrder($classes);
$associationTables = $this->_getAssociationTables($commitOrder);
// Drop association tables first
foreach ($associationTables as $associationTable) {
$orderedTables[] = $associationTable;
if (!in_array($associationTable, $orderedTables)) {
$orderedTables[] = $associationTable;
}
}
// Drop tables in reverse commit order
@ -570,17 +576,27 @@ class SchemaTool
continue;
}
$orderedTables[] = $class->getTableName();
if (!in_array($class->getTableName(), $orderedTables)) {
$orderedTables[] = $class->getTableName();
}
}
//TODO: Drop other schema elements, like sequences etc.
$dropTablesSql = array();
foreach ($orderedTables AS $tableName) {
/* @var $sm \Doctrine\DBAL\Schema\AbstractSchemaManager */
$foreignKeys = $sm->listTableForeignKeys($tableName);
foreach ($foreignKeys AS $foreignKey) {
$sql[] = $this->_platform->getDropForeignKeySQL($foreignKey, $tableName);
}
$dropTablesSql[] = $this->_platform->getDropTableSQL($tableName);
}
return $orderedTables;
return array_merge($sql, $dropTablesSql);
}
/**
* Updates the database schema of the given classes by comparing the ClassMetadata
* instances to the current database schema that is inspected.
* ins$tableNametances to the current database schema that is inspected.
*
* @param array $classes
* @return void
@ -628,7 +644,7 @@ class SchemaTool
$calc->addClass($class);
foreach ($class->associationMappings as $assoc) {
if ($assoc->isOwningSide) {
if ($assoc['isOwningSide']) {
$targetClass = $this->_em->getClassMetadata($assoc['targetEntity']);
if ( ! $calc->hasClass($targetClass->name)) {
@ -650,8 +666,8 @@ class SchemaTool
foreach ($classes as $class) {
foreach ($class->associationMappings as $assoc) {
if ($assoc->isOwningSide && $assoc['type'] == ClassMetadata::MANY_TO_MANY) {
$associationTables[] = $assoc->joinTable['name'];
if ($assoc['isOwningSide'] && $assoc['type'] == ClassMetadata::MANY_TO_MANY) {
$associationTables[] = $assoc['joinTable']['name'];
}
}
}

View file

@ -12,6 +12,9 @@ require_once __DIR__ . '/../../../TestInit.php';
*/
class DDC214Test extends \Doctrine\Tests\OrmFunctionalTestCase
{
private $classes = array();
private $schemaTool = null;
public function setUp() {
parent::setUp();
@ -20,6 +23,7 @@ class DDC214Test extends \Doctrine\Tests\OrmFunctionalTestCase
if (strpos($conn->getDriver()->getName(), "sqlite") !== false) {
$this->markTestSkipped('SQLite does not support ALTER TABLE statements.');
}
$this->schemaTool = new Tools\SchemaTool($this->_em);
}
/**
@ -27,7 +31,7 @@ class DDC214Test extends \Doctrine\Tests\OrmFunctionalTestCase
*/
public function testCmsAddressModel()
{
$classes = array(
$this->classes = array(
'Doctrine\Tests\Models\CMS\CmsUser',
'Doctrine\Tests\Models\CMS\CmsPhonenumber',
'Doctrine\Tests\Models\CMS\CmsAddress',
@ -35,7 +39,7 @@ class DDC214Test extends \Doctrine\Tests\OrmFunctionalTestCase
'Doctrine\Tests\Models\CMS\CmsArticle'
);
$this->assertCreatedSchemaNeedsNoUpdates($classes);
$this->assertCreatedSchemaNeedsNoUpdates($this->classes);
}
/**
@ -43,7 +47,7 @@ class DDC214Test extends \Doctrine\Tests\OrmFunctionalTestCase
*/
public function testCompanyModel()
{
$classes = array(
$this->classes = array(
'Doctrine\Tests\Models\Company\CompanyPerson',
'Doctrine\Tests\Models\Company\CompanyEmployee',
'Doctrine\Tests\Models\Company\CompanyManager',
@ -54,7 +58,7 @@ class DDC214Test extends \Doctrine\Tests\OrmFunctionalTestCase
'Doctrine\Tests\Models\Company\CompanyCar'
);
$this->assertCreatedSchemaNeedsNoUpdates($classes);
$this->assertCreatedSchemaNeedsNoUpdates($this->classes);
}
public function assertCreatedSchemaNeedsNoUpdates($classes)
@ -64,19 +68,18 @@ class DDC214Test extends \Doctrine\Tests\OrmFunctionalTestCase
$classMetadata[] = $this->_em->getClassMetadata($class);
}
$schemaTool = new Tools\SchemaTool($this->_em);
$schemaTool->dropSchema($classMetadata);
$schemaTool->createSchema($classMetadata);
$this->schemaTool->dropDatabase();
$this->schemaTool->createSchema($classMetadata);
$sm = $this->_em->getConnection()->getSchemaManager();
$fromSchema = $sm->createSchema();
$toSchema = $schemaTool->getSchemaFromMetadata($classMetadata);
$toSchema = $this->schemaTool->getSchemaFromMetadata($classMetadata);
$comparator = new \Doctrine\DBAL\Schema\Comparator();
$schemaDiff = $comparator->compare($fromSchema, $toSchema);
$sql = $schemaDiff->toSql($this->_em->getConnection()->getDatabasePlatform());
$this->assertEquals(0, count($sql));
$this->assertEquals(0, count($sql), "SQL: " . implode(PHP_EOL, $sql));
}
}

View file

@ -35,6 +35,7 @@ class DDC735Test extends \Doctrine\Tests\OrmFunctionalTestCase
$this->assertEquals(1, count($product->getReviews()));
// Remove the review
$reviewId = $review->getId();
$product->removeReview($review);
$this->_em->flush();
@ -48,7 +49,7 @@ class DDC735Test extends \Doctrine\Tests\OrmFunctionalTestCase
$this->assertEquals(0, count($product->getReviews()), 'count($reviews) should still be 0 after the refresh');
// Review should also not be available anymore
$this->assertNull($this->_em->find(__NAMESPACE__.'\DDC735Review', $review->getId()));
$this->assertNull($this->_em->find(__NAMESPACE__.'\DDC735Review', $reviewId));
}
}

View file

@ -29,15 +29,15 @@ class DDC809Test extends \Doctrine\Tests\OrmFunctionalTestCase
$conn->insert('variant_test', array('variant_id' => 545208));
$conn->insert('variant_test', array('variant_id' => 545209));
$conn->insert('variant_specification_value_test', array('variant_id' => 545208, 'specification_value_id' => 94606));
$conn->insert('variant_specification_value_test', array('variant_id' => 545208, 'specification_value_id' => 94607));
$conn->insert('variant_specification_value_test', array('variant_id' => 545208, 'specification_value_id' => 94609));
$conn->insert('variant_specification_value_test', array('variant_id' => 545208, 'specification_value_id' => 94711));
$conn->insert('var_spec_value_test', array('variant_id' => 545208, 'specification_value_id' => 94606));
$conn->insert('var_spec_value_test', array('variant_id' => 545208, 'specification_value_id' => 94607));
$conn->insert('var_spec_value_test', array('variant_id' => 545208, 'specification_value_id' => 94609));
$conn->insert('var_spec_value_test', array('variant_id' => 545208, 'specification_value_id' => 94711));
$conn->insert('variant_specification_value_test', array('variant_id' => 545209, 'specification_value_id' => 94589));
$conn->insert('variant_specification_value_test', array('variant_id' => 545209, 'specification_value_id' => 94593));
$conn->insert('variant_specification_value_test', array('variant_id' => 545209, 'specification_value_id' => 94606));
$conn->insert('variant_specification_value_test', array('variant_id' => 545209, 'specification_value_id' => 94607));
$conn->insert('var_spec_value_test', array('variant_id' => 545209, 'specification_value_id' => 94589));
$conn->insert('var_spec_value_test', array('variant_id' => 545209, 'specification_value_id' => 94593));
$conn->insert('var_spec_value_test', array('variant_id' => 545209, 'specification_value_id' => 94606));
$conn->insert('var_spec_value_test', array('variant_id' => 545209, 'specification_value_id' => 94607));
}
/**
@ -72,7 +72,7 @@ class DDC809Variant
/**
* @ManyToMany(targetEntity="DDC809SpecificationValue", inversedBy="Variants")
* @JoinTable(name="variant_specification_value_test",
* @JoinTable(name="var_spec_value_test",
* joinColumns={
* @JoinColumn(name="variant_id", referencedColumnName="variant_id")
* },

View file

@ -13,6 +13,11 @@ class DDC832Test extends \Doctrine\Tests\OrmFunctionalTestCase
public function setUp()
{
parent::setUp();
$platform = $this->_em->getConnection()->getDatabasePlatform();
if ($platform->getName() == "oracle") {
$this->markTestSkipped('Doesnt run on Oracle.');
}
try {
$this->_schemaTool->createSchema(array(
$this->_em->getClassMetadata(__NAMESPACE__ . '\DDC832JoinedIndex'),