1
0
mirror of synced 2024-12-12 22:36:02 +03:00

[2.0] DDC-169 - Introduced handling of schema / database case-sensitivity differences and to allow compability between different platforms.

This commit is contained in:
beberlei 2009-12-03 22:10:13 +00:00
parent 15f84f6eb0
commit b0bbe281f3
11 changed files with 115 additions and 47 deletions

View File

@ -35,11 +35,20 @@ namespace Doctrine\DBAL\Schema;
*/
abstract class AbstractAsset
{
const CASE_UPPER = "upper";
const CASE_LOWER = "lower";
const CASE_KEEP = "keep";
/**
* @var string
*/
protected $_name;
/**
* @var int
*/
protected $_caseMode = self::CASE_KEEP;
/**
* Set name of this asset
*
@ -57,7 +66,7 @@ abstract class AbstractAsset
*/
public function getName()
{
return $this->_name;
return $this->_foldIdentifier($this->_name);
}
/**
@ -82,4 +91,47 @@ abstract class AbstractAsset
$parts[] = $postfix;
return trim(implode("_", $parts), '_');
}
/**
* Set the case mode of this asset.
*
* @param string $caseMode
* @return void
*/
public function setCaseMode($caseMode)
{
if (!in_array($caseMode, array(self::CASE_KEEP, self::CASE_LOWER, self::CASE_UPPER))) {
throw SchemaException::invalidCaseModeGiven($caseMode);
}
$this->_caseMode = $caseMode;
}
/**
* Fold the case of the identifier based on the CASE_* constants.
*
* This has never to be applied on write operation, only on read! This ensures that you can change
* the case at any point. For the keys of arrays however we always store them in lower-case which
* makes it easy to access them. This affects the maps in Schema and Table instances.
*
* @param string $identifier
* @return string
*/
protected function _foldIdentifier($identifier)
{
if ($this->_caseMode == self::CASE_UPPER) {
return strtoupper($identifier);
} else if ($this->_caseMode == self::CASE_LOWER) {
return strtolower($identifier);
}
return $identifier;
}
/**
* @param array $identifiers
* @return array
*/
protected function _foldIdentifiers($identifiers)
{
return array_map(array($this, '_foldIdentifier'), $identifiers);
}
}

View File

@ -213,6 +213,8 @@ abstract class AbstractSchemaManager
/**
* List the indexes for a given table returning an array of Index instances.
*
* Keys of the portable indexes list are all lower-cased.
*
* @param string $table The name of the table
* @return Index[] $tableIndexes
*/
@ -830,12 +832,21 @@ abstract class AbstractSchemaManager
return $tableConstraint;
}
/**
* Independent of the database the keys of the column list result are lowercased.
*
* The name of the created column instance however is kept in its case.
*
* @param array $tableColumns
* @return array
*/
protected function _getPortableTableColumnList($tableColumns)
{
$list = array();
foreach ($tableColumns as $key => $column) {
if ($column = $this->_getPortableTableColumnDefinition($column)) {
$list[$column->getName()] = $column;
$name = strtolower($column->getName());
$list[$name] = $column;
}
}
return $list;
@ -864,6 +875,7 @@ abstract class AbstractSchemaManager
if($tableIndex['primary']) {
$keyName = 'primary';
}
$keyName = strtolower($keyName);
if(!isset($result[$keyName])) {
$result[$keyName] = array(

View File

@ -72,12 +72,12 @@ class ForeignKeyConstraint extends AbstractAsset implements Constraint
*/
public function getLocalColumns()
{
return $this->_localColumnNames;
return $this->_foldIdentifiers($this->_localColumnNames);
}
public function getColumns()
{
return $this->_localColumnNames;
return $this->_foldIdentifiers($this->_localColumnNames);
}
/**
@ -85,7 +85,7 @@ class ForeignKeyConstraint extends AbstractAsset implements Constraint
*/
public function getForeignTableName()
{
return $this->_foreignTableName;
return $this->_foldIdentifier($this->_foreignTableName);
}
/**
@ -93,7 +93,7 @@ class ForeignKeyConstraint extends AbstractAsset implements Constraint
*/
public function getForeignColumns()
{
return $this->_foreignColumnNames;
return $this->_foldIdentifiers($this->_foreignColumnNames);
}
public function hasOption($name)

View File

@ -76,7 +76,7 @@ class Index extends AbstractAsset implements Constraint
*/
public function getColumns()
{
return $this->_columns;
return $this->_foldIdentifiers($this->_columns);
}
/**
@ -102,6 +102,7 @@ class Index extends AbstractAsset implements Constraint
*/
public function hasColumnAtPosition($columnName, $pos=0)
{
return \array_search($columnName, $this->_columns) === $pos;
$columnName = $this->_foldIdentifier($columnName);
return \array_search($columnName, $this->getColumns()) === $pos;
}
}

View File

@ -65,6 +65,8 @@ class Schema extends AbstractAsset
*/
protected function _addTable(Table $table)
{
$table->setCaseMode($this->_caseMode);
$tableName = strtolower($table->getName());
if(isset($this->_tables[$tableName])) {
throw SchemaException::tableAlreadyExists($tableName);
@ -78,6 +80,8 @@ class Schema extends AbstractAsset
*/
protected function _addSequence(Sequence $sequence)
{
$sequence->setCaseMode($this->_caseMode);
$seqName = strtolower($sequence->getName());
if (isset($this->_sequences[$seqName])) {
throw SchemaException::sequenceAlreadyExists($seqName);

View File

@ -109,4 +109,9 @@ class SchemaException extends \Doctrine\DBAL\DBALException
{
return new self("There exists no foreign key with the name '".$fkName."'.", self::FOREIGNKEY_DOESNT_EXIST);
}
static public function invalidCaseModeGiven()
{
return new self("Invalid case mode given to Schema Asset.");
}
}

View File

@ -96,7 +96,7 @@ class Table extends AbstractAsset
*/
public function __construct($tableName, array $columns=array(), array $indexes=array(), array $fkConstraints=array(), $idGeneratorType=self::ID_NONE, array $options=array())
{
$this->_name = $tableName;
$this->_setName($tableName);
$this->_idGeneratorType = $idGeneratorType;
foreach ($columns AS $column) {
@ -215,7 +215,6 @@ class Table extends AbstractAsset
*/
public function renameColumn($oldColumnName, $newColumnName)
{
$columnName = strtolower($columnName);
$column = $this->getColumn($oldColumnName);
$this->dropColumn($oldColumnName);
@ -232,7 +231,6 @@ class Table extends AbstractAsset
*/
public function changeColumn($columnName, array $options)
{
$columnName = strtolower($columnName);
$column = $this->getColumn($columnName);
$column->setOptions($options);
return $this;
@ -339,9 +337,13 @@ class Table extends AbstractAsset
*/
protected function _addColumn(Column $column)
{
$columnName = strtolower($column->getName());
$column->setCaseMode($this->_caseMode);
$columnName = $column->getName();
$columnName = strtolower($columnName);
if (isset($this->_columns[$columnName])) {
throw SchemaException::columnAlreadyExists($this->_name, $columnName);
throw SchemaException::columnAlreadyExists($this->getName(), $columnName);
}
$this->_columns[$columnName] = $column;
@ -355,7 +357,10 @@ class Table extends AbstractAsset
*/
protected function _addIndex(Index $index)
{
$index->setCaseMode($this->_caseMode);
$indexName = $index->getName();
$indexName = strtolower($indexName);
if (isset($this->_indexes[$indexName]) || ($this->_primaryKeyName != false && $index->isPrimary())) {
throw SchemaException::indexAlreadyExists($indexName);
@ -374,6 +379,8 @@ class Table extends AbstractAsset
*/
protected function _addForeignKeyConstraint(ForeignKeyConstraint $constraint)
{
$constraint->setCaseMode($this->_caseMode);
if(strlen($constraint->getName())) {
$name = $constraint->getName();
} else {
@ -381,6 +388,7 @@ class Table extends AbstractAsset
array_merge((array)$this->getName(), $constraint->getLocalColumns()), "fk"
);
}
$name = strtolower($name);
$this->_fkConstraints[$name] = $constraint;
}
@ -393,6 +401,7 @@ class Table extends AbstractAsset
*/
public function hasForeignKey($constraintName)
{
$constraintName = strtolower($constraintName);
return isset($this->_fkConstraints[$constraintName]);
}
@ -402,6 +411,7 @@ class Table extends AbstractAsset
*/
public function getForeignKey($constraintName)
{
$constraintName = strtolower($constraintName);
if(!$this->hasForeignKey($constraintName)) {
throw SchemaException::foreignKeyDoesNotExist($constraintName);
}
@ -476,6 +486,7 @@ class Table extends AbstractAsset
*/
public function hasIndex($indexName)
{
$indexName = strtolower($indexName);
return (isset($this->_indexes[$indexName]));
}
@ -485,6 +496,7 @@ class Table extends AbstractAsset
*/
public function getIndex($indexName)
{
$indexName = strtolower($indexName);
if (!$this->hasIndex($indexName)) {
throw SchemaException::indexDoesNotExist($indexName);
}

View File

@ -109,15 +109,6 @@ class CreateSchemaSqlCollector implements Visitor
}
/**
* @param Table $table
* @param Constraint $constraint
*/
public function acceptCheckConstraint(Table $table, Constraint $constraint)
{
}
/**
* @param Sequence $sequence
*/

View File

@ -107,15 +107,6 @@ class DropSchemaSqlCollector implements Visitor
);
}
/**
* @param Table $table
* @param Constraint $constraint
*/
public function acceptCheckConstraint(Table $table, Constraint $constraint)
{
}
/**
* @param Table $table
* @param Index $index

View File

@ -62,12 +62,6 @@ interface Visitor
*/
public function acceptForeignKey(Table $localTable, ForeignKeyConstraint $fkConstraint);
/**
* @param Table $table
* @param Constraint $constraint
*/
public function acceptCheckConstraint(Table $table, Constraint $constraint);
/**
* @param Table $table
* @param Index $index

View File

@ -69,7 +69,7 @@ class SchemaManagerFunctionalTestCase extends \Doctrine\Tests\DbalFunctionalTest
$foundTable = false;
foreach ($tables AS $table) {
$this->assertType('Doctrine\DBAL\Schema\Table', $table);
if (strtolower($table->getName()) == 'list_tables_test') {
if ($table->getName() == 'list_tables_test') {
$foundTable = true;
$this->assertTrue($table->hasColumn('id'));
@ -94,10 +94,12 @@ class SchemaManagerFunctionalTestCase extends \Doctrine\Tests\DbalFunctionalTest
$columns = $this->_sm->listTableColumns('list_table_columns');
$columns = \array_change_key_case($columns, CASE_LOWER);
foreach ($columns AS $column) {
$column->setCaseMode("lower");
}
$this->assertArrayHasKey('id', $columns);
$this->assertEquals('id', strtolower($columns['id']->getname()));
$this->assertEquals('id', $columns['id']->getname());
$this->assertType('Doctrine\DBAL\Types\IntegerType', $columns['id']->gettype());
$this->assertEquals(false, $columns['id']->getunsigned());
$this->assertEquals(true, $columns['id']->getnotnull());
@ -105,7 +107,7 @@ class SchemaManagerFunctionalTestCase extends \Doctrine\Tests\DbalFunctionalTest
$this->assertType('array', $columns['id']->getPlatformOptions());
$this->assertArrayHasKey('test', $columns);
$this->assertEquals('test', strtolower($columns['test']->getname()));
$this->assertEquals('test', $columns['test']->getname());
$this->assertType('Doctrine\DBAL\Types\StringType', $columns['test']->gettype());
$this->assertEquals(255, $columns['test']->getlength());
$this->assertEquals(false, $columns['test']->getfixed());
@ -113,7 +115,7 @@ class SchemaManagerFunctionalTestCase extends \Doctrine\Tests\DbalFunctionalTest
$this->assertEquals(null, $columns['test']->getdefault());
$this->assertType('array', $columns['test']->getPlatformOptions());
$this->assertEquals('foo', strtolower($columns['foo']->getname()));
$this->assertEquals('foo', ($columns['foo']->getname()));
$this->assertType('Doctrine\DBAL\Types\TextType', $columns['foo']->gettype());
$this->assertEquals(null, $columns['foo']->getlength());
$this->assertEquals(false, $columns['foo']->getunsigned());
@ -122,7 +124,7 @@ class SchemaManagerFunctionalTestCase extends \Doctrine\Tests\DbalFunctionalTest
$this->assertEquals(null, $columns['foo']->getdefault());
$this->assertType('array', $columns['foo']->getPlatformOptions());
$this->assertEquals('bar', strtolower($columns['bar']->getname()));
$this->assertEquals('bar', ($columns['bar']->getname()));
$this->assertType('Doctrine\DBAL\Types\DecimalType', $columns['bar']->gettype());
$this->assertEquals(null, $columns['bar']->getlength());
$this->assertEquals(10, $columns['bar']->getprecision());
@ -133,19 +135,19 @@ class SchemaManagerFunctionalTestCase extends \Doctrine\Tests\DbalFunctionalTest
$this->assertEquals(null, $columns['bar']->getdefault());
$this->assertType('array', $columns['bar']->getPlatformOptions());
$this->assertEquals('baz1', strtolower($columns['baz1']->getname()));
$this->assertEquals('baz1', ($columns['baz1']->getname()));
$this->assertType('Doctrine\DBAL\Types\DateTimeType', $columns['baz1']->gettype());
$this->assertEquals(true, $columns['baz1']->getnotnull());
$this->assertEquals(null, $columns['baz1']->getdefault());
$this->assertType('array', $columns['baz1']->getPlatformOptions());
$this->assertEquals('baz2', strtolower($columns['baz2']->getname()));
$this->assertEquals('baz2', ($columns['baz2']->getname()));
$this->assertContains($columns['baz2']->gettype()->getName(), array('Time', 'Date', 'DateTime'));
$this->assertEquals(true, $columns['baz2']->getnotnull());
$this->assertEquals(null, $columns['baz2']->getdefault());
$this->assertType('array', $columns['baz2']->getPlatformOptions());
$this->assertEquals('baz3', strtolower($columns['baz3']->getname()));
$this->assertEquals('baz3', ($columns['baz3']->getname()));
$this->assertContains($columns['baz2']->gettype()->getName(), array('Time', 'Date', 'DateTime'));
$this->assertEquals(true, $columns['baz3']->getnotnull());
$this->assertEquals(null, $columns['baz3']->getdefault());
@ -212,11 +214,15 @@ class SchemaManagerFunctionalTestCase extends \Doctrine\Tests\DbalFunctionalTest
$fkeys = $this->_sm->listTableForeignKeys('test_create_fk1');
foreach ($fkeys AS $fkey) {
$fkey->setCaseMode("lower");
}
$this->assertEquals(1, count($fkeys));
$this->assertType('Doctrine\DBAL\Schema\ForeignKeyConstraint', $fkeys[0]);
$this->assertEquals(array('foreign_key_test'), array_map('strtolower', $fkeys[0]->getLocalColumns()));
$this->assertEquals(array('id'), array_map('strtolower', $fkeys[0]->getForeignColumns()));
$this->assertEquals('test_create_fk2', strtolower($fkeys[0]->getForeignTableName()));
$this->assertEquals('test_create_fk2', ($fkeys[0]->getForeignTableName()));
if($fkeys[0]->hasOption('onUpdate')) {
$this->assertEquals('CASCADE', $fkeys[0]->getOption('onUpdate'));