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])) {
|
if (isset($this->identityMap[$id])) {
|
||||||
$record = $this->identityMap[$id];
|
$record = $this->identityMap[$id];
|
||||||
} else {
|
} else {
|
||||||
$record = new $this->options['name']($this);
|
$recordName = $this->getClassnameToReturn();
|
||||||
|
$record = new $recordName($this);
|
||||||
$this->identityMap[$id] = $record;
|
$this->identityMap[$id] = $record;
|
||||||
}
|
}
|
||||||
$this->data = array();
|
$this->data = array();
|
||||||
|
|
||||||
return $record;
|
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
|
* @param $id database row id
|
||||||
* @throws Doctrine_Find_Exception
|
* @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'.
|
In the following example we have one database table called 'entity'. Users and groups are both entities and they share the same database table.
|
||||||
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 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('created', 'integer',11);
|
||||||
$this->hasColumn('updated', 'integer',11);
|
$this->hasColumn('updated', 'integer',11);
|
||||||
$this->hasColumn('email_id', 'integer');
|
$this->hasColumn('email_id', 'integer');
|
||||||
|
$this->option('subclasses',array('User','Group'));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
class FieldNameTest extends Doctrine_Record {
|
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_From_TestCase());
|
||||||
$test->addTestCase(new Doctrine_Query_JoinCondition_TestCase());
|
$test->addTestCase(new Doctrine_Query_JoinCondition_TestCase());
|
||||||
$test->addTestCase(new Doctrine_ColumnAlias_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_Subquery_TestCase());
|
||||||
|
|
||||||
$test->addTestCase(new Doctrine_Query_Join_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_FileTestCase());
|
||||||
//$test->addTestCase(new Doctrine_Cache_SqliteTestCase());
|
//$test->addTestCase(new Doctrine_Cache_SqliteTestCase());
|
||||||
|
|
||||||
|
|
||||||
class MyReporter extends HtmlReporter {
|
class MyReporter extends HtmlReporter {
|
||||||
public function paintHeader() {}
|
public function paintHeader() {}
|
||||||
public function paintFooter()
|
public function paintFooter()
|
||||||
|
Loading…
x
Reference in New Issue
Block a user