From 197224de2e4ebd60fd93b9345f26b7034a07b9ff Mon Sep 17 00:00:00 2001 From: beberlei Date: Wed, 2 Dec 2009 22:28:38 +0000 Subject: [PATCH] [2.0] DDC-169 - Changed AbstractPlatform and AbstractSchemaManager Constraint API to accept Constraint interface, which is implemented by indexes and foreign keys. --- .../DBAL/Platforms/AbstractPlatform.php | 105 +++++++++++++----- .../DBAL/Platforms/OraclePlatform.php | 17 ++- .../DBAL/Platforms/PostgreSqlPlatform.php | 14 ++- .../DBAL/Schema/AbstractSchemaManager.php | 78 ++++--------- lib/Doctrine/DBAL/Schema/Constraint.php | 4 +- .../DBAL/Schema/ForeignKeyConstraint.php | 5 + lib/Doctrine/DBAL/Schema/Index.php | 2 +- .../Platforms/AbstractPlatformTestCase.php | 30 +++++ .../DBAL/Platforms/MsSqlPlatformTest.php | 6 - .../DBAL/Platforms/MySqlPlatformTest.php | 6 - .../DBAL/Platforms/OraclePlatformTest.php | 8 +- .../DBAL/Platforms/SqlitePlatformTest.php | 6 - 12 files changed, 160 insertions(+), 121 deletions(-) diff --git a/lib/Doctrine/DBAL/Platforms/AbstractPlatform.php b/lib/Doctrine/DBAL/Platforms/AbstractPlatform.php index 2069eb7b3..66c9865c4 100644 --- a/lib/Doctrine/DBAL/Platforms/AbstractPlatform.php +++ b/lib/Doctrine/DBAL/Platforms/AbstractPlatform.php @@ -454,8 +454,18 @@ abstract class AbstractPlatform return 'DROP DATABASE ' . $database; } + /** + * Drop a Table + * + * @param Table|string $table + * @return string + */ public function getDropTableSql($table) { + if ($table instanceof \Doctrine\DBAL\Schema\Table) { + $table = $table->getName(); + } + return 'DROP TABLE ' . $table; } @@ -477,14 +487,42 @@ abstract class AbstractPlatform return 'DROP INDEX ' . $index; } - public function getDropConstraintSql($table, $name, $primary = false) + /** + * Get drop constraint sql + * + * @param \Doctrine\DBAL\Schema\Constraint $constraint + * @param string|Table $table + * @return string + */ + public function getDropConstraintSql($constraint, $table) { - return 'ALTER TABLE ' . $table . ' DROP CONSTRAINT ' . $name; + if ($constraint->getName()) { + $constraint = $constraint->getName(); + } + + if ($table->getName()) { + $table = $table->getName(); + } + + return 'ALTER TABLE ' . $table . ' DROP CONSTRAINT ' . $constraint; } - public function getDropForeignKeySql($table, $name) + /** + * @param ForeignKeyConstraint|string $foreignKey + * @param Table|string $table + * @return string + */ + public function getDropForeignKeySql($foreignKey, $table) { - return 'ALTER TABLE ' . $table . ' DROP FOREIGN KEY ' . $name; + if ($foreignKey instanceof \Doctrine\DBAL\Schema\ForeignKeyConstraint) { + $foreignKey = $foreignKey->getName(); + } + + if ($table instanceof \Doctrine\DBAL\Schema\Table) { + $table = $table->getName(); + } + + return 'ALTER TABLE ' . $table . ' DROP FOREIGN KEY ' . $foreignKey; } /** @@ -609,39 +647,46 @@ abstract class AbstractPlatform /** * Gets the SQL to create a constraint on a table on this platform. * - * @param string $table name of the table on which the constraint is to be created - * @param string $name name of the constraint to be created - * @param array $definition associative array that defines properties of the constraint to be created. - * Currently, only one property named FIELDS is supported. This property - * is also an associative with the names of the constraint fields as array - * constraints. Each entry of this array is set to another type of associative - * array that specifies properties of the constraint that are specific to - * each field. - * - * Example - * array( - * 'columns' => array( - * 'user_name' => array(), - * 'last_login' => array() - * ) - * ) + * @param Constraint $constraint + * @param string|Table $table * @return string */ - public function getCreateConstraintSql($table, $name, $definition) + public function getCreateConstraintSql(\Doctrine\DBAL\Schema\Constraint $constraint, $table) { - $query = 'ALTER TABLE ' . $table . ' ADD CONSTRAINT ' . $name; - - if (isset($definition['primary']) && $definition['primary']) { - $query .= ' PRIMARY KEY'; - } elseif (isset($definition['unique']) && $definition['unique']) { - $query .= ' UNIQUE'; + if ($table instanceof \Doctrine\DBAL\Schema\Table) { + $table = $table->getName(); } + $query = 'ALTER TABLE ' . $table . ' ADD CONSTRAINT ' . $constraint->getName(); + $columns = array(); - foreach (array_keys($definition['columns']) as $column) { + foreach ($constraint->getColumns() as $column) { $columns[] = $column; } - $query .= ' ('. implode(', ', $columns) . ')'; + $columnList = '('. implode(', ', $columns) . ')'; + + $referencesClause = ''; + if ($constraint instanceof \Doctrine\DBAL\Schema\Index) { + if($constraint->isPrimary()) { + $query .= ' PRIMARY KEY'; + } elseif ($constraint->isUnique()) { + $query .= ' UNIQUE'; + } else { + throw new \InvalidArgumentException( + 'Can only create primary or unique constraints, no common indexes with getCreateConstraintSql().' + ); + } + } else if ($constraint instanceof \Doctrine\DBAL\Schema\ForeignKeyConstraint) { + $query .= ' FOREIGN KEY'; + + $foreignColumns = array(); + foreach ($constraint->getForeignColumns() AS $column) { + $foreignColumns[] = $column; + } + + $referencesClause = ' REFERENCES '.$constraint->getForeignTableName(). ' ('.implode(', ', $foreignColumns).')'; + } + $query .= ' '.$columnList.$referencesClause; return $query; } @@ -1358,7 +1403,7 @@ abstract class AbstractPlatform throw DBALException::notSupported(__METHOD__); } - public function getDropSequenceSql($sequenceName) + public function getDropSequenceSql($sequence) { throw DBALException::notSupported(__METHOD__); } diff --git a/lib/Doctrine/DBAL/Platforms/OraclePlatform.php b/lib/Doctrine/DBAL/Platforms/OraclePlatform.php index 291d09160..96801b6e6 100644 --- a/lib/Doctrine/DBAL/Platforms/OraclePlatform.php +++ b/lib/Doctrine/DBAL/Platforms/OraclePlatform.php @@ -356,12 +356,14 @@ class OraclePlatform extends AbstractPlatform 'columns' => array($name => true), ); + $idx = new \Doctrine\DBAL\Schema\Index($indexName, array($name), true, true); + $sql[] = 'DECLARE constraints_Count NUMBER; BEGIN SELECT COUNT(CONSTRAINT_NAME) INTO constraints_Count FROM USER_CONSTRAINTS WHERE TABLE_NAME = \''.$table.'\' AND CONSTRAINT_TYPE = \'P\'; IF constraints_Count = 0 OR constraints_Count = \'\' THEN - EXECUTE IMMEDIATE \''.$this->getCreateConstraintSql($table, $indexName, $definition).'\'; + EXECUTE IMMEDIATE \''.$this->getCreateConstraintSql($idx, $table).'\'; END IF; END;'; @@ -440,9 +442,18 @@ END;'; return "SELECT * FROM all_tab_columns WHERE table_name = '" . $table . "' ORDER BY column_name"; } - public function getDropSequenceSql($sequenceName) + /** + * + * @param \Doctrine\DBAL\Schema\Sequence $sequence + * @return string + */ + public function getDropSequenceSql($sequence) { - return 'DROP SEQUENCE ' . $sequenceName; + if ($sequence instanceof \Doctrine\DBAL\Schema\Sequence) { + $sequence = $sequence->getName(); + } + + return 'DROP SEQUENCE ' . $sequence; } public function getDropDatabaseSql($database) diff --git a/lib/Doctrine/DBAL/Platforms/PostgreSqlPlatform.php b/lib/Doctrine/DBAL/Platforms/PostgreSqlPlatform.php index 0cc3c2ac3..59cb38aa3 100644 --- a/lib/Doctrine/DBAL/Platforms/PostgreSqlPlatform.php +++ b/lib/Doctrine/DBAL/Platforms/PostgreSqlPlatform.php @@ -572,14 +572,16 @@ class PostgreSqlPlatform extends AbstractPlatform } /** - * drop existing sequence - * - * @param string $sequenceName name of the sequence to be dropped - * @override + * Drop existing sequence + * @param \Doctrine\DBAL\Schema\Sequence $sequence + * @return string */ - public function getDropSequenceSql($sequenceName) + public function getDropSequenceSql($sequence) { - return 'DROP SEQUENCE ' . $sequenceName; + if ($sequence instanceof \Doctrine\DBAL\Schema\Sequence) { + $sequence = $sequence->getName(); + } + return 'DROP SEQUENCE ' . $sequence; } /** diff --git a/lib/Doctrine/DBAL/Schema/AbstractSchemaManager.php b/lib/Doctrine/DBAL/Schema/AbstractSchemaManager.php index 681c0d8e7..370f2189b 100644 --- a/lib/Doctrine/DBAL/Schema/AbstractSchemaManager.php +++ b/lib/Doctrine/DBAL/Schema/AbstractSchemaManager.php @@ -351,25 +351,24 @@ abstract class AbstractSchemaManager /** * Drop the constraint from the given table * + * @param Constraint $constraint * @param string $table The name of the table - * @param string $name The name of the constraint - * @param string $primary Whether or not it is a primary constraint */ - public function dropConstraint($table, $name, $primary = false) + public function dropConstraint(Constraint $constraint, $table) { - $this->_execSql($this->_platform->getDropConstraintSql($table, $name, $primary)); + $this->_execSql($this->_platform->getDropConstraintSql($constraint, $table)); } /** * Drops a foreign key from a table. * - * @param string $table The name of the table with the foreign key. - * @param string $name The name of the foreign key. + * @param ForeignKeyConstraint|string $table The name of the table with the foreign key. + * @param Table|string $name The name of the foreign key. * @return boolean $result */ - public function dropForeignKey($table, $name) + public function dropForeignKey($foreignKey, $table) { - $this->_execSql($this->_platform->getDropForeignKeySql($table, $name)); + $this->_execSql($this->_platform->getDropForeignKeySql($foreignKey, $table)); } /** @@ -429,26 +428,12 @@ abstract class AbstractSchemaManager /** * Create a constraint on a table * - * @param string $table name of the table on which the constraint is to be created - * @param string $name name of the constraint to be created - * @param array $definition associative array that defines properties of the constraint to be created. - * Currently, only one property named FIELDS is supported. This property - * is also an associative with the names of the constraint fields as array - * constraints. Each entry of this array is set to another type of associative - * array that specifies properties of the constraint that are specific to - * each field. - * - * Example - * array( - * 'columns' => array( - * 'user_name' => array(), - * 'last_login' => array() - * ) - * ) + * @param Constraint $constraint + * @param string|Table $table */ - public function createConstraint($table, $name, $definition) + public function createConstraint(Constraint $constraint, $table) { - $this->_execSql($this->_platform->getCreateConstraintSql($table, $name, $definition)); + $this->_execSql($this->_platform->getCreateConstraintSql($constraint, $table)); } /** @@ -489,30 +474,15 @@ abstract class AbstractSchemaManager /** * Drop and create a constraint * - * @param string $table name of the table on which the constraint is to be created - * @param string $name name of the constraint to be created - * @param array $definition associative array that defines properties of the constraint to be created. - * Currently, only one property named FIELDS is supported. This property - * is also an associative with the names of the constraint fields as array - * constraints. Each entry of this array is set to another type of associative - * array that specifies properties of the constraint that are specific to - * each field. - * - * Example - * array( - * 'columns' => array( - * 'user_name' => array(), - * 'last_login' => array() - * ) - * ) - * @param boolean $primary Whether or not it is a primary constraint + * @param Constraint $constraint + * @param string $table * @see dropConstraint() * @see createConstraint() */ - public function dropAndCreateConstraint($table, $name, $definition, $primary = false) + public function dropAndCreateConstraint(Constraint $constraint, $table) { - $this->tryMethod('dropConstraint', $table, $name, $primary); - $this->createConstraint($table, $name, $definition); + $this->tryMethod('dropConstraint', $constraint, $table); + $this->createConstraint($constraint, $table); } /** @@ -530,24 +500,22 @@ abstract class AbstractSchemaManager /** * Drop and create a new foreign key * - * @param string $table name of the table on which the foreign key is to be created - * @param array $definition associative array that defines properties of the foreign key to be created. + * @param ForeignKeyConstraint $foreignKey associative array that defines properties of the foreign key to be created. + * @param string|Table $table name of the table on which the foreign key is to be created */ - public function dropAndCreateForeignKey($table, $definition) + public function dropAndCreateForeignKey(ForeignKeyConstraint $foreignKey, $table) { - $this->tryMethod('dropForeignKey', $table, $definition['name']); - $this->createForeignKey($table, $definition); + $this->tryMethod('dropForeignKey', $foreignKey, $table); + $this->createForeignKey($foreignKey, $table); } /** * Drop and create a new sequence * - * @param string $seqName name of the sequence to be created - * @param string $start start value of the sequence; default is 1 - * @param array $allocationSize The size to allocate for sequence + * @param Sequence $sequence * @throws Doctrine\DBAL\ConnectionException if something fails at database level */ - public function dropAndCreateSequence($seqName, $start = 1, $allocationSize = 1) + public function dropAndCreateSequence(Sequence $sequence) { $this->tryMethod('createSequence', $seqName, $start, $allocationSize); $this->createSequence($seqName, $start, $allocationSize); diff --git a/lib/Doctrine/DBAL/Schema/Constraint.php b/lib/Doctrine/DBAL/Schema/Constraint.php index cc5e5ce2c..9e760ffab 100644 --- a/lib/Doctrine/DBAL/Schema/Constraint.php +++ b/lib/Doctrine/DBAL/Schema/Constraint.php @@ -32,5 +32,7 @@ namespace Doctrine\DBAL\Schema; */ interface Constraint { - + public function getName(); + + public function getColumns(); } \ No newline at end of file diff --git a/lib/Doctrine/DBAL/Schema/ForeignKeyConstraint.php b/lib/Doctrine/DBAL/Schema/ForeignKeyConstraint.php index 1d6f5536b..74c1e4d8c 100644 --- a/lib/Doctrine/DBAL/Schema/ForeignKeyConstraint.php +++ b/lib/Doctrine/DBAL/Schema/ForeignKeyConstraint.php @@ -75,6 +75,11 @@ class ForeignKeyConstraint extends AbstractAsset implements Constraint return $this->_localColumnNames; } + public function getColumns() + { + return $this->_localColumnNames; + } + /** * @return string */ diff --git a/lib/Doctrine/DBAL/Schema/Index.php b/lib/Doctrine/DBAL/Schema/Index.php index 22276fb44..29b0837f3 100644 --- a/lib/Doctrine/DBAL/Schema/Index.php +++ b/lib/Doctrine/DBAL/Schema/Index.php @@ -23,7 +23,7 @@ namespace Doctrine\DBAL\Schema; use Doctrine\DBAL\Schema\Visitor\Visitor; -class Index extends AbstractAsset +class Index extends AbstractAsset implements Constraint { /** * @var array diff --git a/tests/Doctrine/Tests/DBAL/Platforms/AbstractPlatformTestCase.php b/tests/Doctrine/Tests/DBAL/Platforms/AbstractPlatformTestCase.php index ba873fd15..43589aa7a 100644 --- a/tests/Doctrine/Tests/DBAL/Platforms/AbstractPlatformTestCase.php +++ b/tests/Doctrine/Tests/DBAL/Platforms/AbstractPlatformTestCase.php @@ -58,4 +58,34 @@ abstract class AbstractPlatformTestCase extends \Doctrine\Tests\DbalTestCase } abstract public function getGenerateForeignKeySql(); + + public function testGeneratesConstraintCreationSql() + { + $idx = new \Doctrine\DBAL\Schema\Index('constraint_name', array('test'), true, false); + $sql = $this->_platform->getCreateConstraintSql($idx, 'test'); + $this->assertEquals($this->getGenerateConstraintUniqueIndexSql(), $sql); + + $pk = new \Doctrine\DBAL\Schema\Index('constraint_name', array('test'), true, true); + $sql = $this->_platform->getCreateConstraintSql($pk, 'test'); + $this->assertEquals($this->getGenerateConstraintPrimaryIndexSql(), $sql); + + $fk = new \Doctrine\DBAL\Schema\ForeignKeyConstraint(array('fk_name'), 'foreign', array('id'), 'constraint_fk'); + $sql = $this->_platform->getCreateConstraintSql($fk, 'test'); + $this->assertEquals($this->getGenerateConstraintForeignKeySql(), $sql); + } + + public function getGenerateConstraintUniqueIndexSql() + { + return 'ALTER TABLE test ADD CONSTRAINT constraint_name UNIQUE (test)'; + } + + public function getGenerateConstraintPrimaryIndexSql() + { + return 'ALTER TABLE test ADD CONSTRAINT constraint_name PRIMARY KEY (test)'; + } + + public function getGenerateConstraintForeignKeySql() + { + return 'ALTER TABLE test ADD CONSTRAINT constraint_fk FOREIGN KEY (fk_name) REFERENCES foreign (id)'; + } } diff --git a/tests/Doctrine/Tests/DBAL/Platforms/MsSqlPlatformTest.php b/tests/Doctrine/Tests/DBAL/Platforms/MsSqlPlatformTest.php index 0b5fbf0ec..2e9a7c32a 100644 --- a/tests/Doctrine/Tests/DBAL/Platforms/MsSqlPlatformTest.php +++ b/tests/Doctrine/Tests/DBAL/Platforms/MsSqlPlatformTest.php @@ -125,12 +125,6 @@ class MsSqlPlatformTest extends AbstractPlatformTestCase $this->assertFalse($this->_platform->supportsSavepoints()); } - public function testGeneratesConstraintCreationSql() - { - $sql = $this->_platform->getCreateConstraintSql('test', 'constraint_name', array('columns' => array('test' => array()))); - $this->assertEquals($sql, 'ALTER TABLE test ADD CONSTRAINT constraint_name (test)'); - } - public function getGenerateIndexSql() { return 'CREATE INDEX my_idx ON mytable (user_name, last_login)'; diff --git a/tests/Doctrine/Tests/DBAL/Platforms/MySqlPlatformTest.php b/tests/Doctrine/Tests/DBAL/Platforms/MySqlPlatformTest.php index 12ac2d554..24bad0b8a 100644 --- a/tests/Doctrine/Tests/DBAL/Platforms/MySqlPlatformTest.php +++ b/tests/Doctrine/Tests/DBAL/Platforms/MySqlPlatformTest.php @@ -127,12 +127,6 @@ class MySqlPlatformTest extends AbstractPlatformTestCase $this->assertFalse($this->_platform->supportsSavepoints()); } - public function testGeneratesConstraintCreationSql() - { - $sql = $this->_platform->getCreateConstraintSql('test', 'constraint_name', array('columns' => array('test' => array()))); - $this->assertEquals($sql, 'ALTER TABLE test ADD CONSTRAINT constraint_name (test)'); - } - public function getGenerateIndexSql() { return 'CREATE INDEX my_idx ON mytable (user_name, last_login)'; diff --git a/tests/Doctrine/Tests/DBAL/Platforms/OraclePlatformTest.php b/tests/Doctrine/Tests/DBAL/Platforms/OraclePlatformTest.php index 00886807b..3dc59090f 100644 --- a/tests/Doctrine/Tests/DBAL/Platforms/OraclePlatformTest.php +++ b/tests/Doctrine/Tests/DBAL/Platforms/OraclePlatformTest.php @@ -162,13 +162,7 @@ class OraclePlatformTest extends AbstractPlatformTestCase { $this->assertTrue($this->_platform->supportsSavepoints()); } - - public function testGeneratesConstraintCreationSql() - { - $sql = $this->_platform->getCreateConstraintSql('test', 'constraint_name', array('columns' => array('test' => array()))); - $this->assertEquals($sql, 'ALTER TABLE test ADD CONSTRAINT constraint_name (test)'); - } - + public function getGenerateIndexSql() { return 'CREATE INDEX my_idx ON mytable (user_name, last_login)'; diff --git a/tests/Doctrine/Tests/DBAL/Platforms/SqlitePlatformTest.php b/tests/Doctrine/Tests/DBAL/Platforms/SqlitePlatformTest.php index c43f49032..3f9b3700a 100644 --- a/tests/Doctrine/Tests/DBAL/Platforms/SqlitePlatformTest.php +++ b/tests/Doctrine/Tests/DBAL/Platforms/SqlitePlatformTest.php @@ -75,12 +75,6 @@ class SqlitePlatformTest extends AbstractPlatformTestCase ); } - public function testGeneratesConstraintCreationSql() - { - $sql = $this->_platform->getCreateConstraintSql('test', 'constraint_name', array('columns' => array('test' => array()))); - $this->assertEquals('ALTER TABLE test ADD CONSTRAINT constraint_name (test)', $sql); - } - public function getGenerateIndexSql() { return 'CREATE INDEX my_idx ON mytable (user_name, last_login)';