diff --git a/lib/Doctrine/Table.php b/lib/Doctrine/Table.php index 96108f0d5..70d958320 100644 --- a/lib/Doctrine/Table.php +++ b/lib/Doctrine/Table.php @@ -1145,13 +1145,53 @@ class Doctrine_Table extends Doctrine_Configurable implements Countable if (isset($this->identityMap[$id])) { $record = $this->identityMap[$id]; } else { - $record = new $this->options['name']($this); + $recordName = $this->getClassnameToReturn(); + $record = new $recordName($this); $this->identityMap[$id] = $record; } $this->data = array(); return $record; } + + /** + * Get the classname to return. Most often this is just the options['name'] + * + * Check the subclasses option and the inheritanceMap for each subclass to see + * if all the maps in a subclass is met. If this is the case return that + * subclass name. If no subclasses match or if there are no subclasses defined + * return the name of the class for this tables record. + * + * @todo this function could use reflection to check the first time it runs + * if the subclassing option is not set. + * + * @return string The name of the class to create + * + */ + public function getClassnameToReturn() + { + if(!isset($this->options["subclasses"])){ + return $this->options['name']; + } + foreach($this->options["subclasses"] as $subclass){ + $table = $this->conn->getTable($subclass); + $inheritanceMap = $table->getOption("inheritanceMap"); + $nomatch = false; + foreach($inheritanceMap as $key => $value){ + if(!isset($this->data[$key]) || $this->data[$key] != $value){ + $nomatch = true; + break; + } + } + if(!$nomatch){ + return $table->getComponentName(); + } + } + return $this->options['name']; + } + + + /** * @param $id database row id * @throws Doctrine_Find_Exception diff --git a/manual/codes/Object relational mapping - Relations - Inheritance - Column aggregation.php b/manual/codes/Object relational mapping - Relations - Inheritance - Column aggregation.php deleted file mode 100644 index 56e56b7d9..000000000 --- a/manual/codes/Object relational mapping - Relations - Inheritance - Column aggregation.php +++ /dev/null @@ -1,26 +0,0 @@ -hasColumn("name","string",30); - $this->hasColumn("username","string",20); - $this->hasColumn("password","string",16); - $this->hasColumn("created","integer",11); - - // this column is used for column - // aggregation inheritance - $this->hasColumn("type", "integer", 11); - } -} - -class User extends Entity { - public function setUp() { - $this->setInheritanceMap(array("type"=>1)); - } -} - -class Group extends Entity { - public function setUp() { - $this->setInheritanceMap(array("type"=>2)); - } -} -?> diff --git a/manual/docs/Object relational mapping - Relations - Inheritance - Column aggregation.php b/manual/docs/Object relational mapping - Relations - Inheritance - Column aggregation.php index 8d399c14c..ee7969fe3 100644 --- a/manual/docs/Object relational mapping - Relations - Inheritance - Column aggregation.php +++ b/manual/docs/Object relational mapping - Relations - Inheritance - Column aggregation.php @@ -1,8 +1,87 @@ -In the following example we have one database table called 'entity'. -Users and groups are both entities and they share the same database table. -

-The entity table has a column called 'type' which tells whether an entity is a group or a user. -Then we decide that users are type 1 and groups type 2. +In the following example we have one database table called 'entity'. Users and groups are both entities and they share the same database table. + +The entity table has a column called 'type' which tells whether an entity is a group or a user. Then we decide that users are type 1 and groups type 2. + +The only thing we have to do is to create 3 records (the same as before) and add call the Doctrine_Table::setInheritanceMap() method inside the setUp() method. + + +class Entity extends Doctrine_Record { + public function setTableDefinition() { + $this->hasColumn("name","string",30); + $this->hasColumn("username","string",20); + $this->hasColumn("password","string",16); + $this->hasColumn("created","integer",11); + + // this column is used for column + // aggregation inheritance + $this->hasColumn("type", "integer", 11); + } +} + +class User extends Entity { + public function setUp() { + $this->setInheritanceMap(array("type"=>1)); + } +} + +class Group extends Entity { + public function setUp() { + $this->setInheritanceMap(array("type"=>2)); + } +} + + +If we want to be able to fetch a record from the Entity table and automatically get a User record if the Entity we fetched is a user we have to do set the subclasses option in the parent class. The adjusted example: + + +class Entity extends Doctrine_Record { + public function setTableDefinition() { + $this->hasColumn("name","string",30); + $this->hasColumn("username","string",20); + $this->hasColumn("password","string",16); + $this->hasColumn("created","integer",11); + + // this column is used for column + // aggregation inheritance + $this->hasColumn("type", "integer", 11); + $this->option("subclasses", array("User", "Group"); + } +} + +class User extends Entity { + public function setUp() { + $this->setInheritanceMap(array("type"=>1)); + } +} + +class Group extends Entity { + public function setUp() { + $this->setInheritanceMap(array("type"=>2)); + } +} + + +We can then do the following given the previous table mapping. + + +$user = new User(); +$user->name="Bjarte S. Karlsen"; +$user->username="meus"; +$user->password="rat"; +$user->save(); + +$group = new Group(); +$group->name="Users"; +$group->username="users"; +$group->password="password"; +$group->save(); + +$q = Doctrine_Query(); +$user = $q->from("Entity")->where("id=?")->execute(array($user->id))->getFirst(); + +$q = Doctrine_Query(); +$group = $q->from("Entity")->where("id=?")->execute(array($group->id))->getFirst(); + + +The user object is here an instance of User while the group object is an instance of Group. -The only thing we have to do is to create 3 records (the same as before) and add -call the Doctrine_Table::setInheritanceMap() method inside the setUp() method. diff --git a/tests/ColumnAggregationInheritanceTestCase.php b/tests/ColumnAggregationInheritanceTestCase.php new file mode 100644 index 000000000..6df43b9d9 --- /dev/null +++ b/tests/ColumnAggregationInheritanceTestCase.php @@ -0,0 +1,67 @@ +. + */ + +/** + * Doctrine_ColumnAlias_TestCase + * + * @package Doctrine + * @author Bjarte Stien Karlsen + * @license http://www.opensource.org/licenses/lgpl-license.php LGPL + * @category Object Relational Mapping + * @link www.phpdoctrine.com + * @since 1.0 + * @version $Revision$ + */ +class Doctrine_ColumnAggregationInheritance_TestCase extends Doctrine_UnitTestCase +{ + protected $otherEntity = null; + + public function prepareData() + { + + parent::prepareData(); + //we create a test entity that is not a user and not a group + $entity = new Entity(); + $entity->name="Other Entity"; + $entity->type = 2; + $entity->save(); + $this->otherEntity = $entity; + } + + public function testQueriedClassReturnedIfNoSubclassMatch() + { + $q = new Doctrine_Query(); + $entityOther = $q->from("Entity")->where("id=?")->execute(array($this->otherEntity->id))->getFirst(); + $this->assertTrue($entityOther instanceOf Entity); + } + + public function testSubclassReturnedIfInheritanceMatches() + { + $q = new Doctrine_Query(); + $group = $q->from("Entity")->where("id=?")->execute(array(1))->getFirst(); + $this->assertTrue($group instanceOf Group); + + $q = new Doctrine_Query(); + $user = $q->from("Entity")->where("id=?")->execute(array(5))->getFirst(); + $this->assertTrue($user instanceOf User); + } +} + diff --git a/tests/classes.php b/tests/classes.php index 59786c4af..505662c83 100644 --- a/tests/classes.php +++ b/tests/classes.php @@ -15,6 +15,7 @@ class Entity extends Doctrine_Record { $this->hasColumn('created', 'integer',11); $this->hasColumn('updated', 'integer',11); $this->hasColumn('email_id', 'integer'); + $this->option('subclasses',array('User','Group')); } } class FieldNameTest extends Doctrine_Record { diff --git a/tests/run.php b/tests/run.php index a24c7b373..24e1a158e 100644 --- a/tests/run.php +++ b/tests/run.php @@ -222,6 +222,7 @@ $test->addTestCase(new Doctrine_Query_Having_TestCase()); $test->addTestCase(new Doctrine_Query_From_TestCase()); $test->addTestCase(new Doctrine_Query_JoinCondition_TestCase()); $test->addTestCase(new Doctrine_ColumnAlias_TestCase()); +$test->addTestCase(new Doctrine_ColumnAggregationInheritance_TestCase()); $test->addTestCase(new Doctrine_Query_Subquery_TestCase()); $test->addTestCase(new Doctrine_Query_Join_TestCase()); @@ -239,6 +240,7 @@ $test->addTestCase(new Doctrine_Cache_Sqlite_TestCase()); //$test->addTestCase(new Doctrine_Cache_FileTestCase()); //$test->addTestCase(new Doctrine_Cache_SqliteTestCase()); + class MyReporter extends HtmlReporter { public function paintHeader() {} public function paintFooter()