[2.0] DDC-169 - Introduced handling of schema / database case-sensitivity differences and to allow compability between different platforms.
This commit is contained in:
parent
15f84f6eb0
commit
b0bbe281f3
@ -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);
|
||||
}
|
||||
}
|
@ -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(
|
||||
|
@ -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)
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
@ -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);
|
||||
|
@ -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.");
|
||||
}
|
||||
}
|
@ -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);
|
||||
}
|
||||
|
@ -109,15 +109,6 @@ class CreateSchemaSqlCollector implements Visitor
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Table $table
|
||||
* @param Constraint $constraint
|
||||
*/
|
||||
public function acceptCheckConstraint(Table $table, Constraint $constraint)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Sequence $sequence
|
||||
*/
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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'));
|
||||
|
Loading…
Reference in New Issue
Block a user