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.
This commit is contained in:
parent
1af2164b19
commit
f402f879b2
@ -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
|
||||
|
@ -1,26 +0,0 @@
|
||||
<?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));
|
||||
}
|
||||
}
|
||||
?>
|
@ -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.
|
||||
<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.
|
||||
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.
|
||||
|
||||
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.
|
||||
|
67
tests/ColumnAggregationInheritanceTestCase.php
Normal file
67
tests/ColumnAggregationInheritanceTestCase.php
Normal file
@ -0,0 +1,67 @@
|
||||
<?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()
|
||||
|
Loading…
x
Reference in New Issue
Block a user