Commit b66d5305 authored by romanb's avatar romanb

[2.0] Class table inheritance updates. Started work on self-referencing associations.

parent c9cc9f13
...@@ -409,7 +409,7 @@ class Connection ...@@ -409,7 +409,7 @@ class Connection
*/ */
public function fetchAll($sql, array $params = array()) public function fetchAll($sql, array $params = array())
{ {
return $this->execute($sql, $params)->fetchAll(PDO::FETCH_ASSOC); return $this->execute($sql, $params)->fetchAll(\PDO::FETCH_ASSOC);
} }
/** /**
......
...@@ -22,9 +22,11 @@ ...@@ -22,9 +22,11 @@
namespace Doctrine\ORM; namespace Doctrine\ORM;
/** /**
* A repository provides the illusion of an in-memory Entity store. * An EntityRepository serves as a repository for entities with generic as well as
* Base class for all custom user-defined repositories. * business specific methods for retrieving entities.
* Provides basic finder methods, common to all repositories. *
* This class is designed for inheritance and users can subclass this class to
* write their own repositories.
* *
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL * @license http://www.opensource.org/licenses/lgpl-license.php LGPL
* @link www.doctrine-project.org * @link www.doctrine-project.org
......
...@@ -95,13 +95,16 @@ class ObjectHydrator extends AbstractHydrator ...@@ -95,13 +95,16 @@ class ObjectHydrator extends AbstractHydrator
$this->_fetchedAssociations[$assoc->sourceEntityName][$assoc->sourceFieldName] = true; $this->_fetchedAssociations[$assoc->sourceEntityName][$assoc->sourceFieldName] = true;
if ($assoc->mappedByFieldName) { if ($assoc->mappedByFieldName) {
$this->_fetchedAssociations[$assoc->targetEntityName][$assoc->mappedByFieldName] = true; $this->_fetchedAssociations[$assoc->targetEntityName][$assoc->mappedByFieldName] = true;
} else if ($inverseAssoc = $this->_em->getClassMetadata($assoc->targetEntityName) } else {
->inverseMappings[$assoc->sourceFieldName]) { $targetClass = $this->_em->getClassMetadata($assoc->targetEntityName);
if (isset($targetClass->inverseMappings[$assoc->sourceFieldName])) {
$inverseAssoc = $targetClass->inverseMappings[$assoc->sourceFieldName];
$this->_fetchedAssociations[$assoc->targetEntityName][$inverseAssoc->sourceFieldName] = true; $this->_fetchedAssociations[$assoc->targetEntityName][$inverseAssoc->sourceFieldName] = true;
} }
} }
} }
} }
}
/** /**
* {@inheritdoc} * {@inheritdoc}
...@@ -230,10 +233,11 @@ class ObjectHydrator extends AbstractHydrator ...@@ -230,10 +233,11 @@ class ObjectHydrator extends AbstractHydrator
} }
} }
private function getEntity(array $data, $className) private function getEntity(array $data, $dqlAlias)
{ {
if (isset($this->_rsm->discriminatorColumns[$className])) { $className = $this->_rsm->aliasMap[$dqlAlias];
$discrColumn = $this->_rsm->discriminatorColumns[$className]; if (isset($this->_rsm->discriminatorColumns[$dqlAlias])) {
$discrColumn = $this->_rsm->discriminatorColumns[$dqlAlias];
$className = $this->_discriminatorMap[$className][$data[$discrColumn]]; $className = $this->_discriminatorMap[$className][$data[$discrColumn]];
unset($data[$discrColumn]); unset($data[$discrColumn]);
} }
...@@ -351,7 +355,7 @@ class ObjectHydrator extends AbstractHydrator ...@@ -351,7 +355,7 @@ class ObjectHydrator extends AbstractHydrator
$index = $indexExists ? $this->_identifierMap[$path][$id[$parent]][$id[$dqlAlias]] : false; $index = $indexExists ? $this->_identifierMap[$path][$id[$parent]][$id[$dqlAlias]] : false;
$indexIsValid = $index !== false ? $this->isIndexKeyInUse($baseElement, $relationAlias, $index) : false; $indexIsValid = $index !== false ? $this->isIndexKeyInUse($baseElement, $relationAlias, $index) : false;
if ( ! $indexExists || ! $indexIsValid) { if ( ! $indexExists || ! $indexIsValid) {
$element = $this->getEntity($data, $entityName); $element = $this->getEntity($data, $dqlAlias);
// If it's a bi-directional many-to-many, also initialize the reverse collection. // If it's a bi-directional many-to-many, also initialize the reverse collection.
if ($relation->isManyToMany()) { if ($relation->isManyToMany()) {
...@@ -393,7 +397,7 @@ class ObjectHydrator extends AbstractHydrator ...@@ -393,7 +397,7 @@ class ObjectHydrator extends AbstractHydrator
if ( ! isset($nonemptyComponents[$dqlAlias])) { if ( ! isset($nonemptyComponents[$dqlAlias])) {
//$this->setRelatedElement($baseElement, $relationAlias, null); //$this->setRelatedElement($baseElement, $relationAlias, null);
} else { } else {
$this->setRelatedElement($baseElement, $relationAlias, $this->getEntity($data, $entityName)); $this->setRelatedElement($baseElement, $relationAlias, $this->getEntity($data, $dqlAlias));
} }
} }
} }
...@@ -411,7 +415,7 @@ class ObjectHydrator extends AbstractHydrator ...@@ -411,7 +415,7 @@ class ObjectHydrator extends AbstractHydrator
$this->_rootAliases[$dqlAlias] = true; // Mark as root alias $this->_rootAliases[$dqlAlias] = true; // Mark as root alias
if ($this->_isSimpleQuery || ! isset($this->_identifierMap[$dqlAlias][$id[$dqlAlias]])) { if ($this->_isSimpleQuery || ! isset($this->_identifierMap[$dqlAlias][$id[$dqlAlias]])) {
$element = $this->getEntity($rowData[$dqlAlias], $entityName); $element = $this->getEntity($rowData[$dqlAlias], $dqlAlias);
if ($field = $this->_getCustomIndexField($dqlAlias)) { if ($field = $this->_getCustomIndexField($dqlAlias)) {
if ($this->_rsm->isMixed) { if ($this->_rsm->isMixed) {
$result[] = array( $result[] = array(
......
...@@ -27,7 +27,7 @@ namespace Doctrine\ORM; ...@@ -27,7 +27,7 @@ namespace Doctrine\ORM;
* @author Roman Borschel <roman@code-factory.org> * @author Roman Borschel <roman@code-factory.org>
* @since 2.0 * @since 2.0
*/ */
class NativeQuery extends AbstractQuery final class NativeQuery extends AbstractQuery
{ {
private $_sql; private $_sql;
......
...@@ -199,78 +199,64 @@ class JoinedSubclassPersister extends StandardEntityPersister ...@@ -199,78 +199,64 @@ class JoinedSubclassPersister extends StandardEntityPersister
} }
/** /**
* Adds all parent classes as INNER JOINs and subclasses as OUTER JOINs * Gets the SELECT SQL to select a single entity by a set of field criteria.
* to the query.
* *
* Callback that is invoked during the SQL construction process. * @param array $criteria
* * @return string The SQL.
* @return array The custom joins in the format <className> => <joinType> * @todo Quote identifier.
* @override
*/ */
/*public function getCustomJoins() protected function _getSelectSingleEntitySql(array $criteria)
{ {
$customJoins = array(); $tableAliases = array();
$classMetadata = $this->_classMetadata; $aliasIndex = 1;
foreach ($classMetadata->parentClasses as $parentClass) { $idColumns = $this->_class->getIdentifierColumnNames();
$customJoins[$parentClass] = 'INNER'; $baseTableAlias = 't0';
}
foreach ($classMetadata->subClasses as $subClass) { foreach (array_merge($this->_class->subClasses, $this->_class->parentClasses) as $className) {
if ($subClass != $this->getComponentName()) { $tableAliases[$className] = 't' . $aliasIndex++;
$customJoins[$subClass] = 'LEFT';
} }
$columnList = '';
foreach ($this->_class->fieldMappings as $fieldName => $mapping) {
$tableAlias = isset($mapping['inherited']) ?
$tableAliases[$mapping['inherited']] : $baseTableAlias;
if ($columnList != '') $columnList .= ', ';
$columnList .= $tableAlias . '.' . $this->_class->columnNames[$fieldName];
} }
return $customJoins; $sql = 'SELECT ' . $columnList . ' FROM ' . $this->_class->primaryTable['name']. ' ' . $baseTableAlias;
}*/
/** // INNER JOIN parent tables
* Adds the discriminator column to the selected fields in a query as well as foreach ($this->_class->parentClasses as $parentClassName) {
* all fields of subclasses. In Class Table Inheritance the default behavior is that $parentClass = $this->_em->getClassMetadata($parentClassName);
* all subclasses are joined in through OUTER JOINs when querying a base class. $tableAlias = $tableAliases[$parentClassName];
* $sql .= ' INNER JOIN ' . $parentClass->primaryTable['name'] . ' ' . $tableAlias . ' ON ';
* Callback that is invoked during the SQL construction process. $first = true;
* foreach ($idColumns as $idColumn) {
* @return array An array with the field names that will get added to the query. if ($first) $first = false; else $sql .= ' AND ';
*/ $sql .= $baseTableAlias . '.' . $idColumn . ' = ' . $tableAlias . '.' . $idColumn;
/*public function getCustomFields()
{
$classMetadata = $this->_classMetadata;
$conn = $this->_conn;
$discrColumn = $classMetadata->discriminatorColumn;
$fields = array($discrColumn['name']);
if ($classMetadata->subClasses) {
foreach ($classMetadata->subClasses as $subClass) {
$fields = array_merge($conn->getClassMetadata($subClass)->fieldNames, $fields);
} }
} }
return array_unique($fields);
}*/
/** // OUTER JOIN sub tables
* foreach ($this->_class->subClasses as $subClassName) {
* @todo Looks like this better belongs into the ClassMetadata class. $subClass = $this->_em->getClassMetadata($subClassName);
*/ $tableAlias = $tableAliases[$subClassName];
/*public function getOwningClass($fieldName) $sql .= ' LEFT JOIN ' . $subClass->primaryTable['name'] . ' ' . $tableAlias . ' ON ';
{ $first = true;
$conn = $this->_conn; foreach ($idColumns as $idColumn) {
$classMetadata = $this->_classMetadata; if ($first) $first = false; else $sql .= ' AND ';
if ($classMetadata->hasField($fieldName) && ! $classMetadata->isInheritedField($fieldName)) { $sql .= $baseTableAlias . '.' . $idColumn . ' = ' . $tableAlias . '.' . $idColumn;
return $classMetadata;
}
foreach ($classMetadata->parentClasses as $parentClass) {
$parentTable = $conn->getClassMetadata($parentClass);
if ($parentTable->hasField($fieldName) && ! $parentTable->isInheritedField($fieldName)) {
return $parentTable;
} }
} }
foreach ((array)$classMetadata->subClasses as $subClass) { $conditionSql = '';
$subTable = $conn->getClassMetadata($subClass); foreach ($criteria as $field => $value) {
if ($subTable->hasField($fieldName) && ! $subTable->isInheritedField($fieldName)) { if ($conditionSql != '') $conditionSql .= ' AND ';
return $subTable; $conditionSql .= $baseTableAlias . '.' . $this->_class->columnNames[$field] . ' = ?';
}
} }
throw \Doctrine\Common\DoctrineException::updateMe("Unable to find defining class of field '$fieldName'."); return $sql . ' WHERE ' . $conditionSql;
}*/ }
} }
\ No newline at end of file
...@@ -199,26 +199,21 @@ class StandardEntityPersister ...@@ -199,26 +199,21 @@ class StandardEntityPersister
//... //...
} }
/**
* Callback that is invoked during the SQL construction process.
*/
public function getCustomJoins()
{
return array();
}
/**
* Callback that is invoked during the SQL construction process.
*/
public function getCustomFields()
{
return array();
}
/** /**
* Prepares the data changeset of an entity for database insertion. * Prepares the data changeset of an entity for database insertion.
* The array that is passed as the second parameter is filled with * The array that is passed as the second parameter is filled with
* <columnName> => <value> pairs during this preparation. * <columnName> => <value> pairs, grouped by table name, during this preparation.
*
* Example:
* <code>
* array(
* 'foo_table' => array('column1' => 'value1', 'column2' => 'value2', ...),
* 'bar_table' => array('columnX' => 'valueX', 'columnY' => 'valueY', ...),
* ...
* )
* </code>
*
* Notes to inheritors: Be sure to call <code>parent::_prepareData($entity, $result, $isInsert);</code>
* *
* @param object $entity * @param object $entity
* @param array $result The reference to the data array. * @param array $result The reference to the data array.
...@@ -227,7 +222,9 @@ class StandardEntityPersister ...@@ -227,7 +222,9 @@ class StandardEntityPersister
protected function _prepareData($entity, array &$result, $isInsert = false) protected function _prepareData($entity, array &$result, $isInsert = false)
{ {
$platform = $this->_conn->getDatabasePlatform(); $platform = $this->_conn->getDatabasePlatform();
foreach ($this->_em->getUnitOfWork()->getEntityChangeSet($entity) as $field => $change) { $uow = $this->_em->getUnitOfWork();
foreach ($uow->getEntityChangeSet($entity) as $field => $change) {
$oldVal = $change[0]; $oldVal = $change[0];
$newVal = $change[1]; $newVal = $change[1];
...@@ -239,6 +236,18 @@ class StandardEntityPersister ...@@ -239,6 +236,18 @@ class StandardEntityPersister
if ( ! $assocMapping->isOneToOne() || $assocMapping->isInverseSide()) { if ( ! $assocMapping->isOneToOne() || $assocMapping->isInverseSide()) {
continue; continue;
} }
//TODO: If the one-one is self-referencing, check whether the referenced entity ($newVal)
// is still scheduled for insertion. If so:
// 1) set $newVal = null, so that we insert a null value
// 2) schedule $entity for an update, so that the FK gets set through an update
// later, after the referenced entity has been inserted.
//$needsPostponedUpdate = ...
/*if ($assocMapping->sourceEntityName == $assocMapping->targetEntityName &&
isset($this->_queuedInserts[spl_object_hash($entity)])) {
echo "SELF-REFERENCING!";
}*/
foreach ($assocMapping->sourceToTargetKeyColumns as $sourceColumn => $targetColumn) { foreach ($assocMapping->sourceToTargetKeyColumns as $sourceColumn => $targetColumn) {
$otherClass = $this->_em->getClassMetadata($assocMapping->targetEntityName); $otherClass = $this->_em->getClassMetadata($assocMapping->targetEntityName);
if ($newVal === null) { if ($newVal === null) {
...@@ -283,7 +292,7 @@ class StandardEntityPersister ...@@ -283,7 +292,7 @@ class StandardEntityPersister
$stmt->execute(array_values($criteria)); $stmt->execute(array_values($criteria));
$data = array(); $data = array();
foreach ($stmt->fetch(\PDO::FETCH_ASSOC) as $column => $value) { foreach ($stmt->fetch(\PDO::FETCH_ASSOC) as $column => $value) {
$fieldName = $this->_class->lcColumnToFieldNames[$column]; $fieldName = $this->_class->fieldNames[$column];
$data[$fieldName] = Type::getType($this->_class->getTypeOfField($fieldName)) $data[$fieldName] = Type::getType($this->_class->getTypeOfField($fieldName))
->convertToPHPValue($value); ->convertToPHPValue($value);
} }
......
...@@ -36,7 +36,7 @@ use Doctrine\ORM\Query\QueryException; ...@@ -36,7 +36,7 @@ use Doctrine\ORM\Query\QueryException;
* @author Konsta Vesterinen <kvesteri@cc.hut.fi> * @author Konsta Vesterinen <kvesteri@cc.hut.fi>
* @author Roman Borschel <roman@code-factory.org> * @author Roman Borschel <roman@code-factory.org>
*/ */
class Query extends AbstractQuery final class Query extends AbstractQuery
{ {
/** /**
* A query object is in CLEAN state when it has NO unparsed/unprocessed DQL parts. * A query object is in CLEAN state when it has NO unparsed/unprocessed DQL parts.
...@@ -53,32 +53,32 @@ class Query extends AbstractQuery ...@@ -53,32 +53,32 @@ class Query extends AbstractQuery
/** /**
* @var integer $_state The current state of this query. * @var integer $_state The current state of this query.
*/ */
protected $_state = self::STATE_CLEAN; private $_state = self::STATE_CLEAN;
/** /**
* @var string $_dql Cached DQL query. * @var string $_dql Cached DQL query.
*/ */
protected $_dql = null; private $_dql = null;
/** /**
* @var Doctrine\ORM\Query\ParserResult The parser result that holds DQL => SQL information. * @var Doctrine\ORM\Query\ParserResult The parser result that holds DQL => SQL information.
*/ */
protected $_parserResult; private $_parserResult;
/** /**
* @var CacheDriver The cache driver used for caching queries. * @var CacheDriver The cache driver used for caching queries.
*/ */
protected $_queryCache; private $_queryCache;
/** /**
* @var boolean Boolean value that indicates whether or not expire the query cache. * @var boolean Boolean value that indicates whether or not expire the query cache.
*/ */
protected $_expireQueryCache = false; private $_expireQueryCache = false;
/** /**
* @var int Query Cache lifetime. * @var int Query Cache lifetime.
*/ */
protected $_queryCacheTTL; private $_queryCacheTTL;
// End of Caching Stuff // End of Caching Stuff
......
<?php <?php
/*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/
namespace Doctrine\ORM\Query\AST; namespace Doctrine\ORM\Query\AST;
/** /**
* Description of JoinCollectionValuedPathExpression * JoinAssociationPathExpression ::= JoinCollectionValuedPathExpression | JoinSingleValuedAssociationPathExpression
* JoinCollectionValuedPathExpression ::= IdentificationVariable "." CollectionValuedAssociationField
* JoinSingleValuedAssociationPathExpression ::= IdentificationVariable "." SingleValuedAssociationField
* *
* @author robo * @author robo
* @todo Rename: JoinAssociationPathExpression * @todo Rename: JoinAssociationPathExpression
......
<?php <?php
/* /*
* To change this template, choose Tools | Templates * $Id$
* and open the template in the editor. *
* 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.doctrine-project.org>.
*/ */
namespace Doctrine\ORM\Query\AST; namespace Doctrine\ORM\Query\AST;
...@@ -13,6 +28,12 @@ namespace Doctrine\ORM\Query\AST; ...@@ -13,6 +28,12 @@ namespace Doctrine\ORM\Query\AST;
*/ */
class StateFieldPathExpression extends Node class StateFieldPathExpression extends Node
{ {
//const TYPE_COLLECTION_VALUED_ASSOCIATION = 1;
//const TYPE_SINGLE_VALUED_ASSOCIATION = 2;
//const TYPE_STATE_FIELD = 3;
//private $_type;
private $_parts; private $_parts;
// Information that is attached during semantical analysis. // Information that is attached during semantical analysis.
private $_isSimpleStateFieldPathExpression = false; private $_isSimpleStateFieldPathExpression = false;
......
...@@ -71,9 +71,9 @@ class ResultSetMapping ...@@ -71,9 +71,9 @@ class ResultSetMapping
* @param <type> $alias * @param <type> $alias
* @param <type> $discrColumn * @param <type> $discrColumn
*/ */
public function setDiscriminatorColumn($className, $alias, $discrColumn) public function setDiscriminatorColumn($alias, $discrColumn)
{ {
$this->discriminatorColumns[$className] = $discrColumn; $this->discriminatorColumns[$alias] = $discrColumn;
$this->columnOwnerMap[$discrColumn] = $alias; $this->columnOwnerMap[$discrColumn] = $alias;
} }
......
...@@ -122,6 +122,7 @@ class SqlWalker ...@@ -122,6 +122,7 @@ class SqlWalker
$this->_queryComponents[$dqlAlias]['relation'] $this->_queryComponents[$dqlAlias]['relation']
); );
} }
//if ($this->_query->getHydrationMode() == \Doctrine\ORM\Query::HYDRATE_OBJECT) { //if ($this->_query->getHydrationMode() == \Doctrine\ORM\Query::HYDRATE_OBJECT) {
if ($class->isInheritanceTypeSingleTable() || $class->isInheritanceTypeJoined()) { if ($class->isInheritanceTypeSingleTable() || $class->isInheritanceTypeJoined()) {
$rootClass = $this->_em->getClassMetadata($class->rootEntityName); $rootClass = $this->_em->getClassMetadata($class->rootEntityName);
...@@ -129,7 +130,7 @@ class SqlWalker ...@@ -129,7 +130,7 @@ class SqlWalker
$discrColumn = $rootClass->discriminatorColumn; $discrColumn = $rootClass->discriminatorColumn;
$columnAlias = $this->getSqlColumnAlias($discrColumn['name']); $columnAlias = $this->getSqlColumnAlias($discrColumn['name']);
$sql .= ", $tblAlias." . $discrColumn['name'] . ' AS ' . $columnAlias; $sql .= ", $tblAlias." . $discrColumn['name'] . ' AS ' . $columnAlias;
$this->_resultSetMapping->setDiscriminatorColumn($class->name, $dqlAlias, $columnAlias); $this->_resultSetMapping->setDiscriminatorColumn($dqlAlias, $columnAlias);
} }
//} //}
} }
...@@ -253,7 +254,7 @@ class SqlWalker ...@@ -253,7 +254,7 @@ class SqlWalker
$assoc = $targetQComp['relation']; $assoc = $targetQComp['relation'];
} }
if ($assoc->isOneToOne()/* || $assoc->isOneToMany()*/) { if ($assoc->isOneToOne()) {
$sql .= $targetTableName . ' ' . $targetTableAlias . ' ON '; $sql .= $targetTableName . ' ' . $targetTableAlias . ' ON ';
$joinColumns = $assoc->getSourceToTargetKeyColumns(); $joinColumns = $assoc->getSourceToTargetKeyColumns();
$first = true; $first = true;
......
<?php <?php
/*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/
namespace Doctrine\Tests\Models\Company; namespace Doctrine\Tests\Models\Company;
......
...@@ -9,7 +9,7 @@ use Doctrine\Tests\Models\Company\CompanyEmployee; ...@@ -9,7 +9,7 @@ use Doctrine\Tests\Models\Company\CompanyEmployee;
use Doctrine\Tests\Models\Company\CompanyManager; use Doctrine\Tests\Models\Company\CompanyManager;
/** /**
* Functional tests for the Single Table Inheritance mapping strategy. * Functional tests for the Class Table Inheritance mapping strategy.
* *
* @author robo * @author robo
*/ */
...@@ -22,7 +22,6 @@ class ClassTableInheritanceTest extends \Doctrine\Tests\OrmFunctionalTestCase ...@@ -22,7 +22,6 @@ class ClassTableInheritanceTest extends \Doctrine\Tests\OrmFunctionalTestCase
public function testCRUD() public function testCRUD()
{ {
$person = new CompanyPerson; $person = new CompanyPerson;
$person->setName('Roman S. Borschel'); $person->setName('Roman S. Borschel');
...@@ -89,4 +88,66 @@ class ClassTableInheritanceTest extends \Doctrine\Tests\OrmFunctionalTestCase ...@@ -89,4 +88,66 @@ class ClassTableInheritanceTest extends \Doctrine\Tests\OrmFunctionalTestCase
$this->assertEquals(2, $affected); $this->assertEquals(2, $affected);
*/ */
} }
public function testMultiLevelUpdateAndFind() {
$manager = new CompanyManager;
$manager->setName('Roman S. Borschel');
$manager->setSalary(100000);
$manager->setDepartment('IT');
$manager->setTitle('CTO');
$this->_em->save($manager);
$this->_em->flush();
$manager->setName('Roman B.');
$manager->setSalary(119000);
$manager->setTitle('CEO');
$this->_em->save($manager);
$this->_em->flush();
$this->_em->clear();
$manager = $this->_em->find('Doctrine\Tests\Models\Company\CompanyManager', $manager->getId());
$this->assertEquals('Roman B.', $manager->getName());
$this->assertEquals(119000, $manager->getSalary());
$this->assertEquals('CEO', $manager->getTitle());
$this->assertTrue(is_numeric($manager->getId()));
}
public function testSelfReferencingOneToOne() {
$manager = new CompanyManager;
$manager->setName('John Smith');
$manager->setSalary(100000);
$manager->setDepartment('IT');
$manager->setTitle('CTO');
$wife = new CompanyPerson;
$wife->setName('Mary Smith');
$wife->setSpouse($manager);
$this->assertSame($manager, $wife->getSpouse());
$this->assertSame($wife, $manager->getSpouse());
$this->_em->save($manager);
$this->_em->save($wife);
$this->_em->flush();
//var_dump($this->_em->getConnection()->fetchAll('select * from company_persons'));
//var_dump($this->_em->getConnection()->fetchAll('select * from company_employees'));
//var_dump($this->_em->getConnection()->fetchAll('select * from company_managers'));
$this->_em->clear();
$query = $this->_em->createQuery('select p, s from Doctrine\Tests\Models\Company\CompanyPerson p join p.spouse s where p.name=\'Mary Smith\'');
$result = $query->getResultList();
$this->assertEquals(1, count($result));
$this->assertTrue($result[0] instanceof CompanyPerson);
$this->assertEquals('Mary Smith', $result[0]->getName());
$this->assertTrue($result[0]->getSpouse() instanceof CompanyEmployee);
//var_dump($result);
}
} }
...@@ -39,6 +39,7 @@ class NativeQueryTest extends \Doctrine\Tests\OrmFunctionalTestCase ...@@ -39,6 +39,7 @@ class NativeQueryTest extends \Doctrine\Tests\OrmFunctionalTestCase
$users = $query->getResultList(); $users = $query->getResultList();
$this->assertEquals(1, count($users)); $this->assertEquals(1, count($users));
$this->assertTrue($users[0] instanceof CmsUser);
$this->assertEquals('Roman', $users[0]->name); $this->assertEquals('Roman', $users[0]->name);
} }
} }
......
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