diff -r 000000000000 -r 7f95f8617b0b vendor/doctrine/lib/Doctrine/ORM/Internal/Hydration/ArrayHydrator.php --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vendor/doctrine/lib/Doctrine/ORM/Internal/Hydration/ArrayHydrator.php Sat Sep 24 15:40:41 2011 +0200 @@ -0,0 +1,235 @@ +. + */ + +namespace Doctrine\ORM\Internal\Hydration; + +use PDO, Doctrine\DBAL\Connection, Doctrine\ORM\Mapping\ClassMetadata; + +/** + * The ArrayHydrator produces a nested array "graph" that is often (not always) + * interchangeable with the corresponding object graph for read-only access. + * + * @author Roman Borschel + * @since 1.0 + */ +class ArrayHydrator extends AbstractHydrator +{ + private $_ce = array(); + private $_rootAliases = array(); + private $_isSimpleQuery = false; + private $_identifierMap = array(); + private $_resultPointers = array(); + private $_idTemplate = array(); + private $_resultCounter = 0; + + /** @override */ + protected function _prepare() + { + $this->_isSimpleQuery = count($this->_rsm->aliasMap) <= 1; + $this->_identifierMap = array(); + $this->_resultPointers = array(); + $this->_idTemplate = array(); + $this->_resultCounter = 0; + foreach ($this->_rsm->aliasMap as $dqlAlias => $className) { + $this->_identifierMap[$dqlAlias] = array(); + $this->_resultPointers[$dqlAlias] = array(); + $this->_idTemplate[$dqlAlias] = ''; + } + } + + /** @override */ + protected function _hydrateAll() + { + $result = array(); + $cache = array(); + while ($data = $this->_stmt->fetch(PDO::FETCH_ASSOC)) { + $this->_hydrateRow($data, $cache, $result); + } + + return $result; + } + + /** @override */ + protected function _hydrateRow(array $data, array &$cache, array &$result) + { + // 1) Initialize + $id = $this->_idTemplate; // initialize the id-memory + $nonemptyComponents = array(); + $rowData = $this->_gatherRowData($data, $cache, $id, $nonemptyComponents); + + // Extract scalar values. They're appended at the end. + if (isset($rowData['scalars'])) { + $scalars = $rowData['scalars']; + unset($rowData['scalars']); + if (empty($rowData)) { + ++$this->_resultCounter; + } + } + + // 2) Now hydrate the data found in the current row. + foreach ($rowData as $dqlAlias => $data) { + $index = false; + + if (isset($this->_rsm->parentAliasMap[$dqlAlias])) { + // It's a joined result + + $parent = $this->_rsm->parentAliasMap[$dqlAlias]; + $path = $parent . '.' . $dqlAlias; + + // Get a reference to the right element in the result tree. + // This element will get the associated element attached. + if ($this->_rsm->isMixed && isset($this->_rootAliases[$parent])) { + $first = reset($this->_resultPointers); + // TODO: Exception if $key === null ? + $baseElement =& $this->_resultPointers[$parent][key($first)]; + } else if (isset($this->_resultPointers[$parent])) { + $baseElement =& $this->_resultPointers[$parent]; + } else { + unset($this->_resultPointers[$dqlAlias]); // Ticket #1228 + continue; + } + + $relationAlias = $this->_rsm->relationMap[$dqlAlias]; + $relation = $this->_getClassMetadata($this->_rsm->aliasMap[$parent])->associationMappings[$relationAlias]; + + // Check the type of the relation (many or single-valued) + if ( ! ($relation['type'] & ClassMetadata::TO_ONE)) { + $oneToOne = false; + if (isset($nonemptyComponents[$dqlAlias])) { + if ( ! isset($baseElement[$relationAlias])) { + $baseElement[$relationAlias] = array(); + } + + $indexExists = isset($this->_identifierMap[$path][$id[$parent]][$id[$dqlAlias]]); + $index = $indexExists ? $this->_identifierMap[$path][$id[$parent]][$id[$dqlAlias]] : false; + $indexIsValid = $index !== false ? isset($baseElement[$relationAlias][$index]) : false; + + if ( ! $indexExists || ! $indexIsValid) { + $element = $data; + if (isset($this->_rsm->indexByMap[$dqlAlias])) { + $field = $this->_rsm->indexByMap[$dqlAlias]; + $baseElement[$relationAlias][$element[$field]] = $element; + } else { + $baseElement[$relationAlias][] = $element; + } + end($baseElement[$relationAlias]); + $this->_identifierMap[$path][$id[$parent]][$id[$dqlAlias]] = + key($baseElement[$relationAlias]); + } + } else if ( ! isset($baseElement[$relationAlias])) { + $baseElement[$relationAlias] = array(); + } + } else { + $oneToOne = true; + if ( ! isset($nonemptyComponents[$dqlAlias]) && ! isset($baseElement[$relationAlias])) { + $baseElement[$relationAlias] = null; + } else if ( ! isset($baseElement[$relationAlias])) { + $baseElement[$relationAlias] = $data; + } + } + + $coll =& $baseElement[$relationAlias]; + + if ($coll !== null) { + $this->updateResultPointer($coll, $index, $dqlAlias, $oneToOne); + } + + } else { + // It's a root result element + + $this->_rootAliases[$dqlAlias] = true; // Mark as root + + // Check for an existing element + if ($this->_isSimpleQuery || ! isset($this->_identifierMap[$dqlAlias][$id[$dqlAlias]])) { + $element = $rowData[$dqlAlias]; + if (isset($this->_rsm->indexByMap[$dqlAlias])) { + $field = $this->_rsm->indexByMap[$dqlAlias]; + if ($this->_rsm->isMixed) { + $result[] = array($element[$field] => $element); + ++$this->_resultCounter; + } else { + $result[$element[$field]] = $element; + } + } else { + if ($this->_rsm->isMixed) { + $result[] = array($element); + ++$this->_resultCounter; + } else { + $result[] = $element; + } + } + end($result); + $this->_identifierMap[$dqlAlias][$id[$dqlAlias]] = key($result); + } else { + $index = $this->_identifierMap[$dqlAlias][$id[$dqlAlias]]; + /*if ($this->_rsm->isMixed) { + $result[] =& $result[$index]; + ++$this->_resultCounter; + }*/ + } + $this->updateResultPointer($result, $index, $dqlAlias, false); + } + } + + // Append scalar values to mixed result sets + if (isset($scalars)) { + foreach ($scalars as $name => $value) { + $result[$this->_resultCounter - 1][$name] = $value; + } + } + } + + /** + * Updates the result pointer for an Entity. The result pointers point to the + * last seen instance of each Entity type. This is used for graph construction. + * + * @param array $coll The element. + * @param boolean|integer $index Index of the element in the collection. + * @param string $dqlAlias + * @param boolean $oneToOne Whether it is a single-valued association or not. + */ + private function updateResultPointer(array &$coll, $index, $dqlAlias, $oneToOne) + { + if ($coll === null) { + unset($this->_resultPointers[$dqlAlias]); // Ticket #1228 + return; + } + if ($index !== false) { + $this->_resultPointers[$dqlAlias] =& $coll[$index]; + return; + } else { + if ($coll) { + if ($oneToOne) { + $this->_resultPointers[$dqlAlias] =& $coll; + } else { + end($coll); + $this->_resultPointers[$dqlAlias] =& $coll[key($coll)]; + } + } + } + } + + private function _getClassMetadata($className) + { + if ( ! isset($this->_ce[$className])) { + $this->_ce[$className] = $this->_em->getClassMetadata($className); + } + return $this->_ce[$className]; + } +} \ No newline at end of file