[2.0] Some hydration simplifications and cleanups.
This commit is contained in:
parent
4f64490137
commit
59fff29c1b
@ -19,15 +19,6 @@ Url: http://www.symfony-project.org
|
|||||||
Copyright: Fabien Potencier
|
Copyright: Fabien Potencier
|
||||||
License: MIT - see LICENSE file
|
License: MIT - see LICENSE file
|
||||||
|
|
||||||
Spyc
|
|
||||||
----
|
|
||||||
|
|
||||||
Doctrine contains a port of the Spyc software
|
|
||||||
|
|
||||||
Url: http://spyc.sourceforge.net/
|
|
||||||
Copyright: 2005-2006 Chris Wanstrath
|
|
||||||
License: MIT - http://www.opensource.org/licenses/mit-license.php
|
|
||||||
|
|
||||||
Zend Framework
|
Zend Framework
|
||||||
--------------
|
--------------
|
||||||
|
|
||||||
|
@ -66,9 +66,9 @@ class DoctrineException extends \Exception
|
|||||||
if ($method && $class) {
|
if ($method && $class) {
|
||||||
return new self("The method '$method' is not implemented in class '$class'.");
|
return new self("The method '$method' is not implemented in class '$class'.");
|
||||||
} else if ($method && ! $class) {
|
} else if ($method && ! $class) {
|
||||||
return new self($method);
|
return new self($method);
|
||||||
} else {
|
} else {
|
||||||
return new self('Functionality is not implemented.');
|
return new self('Functionality is not implemented.');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -92,6 +92,10 @@ final class Events
|
|||||||
* into the current EntityManager from the database or after the refresh operation
|
* into the current EntityManager from the database or after the refresh operation
|
||||||
* has been applied to it.
|
* has been applied to it.
|
||||||
*
|
*
|
||||||
|
* Note that the postLoad event occurs for an entity before any associations have been
|
||||||
|
* initialized. Therefore it is not safe to access associations in a postLoad callback
|
||||||
|
* or event handler.
|
||||||
|
*
|
||||||
* This is an entity lifecycle event.
|
* This is an entity lifecycle event.
|
||||||
*
|
*
|
||||||
* @var string
|
* @var string
|
||||||
|
@ -162,7 +162,10 @@ abstract class AbstractHydrator
|
|||||||
/**
|
/**
|
||||||
* Gets the row container used during row-by-row hydration through {@link iterate()}.
|
* Gets the row container used during row-by-row hydration through {@link iterate()}.
|
||||||
*/
|
*/
|
||||||
abstract protected function _getRowContainer();
|
protected function _getRowContainer()
|
||||||
|
{
|
||||||
|
return array();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Processes a row of the result set.
|
* Processes a row of the result set.
|
||||||
|
@ -228,10 +228,4 @@ class ArrayHydrator extends AbstractHydrator
|
|||||||
}
|
}
|
||||||
return $this->_ce[$className];
|
return $this->_ce[$className];
|
||||||
}
|
}
|
||||||
|
|
||||||
/** {@inheritdoc} */
|
|
||||||
protected function _getRowContainer()
|
|
||||||
{
|
|
||||||
return array();
|
|
||||||
}
|
|
||||||
}
|
}
|
@ -8,4 +8,10 @@ class HydrationException extends \Doctrine\Common\DoctrineException
|
|||||||
{
|
{
|
||||||
return new self("The result returned by the query was not unique.");
|
return new self("The result returned by the query was not unique.");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static function parentObjectOfRelationNotFound($alias, $parentAlias)
|
||||||
|
{
|
||||||
|
return new self("The parent object of entity result with alias '$alias' was not found."
|
||||||
|
. " The parent alias is '$parentAlias'.");
|
||||||
|
}
|
||||||
}
|
}
|
@ -21,8 +21,7 @@
|
|||||||
|
|
||||||
namespace Doctrine\ORM\Internal\Hydration;
|
namespace Doctrine\ORM\Internal\Hydration;
|
||||||
|
|
||||||
use Doctrine\DBAL\Connection,
|
use Doctrine\ORM\PersistentCollection,
|
||||||
Doctrine\ORM\PersistentCollection,
|
|
||||||
Doctrine\ORM\Query,
|
Doctrine\ORM\Query,
|
||||||
Doctrine\Common\Collections\ArrayCollection,
|
Doctrine\Common\Collections\ArrayCollection,
|
||||||
Doctrine\Common\Collections\Collection;
|
Doctrine\Common\Collections\Collection;
|
||||||
@ -35,29 +34,25 @@ use Doctrine\DBAL\Connection,
|
|||||||
*/
|
*/
|
||||||
class ObjectHydrator extends AbstractHydrator
|
class ObjectHydrator extends AbstractHydrator
|
||||||
{
|
{
|
||||||
/*
|
/* Local ClassMetadata cache to avoid going to the EntityManager all the time.
|
||||||
* These two properties maintain their values between hydration runs.
|
* This local cache is maintained between hydration runs and not cleared.
|
||||||
*/
|
*/
|
||||||
/* Local ClassMetadata cache to avoid going to the EntityManager all the time. */
|
|
||||||
private $_ce = array();
|
private $_ce = array();
|
||||||
/*
|
|
||||||
* The following parts are reinitialized on every hydration run.
|
/* The following parts are reinitialized on every hydration run. */
|
||||||
*/
|
|
||||||
private $_isSimpleQuery = false;
|
|
||||||
private $_allowPartialObjects = false;
|
private $_allowPartialObjects = false;
|
||||||
private $_identifierMap = array();
|
private $_identifierMap;
|
||||||
private $_resultPointers = array();
|
private $_resultPointers;
|
||||||
private $_idTemplate = array();
|
private $_idTemplate;
|
||||||
private $_resultCounter;
|
private $_resultCounter;
|
||||||
private $_rootAliases = array();
|
|
||||||
private $_fetchedAssociations;
|
private $_fetchedAssociations;
|
||||||
/** Memory for initialized collections. */
|
private $_rootAliases = array();
|
||||||
private $_initializedCollections = array();
|
private $_initializedCollections = array();
|
||||||
|
|
||||||
/** @override */
|
/** @override */
|
||||||
protected function _prepare()
|
protected function _prepare()
|
||||||
{
|
{
|
||||||
$this->_isSimpleQuery = count($this->_rsm->aliasMap) <= 1;
|
|
||||||
$this->_allowPartialObjects = $this->_em->getConfiguration()->getAllowPartialObjects()
|
$this->_allowPartialObjects = $this->_em->getConfiguration()->getAllowPartialObjects()
|
||||||
|| isset($this->_hints[Query::HINT_FORCE_PARTIAL_LOAD]);
|
|| isset($this->_hints[Query::HINT_FORCE_PARTIAL_LOAD]);
|
||||||
|
|
||||||
@ -77,7 +72,8 @@ class ObjectHydrator extends AbstractHydrator
|
|||||||
$this->_ce[$className] = $class;
|
$this->_ce[$className] = $class;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Remember which associations are "fetch joined"
|
// Remember which associations are "fetch joined", so that we know where to inject
|
||||||
|
// collection stubs or proxies and where not.
|
||||||
if (isset($this->_rsm->relationMap[$dqlAlias])) {
|
if (isset($this->_rsm->relationMap[$dqlAlias])) {
|
||||||
$targetClassName = $this->_rsm->aliasMap[$this->_rsm->parentAliasMap[$dqlAlias]];
|
$targetClassName = $this->_rsm->aliasMap[$this->_rsm->parentAliasMap[$dqlAlias]];
|
||||||
$targetClass = $this->_em->getClassMetadata($targetClassName);
|
$targetClass = $this->_em->getClassMetadata($targetClassName);
|
||||||
@ -96,6 +92,11 @@ class ObjectHydrator extends AbstractHydrator
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*
|
||||||
|
* @override
|
||||||
|
*/
|
||||||
protected function _cleanup()
|
protected function _cleanup()
|
||||||
{
|
{
|
||||||
parent::_cleanup();
|
parent::_cleanup();
|
||||||
@ -112,7 +113,7 @@ class ObjectHydrator extends AbstractHydrator
|
|||||||
{
|
{
|
||||||
$result = array();
|
$result = array();
|
||||||
$cache = array();
|
$cache = array();
|
||||||
while ($data = $this->_stmt->fetch(Connection::FETCH_ASSOC)) {
|
while ($data = $this->_stmt->fetch(\Doctrine\DBAL\Connection::FETCH_ASSOC)) {
|
||||||
$this->_hydrateRow($data, $cache, $result);
|
$this->_hydrateRow($data, $cache, $result);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -131,7 +132,7 @@ class ObjectHydrator extends AbstractHydrator
|
|||||||
* @param object $entity The entity to which the collection belongs.
|
* @param object $entity The entity to which the collection belongs.
|
||||||
* @param string $name The name of the field on the entity that holds the collection.
|
* @param string $name The name of the field on the entity that holds the collection.
|
||||||
*/
|
*/
|
||||||
private function initRelatedCollection($entity, $name)
|
private function _initRelatedCollection($entity, $name)
|
||||||
{
|
{
|
||||||
$oid = spl_object_hash($entity);
|
$oid = spl_object_hash($entity);
|
||||||
$class = $this->_ce[get_class($entity)];
|
$class = $this->_ce[get_class($entity)];
|
||||||
@ -155,7 +156,7 @@ class ObjectHydrator extends AbstractHydrator
|
|||||||
* @param $dqlAlias The DQL alias of the entity's class.
|
* @param $dqlAlias The DQL alias of the entity's class.
|
||||||
* @return object The entity.
|
* @return object The entity.
|
||||||
*/
|
*/
|
||||||
private function getEntity(array $data, $dqlAlias)
|
private function _getEntity(array $data, $dqlAlias)
|
||||||
{
|
{
|
||||||
$className = $this->_rsm->aliasMap[$dqlAlias];
|
$className = $this->_rsm->aliasMap[$dqlAlias];
|
||||||
if (isset($this->_rsm->discriminatorColumns[$dqlAlias])) {
|
if (isset($this->_rsm->discriminatorColumns[$dqlAlias])) {
|
||||||
@ -232,7 +233,7 @@ class ObjectHydrator extends AbstractHydrator
|
|||||||
*/
|
*/
|
||||||
protected function _hydrateRow(array &$data, array &$cache, array &$result)
|
protected function _hydrateRow(array &$data, array &$cache, array &$result)
|
||||||
{
|
{
|
||||||
// 1) Initialize
|
// Initialize
|
||||||
$id = $this->_idTemplate; // initialize the id-memory
|
$id = $this->_idTemplate; // initialize the id-memory
|
||||||
$nonemptyComponents = array();
|
$nonemptyComponents = array();
|
||||||
$rowData = $this->_gatherRowData($data, $cache, $id, $nonemptyComponents);
|
$rowData = $this->_gatherRowData($data, $cache, $id, $nonemptyComponents);
|
||||||
@ -253,17 +254,14 @@ class ObjectHydrator extends AbstractHydrator
|
|||||||
|
|
||||||
$parent = $this->_rsm->parentAliasMap[$dqlAlias];
|
$parent = $this->_rsm->parentAliasMap[$dqlAlias];
|
||||||
|
|
||||||
// Get a reference to the right element in the result tree.
|
// Get a reference to the right object to which the joined result belongs.
|
||||||
// This element will get the associated element attached.
|
|
||||||
if ($this->_rsm->isMixed && isset($this->_rootAliases[$parent])) {
|
if ($this->_rsm->isMixed && isset($this->_rootAliases[$parent])) {
|
||||||
$first = reset($this->_resultPointers);
|
$first = reset($this->_resultPointers);
|
||||||
// TODO: Exception if key($first) === null ?
|
|
||||||
$baseElement = $this->_resultPointers[$parent][key($first)];
|
$baseElement = $this->_resultPointers[$parent][key($first)];
|
||||||
} else if (isset($this->_resultPointers[$parent])) {
|
} else if (isset($this->_resultPointers[$parent])) {
|
||||||
$baseElement = $this->_resultPointers[$parent];
|
$baseElement = $this->_resultPointers[$parent];
|
||||||
} else {
|
} else {
|
||||||
unset($this->_resultPointers[$dqlAlias]); // Ticket #1228
|
throw HydrationException::parentObjectOfRelationNotFound($dqlAlias, $parent);
|
||||||
continue;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
$parentClass = get_class($baseElement);
|
$parentClass = get_class($baseElement);
|
||||||
@ -278,16 +276,15 @@ class ObjectHydrator extends AbstractHydrator
|
|||||||
// Collection-valued association
|
// Collection-valued association
|
||||||
if (isset($nonemptyComponents[$dqlAlias])) {
|
if (isset($nonemptyComponents[$dqlAlias])) {
|
||||||
if ( ! isset($this->_initializedCollections[$oid . $relationField])) {
|
if ( ! isset($this->_initializedCollections[$oid . $relationField])) {
|
||||||
$reflFieldValue = $this->initRelatedCollection($baseElement, $relationField);
|
$reflFieldValue = $this->_initRelatedCollection($baseElement, $relationField);
|
||||||
}
|
}
|
||||||
|
|
||||||
$path = $parent . '.' . $dqlAlias;
|
$indexExists = isset($this->_identifierMap[$dqlAlias][$id[$dqlAlias]]);
|
||||||
$indexExists = isset($this->_identifierMap[$path][$id[$parent]][$id[$dqlAlias]]);
|
$index = $indexExists ? $this->_identifierMap[$dqlAlias][$id[$dqlAlias]] : false;
|
||||||
$index = $indexExists ? $this->_identifierMap[$path][$id[$parent]][$id[$dqlAlias]] : false;
|
$indexIsValid = $index !== false ? isset($reflFieldValue[$index]) : false;
|
||||||
$indexIsValid = $index !== false ? $reflFieldValue->containsKey($index) : false;
|
|
||||||
|
|
||||||
if ( ! $indexExists || ! $indexIsValid) {
|
if ( ! $indexExists || ! $indexIsValid) {
|
||||||
$element = $this->getEntity($data, $dqlAlias);
|
$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()) {
|
||||||
@ -295,45 +292,42 @@ class ObjectHydrator extends AbstractHydrator
|
|||||||
$inverseFieldName = $this->_ce[$entityName]->inverseMappings[$relation->sourceEntityName][$relationField]->sourceFieldName;
|
$inverseFieldName = $this->_ce[$entityName]->inverseMappings[$relation->sourceEntityName][$relationField]->sourceFieldName;
|
||||||
// Only initialize reverse collection if it is not yet initialized.
|
// Only initialize reverse collection if it is not yet initialized.
|
||||||
if ( ! isset($this->_initializedCollections[spl_object_hash($element) . $inverseFieldName])) {
|
if ( ! isset($this->_initializedCollections[spl_object_hash($element) . $inverseFieldName])) {
|
||||||
$this->initRelatedCollection($element, $inverseFieldName);
|
$this->_initRelatedCollection($element, $inverseFieldName);
|
||||||
}
|
}
|
||||||
} else if ($relation->mappedByFieldName) {
|
} else if ($relation->mappedByFieldName) {
|
||||||
// Only initialize reverse collection if it is not yet initialized.
|
// Only initialize reverse collection if it is not yet initialized.
|
||||||
if ( ! isset($this->_initializedCollections[spl_object_hash($element) . $relation->mappedByFieldName])) {
|
if ( ! isset($this->_initializedCollections[spl_object_hash($element) . $relation->mappedByFieldName])) {
|
||||||
$this->initRelatedCollection($element, $relation->mappedByFieldName);
|
$this->_initRelatedCollection($element, $relation->mappedByFieldName);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isset($this->_rsm->indexByMap[$dqlAlias])) {
|
if (isset($this->_rsm->indexByMap[$dqlAlias])) {
|
||||||
$field = $this->_rsm->indexByMap[$dqlAlias];
|
$field = $this->_rsm->indexByMap[$dqlAlias];
|
||||||
$indexValue = $this->_ce[$entityName]
|
$indexValue = $this->_ce[$entityName]->reflFields[$field]->getValue($element);
|
||||||
->reflFields[$field]
|
|
||||||
->getValue($element);
|
|
||||||
$reflFieldValue->hydrateSet($indexValue, $element);
|
$reflFieldValue->hydrateSet($indexValue, $element);
|
||||||
|
$this->_identifierMap[$dqlAlias][$id[$dqlAlias]] = $indexValue;
|
||||||
} else {
|
} else {
|
||||||
$reflFieldValue->hydrateAdd($element);
|
$reflFieldValue->hydrateAdd($element);
|
||||||
|
$reflFieldValue->last();
|
||||||
|
$this->_identifierMap[$dqlAlias][$id[$dqlAlias]] = $reflFieldValue->key();
|
||||||
}
|
}
|
||||||
|
|
||||||
$reflFieldValue->last();
|
|
||||||
$this->_identifierMap[$path][$id[$parent]][$id[$dqlAlias]] = $reflFieldValue->key();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Update result pointer
|
||||||
|
$this->_resultPointers[$dqlAlias] = $index === false ? $element : $reflFieldValue[$index];
|
||||||
|
|
||||||
} else if ( ! $reflFieldValue) {
|
} else if ( ! $reflFieldValue) {
|
||||||
$coll = new PersistentCollection($this->_em, $this->_ce[$entityName], new ArrayCollection);
|
$coll = new PersistentCollection($this->_em, $this->_ce[$entityName], new ArrayCollection);
|
||||||
$reflField->setValue($baseElement, $coll);
|
$reflField->setValue($baseElement, $coll);
|
||||||
$reflFieldValue = $coll;
|
|
||||||
$this->_uow->setOriginalEntityProperty($oid, $relationField, $coll);
|
$this->_uow->setOriginalEntityProperty($oid, $relationField, $coll);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update result pointer
|
|
||||||
$this->_resultPointers[$dqlAlias] = $index === false ?
|
|
||||||
$reflFieldValue->last() : $reflFieldValue[$index];
|
|
||||||
} else {
|
} else {
|
||||||
// Single-valued association
|
// Single-valued association
|
||||||
$reflFieldValue = $reflField->getValue($baseElement);
|
$reflFieldValue = $reflField->getValue($baseElement);
|
||||||
if ( ! $reflFieldValue) {
|
if ( ! $reflFieldValue) {
|
||||||
if (isset($nonemptyComponents[$dqlAlias])) {
|
if (isset($nonemptyComponents[$dqlAlias])) {
|
||||||
$element = $this->getEntity($data, $dqlAlias);
|
$element = $this->_getEntity($data, $dqlAlias);
|
||||||
$reflField->setValue($baseElement, $element);
|
$reflField->setValue($baseElement, $element);
|
||||||
$this->_uow->setOriginalEntityProperty($oid, $relationField, $element);
|
$this->_uow->setOriginalEntityProperty($oid, $relationField, $element);
|
||||||
$targetClass = $this->_ce[$relation->targetEntityName];
|
$targetClass = $this->_ce[$relation->targetEntityName];
|
||||||
@ -351,10 +345,9 @@ class ObjectHydrator extends AbstractHydrator
|
|||||||
$targetClass->reflFields[$relation->mappedByFieldName]->setValue($element, $baseElement);
|
$targetClass->reflFields[$relation->mappedByFieldName]->setValue($element, $baseElement);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
// else leave $reflFieldValue null for single-valued associations
|
||||||
|
} else {
|
||||||
// Update result pointer
|
// Update result pointer
|
||||||
if ($reflFieldValue !== null) {
|
|
||||||
$this->_resultPointers[$dqlAlias] = $reflFieldValue;
|
$this->_resultPointers[$dqlAlias] = $reflFieldValue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -362,36 +355,34 @@ class ObjectHydrator extends AbstractHydrator
|
|||||||
// Its a root result element
|
// Its a root result element
|
||||||
$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 ( ! isset($this->_identifierMap[$dqlAlias][$id[$dqlAlias]])) {
|
||||||
$element = $this->getEntity($rowData[$dqlAlias], $dqlAlias);
|
$element = $this->_getEntity($rowData[$dqlAlias], $dqlAlias);
|
||||||
if (isset($this->_rsm->indexByMap[$dqlAlias])) {
|
if (isset($this->_rsm->indexByMap[$dqlAlias])) {
|
||||||
$field = $this->_rsm->indexByMap[$dqlAlias];
|
$field = $this->_rsm->indexByMap[$dqlAlias];
|
||||||
|
$key = $this->_ce[$entityName]->reflFields[$field]->getValue($element);
|
||||||
if ($this->_rsm->isMixed) {
|
if ($this->_rsm->isMixed) {
|
||||||
$result[] = array(
|
$element = array($key => $element);
|
||||||
$this->_ce[$entityName]
|
$result[] = $element;
|
||||||
->reflFields[$field]
|
|
||||||
->getValue($element) => $element
|
|
||||||
);
|
|
||||||
++$this->_resultCounter;
|
++$this->_resultCounter;
|
||||||
|
end($result);
|
||||||
|
$this->_identifierMap[$dqlAlias][$id[$dqlAlias]] = key($result);
|
||||||
} else {
|
} else {
|
||||||
$result[$this->_ce[$entityName]
|
$result[$key] = $element;
|
||||||
->reflFields[$field]
|
$this->_identifierMap[$dqlAlias][$id[$dqlAlias]] = $key;
|
||||||
->getValue($element)] = $element;
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if ($this->_rsm->isMixed) {
|
if ($this->_rsm->isMixed) {
|
||||||
$result[] = array($element);
|
$element = array(0 => $element);
|
||||||
++$this->_resultCounter;
|
++$this->_resultCounter;
|
||||||
} else {
|
|
||||||
$result[] = $element;
|
|
||||||
}
|
}
|
||||||
|
$result[] = $element;
|
||||||
|
end($result);
|
||||||
|
$this->_identifierMap[$dqlAlias][$id[$dqlAlias]] = key($result);
|
||||||
}
|
}
|
||||||
|
|
||||||
$last = end($result);
|
|
||||||
$this->_identifierMap[$dqlAlias][$id[$dqlAlias]] = key($result);
|
|
||||||
|
|
||||||
// Update result pointer
|
// Update result pointer
|
||||||
$this->_resultPointers[$dqlAlias] = $last;
|
$this->_resultPointers[$dqlAlias] = $element;
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
// Update result pointer
|
// Update result pointer
|
||||||
$index = $this->_identifierMap[$dqlAlias][$id[$dqlAlias]];
|
$index = $this->_identifierMap[$dqlAlias][$id[$dqlAlias]];
|
||||||
@ -407,10 +398,4 @@ class ObjectHydrator extends AbstractHydrator
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** {@inheritdoc} */
|
|
||||||
protected function _getRowContainer()
|
|
||||||
{
|
|
||||||
return array();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user