diff --git a/lib/Doctrine.php b/lib/Doctrine.php index e28493709..95747a8a9 100644 --- a/lib/Doctrine.php +++ b/lib/Doctrine.php @@ -344,14 +344,14 @@ final class Doctrine * turns of exporting */ const EXPORT_NONE = 0; - /** - * export constraints - */ - const EXPORT_CONSTRAINTS = 1; /** * export tables */ - const EXPORT_TABLES = 2; + const EXPORT_TABLES = 1; + /** + * export constraints + */ + const EXPORT_CONSTRAINTS = 2; /** * export all */ diff --git a/lib/Doctrine/Configurable.php b/lib/Doctrine/Configurable.php index 437e006d6..9912b28b2 100644 --- a/lib/Doctrine/Configurable.php +++ b/lib/Doctrine/Configurable.php @@ -94,7 +94,8 @@ abstract class Doctrine_Configurable } break; case Doctrine::ATTR_CREATE_TABLES: - $value = (bool) $value; + $attribute = Doctrine::ATTR_EXPORT; + $value = Doctrine::EXPORT_ALL; break; case Doctrine::ATTR_ACCESSORS: $accessors = array('none','get','set','both'); @@ -128,6 +129,7 @@ abstract class Doctrine_Configurable case Doctrine::ATTR_ACCESSOR_PREFIX_SET: case Doctrine::ATTR_EMULATE_DATABASE: case Doctrine::ATTR_DEFAULT_SEQUENCE: + case Doctrine::ATTR_EXPORT: break; case Doctrine::ATTR_SEQCOL_NAME: diff --git a/lib/Doctrine/Connection.php b/lib/Doctrine/Connection.php index 9b45c64a1..ce11661ba 100644 --- a/lib/Doctrine/Connection.php +++ b/lib/Doctrine/Connection.php @@ -758,6 +758,10 @@ abstract class Doctrine_Connection extends Doctrine_Configurable implements Coun $this->tables[$name] = $table; + if ($table->getAttribute(Doctrine::ATTR_EXPORT) & Doctrine::EXPORT_TABLES) { + $table->export(); + } + return $table; } /** diff --git a/lib/Doctrine/Locking/Manager/Pessimistic.php b/lib/Doctrine/Locking/Manager/Pessimistic.php index b57079ab4..647187616 100644 --- a/lib/Doctrine/Locking/Manager/Pessimistic.php +++ b/lib/Doctrine/Locking/Manager/Pessimistic.php @@ -58,7 +58,7 @@ class Doctrine_Locking_Manager_Pessimistic { $this->conn = $conn; - if ($this->conn->getAttribute(Doctrine::ATTR_CREATE_TABLES) === true) { + if ($this->conn->getAttribute(Doctrine::ATTR_EXPORT) & Doctrine::EXPORT_TABLES) { $columns = array(); $columns['object_type'] = array('type' => 'string', 'length' => 50, diff --git a/lib/Doctrine/Manager.php b/lib/Doctrine/Manager.php index c32136c93..d081d39ff 100644 --- a/lib/Doctrine/Manager.php +++ b/lib/Doctrine/Manager.php @@ -114,6 +114,7 @@ class Doctrine_Manager extends Doctrine_Configurable implements Countable, Itera Doctrine::ATTR_QUOTE_IDENTIFIER => false, Doctrine::ATTR_SEQCOL_NAME => 'id', Doctrine::ATTR_PORTABILITY => Doctrine::PORTABILITY_ALL, + Doctrine::ATTR_EXPORT => Doctrine::EXPORT_NONE, ); foreach ($attributes as $attribute => $value) { $old = $this->getAttribute($attribute); diff --git a/lib/Doctrine/Relation.php b/lib/Doctrine/Relation.php index df3d0518b..74f392ce7 100644 --- a/lib/Doctrine/Relation.php +++ b/lib/Doctrine/Relation.php @@ -66,6 +66,7 @@ abstract class Doctrine_Relation 'onDelete' => false, 'onUpdate' => false, 'deferred' => false, + 'constraint' => false, ); /** * constructor @@ -91,6 +92,8 @@ abstract class Doctrine_Relation * * type the relation type, either Doctrine_Relation::ONE or Doctrine_Relation::MANY * + * constraint boolean value, true if the relation needs referential integrity constraint + * * The onDelete and onUpdate keys accept the following values: * * CASCADE: Delete or update the row from the parent table and automatically delete or @@ -119,6 +122,8 @@ abstract class Doctrine_Relation } if (isset($definition[$key])) { $def[$key] = $definition[$key]; + } else { + $def[$key] = null; } } @@ -133,6 +138,15 @@ abstract class Doctrine_Relation { return $this->definition; } + /** + * hasConstraint + * + * @return boolean + */ + public function hasConstraint() + { + return $this->definition['constraint']; + } /** * getAlias * returns the relation alias diff --git a/lib/Doctrine/Table.php b/lib/Doctrine/Table.php index d6106e87d..c133874b3 100644 --- a/lib/Doctrine/Table.php +++ b/lib/Doctrine/Table.php @@ -295,9 +295,7 @@ class Doctrine_Table extends Doctrine_Configurable implements Countable } */ - if ($this->getAttribute(Doctrine::ATTR_CREATE_TABLES)) { - $this->export(); - } + } } else { @@ -362,13 +360,21 @@ class Doctrine_Table extends Doctrine_Configurable implements Countable $primary[] = $name; } } - /** - foreach ($this->getRelations() as $name => $relation) { - $fk = $relation->toArray(); - $fk['foreignTable'] = $relation->getTable()->getTableName(); - $options['foreignKeys'][] = $fk; - } */ + if ($this->getAttribute(Doctrine::ATTR_EXPORT) & Doctrine::EXPORT_CONSTRAINTS) { + + foreach ($this->getRelations() as $name => $relation) { + $fk = $relation->toArray(); + $fk['foreignTable'] = $relation->getTable()->getTableName(); + + if ($relation->hasConstraint()) { + + $options['foreignKeys'][] = $fk; + } elseif ($relation instanceof Doctrine_Relation_LocalKey) { + $options['foreignKeys'][] = $fk; + } + } + } $options['primary'] = $primary; @@ -847,6 +853,7 @@ class Doctrine_Table extends Doctrine_Configurable implements Countable unset($definition['field']); $definition['table'] = $this->conn->getTable($definition['class'], false); + $definition['constraint'] = false; if ($component == $this->options['name'] || in_array($component, $this->options['parents'])) { @@ -872,6 +879,7 @@ class Doctrine_Table extends Doctrine_Configurable implements Countable } //$definition['foreign'] = $tmp; + $definition['constraint'] = true; $relation = new Doctrine_Relation_ForeignKey($definition); } @@ -882,6 +890,9 @@ class Doctrine_Table extends Doctrine_Configurable implements Countable if ( ! isset($defintion['local'])) { $definition['local'] = $this->identifier; } + + $definition['constraint'] = true; + // ONE-TO-MANY or ONE-TO-ONE $relation = new Doctrine_Relation_ForeignKey($definition); @@ -914,7 +925,7 @@ class Doctrine_Table extends Doctrine_Configurable implements Countable if ($e2[0] != $component) { throw new Doctrine_Table_Exception($e2[0] . ' doesn\'t match ' . $component); } - $associationTable = $this->conn->getTable($e2[0], false); + $associationTable = $this->conn->getTable($e2[0]); if (count($fields) > 1) { // SELF-REFERENCING THROUGH JOIN TABLE diff --git a/tests/Export/MysqlTestCase.php b/tests/Export/MysqlTestCase.php index 41e67766a..674f9239c 100644 --- a/tests/Export/MysqlTestCase.php +++ b/tests/Export/MysqlTestCase.php @@ -32,6 +32,11 @@ */ class Doctrine_Export_Mysql_TestCase extends Doctrine_UnitTestCase { + public function prepareTables() + { } + public function prepareData() + { } + public function testAlterTableThrowsExceptionWithoutValidTableName() { try { @@ -248,7 +253,8 @@ class Doctrine_Export_Mysql_TestCase extends Doctrine_UnitTestCase $this->assertEqual($this->adapter->pop(), 'CREATE TABLE sometable (id INT UNSIGNED AUTO_INCREMENT, content VARCHAR(4), FULLTEXT INDEX myindex (content DESC), PRIMARY KEY(id)) ENGINE = MYISAM'); } - public function testExportSupportsIndexes() + + public function testExportSupportsIndexes() { $r = new MysqlIndexTestRecord; @@ -259,19 +265,45 @@ class Doctrine_Export_Mysql_TestCase extends Doctrine_UnitTestCase { $r = new MysqlForeignKeyTest; - $this->assertEqual($this->adapter->pop(), 'CREATE TABLE mysql_foreign_key_test (id BIGINT AUTO_INCREMENT, name TEXT, code INT, content TEXT, parent_id BIGINT, FOREIGN KEY id REFERENCES mysql_foreign_key_test(parent_id) ON UPDATE RESTRICT ON DELETE CASCADE, PRIMARY KEY(id)) ENGINE = INNODB'); + $this->assertEqual($this->adapter->pop(), 'CREATE TABLE mysql_foreign_key_test (id BIGINT AUTO_INCREMENT, name TEXT, code INT, content TEXT, parent_id BIGINT, FOREIGN KEY parent_id REFERENCES mysql_foreign_key_test(id), FOREIGN KEY id REFERENCES mysql_foreign_key_test(parent_id) ON UPDATE RESTRICT ON DELETE CASCADE, PRIMARY KEY(id)) ENGINE = INNODB'); } + + public function testExportSupportsForeignKeysWithoutAttributes() + { + $r = new MysqlForeignKeyTest2; + + $this->assertEqual($this->adapter->pop(), 'CREATE TABLE mysql_foreign_key_test2 (id BIGINT AUTO_INCREMENT, name TEXT, foreignkey BIGINT, FOREIGN KEY foreignkey REFERENCES mysql_foreign_key_test(id), PRIMARY KEY(id)) ENGINE = INNODB'); + + } + public function testExportSupportsForeignKeysForManyToManyRelations() + { + $r = new MysqlUser; + + $this->assertEqual($this->adapter->pop(), 'CREATE TABLE mysql_user (id BIGINT AUTO_INCREMENT, name TEXT, PRIMARY KEY(id)) ENGINE = INNODB'); + + $r->MysqlGroup[0]; + + $this->assertEqual($this->adapter->pop(), 'CREATE TABLE mysql_group (id BIGINT AUTO_INCREMENT, name TEXT, PRIMARY KEY(id)) ENGINE = INNODB'); + + + $this->assertEqual($this->adapter->pop(), 'CREATE TABLE mysql_group_member (group_id BIGINT, user_id BIGINT, PRIMARY KEY(group_id, user_id)) ENGINE = INNODB'); + } + } class MysqlForeignKeyTest extends Doctrine_Record { - public function setTableDefinition() + public function setTableDefinition() { $this->hasColumn('name', 'string', null); $this->hasColumn('code', 'integer', 4); $this->hasColumn('content', 'string', 4000); $this->hasColumn('parent_id', 'integer'); - $this->hasMany('MysqlForeignKeyTest as Children', + $this->hasOne('MysqlForeignKeyTest as Parent', + 'MysqlForeignKeyTest.parent_id' + ); + + $this->hasMany('MysqlForeignKeyTest as Children', 'MysqlForeignKeyTest.parent_id', array('onDelete' => 'CASCADE', 'onUpdate' => 'RESTRICT') @@ -281,7 +313,43 @@ class MysqlForeignKeyTest extends Doctrine_Record } } -class MysqlIndexTestRecord extends Doctrine_Record +class MysqlGroupMember extends Doctrine_Record +{ + public function setTableDefinition() + { + $this->hasColumn('group_id', 'integer', null, 'primary'); + $this->hasColumn('user_id', 'integer', null, 'primary'); + } +} +class MysqlUser extends Doctrine_Record +{ + public function setTableDefinition() + { + $this->hasColumn('name', 'string', null); + + $this->hasMany('MysqlGroup', 'MysqlGroupMember.group_id'); + } +} +class MysqlGroup extends Doctrine_Record +{ + public function setTableDefinition() + { + $this->hasColumn('name', 'string', null); + + $this->hasMany('MysqlUser', 'MysqlGroupMember.user_id'); + } +} +class MysqlForeignKeyTest2 extends Doctrine_Record +{ + public function setTableDefinition() + { + $this->hasColumn('name', 'string', null); + $this->hasColumn('foreignkey', 'integer'); + + $this->hasOne('MysqlForeignKeyTest', 'MysqlForeignKeyTest2.foreignkey'); + } +} +class MysqlIndexTestRecord extends Doctrine_Record { public function setTableDefinition() { diff --git a/tests/Relation/ManyToManyTestCase.php b/tests/Relation/ManyToManyTestCase.php index c2f7bf7b3..ce7e9c231 100644 --- a/tests/Relation/ManyToManyTestCase.php +++ b/tests/Relation/ManyToManyTestCase.php @@ -5,7 +5,7 @@ class M2MTest extends Doctrine_Record { $this->hasColumn('child_id', 'integer'); } public function setUp() { - $this->ownsMany('OwnsOneToManyWithAlias as AliasO2M', 'AliasO2M.component_id'); + $this->hasMany('RTC1 as RTC1', 'JC1.c1_id'); $this->hasMany('RTC2 as RTC2', 'JC1.c1_id'); $this->hasMany('RTC3 as RTC3', 'JC2.c1_id'); @@ -155,9 +155,10 @@ class Doctrine_Relation_ManyToMany_TestCase extends Doctrine_UnitTestCase { } public function testUnknownManyToManyRelation() { - $component = new RelationErrorTest(); - try { + $component = new RelationErrorTest(); + + $rel = $component->getTable()->getRelation('RTCUnknown'); $this->fail(); } catch(Doctrine_Table_Exception $e) { @@ -211,7 +212,6 @@ class Doctrine_Relation_ManyToMany_TestCase extends Doctrine_UnitTestCase { public function testManyToManyHasRelationWithAliases() { $component = new M2MTest(); - $component->AliasO2M; try { $rel = $component->getTable()->getRelation('RTC1'); diff --git a/tests/UnitOfWorkTestCase.php b/tests/UnitOfWorkTestCase.php index b11de9c19..e29506746 100644 --- a/tests/UnitOfWorkTestCase.php +++ b/tests/UnitOfWorkTestCase.php @@ -22,7 +22,8 @@ class Doctrine_UnitOfWork_TestCase extends Doctrine_UnitTestCase { $this->assertEqual($tree, $this->correct); $tree = $this->unitOfWork->buildFlushTree(array("Assignment","Task","Resource")); - $this->assertEqual($tree, $this->correct2); + + $this->assertEqual($tree, $this->correct); } public function testbuildFlushTree2() { $this->correct = array("Forum_Category","Forum_Board","Forum_Thread"); diff --git a/tests/UnitTestCase.php b/tests/UnitTestCase.php index c61661cc9..a8d814f38 100644 --- a/tests/UnitTestCase.php +++ b/tests/UnitTestCase.php @@ -29,7 +29,7 @@ class Doctrine_UnitTestCase extends UnitTestCase { $this->manager = Doctrine_Manager::getInstance(); $this->manager->setAttribute(Doctrine::ATTR_FETCHMODE, Doctrine::FETCH_IMMEDIATE); - + $this->manager->setAttribute(Doctrine::ATTR_EXPORT, Doctrine::EXPORT_ALL); $this->tables = array_merge($this->tables, array("entity", @@ -92,6 +92,7 @@ class Doctrine_UnitTestCase extends UnitTestCase { $this->listener = $this->manager->getAttribute(Doctrine::ATTR_LISTENER); $this->manager->setAttribute(Doctrine::ATTR_LISTENER, $this->listener); + } catch(Doctrine_Manager_Exception $e) { if($this->driverName == 'main') { $this->dbh = Doctrine_Db::getConnection('sqlite::memory:'); diff --git a/tests/run.php b/tests/run.php index f7e8b21db..a24c7b373 100644 --- a/tests/run.php +++ b/tests/run.php @@ -62,7 +62,7 @@ $test = new GroupTest('Doctrine Framework Unit Tests'); // DATABASE ABSTRACTION tests -/** + // Connection drivers (not yet fully tested) $test->addTestCase(new Doctrine_Connection_Pgsql_TestCase()); $test->addTestCase(new Doctrine_Connection_Oracle_TestCase()); @@ -108,12 +108,13 @@ $test->addTestCase(new Doctrine_Export_TestCase()); //$test->addTestCase(new Doctrine_Export_Reporter_TestCase()); $test->addTestCase(new Doctrine_Export_Firebird_TestCase()); $test->addTestCase(new Doctrine_Export_Informix_TestCase()); -$test->addTestCase(new Doctrine_Export_Mysql_TestCase()); + $test->addTestCase(new Doctrine_Export_Mssql_TestCase()); $test->addTestCase(new Doctrine_Export_Pgsql_TestCase()); $test->addTestCase(new Doctrine_Export_Oracle_TestCase()); $test->addTestCase(new Doctrine_Export_Sqlite_TestCase()); +$test->addTestCase(new Doctrine_Export_Mysql_TestCase()); // Import module (not yet fully tested) //$test->addTestCase(new Doctrine_Import_TestCase()); @@ -153,6 +154,7 @@ $test->addTestCase(new Doctrine_Collection_TestCase()); $test->addTestCase(new Doctrine_TreeStructure_TestCase()); $test->addTestCase(new Doctrine_Relation_TestCase()); + $test->addTestCase(new Doctrine_Relation_Access_TestCase()); $test->addTestCase(new Doctrine_Relation_ManyToMany_TestCase()); $test->addTestCase(new Doctrine_Relation_OneToOne_TestCase()); @@ -163,13 +165,15 @@ $test->addTestCase(new Doctrine_Boolean_TestCase()); // Utility components -$test->addTestCase(new Doctrine_Hook_TestCase()); + $test->addTestCase(new Doctrine_PessimisticLocking_TestCase()); $test->addTestCase(new Doctrine_RawSql_TestCase()); $test->addTestCase(new Doctrine_View_TestCase()); + $test->addTestCase(new Doctrine_Validator_TestCase()); +$test->addTestCase(new Doctrine_Hook_TestCase()); // Db component $test->addTestCase(new Doctrine_Db_TestCase()); @@ -196,7 +200,7 @@ $test->addTestCase(new Doctrine_CustomResultSetOrderTestCase()); //$test->addTestCase(new Doctrine_Collection_Offset_TestCase()); -// Query tests */ +// Query tests $test->addTestCase(new Doctrine_Query_MultiJoin_TestCase()); $test->addTestCase(new Doctrine_Query_ReferenceModel_TestCase()); @@ -205,7 +209,7 @@ $test->addTestCase(new Doctrine_Query_ComponentAlias_TestCase()); $test->addTestCase(new Doctrine_Query_TestCase()); $test->addTestCase(new Doctrine_Query_ShortAliases_TestCase()); - +$test->addTestCase(new Doctrine_Query_Delete_TestCase()); $test->addTestCase(new Doctrine_Query_Where_TestCase()); $test->addTestCase(new Doctrine_Query_Limit_TestCase()); $test->addTestCase(new Doctrine_Query_IdentifierQuoting_TestCase()); @@ -229,7 +233,6 @@ $test->addTestCase(new Doctrine_Cache_Apc_TestCase()); $test->addTestCase(new Doctrine_Cache_Memcache_TestCase()); $test->addTestCase(new Doctrine_Cache_Sqlite_TestCase()); -$test->addTestCase(new Doctrine_Query_Delete_TestCase()); // Cache tests //$test->addTestCase(new Doctrine_Cache_Query_SqliteTestCase());