Initial code optimization in Hydrators.
This commit is contained in:
parent
d532de9da3
commit
d1bfd57fd9
@ -22,15 +22,17 @@ namespace Doctrine\ORM\Internal\Hydration;
|
|||||||
use PDO,
|
use PDO,
|
||||||
Doctrine\DBAL\Connection,
|
Doctrine\DBAL\Connection,
|
||||||
Doctrine\DBAL\Types\Type,
|
Doctrine\DBAL\Types\Type,
|
||||||
Doctrine\ORM\EntityManager;
|
Doctrine\ORM\EntityManager,
|
||||||
|
Doctrine\ORM\Mapping\ClassMetadata;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Base class for all hydrators. A hydrator is a class that provides some form
|
* Base class for all hydrators. A hydrator is a class that provides some form
|
||||||
* of transformation of an SQL result set into another structure.
|
* of transformation of an SQL result set into another structure.
|
||||||
*
|
*
|
||||||
* @since 2.0
|
* @since 2.0
|
||||||
* @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>
|
||||||
|
* @author Guilherme Blanco <guilhermeblanoc@hotmail.com>
|
||||||
*/
|
*/
|
||||||
abstract class AbstractHydrator
|
abstract class AbstractHydrator
|
||||||
{
|
{
|
||||||
@ -62,9 +64,9 @@ abstract class AbstractHydrator
|
|||||||
*/
|
*/
|
||||||
public function __construct(EntityManager $em)
|
public function __construct(EntityManager $em)
|
||||||
{
|
{
|
||||||
$this->_em = $em;
|
$this->_em = $em;
|
||||||
$this->_platform = $em->getConnection()->getDatabasePlatform();
|
$this->_platform = $em->getConnection()->getDatabasePlatform();
|
||||||
$this->_uow = $em->getUnitOfWork();
|
$this->_uow = $em->getUnitOfWork();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -72,14 +74,17 @@ abstract class AbstractHydrator
|
|||||||
*
|
*
|
||||||
* @param object $stmt
|
* @param object $stmt
|
||||||
* @param object $resultSetMapping
|
* @param object $resultSetMapping
|
||||||
|
*
|
||||||
* @return IterableResult
|
* @return IterableResult
|
||||||
*/
|
*/
|
||||||
public function iterate($stmt, $resultSetMapping, array $hints = array())
|
public function iterate($stmt, $resultSetMapping, array $hints = array())
|
||||||
{
|
{
|
||||||
$this->_stmt = $stmt;
|
$this->_stmt = $stmt;
|
||||||
$this->_rsm = $resultSetMapping;
|
$this->_rsm = $resultSetMapping;
|
||||||
$this->_hints = $hints;
|
$this->_hints = $hints;
|
||||||
$this->_prepare();
|
|
||||||
|
$this->prepare();
|
||||||
|
|
||||||
return new IterableResult($this);
|
return new IterableResult($this);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -92,12 +97,16 @@ abstract class AbstractHydrator
|
|||||||
*/
|
*/
|
||||||
public function hydrateAll($stmt, $resultSetMapping, array $hints = array())
|
public function hydrateAll($stmt, $resultSetMapping, array $hints = array())
|
||||||
{
|
{
|
||||||
$this->_stmt = $stmt;
|
$this->_stmt = $stmt;
|
||||||
$this->_rsm = $resultSetMapping;
|
$this->_rsm = $resultSetMapping;
|
||||||
$this->_hints = $hints;
|
$this->_hints = $hints;
|
||||||
$this->_prepare();
|
|
||||||
$result = $this->_hydrateAll();
|
$this->prepare();
|
||||||
$this->_cleanup();
|
|
||||||
|
$result = $this->hydrateAllData();
|
||||||
|
|
||||||
|
$this->cleanup();
|
||||||
|
|
||||||
return $result;
|
return $result;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -110,12 +119,17 @@ abstract class AbstractHydrator
|
|||||||
public function hydrateRow()
|
public function hydrateRow()
|
||||||
{
|
{
|
||||||
$row = $this->_stmt->fetch(PDO::FETCH_ASSOC);
|
$row = $this->_stmt->fetch(PDO::FETCH_ASSOC);
|
||||||
|
|
||||||
if ( ! $row) {
|
if ( ! $row) {
|
||||||
$this->_cleanup();
|
$this->cleanup();
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
$result = array();
|
$result = array();
|
||||||
$this->_hydrateRow($row, $this->_cache, $result);
|
|
||||||
|
$this->hydrateRowData($row, $this->_cache, $result);
|
||||||
|
|
||||||
return $result;
|
return $result;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -123,16 +137,17 @@ abstract class AbstractHydrator
|
|||||||
* Excutes one-time preparation tasks, once each time hydration is started
|
* Excutes one-time preparation tasks, once each time hydration is started
|
||||||
* through {@link hydrateAll} or {@link iterate()}.
|
* through {@link hydrateAll} or {@link iterate()}.
|
||||||
*/
|
*/
|
||||||
protected function _prepare()
|
protected function prepare()
|
||||||
{}
|
{}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Excutes one-time cleanup tasks at the end of a hydration that was initiated
|
* Excutes one-time cleanup tasks at the end of a hydration that was initiated
|
||||||
* through {@link hydrateAll} or {@link iterate()}.
|
* through {@link hydrateAll} or {@link iterate()}.
|
||||||
*/
|
*/
|
||||||
protected function _cleanup()
|
protected function cleanup()
|
||||||
{
|
{
|
||||||
$this->_rsm = null;
|
$this->_rsm = null;
|
||||||
|
|
||||||
$this->_stmt->closeCursor();
|
$this->_stmt->closeCursor();
|
||||||
$this->_stmt = null;
|
$this->_stmt = null;
|
||||||
}
|
}
|
||||||
@ -146,15 +161,15 @@ abstract class AbstractHydrator
|
|||||||
* @param array $cache The cache to use.
|
* @param array $cache The cache to use.
|
||||||
* @param mixed $result The result to fill.
|
* @param mixed $result The result to fill.
|
||||||
*/
|
*/
|
||||||
protected function _hydrateRow(array $data, array &$cache, array &$result)
|
protected function hydrateRowData(array $data, array &$cache, array &$result)
|
||||||
{
|
{
|
||||||
throw new HydrationException("_hydrateRow() not implemented by this hydrator.");
|
throw new HydrationException("hydrateRowData() not implemented by this hydrator.");
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Hydrates all rows from the current statement instance at once.
|
* Hydrates all rows from the current statement instance at once.
|
||||||
*/
|
*/
|
||||||
abstract protected function _hydrateAll();
|
abstract protected function hydrateAllData();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Processes a row of the result set.
|
* Processes a row of the result set.
|
||||||
@ -173,7 +188,7 @@ abstract class AbstractHydrator
|
|||||||
* @return array An array with all the fields (name => value) of the data row,
|
* @return array An array with all the fields (name => value) of the data row,
|
||||||
* grouped by their component alias.
|
* grouped by their component alias.
|
||||||
*/
|
*/
|
||||||
protected function _gatherRowData(array $data, array &$cache, array &$id, array &$nonemptyComponents)
|
protected function gatherRowData(array $data, array &$cache, array &$id, array &$nonemptyComponents)
|
||||||
{
|
{
|
||||||
$rowData = array();
|
$rowData = array();
|
||||||
|
|
||||||
@ -207,6 +222,7 @@ abstract class AbstractHydrator
|
|||||||
|
|
||||||
if (isset($cache[$key]['isScalar'])) {
|
if (isset($cache[$key]['isScalar'])) {
|
||||||
$rowData['scalars'][$cache[$key]['fieldName']] = $value;
|
$rowData['scalars'][$cache[$key]['fieldName']] = $value;
|
||||||
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -220,10 +236,11 @@ abstract class AbstractHydrator
|
|||||||
if (!isset($rowData[$dqlAlias][$cache[$key]['fieldName']]) || $value !== null) {
|
if (!isset($rowData[$dqlAlias][$cache[$key]['fieldName']]) || $value !== null) {
|
||||||
$rowData[$dqlAlias][$cache[$key]['fieldName']] = $value;
|
$rowData[$dqlAlias][$cache[$key]['fieldName']] = $value;
|
||||||
}
|
}
|
||||||
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
// in an inheritance hierachy the same field could be defined several times.
|
// in an inheritance hierarchy the same field could be defined several times.
|
||||||
// We overwrite this value so long we dont have a non-null value, that value we keep.
|
// We overwrite this value so long we dont have a non-null value, that value we keep.
|
||||||
// Per definition it cannot be that a field is defined several times and has several values.
|
// Per definition it cannot be that a field is defined several times and has several values.
|
||||||
if (isset($rowData[$dqlAlias][$cache[$key]['fieldName']]) && $value === null) {
|
if (isset($rowData[$dqlAlias][$cache[$key]['fieldName']]) && $value === null) {
|
||||||
@ -250,9 +267,10 @@ abstract class AbstractHydrator
|
|||||||
*
|
*
|
||||||
* @param array $data
|
* @param array $data
|
||||||
* @param array $cache
|
* @param array $cache
|
||||||
|
*
|
||||||
* @return array The processed row.
|
* @return array The processed row.
|
||||||
*/
|
*/
|
||||||
protected function _gatherScalarRowData(&$data, &$cache)
|
protected function gatherScalarRowData(&$data, &$cache)
|
||||||
{
|
{
|
||||||
$rowData = array();
|
$rowData = array();
|
||||||
|
|
||||||
@ -295,7 +313,14 @@ abstract class AbstractHydrator
|
|||||||
return $rowData;
|
return $rowData;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function registerManaged($class, $entity, $data)
|
/**
|
||||||
|
* Register entity as managed in UnitOfWork.
|
||||||
|
*
|
||||||
|
* @param Doctrine\ORM\Mapping\ClassMetadata $class
|
||||||
|
* @param object $entity
|
||||||
|
* @param array $data
|
||||||
|
*/
|
||||||
|
protected function registerManaged(ClassMetadata $class, $entity, array $data)
|
||||||
{
|
{
|
||||||
if ($class->isIdentifierComposite) {
|
if ($class->isIdentifierComposite) {
|
||||||
$id = array();
|
$id = array();
|
||||||
@ -313,6 +338,7 @@ abstract class AbstractHydrator
|
|||||||
$id = array($class->identifier[0] => $data[$class->identifier[0]]);
|
$id = array($class->identifier[0] => $data[$class->identifier[0]]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->_em->getUnitOfWork()->registerManaged($entity, $id, $data);
|
$this->_em->getUnitOfWork()->registerManaged($entity, $id, $data);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -25,8 +25,9 @@ use PDO, Doctrine\DBAL\Connection, Doctrine\ORM\Mapping\ClassMetadata;
|
|||||||
* The ArrayHydrator produces a nested array "graph" that is often (not always)
|
* The ArrayHydrator produces a nested array "graph" that is often (not always)
|
||||||
* interchangeable with the corresponding object graph for read-only access.
|
* interchangeable with the corresponding object graph for read-only access.
|
||||||
*
|
*
|
||||||
|
* @since 2.0
|
||||||
* @author Roman Borschel <roman@code-factory.org>
|
* @author Roman Borschel <roman@code-factory.org>
|
||||||
* @since 1.0
|
* @author Guilherme Blanco <guilhermeblanoc@hotmail.com>
|
||||||
*/
|
*/
|
||||||
class ArrayHydrator extends AbstractHydrator
|
class ArrayHydrator extends AbstractHydrator
|
||||||
{
|
{
|
||||||
@ -38,45 +39,54 @@ class ArrayHydrator extends AbstractHydrator
|
|||||||
private $_idTemplate = array();
|
private $_idTemplate = array();
|
||||||
private $_resultCounter = 0;
|
private $_resultCounter = 0;
|
||||||
|
|
||||||
/** @override */
|
/**
|
||||||
protected function _prepare()
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
protected function prepare()
|
||||||
{
|
{
|
||||||
$this->_isSimpleQuery = count($this->_rsm->aliasMap) <= 1;
|
$this->_isSimpleQuery = count($this->_rsm->aliasMap) <= 1;
|
||||||
$this->_identifierMap = array();
|
$this->_identifierMap = array();
|
||||||
$this->_resultPointers = array();
|
$this->_resultPointers = array();
|
||||||
$this->_idTemplate = array();
|
$this->_idTemplate = array();
|
||||||
$this->_resultCounter = 0;
|
$this->_resultCounter = 0;
|
||||||
|
|
||||||
foreach ($this->_rsm->aliasMap as $dqlAlias => $className) {
|
foreach ($this->_rsm->aliasMap as $dqlAlias => $className) {
|
||||||
$this->_identifierMap[$dqlAlias] = array();
|
$this->_identifierMap[$dqlAlias] = array();
|
||||||
$this->_resultPointers[$dqlAlias] = array();
|
$this->_resultPointers[$dqlAlias] = array();
|
||||||
$this->_idTemplate[$dqlAlias] = '';
|
$this->_idTemplate[$dqlAlias] = '';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @override */
|
/**
|
||||||
protected function _hydrateAll()
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
protected function hydrateAllData()
|
||||||
{
|
{
|
||||||
$result = array();
|
$result = array();
|
||||||
$cache = array();
|
$cache = array();
|
||||||
|
|
||||||
while ($data = $this->_stmt->fetch(PDO::FETCH_ASSOC)) {
|
while ($data = $this->_stmt->fetch(PDO::FETCH_ASSOC)) {
|
||||||
$this->_hydrateRow($data, $cache, $result);
|
$this->hydrateRowData($data, $cache, $result);
|
||||||
}
|
}
|
||||||
|
|
||||||
return $result;
|
return $result;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @override */
|
/**
|
||||||
protected function _hydrateRow(array $row, array &$cache, array &$result)
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
protected function hydrateRowData(array $row, array &$cache, array &$result)
|
||||||
{
|
{
|
||||||
// 1) Initialize
|
// 1) Initialize
|
||||||
$id = $this->_idTemplate; // initialize the id-memory
|
$id = $this->_idTemplate; // initialize the id-memory
|
||||||
$nonemptyComponents = array();
|
$nonemptyComponents = array();
|
||||||
$rowData = $this->_gatherRowData($row, $cache, $id, $nonemptyComponents);
|
$rowData = $this->gatherRowData($row, $cache, $id, $nonemptyComponents);
|
||||||
|
|
||||||
// Extract scalar values. They're appended at the end.
|
// Extract scalar values. They're appended at the end.
|
||||||
if (isset($rowData['scalars'])) {
|
if (isset($rowData['scalars'])) {
|
||||||
$scalars = $rowData['scalars'];
|
$scalars = $rowData['scalars'];
|
||||||
unset($rowData['scalars']);
|
unset($rowData['scalars']);
|
||||||
|
|
||||||
if (empty($rowData)) {
|
if (empty($rowData)) {
|
||||||
++$this->_resultCounter;
|
++$this->_resultCounter;
|
||||||
}
|
}
|
||||||
@ -111,7 +121,7 @@ class ArrayHydrator extends AbstractHydrator
|
|||||||
}
|
}
|
||||||
|
|
||||||
$relationAlias = $this->_rsm->relationMap[$dqlAlias];
|
$relationAlias = $this->_rsm->relationMap[$dqlAlias];
|
||||||
$relation = $this->_getClassMetadata($this->_rsm->aliasMap[$parent])->associationMappings[$relationAlias];
|
$relation = $this->getClassMetadata($this->_rsm->aliasMap[$parent])->associationMappings[$relationAlias];
|
||||||
|
|
||||||
// Check the type of the relation (many or single-valued)
|
// Check the type of the relation (many or single-valued)
|
||||||
if ( ! ($relation['type'] & ClassMetadata::TO_ONE)) {
|
if ( ! ($relation['type'] & ClassMetadata::TO_ONE)) {
|
||||||
@ -230,28 +240,45 @@ class ArrayHydrator extends AbstractHydrator
|
|||||||
{
|
{
|
||||||
if ($coll === null) {
|
if ($coll === null) {
|
||||||
unset($this->_resultPointers[$dqlAlias]); // Ticket #1228
|
unset($this->_resultPointers[$dqlAlias]); // Ticket #1228
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($index !== false) {
|
if ($index !== false) {
|
||||||
$this->_resultPointers[$dqlAlias] =& $coll[$index];
|
$this->_resultPointers[$dqlAlias] =& $coll[$index];
|
||||||
|
|
||||||
return;
|
return;
|
||||||
} else {
|
|
||||||
if ($coll) {
|
|
||||||
if ($oneToOne) {
|
|
||||||
$this->_resultPointers[$dqlAlias] =& $coll;
|
|
||||||
} else {
|
|
||||||
end($coll);
|
|
||||||
$this->_resultPointers[$dqlAlias] =& $coll[key($coll)];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ( ! $coll) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($oneToOne) {
|
||||||
|
$this->_resultPointers[$dqlAlias] =& $coll;
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
end($coll);
|
||||||
|
$this->_resultPointers[$dqlAlias] =& $coll[key($coll)];
|
||||||
|
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
private function _getClassMetadata($className)
|
/**
|
||||||
|
* Retrieve ClassMetadata associated to entity class name.
|
||||||
|
*
|
||||||
|
* @param string $className
|
||||||
|
*
|
||||||
|
* @return Doctrine\ORM\Mapping\ClassMetadata
|
||||||
|
*/
|
||||||
|
private function getClassMetadata($className)
|
||||||
{
|
{
|
||||||
if ( ! isset($this->_ce[$className])) {
|
if ( ! isset($this->_ce[$className])) {
|
||||||
$this->_ce[$className] = $this->_em->getClassMetadata($className);
|
$this->_ce[$className] = $this->_em->getClassMetadata($className);
|
||||||
}
|
}
|
||||||
|
|
||||||
return $this->_ce[$className];
|
return $this->_ce[$className];
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -29,8 +29,10 @@ use PDO,
|
|||||||
/**
|
/**
|
||||||
* The ObjectHydrator constructs an object graph out of an SQL result set.
|
* The ObjectHydrator constructs an object graph out of an SQL result set.
|
||||||
*
|
*
|
||||||
|
* @since 2.0
|
||||||
* @author Roman Borschel <roman@code-factory.org>
|
* @author Roman Borschel <roman@code-factory.org>
|
||||||
* @since 2.0
|
* @author Guilherme Blanco <guilhermeblanoc@hotmail.com>
|
||||||
|
*
|
||||||
* @internal Highly performance-sensitive code.
|
* @internal Highly performance-sensitive code.
|
||||||
*/
|
*/
|
||||||
class ObjectHydrator extends AbstractHydrator
|
class ObjectHydrator extends AbstractHydrator
|
||||||
@ -53,7 +55,7 @@ class ObjectHydrator extends AbstractHydrator
|
|||||||
|
|
||||||
|
|
||||||
/** @override */
|
/** @override */
|
||||||
protected function _prepare()
|
protected function prepare()
|
||||||
{
|
{
|
||||||
$this->_identifierMap =
|
$this->_identifierMap =
|
||||||
$this->_resultPointers =
|
$this->_resultPointers =
|
||||||
@ -113,11 +115,12 @@ class ObjectHydrator extends AbstractHydrator
|
|||||||
/**
|
/**
|
||||||
* {@inheritdoc}
|
* {@inheritdoc}
|
||||||
*/
|
*/
|
||||||
protected function _cleanup()
|
protected function cleanup()
|
||||||
{
|
{
|
||||||
$eagerLoad = (isset($this->_hints['deferEagerLoad'])) && $this->_hints['deferEagerLoad'] == true;
|
$eagerLoad = (isset($this->_hints['deferEagerLoad'])) && $this->_hints['deferEagerLoad'] == true;
|
||||||
|
|
||||||
parent::_cleanup();
|
parent::cleanup();
|
||||||
|
|
||||||
$this->_identifierMap =
|
$this->_identifierMap =
|
||||||
$this->_initializedCollections =
|
$this->_initializedCollections =
|
||||||
$this->_existingCollections =
|
$this->_existingCollections =
|
||||||
@ -131,13 +134,13 @@ class ObjectHydrator extends AbstractHydrator
|
|||||||
/**
|
/**
|
||||||
* {@inheritdoc}
|
* {@inheritdoc}
|
||||||
*/
|
*/
|
||||||
protected function _hydrateAll()
|
protected function hydrateAllData()
|
||||||
{
|
{
|
||||||
$result = array();
|
$result = array();
|
||||||
$cache = array();
|
$cache = array();
|
||||||
|
|
||||||
while ($row = $this->_stmt->fetch(PDO::FETCH_ASSOC)) {
|
while ($row = $this->_stmt->fetch(PDO::FETCH_ASSOC)) {
|
||||||
$this->_hydrateRow($row, $cache, $result);
|
$this->hydrateRowData($row, $cache, $result);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Take snapshots from all newly initialized collections
|
// Take snapshots from all newly initialized collections
|
||||||
@ -278,13 +281,13 @@ class ObjectHydrator extends AbstractHydrator
|
|||||||
* @param array $cache The cache to use.
|
* @param array $cache The cache to use.
|
||||||
* @param array $result The result array to fill.
|
* @param array $result The result array to fill.
|
||||||
*/
|
*/
|
||||||
protected function _hydrateRow(array $row, array &$cache, array &$result)
|
protected function hydrateRowData(array $row, array &$cache, array &$result)
|
||||||
{
|
{
|
||||||
// Initialize
|
// Initialize
|
||||||
$id = $this->_idTemplate; // initialize the id-memory
|
$id = $this->_idTemplate; // initialize the id-memory
|
||||||
$nonemptyComponents = array();
|
$nonemptyComponents = array();
|
||||||
// Split the row data into chunks of class data.
|
// Split the row data into chunks of class data.
|
||||||
$rowData = $this->_gatherRowData($row, $cache, $id, $nonemptyComponents);
|
$rowData = $this->gatherRowData($row, $cache, $id, $nonemptyComponents);
|
||||||
|
|
||||||
// Extract scalar values. They're appended at the end.
|
// Extract scalar values. They're appended at the end.
|
||||||
if (isset($rowData['scalars'])) {
|
if (isset($rowData['scalars'])) {
|
||||||
|
@ -26,25 +26,32 @@ use Doctrine\DBAL\Connection;
|
|||||||
* The created result is almost the same as a regular SQL result set, except
|
* The created result is almost the same as a regular SQL result set, except
|
||||||
* that column names are mapped to field names and data type conversions take place.
|
* that column names are mapped to field names and data type conversions take place.
|
||||||
*
|
*
|
||||||
|
* @since 2.0
|
||||||
* @author Roman Borschel <roman@code-factory.org>
|
* @author Roman Borschel <roman@code-factory.org>
|
||||||
* @since 2.0
|
* @author Guilherme Blanco <guilhermeblanco@hotmail.com>
|
||||||
*/
|
*/
|
||||||
class ScalarHydrator extends AbstractHydrator
|
class ScalarHydrator extends AbstractHydrator
|
||||||
{
|
{
|
||||||
/** @override */
|
/**
|
||||||
protected function _hydrateAll()
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
protected function hydrateAllData()
|
||||||
{
|
{
|
||||||
$result = array();
|
$result = array();
|
||||||
$cache = array();
|
$cache = array();
|
||||||
|
|
||||||
while ($data = $this->_stmt->fetch(\PDO::FETCH_ASSOC)) {
|
while ($data = $this->_stmt->fetch(\PDO::FETCH_ASSOC)) {
|
||||||
$result[] = $this->_gatherScalarRowData($data, $cache);
|
$this->hydrateRowData($data, $cache, $result);
|
||||||
}
|
}
|
||||||
|
|
||||||
return $result;
|
return $result;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @override */
|
/**
|
||||||
protected function _hydrateRow(array $data, array &$cache, array &$result)
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
protected function hydrateRowData(array $data, array &$cache, array &$result)
|
||||||
{
|
{
|
||||||
$result[] = $this->_gatherScalarRowData($data, $cache);
|
$result[] = $this->gatherScalarRowData($data, $cache);
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -17,7 +17,6 @@
|
|||||||
* <http://www.doctrine-project.org>.
|
* <http://www.doctrine-project.org>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
namespace Doctrine\ORM\Internal\Hydration;
|
namespace Doctrine\ORM\Internal\Hydration;
|
||||||
|
|
||||||
use \PDO;
|
use \PDO;
|
||||||
@ -32,15 +31,21 @@ class SimpleObjectHydrator extends AbstractHydrator
|
|||||||
*/
|
*/
|
||||||
private $class;
|
private $class;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var array
|
||||||
|
*/
|
||||||
private $declaringClasses = array();
|
private $declaringClasses = array();
|
||||||
|
|
||||||
protected function _hydrateAll()
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
protected function hydrateAllData()
|
||||||
{
|
{
|
||||||
$result = array();
|
$result = array();
|
||||||
$cache = array();
|
$cache = array();
|
||||||
|
|
||||||
while ($row = $this->_stmt->fetch(PDO::FETCH_ASSOC)) {
|
while ($row = $this->_stmt->fetch(PDO::FETCH_ASSOC)) {
|
||||||
$this->_hydrateRow($row, $cache, $result);
|
$this->hydrateRowData($row, $cache, $result);
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->_em->getUnitOfWork()->triggerEagerLoads();
|
$this->_em->getUnitOfWork()->triggerEagerLoads();
|
||||||
@ -48,82 +53,71 @@ class SimpleObjectHydrator extends AbstractHydrator
|
|||||||
return $result;
|
return $result;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function _prepare()
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
protected function prepare()
|
||||||
{
|
{
|
||||||
if (count($this->_rsm->aliasMap) == 1) {
|
if (count($this->_rsm->aliasMap) !== 1) {
|
||||||
$this->class = $this->_em->getClassMetadata(reset($this->_rsm->aliasMap));
|
throw new \RuntimeException("Cannot use SimpleObjectHydrator with a ResultSetMapping that contains more than one object result.");
|
||||||
if ($this->class->inheritanceType !== ClassMetadata::INHERITANCE_TYPE_NONE) {
|
|
||||||
foreach ($this->_rsm->declaringClasses AS $column => $class) {
|
|
||||||
$this->declaringClasses[$column] = $this->_em->getClassMetadata($class);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
throw new \RuntimeException("Cannot use SimpleObjectHydrator with a ResultSetMapping not containing exactly one object result.");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($this->_rsm->scalarMappings) {
|
if ($this->_rsm->scalarMappings) {
|
||||||
throw new \RuntimeException("Cannot use SimpleObjectHydrator with a ResultSetMapping that contains scalar mappings.");
|
throw new \RuntimeException("Cannot use SimpleObjectHydrator with a ResultSetMapping that contains scalar mappings.");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$this->class = $this->_em->getClassMetadata(reset($this->_rsm->aliasMap));
|
||||||
|
|
||||||
|
// We only need to add declaring classes if we have inheritance.
|
||||||
|
if ($this->class->inheritanceType === ClassMetadata::INHERITANCE_TYPE_NONE) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach ($this->_rsm->declaringClasses AS $column => $class) {
|
||||||
|
$this->declaringClasses[$column] = $this->_em->getClassMetadata($class);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function _hydrateRow(array $sqlResult, array &$cache, array &$result)
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
protected function hydrateRowData(array $sqlResult, array &$cache, array &$result)
|
||||||
{
|
{
|
||||||
$data = array();
|
$entityName = $this->class->name;
|
||||||
if ($this->class->inheritanceType == ClassMetadata::INHERITANCE_TYPE_NONE) {
|
$data = array();
|
||||||
foreach ($sqlResult as $column => $value) {
|
|
||||||
|
|
||||||
if (!isset($cache[$column])) {
|
// We need to find the correct entity class name if we have inheritance in resultset
|
||||||
if (isset($this->_rsm->fieldMappings[$column])) {
|
if ($this->class->inheritanceType !== ClassMetadata::INHERITANCE_TYPE_NONE) {
|
||||||
$cache[$column]['name'] = $this->_rsm->fieldMappings[$column];
|
|
||||||
$cache[$column]['field'] = true;
|
|
||||||
} else {
|
|
||||||
$cache[$column]['name'] = $this->_rsm->metaMappings[$column];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (isset($cache[$column]['field'])) {
|
|
||||||
$value = Type::getType($this->class->fieldMappings[$cache[$column]['name']]['type'])
|
|
||||||
->convertToPHPValue($value, $this->_platform);
|
|
||||||
}
|
|
||||||
$data[$cache[$column]['name']] = $value;
|
|
||||||
}
|
|
||||||
$entityName = $this->class->name;
|
|
||||||
} else {
|
|
||||||
$discrColumnName = $this->_platform->getSQLResultCasing($this->class->discriminatorColumn['name']);
|
$discrColumnName = $this->_platform->getSQLResultCasing($this->class->discriminatorColumn['name']);
|
||||||
if ($sqlResult[$discrColumnName] === "") {
|
|
||||||
|
if ($sqlResult[$discrColumnName] === '') {
|
||||||
throw HydrationException::emptyDiscriminatorValue(key($this->_rsm->aliasMap));
|
throw HydrationException::emptyDiscriminatorValue(key($this->_rsm->aliasMap));
|
||||||
}
|
}
|
||||||
|
|
||||||
$entityName = $this->class->discriminatorMap[$sqlResult[$discrColumnName]];
|
$entityName = $this->class->discriminatorMap[$sqlResult[$discrColumnName]];
|
||||||
|
|
||||||
unset($sqlResult[$discrColumnName]);
|
unset($sqlResult[$discrColumnName]);
|
||||||
|
}
|
||||||
|
|
||||||
foreach ($sqlResult as $column => $value) {
|
foreach ($sqlResult as $column => $value) {
|
||||||
if (!isset($cache[$column])) {
|
// Hydrate column information if not yet present
|
||||||
if (isset($this->_rsm->fieldMappings[$column])) {
|
if ( ! isset($cache[$column])) {
|
||||||
$field = $this->_rsm->fieldMappings[$column];
|
if (($info = $this->hydrateColumnInfo($entityName, $column)) === null) {
|
||||||
$class = $this->declaringClasses[$column];
|
continue;
|
||||||
if ($class->name == $entityName || is_subclass_of($entityName, $class->name)) {
|
|
||||||
$cache[$column]['name'] = $field;
|
|
||||||
$cache[$column]['class'] = $class;
|
|
||||||
}
|
|
||||||
} else if (isset($this->_rsm->relationMap[$column])) {
|
|
||||||
if ($this->_rsm->relationMap[$column] == $entityName || is_subclass_of($entityName, $this->_rsm->relationMap[$column])) {
|
|
||||||
$cache[$column]['name'] = $field;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
$cache[$column]['name'] = $this->_rsm->metaMappings[$column];
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isset($cache[$column]['class'])) {
|
$cache[$column] = $info;
|
||||||
$value = Type::getType($cache[$column]['class']->fieldMappings[$cache[$column]['name']]['type'])
|
}
|
||||||
->convertToPHPValue($value, $this->_platform);
|
|
||||||
}
|
|
||||||
|
|
||||||
// the second and part is to prevent overwrites in case of multiple
|
// Convert field to a valid PHP value
|
||||||
// inheritance classes using the same property name (See AbstractHydrator)
|
if (isset($cache[$column]['field'])) {
|
||||||
if (isset($cache[$column]) && (!isset($data[$cache[$column]['name']]) || $value !== null)) {
|
$type = Type::getType($cache[$column]['class']->fieldMappings[$cache[$column]['name']]['type']);
|
||||||
$data[$cache[$column]['name']] = $value;
|
$value = $type->convertToPHPValue($value, $this->_platform);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Prevent overwrite in case of inherit classes using same property name (See AbstractHydrator)
|
||||||
|
if (isset($cache[$column]) && ( ! isset($data[$cache[$column]['name']]) || $value !== null)) {
|
||||||
|
$data[$cache[$column]['name']] = $value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -133,4 +127,52 @@ class SimpleObjectHydrator extends AbstractHydrator
|
|||||||
|
|
||||||
$result[] = $this->_em->getUnitOfWork()->createEntity($entityName, $data, $this->_hints);
|
$result[] = $this->_em->getUnitOfWork()->createEntity($entityName, $data, $this->_hints);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieve column information form ResultSetMapping.
|
||||||
|
*
|
||||||
|
* @param string $entityName
|
||||||
|
* @param string $column
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
protected function hydrateColumnInfo($entityName, $column)
|
||||||
|
{
|
||||||
|
switch (true) {
|
||||||
|
case (isset($this->_rsm->fieldMappings[$column])):
|
||||||
|
$class = isset($this->declaringClasses[$column])
|
||||||
|
? $this->declaringClasses[$column]
|
||||||
|
: $this->class;
|
||||||
|
|
||||||
|
// If class is not part of the inheritance, ignore
|
||||||
|
if ( ! ($class->name === $entityName || is_subclass_of($entityName, $class->name))) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return array(
|
||||||
|
'class' => $class,
|
||||||
|
'name' => $this->_rsm->fieldMappings[$column],
|
||||||
|
'field' => true,
|
||||||
|
);
|
||||||
|
|
||||||
|
case (isset($this->_rsm->relationMap[$column])):
|
||||||
|
$class = isset($this->_rsm->relationMap[$column])
|
||||||
|
? $this->_rsm->relationMap[$column]
|
||||||
|
: $this->class;
|
||||||
|
|
||||||
|
// If class is not self referencing, ignore
|
||||||
|
if ( ! ($class === $entityName || is_subclass_of($entityName, $class))) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: Decide what to do with associations. It seems original code is incomplete.
|
||||||
|
// One solution is to load the association, but it might require extra efforts.
|
||||||
|
return array('name' => $column);
|
||||||
|
|
||||||
|
default:
|
||||||
|
return array(
|
||||||
|
'name' => $this->_rsm->metaMappings[$column]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
@ -19,30 +19,37 @@
|
|||||||
|
|
||||||
namespace Doctrine\ORM\Internal\Hydration;
|
namespace Doctrine\ORM\Internal\Hydration;
|
||||||
|
|
||||||
use Doctrine\DBAL\Connection;
|
use Doctrine\DBAL\Connection,
|
||||||
|
Doctrine\ORM\NoResultException,
|
||||||
|
Doctrine\ORM\NonUniqueResultException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Hydrator that hydrates a single scalar value from the result set.
|
* Hydrator that hydrates a single scalar value from the result set.
|
||||||
*
|
*
|
||||||
|
* @since 2.0
|
||||||
* @author Roman Borschel <roman@code-factory.org>
|
* @author Roman Borschel <roman@code-factory.org>
|
||||||
* @since 2.0
|
* @author Guilherme Blanco <guilhermeblanco@hotmail.com>
|
||||||
*/
|
*/
|
||||||
class SingleScalarHydrator extends AbstractHydrator
|
class SingleScalarHydrator extends AbstractHydrator
|
||||||
{
|
{
|
||||||
/** @override */
|
/**
|
||||||
protected function _hydrateAll()
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
protected function hydrateAllData()
|
||||||
{
|
{
|
||||||
$cache = array();
|
$data = $this->_stmt->fetchAll(\PDO::FETCH_ASSOC);
|
||||||
$result = $this->_stmt->fetchAll(\PDO::FETCH_ASSOC);
|
$numRows = count($data);
|
||||||
$num = count($result);
|
|
||||||
|
|
||||||
if ($num == 0) {
|
if ($numRows === 0) {
|
||||||
throw new \Doctrine\ORM\NoResultException;
|
throw new NoResultException();
|
||||||
} else if ($num > 1 || count($result[key($result)]) > 1) {
|
|
||||||
throw new \Doctrine\ORM\NonUniqueResultException;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
$result = $this->_gatherScalarRowData($result[key($result)], $cache);
|
if ($numRows > 1 || count($data[key($data)]) > 1) {
|
||||||
|
throw new NonUniqueResultException();
|
||||||
|
}
|
||||||
|
|
||||||
|
$cache = array();
|
||||||
|
$result = $this->gatherScalarRowData($data[key($data)], $cache);
|
||||||
|
|
||||||
return array_shift($result);
|
return array_shift($result);
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user