Skip to content

Commit

Permalink
DDC-853, DDC-629 - Fix drop schema always dropping everything at the …
Browse files Browse the repository at this point in the history
…cost of potential failures when dropping due to foreign keys. Added a full-database drop mode that resembles the old behavior.
  • Loading branch information
beberlei committed Nov 16, 2010
1 parent 85a579f commit ae76b2a
Show file tree
Hide file tree
Showing 6 changed files with 95 additions and 52 deletions.
24 changes: 21 additions & 3 deletions lib/Doctrine/ORM/Tools/Console/Command/SchemaTool/DropCommand.php
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,10 @@ protected function configure()
'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.
Expand All @@ -70,17 +74,31 @@ protected function configure()

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);
Expand Down
76 changes: 46 additions & 30 deletions lib/Doctrine/ORM/Tools/SchemaTool.php
Original file line number Diff line number Diff line change
Expand Up @@ -509,12 +509,26 @@ public function dropSchema(array $classes)
}

/**
* 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();
Expand All @@ -526,39 +540,31 @@ public function getDropSchemaSql(array $classes)
}

/**
* 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 = $conn->getSchemaManager();
/* @var $sm \Doctrine\DBAL\Schema\AbstractSchemaManager */

$allTables = $sm->listTables();
$sm = $this->_em->getConnection()->getSchemaManager();

$sql = array();
$orderedTables = array();

$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
Expand All @@ -570,17 +576,27 @@ private function _getDropSchemaTablesMetadataMode(array $classes)
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
Expand Down Expand Up @@ -628,7 +644,7 @@ private function _getCommitOrder(array $classes)
$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)) {
Expand All @@ -650,8 +666,8 @@ private function _getAssociationTables(array $classes)

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'];
}
}
}
Expand Down
21 changes: 12 additions & 9 deletions tests/Doctrine/Tests/ORM/Functional/SchemaTool/DDC214Test.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,9 @@
*/
class DDC214Test extends \Doctrine\Tests\OrmFunctionalTestCase
{
private $classes = array();
private $schemaTool = null;

public function setUp() {
parent::setUp();

Expand All @@ -20,30 +23,31 @@ public function setUp() {
if (strpos($conn->getDriver()->getName(), "sqlite") !== false) {
$this->markTestSkipped('SQLite does not support ALTER TABLE statements.');
}
$this->schemaTool = new Tools\SchemaTool($this->_em);
}

/**
* @group DDC-214
*/
public function testCmsAddressModel()
{
$classes = array(
$this->classes = array(
'Doctrine\Tests\Models\CMS\CmsUser',
'Doctrine\Tests\Models\CMS\CmsPhonenumber',
'Doctrine\Tests\Models\CMS\CmsAddress',
'Doctrine\Tests\Models\CMS\CmsGroup',
'Doctrine\Tests\Models\CMS\CmsArticle'
);

$this->assertCreatedSchemaNeedsNoUpdates($classes);
$this->assertCreatedSchemaNeedsNoUpdates($this->classes);
}

/**
* @group DDC-214
*/
public function testCompanyModel()
{
$classes = array(
$this->classes = array(
'Doctrine\Tests\Models\Company\CompanyPerson',
'Doctrine\Tests\Models\Company\CompanyEmployee',
'Doctrine\Tests\Models\Company\CompanyManager',
Expand All @@ -54,7 +58,7 @@ public function testCompanyModel()
'Doctrine\Tests\Models\Company\CompanyCar'
);

$this->assertCreatedSchemaNeedsNoUpdates($classes);
$this->assertCreatedSchemaNeedsNoUpdates($this->classes);
}

public function assertCreatedSchemaNeedsNoUpdates($classes)
Expand All @@ -64,19 +68,18 @@ public function assertCreatedSchemaNeedsNoUpdates($classes)
$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));
}
}
3 changes: 2 additions & 1 deletion tests/Doctrine/Tests/ORM/Functional/Ticket/DDC735Test.php
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ public function testRemoveElement_AppliesOrphanRemoval()
$this->assertEquals(1, count($product->getReviews()));

// Remove the review
$reviewId = $review->getId();
$product->removeReview($review);
$this->_em->flush();

Expand All @@ -48,7 +49,7 @@ public function testRemoveElement_AppliesOrphanRemoval()
$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));
}
}

Expand Down
18 changes: 9 additions & 9 deletions tests/Doctrine/Tests/ORM/Functional/Ticket/DDC809Test.php
Original file line number Diff line number Diff line change
Expand Up @@ -29,15 +29,15 @@ public function setUp()
$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));
}

/**
Expand Down Expand Up @@ -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")
* },
Expand Down
5 changes: 5 additions & 0 deletions tests/Doctrine/Tests/ORM/Functional/Ticket/DDC832Test.php
Original file line number Diff line number Diff line change
Expand Up @@ -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'),
Expand Down

0 comments on commit ae76b2a

Please sign in to comment.