1
0
mirror of synced 2024-12-13 06:46:03 +03:00

[2.0] DDC-169 - Finalized implementation of Schema diff algorithm, added diffs of sequences and foreign keys. Fixed several bugs and changed the API of the Schema objects.

This commit is contained in:
beberlei 2009-11-29 15:51:14 +00:00
parent f22a56cdd7
commit 709dfb52c4
11 changed files with 467 additions and 85 deletions

View File

@ -59,4 +59,27 @@ abstract class AbstractAsset
{
return $this->_name;
}
/**
* Generate an identifier from a list of column names obeying a certain string length.
*
* This is especially important for Oracle, since it does not allow identifiers larger than 30 chars,
* however building idents automatically for foreign keys, composite keys or such can easily create
* very long names.
*
* @param array $columnNames
* @param string $postfix
* @param int $maxSize
* @return string
*/
protected function _generateIdentifierName($columnNames, $postfix='', $maxSize=30)
{
$columnCount = count($columnNames);
$postfixLen = strlen($postfix);
$parts = array_map(function($columnName) use($columnCount, $postfixLen, $maxSize) {
return substr($columnName, 0, floor(($maxSize-$postfixLen)/$columnCount - 1));
}, $columnNames);
$parts[] = $postfix;
return implode("_", $parts);
}
}

View File

