Commit f402f879 authored by meus's avatar meus

Added support for fetching a subclass when querying the baseclass if the

inheritance mapping is met. Added tests for this and included tests. Wrote
documentation. 
parent 1af2164b
......@@ -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
......
<?php
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));
}
}
?>
In the following example we have one database table called 'entity'.
Users and groups are both entities and they share the same database table.
<br \><br \>
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.
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.
<code type="php">
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));
}
}
</code>
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:
<code type="php">
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));
}
}
</code>
We can then do the following given the previous table mapping.
<code type="php">
$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();
</code>
The user object is here an instance of User while the group object is an instance of Group.
<?php
/*
* $Id$
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* This software consists of voluntary contributions made by many individuals
* and is licensed under the LGPL. For more information, see
* <http://www.phpdoctrine.com>.
*/
/**
* Doctrine_ColumnAlias_TestCase
*
* @package Doctrine
* @author Bjarte Stien Karlsen <bjartka@pvv.ntnu.no>
* @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);
}
}
......@@ -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 {
......
......@@ -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()
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment