From a04ba4487469d890ea20063b5b6911cc780eccd4 Mon Sep 17 00:00:00 2001 From: Benjamin Eberlei Date: Tue, 15 Mar 2011 19:48:04 +0100 Subject: [PATCH] [DDC-952] Introduced SimpleObjectHydrator again for performance reasons. --- lib/Doctrine/ORM/AbstractQuery.php | 5 + lib/Doctrine/ORM/EntityManager.php | 3 + .../Hydration/SimpleObjectHydrator.php | 126 ++++++++++++++++++ .../ORM/Persisters/BasicEntityPersister.php | 6 +- 4 files changed, 139 insertions(+), 1 deletion(-) create mode 100644 lib/Doctrine/ORM/Internal/Hydration/SimpleObjectHydrator.php diff --git a/lib/Doctrine/ORM/AbstractQuery.php b/lib/Doctrine/ORM/AbstractQuery.php index b1b24230b..677de4472 100644 --- a/lib/Doctrine/ORM/AbstractQuery.php +++ b/lib/Doctrine/ORM/AbstractQuery.php @@ -57,6 +57,11 @@ abstract class AbstractQuery */ const HYDRATE_SINGLE_SCALAR = 4; + /** + * Very simple object hydrator (optimized for performance). + */ + const HYDRATE_SIMPLEOBJECT = 5; + /** * @var array The parameter map of this query. */ diff --git a/lib/Doctrine/ORM/EntityManager.php b/lib/Doctrine/ORM/EntityManager.php index 2839099fc..43b257788 100644 --- a/lib/Doctrine/ORM/EntityManager.php +++ b/lib/Doctrine/ORM/EntityManager.php @@ -679,6 +679,9 @@ class EntityManager implements ObjectManager case Query::HYDRATE_SINGLE_SCALAR: $hydrator = new Internal\Hydration\SingleScalarHydrator($this); break; + case Query::HYDRATE_SIMPLEOBJECT: + $hydrator = new Internal\Hydration\SimpleObjectHydrator($this); + break; default: if ($class = $this->config->getCustomHydrationMode($hydrationMode)) { $hydrator = new $class($this); diff --git a/lib/Doctrine/ORM/Internal/Hydration/SimpleObjectHydrator.php b/lib/Doctrine/ORM/Internal/Hydration/SimpleObjectHydrator.php new file mode 100644 index 000000000..68cdc3653 --- /dev/null +++ b/lib/Doctrine/ORM/Internal/Hydration/SimpleObjectHydrator.php @@ -0,0 +1,126 @@ +. + */ + + +namespace Doctrine\ORM\Internal\Hydration; + +use \PDO; +use Doctrine\ORM\Mapping\ClassMetadata; +use Doctrine\DBAL\Types\Type; + +class SimpleObjectHydrator extends AbstractHydrator +{ + const REFRESH_ENTITY = 'doctrine_refresh_entity'; + + /** + * @var ClassMetadata + */ + private $class; + + protected function _hydrateAll() + { + $result = array(); + $cache = array(); + + while ($row = $this->_stmt->fetch(PDO::FETCH_ASSOC)) { + $this->_hydrateRow($row, $cache, $result); + } + + $this->_em->getUnitOfWork()->triggerEagerLoads(); + + return $result; + } + + protected function _prepare() + { + if (count($this->_rsm->aliasMap) == 1) { + $this->class = $this->_em->getClassMetadata(current($this->_rsm->aliasMap)); + } else { + throw new \RuntimeException("Cannot use SimpleObjectHydrator with a ResultSetMapping not containing exactly one object result."); + } + if ($this->_rsm->scalarMappings) { + throw new \RuntimeException("Cannot use SimpleObjectHydrator with a ResultSetMapping that contains scalar mappings."); + } + } + + protected function _hydrateRow(array $sqlResult, array &$cache, array &$result) + { + $data = array(); + if ($this->class->inheritanceType == ClassMetadata::INHERITANCE_TYPE_NONE) { + foreach ($sqlResult as $column => $value) { + + if (isset($this->_rsm->fieldMappings[$column])) { + $column = $this->_rsm->fieldMappings[$column]; + $field = $this->class->fieldNames[$column]; + if (isset($data[$field])) { + $data[$column] = $value; + } else { + $data[$field] = Type::getType($this->class->fieldMappings[$field]['type']) + ->convertToPHPValue($value, $this->_platform); + } + } else { + $column = $this->_rsm->metaMappings[$column]; + $data[$column] = $value; + } + } + $entityName = $this->class->name; + } else { + $discrColumnName = $this->_platform->getSQLResultCasing($this->class->discriminatorColumn['name']); + $entityName = $this->class->discriminatorMap[$sqlResult[$discrColumnName]]; + unset($sqlResult[$discrColumnName]); + foreach ($sqlResult as $column => $value) { + if (isset($this->_rsm->fieldMappings[$column])) { + $realColumnName = $this->_rsm->fieldMappings[$column]; + $class = $this->_em->getClassMetadata($this->_rsm->declaringClasses[$column]); + if ($class->name == $entityName || is_subclass_of($entityName, $class->name)) { + $field = $class->fieldNames[$realColumnName]; + if (isset($data[$field])) { + $data[$realColumnName] = $value; + } else { + $data[$field] = Type::getType($class->fieldMappings[$field]['type']) + ->convertToPHPValue($value, $this->_platform); + } + } + } else if (isset($this->_rsm->relationMap[$column])) { + if ($this->_rsm->relationMap[$column] == $entityName || is_subclass_of($entityName, $this->_rsm->relationMap[$column])) { + $data[$realColumnName] = $value; + } + } else { + $column = $this->_rsm->metaMappings[$column]; + $data[$realColumnName] = $value; + } + } + } + + if (isset($this->_hints[self::REFRESH_ENTITY])) { + $this->_hints[Query::HINT_REFRESH] = true; + $id = array(); + if ($this->_class->isIdentifierComposite) { + foreach ($this->_class->identifier as $fieldName) { + $id[$fieldName] = $data[$fieldName]; + } + } else { + $id = array($this->_class->identifier[0] => $data[$this->_class->identifier[0]]); + } + $this->_em->getUnitOfWork()->registerManaged($this->_hints[self::REFRESH_ENTITY], $id, $data); + } + + $result[] = $this->_em->getUnitOfWork()->createEntity($entityName, $data, $this->_hints); + } +} \ No newline at end of file diff --git a/lib/Doctrine/ORM/Persisters/BasicEntityPersister.php b/lib/Doctrine/ORM/Persisters/BasicEntityPersister.php index 016184679..9671f945a 100644 --- a/lib/Doctrine/ORM/Persisters/BasicEntityPersister.php +++ b/lib/Doctrine/ORM/Persisters/BasicEntityPersister.php @@ -685,7 +685,11 @@ class BasicEntityPersister list($params, $types) = $this->expandParameters($criteria); $stmt = $this->_conn->executeQuery($sql, $params, $types); - $hydrator = $this->_em->newHydrator(Query::HYDRATE_OBJECT); + if ($this->_selectJoinSql) { + $hydrator = $this->_em->newHydrator(Query::HYDRATE_OBJECT); + } else { + $hydrator = $this->_em->newHydrator(Query::HYDRATE_SIMPLEOBJECT); + } return $hydrator->hydrateAll($stmt, $this->_rsm, array('deferEagerLoads' => true)); }