From 3678b65186226a1c1672b8a2778f84b2767cbc34 Mon Sep 17 00:00:00 2001 From: beberlei Date: Thu, 5 Nov 2009 08:47:56 +0000 Subject: [PATCH] [2.0] DDC-114 - Extend SchemaTool Drop functionality to optionally drop the complete database. Additionally a filter against all existing table is applied to avoid errors due to dropping non-existant tables. Updated Schema-Tool CLI command with optional calls --drop=database --drop=metadata but kept original --drop which defaults to "metadata". Updated documentation. --- .../ORM/Tools/Cli/Tasks/SchemaToolTask.php | 18 ++-- lib/Doctrine/ORM/Tools/SchemaTool.php | 88 ++++++++++++++++--- 2 files changed, 87 insertions(+), 19 deletions(-) diff --git a/lib/Doctrine/ORM/Tools/Cli/Tasks/SchemaToolTask.php b/lib/Doctrine/ORM/Tools/Cli/Tasks/SchemaToolTask.php index 13fea81f3..bacbdadd7 100644 --- a/lib/Doctrine/ORM/Tools/Cli/Tasks/SchemaToolTask.php +++ b/lib/Doctrine/ORM/Tools/Cli/Tasks/SchemaToolTask.php @@ -60,8 +60,9 @@ class SchemaToolTask extends AbstractTask ->writeln("\t\tCreates the schema in EntityManager (create tables on Database)") ->writeln("\t\t\tIf defined, --drop and --update can not be requested on same task") ->write(PHP_EOL) - ->write('--drop', 'REQ_ARG') + ->write('--drop=', 'REQ_ARG') ->writeln("\t\t\tDrops the schema of EntityManager (drop tables on Database)") + ->writeln("\t\t\tDefaults to 'metadata' if only --drop is specified.") ->writeln("\t\t\tIf defined, --create and --update can not be requested on same task") ->write(PHP_EOL) ->write('--update', 'REQ_ARG') @@ -90,7 +91,7 @@ class SchemaToolTask extends AbstractTask private function _writeSynopsis($printer) { $printer->write('schema-tool', 'KEYWORD') - ->write(' (--create | --drop | --update | --re-create)', 'REQ_ARG') + ->write(' (--create | --drop= | --update | --re-create)', 'REQ_ARG') ->writeln(' [--dump-sql] [--class-dir=]', 'OPT_ARG'); } @@ -151,10 +152,10 @@ class SchemaToolTask extends AbstractTask $em = $this->getEntityManager(); $cmf = $em->getMetadataFactory(); $driver = $em->getConfiguration()->getMetadataDriverImpl(); - + $classes = array(); $preloadedClasses = $driver->preload(true); - + foreach ($preloadedClasses as $className) { $classes[] = $cmf->getMetadataFor($className); } @@ -169,15 +170,20 @@ class SchemaToolTask extends AbstractTask $tool = new SchemaTool($em); if ($isDrop) { + $dropMode = $args['drop']; + if(!in_array($dropMode, array('metadata', 'database'))) { + $dropMode = 'metadata'; + } + if (isset($args['dump-sql'])) { - foreach ($tool->getDropSchemaSql($classes) as $sql) { + foreach ($tool->getDropSchemaSql($classes, $dropMode) as $sql) { $printer->writeln($sql); } } else { $printer->writeln('Dropping database schema...', 'INFO'); try { - $tool->dropSchema($classes); + $tool->dropSchema($classes, $dropMode); $printer->writeln('Database schema dropped successfully.', 'INFO'); } catch (\Exception $ex) { throw new DoctrineException($ex); diff --git a/lib/Doctrine/ORM/Tools/SchemaTool.php b/lib/Doctrine/ORM/Tools/SchemaTool.php index 8b164813b..0c844bbcb 100644 --- a/lib/Doctrine/ORM/Tools/SchemaTool.php +++ b/lib/Doctrine/ORM/Tools/SchemaTool.php @@ -40,6 +40,15 @@ use Doctrine\DBAL\Types\Type, */ class SchemaTool { + /** + * @var string + */ + const DROP_METADATA = "metadata"; + /** + * @var string + */ + const DROP_DATABASE = "database"; + /** * @var \Doctrine\ORM\EntityManager */ @@ -417,13 +426,17 @@ class SchemaTool /** * Drops the database schema for the given classes. - * + * + * In any way when an exception is thrown it is supressed since drop was + * issued for all classes of the schema and some probably just don't exist. + * * @param array $classes + * @param string $mode * @return void */ - public function dropSchema(array $classes) + public function dropSchema(array $classes, $mode=self::DROP_METADATA) { - $dropSchemaSql = $this->getDropSchemaSql($classes); + $dropSchemaSql = $this->getDropSchemaSql($classes, $mode); $conn = $this->_em->getConnection(); foreach ($dropSchemaSql as $sql) { @@ -435,35 +448,84 @@ class SchemaTool * Gets the SQL needed to drop the database schema for the given classes. * * @param array $classes + * @param string $mode * @return array */ - public function getDropSchemaSql(array $classes) + public function getDropSchemaSql(array $classes, $mode=self::DROP_METADATA) { + if($mode == self::DROP_METADATA) { + $tables = $this->_getDropSchemaTablesMetadataMode($classes); + } else if($mode == self::DROP_DATABASE) { + $tables = $this->_getDropSchemaTablesDatabaseMode($classes); + } else { + throw new \Doctrine\ORM\ORMException("Given Drop Schema Mode is not supported."); + } + + $sm = $this->_em->getConnection()->getSchemaManager(); + /* @var $sm \Doctrine\DBAL\Schema\AbstractSchemaManager */ + $allTables = $sm->listTables(); + $sql = array(); + foreach($tables AS $tableName) { + if(in_array($tableName, $allTables)) { + $sql[] = $this->_platform->getDropTableSql($tableName); + } + } + + return $sql; + } + + /** + * Drop all tables of the database connection. + * + * @return array + */ + private function _getDropSchemaTablesDatabaseMode($classes) + { + $conn = $this->_em->getConnection(); + + $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; + } + } + + 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) { - $sql[] = $this->_platform->getDropTableSql($associationTable); + $orderedTables[] = $associationTable; } // Drop tables in reverse commit order for ($i = count($commitOrder) - 1; $i >= 0; --$i) { $class = $commitOrder[$i]; - + if (($class->isInheritanceTypeSingleTable() && $class->name != $class->rootEntityName) || $class->isMappedSuperclass) { continue; } - - $sql[] = $this->_platform->getDropTableSql($class->getTableName()); + + $orderedTables[] = $class->getTableName(); } - + //TODO: Drop other schema elements, like sequences etc. - - return $sql; + + return $orderedTables; } /** @@ -713,7 +775,7 @@ class SchemaTool private function _getCommitOrder(array $classes) { $calc = new CommitOrderCalculator; - + // Calculate dependencies foreach ($classes as $class) { $calc->addClass($class);