@ -34,6 +34,19 @@ namespace Doctrine\DBAL\Schema;
*/
class Comparator
{
/**
* @var array
*/
private $_checkColumnPlatformOptions = array();
/**
* @param string $optionName
*/
public function addColumnPlatformOptionCheck($optionName)
{
$this->_checkColumnPlatformOptions[] = $optionName;
}
/**
* @param Schema $fromSchema
* @param Schema $toSchema
@ -79,11 +92,43 @@ class Comparator
}
}
// Todo add code for sequence diff
foreach ( $toSchema->getSequences() AS $sequenceName => $sequence) {
if (!$fromSchema->hasSequence($sequenceName)) {
$diff->newSequences[] = $sequence;
} else {
if ($this->diffSequence($sequence, $fromSchema->getSequence($sequenceName))) {
$diff->changedSequences[] = $fromSchema->getSequence($sequenceName);
}
}
}
foreach ($fromSchema->getSequences() AS $sequenceName => $sequence) {
if (!$toSchema->hasSequence($sequenceName)) {
$diff->removedSequences[] = $sequence;
}
}
return $diff;
}
/**
*
* @param Sequence $sequence1
* @param Sequence $sequence2
*/
public function diffSequence($sequence1, $sequence2)
{
if($sequence1->getAllocationSize() != $sequence2->getAllocationSize()) {
return true;
}
if($sequence1->getInitialValue() != $sequence2->getInitialValue()) {
return true;
}
return false;
}
/**
* Returns the difference between the tables $table1 and $table2.
*
@ -94,7 +139,7 @@ class Comparator
*
* @return bool|TableDiff
*/
private function diffTable( Table $table1, Table $table2 )
public function diffTable( Table $table1, Table $table2 )
{
$changes = 0;
$tableDifferences = new TableDiff();
@ -116,9 +161,8 @@ class Comparator
/* See if there are any changed fieldDefinitioninitions */
foreach ( $table1->getColumns() as $columnName => $column ) {
if ( $table2->hasColumn($columnName) ) {
$fieldDifferences = $this->diffField( $column, $table2->getColumn($columnName) );
if ( $fieldDifferences ) {
$tableDifferences->changedFields[$columnName] = $fieldDifferences;
if ( $this->diffColumn( $column, $table2->getColumn($columnName) ) ) {
$tableDifferences->changedFields[$columnName] = $table2->getColumn($columnName);
$changes++;
}
}
@ -144,19 +188,71 @@ class Comparator
/* See if there are any changed indexDefinitions */
foreach ( $table1Indexes as $indexName => $indexDefinition ) {
if ( isset( $table2Indexes[$indexName] ) ) {
$indexDifferences = $this->diffIndex( $indexDefinition, $table2Indexes[$indexName] );
if ( $indexDifferences ) {
$tableDifferences->changedIndexes[$indexName] = $indexDifferences;
if ( $this->diffIndex( $indexDefinition, $table2Indexes[$indexName] ) ) {
$tableDifferences->changedIndexes[$indexName] = $table2Indexes[$indexName];
$changes++;
}
}
}
// Todo add code for foreign key differences
foreach ($table2->getForeignKeys() AS $constraint) {
$fkName = $constraint->getName();
if (!$table1->hasForeignKey($fkName)) {
$tableDifferences->addedForeignKeys[$fkName] = $constraint;
$changes++;
} else {
if ($this->diffForeignKey($constraint, $table1->getForeignKey($fkName))) {
$tableDifferences->changedForeignKeys[$fkName] = $constraint;
$changes++;
}
}
}
foreach ($table1->getForeignKeys() AS $constraint) {
$fkName = $constraint->getName();
if (!$table2->hasForeignKey($fkName)) {
$tableDifferences->removedForeignKeys[$fkName] = $constraint;
$changes++;
}
}
return $changes ? $tableDifferences : false;
}
/**
* @param ForeignKeyConstraint $key1
* @param ForeignKeyConstraint $key2
* @return bool
*/
public function diffForeignKey($key1, $key2)
{
if ($key1->getLocalColumnNames() != $key2->getLocalColumnNames()) {
return true;
}
if ($key1->getForeignColumnNames() != $key2->getForeignColumnNames()) {
return true;
}
if ($key1->hasOption('onUpdate') != $key2->hasOption('onUpdate')) {
return true;
}
if ($key1->getOption('onUpdate') != $key2->getOption('onUpdate')) {
return true;
}
if ($key1->hasOption('onDelete') != $key2->hasOption('onDelete')) {
return true;
}
if ($key1->getOption('onDelete') != $key2->getOption('onDelete')) {
return true;
}
return false;
}
/**
* Returns the difference between the fields $field1 and $field2.
*
@ -166,12 +262,53 @@ class Comparator
* @param Column $column1
* @param Column $column2
*
* @return bool|Column
* @return bool
*/
private function diffField( Column $column1, Column $column2 )
public function diffColumn( Column $column1, Column $column2 )
{
if ( $column1->getType() != $column2->getType() ) {
return $column2;
return true;
}
if ($column1->getNotnull() != $column2->getNotnull()) {
return true;
}
if ($column1->getDefault() != $column2->getDefault()) {
return true;
}
if ($column1->getUnsigned() != $column2->getUnsigned()) {
return true;
}
if ($column1->getType() instanceof \Doctrine\DBAL\Types\StringType) {
if ($column1->getLength() != $column2->getLength()) {
return true;
}
if ($column1->getFixed() != $column2->getFixed()) {
return true;
}
}
if ($column1->getType() instanceof \Doctrine\DBAL\Types\DecimalType) {
if ($column1->getPrecision() != $column2->getPrecision()) {
return true;
}
if ($column1->getScale() != $column2->getScale()) {
return true;
}
}
foreach ($this->_checkColumnPlatformOptions AS $optionName) {
if ($column1->hasPlatformOption($optionName) != $column2->hasPlatformOption($optionName)) {
return true;
}
if ($column1->getPlatformOption($optionName) != $column2->getPlatformOption($optionName)) {
return true;
}
}
return false;
@ -185,15 +322,15 @@ class Comparator
*
* @param Index $index1
* @param Index $index2
* @return bool|Index
* @return bool
*/
private function diffIndex( Index $index1, Index $index2 )
public function diffIndex( Index $index1, Index $index2 )
{
if($index1->isPrimary() != $index2->isPrimary()) {
return $index2;
return true;
}
if($index1->isUnique() != $index2->isUnique()) {
return $index2;
return true;
}
// Check for removed index fields in $index2
@ -201,7 +338,7 @@ class Comparator
for($i = 0; $i < count($index1Columns); $i++) {
$indexColumn = $index1Columns[$i];
if (!$index2->hasColumnAtPosition($indexColumn, $i)) {
return $index2;
return true;
}
}
@ -210,7 +347,7 @@ class Comparator
for($i = 0; $i < count($index2Columns); $i++) {
$indexColumn = $index2Columns[$i];
if (!$index1->hasColumnAtPosition($indexColumn, $i)) {
return $index2;
return true;
}
}

View File

@ -48,6 +48,8 @@ class Index extends AbstractAsset
*/
public function __construct($indexName, array $columns, $isUnique=false, $isPrimary=false)
{
$isUnique = ($isPrimary)?true:$isUnique;
$this->_setName($indexName);
$this->_isUnique = $isUnique;
$this->_isPrimary = $isPrimary;

View File

@ -39,21 +39,36 @@ class SchemaDiff
*
* @var array(string=>ezcDbSchemaTable)
*/
public $newTables;
public $newTables = array();
/**
* All changed tables
*
* @var array(string=>ezcDbSchemaTableDiff)
*/
public $changedTables;
public $changedTables = array();
/**
* All removed tables
*
* @var array(string=>bool)
* @var array(string=>Table)
*/
public $removedTables;
public $removedTables = array();
/**
* @var array
*/
public $newSequences = array();
/**
* @var array
*/
public $changedSequences = array();
/**
* @var array
*/
public $removedSequences = array();
/**
* Constructs an SchemaDiff object.

View File

@ -13,6 +13,7 @@ class SchemaException extends \Doctrine\DBAL\DBALException
const SEQUENCE_DOENST_EXIST = 70;
const SEQUENCE_ALREADY_EXISTS = 80;
const INDEX_INVALID_NAME = 90;
const FOREIGNKEY_DOESNT_EXIST = 100;
/**
* @param string $tableName
@ -99,4 +100,13 @@ class SchemaException extends \Doctrine\DBAL\DBALException
{
return new self("There exists no sequence with the name '".$sequenceName."'.", self::SEQUENCE_DOENST_EXIST);
}
/**
* @param string $fkName
* @return SchemaException
*/
static public function foreignKeyDoesNotExist($fkName)
{
return new self("There exists no foreign key with the name '".$fkName."'.", self::FOREIGNKEY_DOESNT_EXIST);
}
}

View File

@ -73,7 +73,7 @@ class Table extends AbstractAsset
/**
* @var array
*/
protected $_constraints = array();
protected $_fkConstraints = array();
/**
* @var array
@ -90,11 +90,11 @@ class Table extends AbstractAsset
* @param string $tableName
* @param array $columns
* @param array $indexes
* @param array $constraints
* @param array $fkConstraints
* @param int $idGeneratorType
* @param array $options
*/
public function __construct($tableName, array $columns=array(), array $indexes=array(), array $constraints=array(), $idGeneratorType=self::ID_NONE, array $options=array())
public function __construct($tableName, array $columns=array(), array $indexes=array(), array $fkConstraints=array(), $idGeneratorType=self::ID_NONE, array $options=array())
{
$this->_name = $tableName;
$this->_idGeneratorType = $idGeneratorType;
@ -107,8 +107,8 @@ class Table extends AbstractAsset
$this->_addIndex($idx);
}
foreach ($constraints AS $constraint) {
$this->_addConstraint($constraint);
foreach ($fkConstraints AS $constraint) {
$this->_addForeignKeyConstraint($constraint);
}
$this->_options = $options;
@ -143,6 +143,10 @@ class Table extends AbstractAsset
*/
public function addIndex(array $columnNames, $indexName=null)
{
if($indexName == null) {
$indexName = $this->_generateIdentifierName($columnNames, "idx");
}
return $this->_createIndex($columnNames, $indexName, false, false);
}
@ -154,6 +158,10 @@ class Table extends AbstractAsset
*/
public function addUniqueIndex(array $columnNames, $indexName=null)
{
if ($indexName == null) {
$indexName = $this->_generateIdentifierName($columnNames, "uniq");
}
return $this->_createIndex($columnNames, $indexName, true, false);
}
@ -241,13 +249,31 @@ class Table extends AbstractAsset
/**
* Add a foreign key constraint
*
* Name is inferred from the local columns
*
* @param Table $foreignTable
* @param array $localColumns
* @param array $foreignColumns
* @param array $options
* @return Table
*/
public function addForeignKeyConstraint($foreignTable, array $localColumnNames, array $foreignColumnNames, $name=null, array $options=array())
public function addForeignKeyConstraint($foreignTable, array $localColumnNames, array $foreignColumnNames, array $options=array())
{
$name = $this->_generateIdentifierName($localColumnNames, "fk");
return $this->addNamedForeignKeyConstraint($name, $foreignTable, $localColumnNames, $foreignColumnNames, $options);
}
/**
* Add a foreign key constraint with a given name
*
* @param string $name
* @param Table $foreignTable
* @param array $localColumns
* @param array $foreignColumns
* @param array $options
* @return Table
*/
public function addNamedForeignKeyConstraint($name, $foreignTable, array $localColumnNames, array $foreignColumnNames, array $options=array())
{
if ($foreignTable instanceof Table) {
$foreignTableName = $foreignTable->getName();
@ -270,7 +296,7 @@ class Table extends AbstractAsset
$constraint = new ForeignKeyConstraint(
$localColumnNames, $foreignTableName, $foreignColumnNames, $name, $options
);
$this->_addConstraint($constraint);
$this->_addForeignKeyConstraint($constraint);
return $this;
}
@ -323,9 +349,33 @@ class Table extends AbstractAsset
/**
* @param Constraint $constraint
*/
protected function _addConstraint(Constraint $constraint)
protected function _addForeignKeyConstraint(Constraint $constraint)
{
$this->_constraints[] = $constraint;
$this->_fkConstraints[$constraint->getName()] = $constraint;
}
/**
* Does Table have a foreign key constraint with the given name?
* *
* @param string $constraintName
* @return bool
*/
public function hasForeignKey($constraintName)
{
return isset($this->_fkConstraints[$constraintName]);
}
/**
* @param string $constraintName
* @return ForeignKeyConstraint
*/
public function getForeignKey($constraintName)
{
if(!$this->hasForeignKey($constraintName)) {
throw SchemaException::foreignKeyDoesNotExist($constraintName);
}
return $this->_fkConstraints[$constraintName];
}
/**
@ -421,9 +471,9 @@ class Table extends AbstractAsset
*
* @return array
*/
public function getConstraints()
public function getForeignKeys()
{
return $this->_constraints;
return $this->_fkConstraints;
}
public function hasOption($name)
@ -456,12 +506,8 @@ class Table extends AbstractAsset
$visitor->acceptIndex($this, $index);
}
foreach ($this->getConstraints() AS $constraint) {
if ($constraint instanceof ForeignKeyConstraint) {
foreach ($this->getForeignKeys() AS $constraint) {
$visitor->acceptForeignKey($this, $constraint);
} else {
$visitor->acceptCheckConstraint($this, $constraint);
}
}
}
}

View File

@ -44,37 +44,58 @@ class TableDiff
/**
* All changed fields
*
* @var array(string=>ezcDbSchemaField)
* @var array(string=>Column)
*/
public $changedFields;
public $changedFields = array();
/**
* All removed fields
*
* @var array(string=>bool)
*/
public $removedFields;
public $removedFields = array();
/**
* All added indexes
*
* @var array(string=>ezcDbSchemaIndex)
* @var array(string=>Index)
*/
public $addedIndexes;
public $addedIndexes = array();
/**
* All changed indexes
*
* @var array(string=>ezcDbSchemaIndex)
* @var array(string=>Index)
*/
public $changedIndexes;
public $changedIndexes = array();
/**
* All removed indexes
*
* @var array(string=>bool)
*/
public $removedIndexes;
public $removedIndexes = array();
/**
* All added foreign key definitions
*
* @var array
*/
public $addedForeignKeys = array();
/**
* All changed foreign keys
*
* @var array
*/
public $changedForeignKeys = array();
/**
* All removed foreign keys
*
* @var array
*/
public $removedForeignKeys = array();
/**
* Constructs an TableDiff object.

View File

@ -179,8 +179,7 @@ class SchemaTool
// Add a FK constraint on the ID column
$table->addForeignKeyConstraint(
$this->_em->getClassMetadata($class->rootEntityName)->getQuotedTableName($this->_platform),
array($columnName), array($columnName), null,
array('onDelete' => 'CASCADE')
array($columnName), array($columnName), array('onDelete' => 'CASCADE')
);
}
@ -416,7 +415,7 @@ class SchemaTool
}
$theJoinTable->addForeignKeyConstraint(
$class->getQuotedTableName($this->_platform), $localColumns, $foreignColumns, null, $fkOptions
$class->getQuotedTableName($this->_platform), $localColumns, $foreignColumns, $fkOptions
);
}

View File

@ -193,31 +193,12 @@ class ComparatorTest extends \PHPUnit_Framework_TestCase
public function testCompareChangedColumns_ChangeType()
{
$schema1 = new Schema( array(
'bugdb' => new Table('bugdb',
array (
'charfield1' => new Column('charfield1', Type::getType('string')),
)
),
) );
$schema2 = new Schema( array(
'bugdb' => new Table('bugdb',
array (
'charfield1' => new Column('charfield1', Type::getType('integer')),
)
),
) );
$column1 = new Column('charfield1', Type::getType('string'));
$column2 = new Column('charfield1', Type::getType('integer'));
$expected = new SchemaDiff ( array(),
array (
'bugdb' => new TableDiff( array(),
array (
'charfield1' => new Column('charfield1', Type::getType('integer')),
)
),
)
);
$this->assertEquals($expected, Comparator::compareSchemas( $schema1, $schema2 ) );
$c = new Comparator();
$this->assertTrue($c->diffColumn($column1, $column2));
$this->assertFalse($c->diffColumn($column1, $column1));
}
public function testCompareRemovedIndex()
@ -354,4 +335,140 @@ class ComparatorTest extends \PHPUnit_Framework_TestCase
$actual = Comparator::compareSchemas( $schema1, $schema2 );
$this->assertEquals($expected, $actual);
}
public function testCompareChangedIndexFieldPositions()
{
$schema1 = new Schema( array(
'bugdb' => new Table('bugdb',
array (
'integerfield1' => new Column('integerfield1', Type::getType('integer')),
'integerfield2' => new Column('integerfield2', Type::getType('integer')),
),
array (
'primary' => new Index('primary', array('integerfield1', 'integerfield2'), true)
)
),
) );
$schema2 = new Schema( array(
'bugdb' => new Table('bugdb',
array (
'integerfield1' => new Column('integerfield1', Type::getType('integer')),
'integerfield2' => new Column('integerfield2', Type::getType('integer')),
),
array (
'primary' => new Index('primary', array('integerfield2', 'integerfield1'), true)
)
),
) );
$expected = new SchemaDiff ( array(),
array (
'bugdb' => new TableDiff( array(), array(), array(), array(),
array (
'primary' => new Index('primary', array('integerfield2', 'integerfield1'), true)
)
),
)
);
$actual = Comparator::compareSchemas( $schema1, $schema2 );
$this->assertEquals($expected, $actual);
}
public function testCompareSequences()
{
$seq1 = new Sequence('foo', 1, 1);
$seq2 = new Sequence('foo', 1, 2);
$seq3 = new Sequence('foo', 2, 1);
$c = new Comparator();
$this->assertTrue($c->diffSequence($seq1, $seq2));
$this->assertTrue($c->diffSequence($seq1, $seq3));
}
public function testRemovedSequence()
{
$schema1 = new Schema();
$seq = $schema1->createSequence('foo');
$schema2 = new Schema();
$c = new Comparator();
$diffSchema = $c->compare($schema1, $schema2);
$this->assertEquals(1, count($diffSchema->removedSequences));
$this->assertSame($seq, $diffSchema->removedSequences[0]);
}
public function testAddedSequence()
{
$schema1 = new Schema();
$schema2 = new Schema();
$seq = $schema2->createSequence('foo');
$c = new Comparator();
$diffSchema = $c->compare($schema1, $schema2);
$this->assertEquals(1, count($diffSchema->newSequences));
$this->assertSame($seq, $diffSchema->newSequences[0]);
}
public function testTableAddForeignKey()
{
$tableForeign = new Table("bar");
$tableForeign->createColumn('id', 'integer');
$table1 = new Table("foo");
$table1->createColumn('fk', 'integer');
$table2 = new Table("foo");
$table2->createColumn('fk', 'integer');
$table2->addForeignKeyConstraint($tableForeign, array('fk'), array('id'));
$c = new Comparator();
$tableDiff = $c->diffTable($table1, $table2);
$this->assertType('Doctrine\DBAL\Schema\TableDiff', $tableDiff);
$this->assertEquals(1, count($tableDiff->addedForeignKeys));
}
public function testTableRemoveForeignKey()
{
$tableForeign = new Table("bar");
$tableForeign->createColumn('id', 'integer');
$table1 = new Table("foo");
$table1->createColumn('fk', 'integer');
$table2 = new Table("foo");
$table2->createColumn('fk', 'integer');
$table2->addForeignKeyConstraint($tableForeign, array('fk'), array('id'));
$c = new Comparator();
$tableDiff = $c->diffTable($table2, $table1);
$this->assertType('Doctrine\DBAL\Schema\TableDiff', $tableDiff);
$this->assertEquals(1, count($tableDiff->removedForeignKeys));
}
public function testTableUpdateForeignKey()
{
$tableForeign = new Table("bar");
$tableForeign->createColumn('id', 'integer');
$table1 = new Table("foo");
$table1->createColumn('fk', 'integer');
$table1->addForeignKeyConstraint($tableForeign, array('fk'), array('id'));
$table2 = new Table("foo");
$table2->createColumn('fk', 'integer');
$table2->addForeignKeyConstraint($tableForeign, array('fk'), array('id'), array('onUpdate' => 'CASCADE'));
$c = new Comparator();
$tableDiff = $c->diffTable($table1, $table2);
$this->assertType('Doctrine\DBAL\Schema\TableDiff', $tableDiff);
$this->assertEquals(1, count($tableDiff->changedForeignKeys));
}
}

View File

@ -30,7 +30,7 @@ class IndexTest extends \PHPUnit_Framework_TestCase
public function testCreatePrimary()
{
$idx = $this->createIndex(false, true);
$this->assertFalse($idx->isUnique());
$this->assertTrue($idx->isUnique());
$this->assertTrue($idx->isPrimary());
}

View File

@ -86,6 +86,18 @@ class TableTest extends \PHPUnit_Framework_TestCase
$table = new Table("foo", $columns, array(), array());
}
public function testCreateIndex()
{
$type = \Doctrine\DBAL\Types\Type::getType('integer');
$columns = array(new Column("foo", $type), new Column("bar", $type), new Column("baz", $type));
$table = new Table("foo", $columns);
$table->addIndex(array("foo", "bar", "baz"));
$table->addUniqueIndex(array("foo", "bar", "baz"));
$this->assertTrue($table->hasIndex("foo_bar_baz_idx"));
$this->assertTrue($table->hasIndex("foo_bar_baz_uniq"));
}
public function testAddIndexes()
{
$type = \Doctrine\DBAL\Types\Type::getType('integer');
@ -159,10 +171,10 @@ class TableTest extends \PHPUnit_Framework_TestCase
$constraint = new ForeignKeyConstraint(array(), "foo", array());
$tableA = new Table("foo", array(), array(), array($constraint));
$constraints = $tableA->getConstraints();
$constraints = $tableA->getForeignKeys();
$this->assertEquals(1, count($constraints));
$this->assertSame($constraint, $constraints[0]);
$this->assertSame($constraint, array_shift($constraints));
}
public function testOptions()
@ -256,7 +268,7 @@ class TableTest extends \PHPUnit_Framework_TestCase
$foreignTable = new Table("bar");
$foreignTable->createColumn("id", 'int');
$table->addForeignKeyConstraint($foreignTable, array("foo"), array("id"), array());
$table->addForeignKeyConstraint($foreignTable, array("foo"), array("id"));
}
public function testAddForeignKeyConstraint_UnknownForeignColumn_ThrowsException()
@ -269,7 +281,7 @@ class TableTest extends \PHPUnit_Framework_TestCase
$foreignTable = new Table("bar");
$foreignTable->createColumn("id", 'integer');
$table->addForeignKeyConstraint($foreignTable, array("id"), array("foo"), array());
$table->addForeignKeyConstraint($foreignTable, array("id"), array("foo"));
}
public function testAddForeignKeyConstraint()
@ -280,15 +292,15 @@ class TableTest extends \PHPUnit_Framework_TestCase
$foreignTable = new Table("bar");
$foreignTable->createColumn("id", 'integer');
$table->addForeignKeyConstraint($foreignTable, array("id"), array("id"), "fkName", array("foo" => "bar"));
$table->addForeignKeyConstraint($foreignTable, array("id"), array("id"), array("foo" => "bar"));
$constraints = $table->getConstraints();
$constraints = $table->getForeignKeys();
$this->assertEquals(1, count($constraints));
$this->assertType('Doctrine\DBAL\Schema\ForeignKeyConstraint', $constraints[0]);
$this->assertType('Doctrine\DBAL\Schema\ForeignKeyConstraint', $constraints["id_fk"]);
$this->assertEquals("fkName", $constraints[0]->getName());
$this->assertTrue($constraints[0]->hasOption("foo"));
$this->assertEquals("bar", $constraints[0]->getOption("foo"));
$this->assertEquals("id_fk", $constraints["id_fk"]->getName());
$this->assertTrue($constraints["id_fk"]->hasOption("foo"));
$this->assertEquals("bar", $constraints["id_fk"]->getOption("foo"));
}
}