Heavily simplified code on simple object hydrator. Code cleanup on column information cache; by reference cache variable is no longer needed and protected variable is used in a standardized way everywhere.
This commit is contained in:
parent
e8e86205f5
commit
21437bb276
@ -1,5 +1,13 @@
|
||||
# Upgrade to 2.5
|
||||
|
||||
## Minor BC BREAK: Custom Hydrators API change
|
||||
|
||||
As of 2.5, `AbstractHydrator` does not enforce the usage of cache as part of
|
||||
API, and now provides you a clean API for column information through the method
|
||||
`hydrateColumnInfo($column)`.
|
||||
Cache variable being passed around by reference is no longer needed since
|
||||
Hydrators are per query instantiated since Doctrine 2.4.
|
||||
|
||||
## Minor BC BREAK: Entity based ``EntityManager#clear()`` calls follow cascade detach
|
||||
|
||||
Whenever ``EntityManager#clear()`` method gets called with a given entity class
|
||||
|
@ -162,7 +162,7 @@ abstract class AbstractHydrator
|
||||
|
||||
$result = array();
|
||||
|
||||
$this->hydrateRowData($row, $this->_cache, $result);
|
||||
$this->hydrateRowData($row, $result);
|
||||
|
||||
return $result;
|
||||
}
|
||||
@ -209,14 +209,13 @@ abstract class AbstractHydrator
|
||||
* Template method.
|
||||
*
|
||||
* @param array $data The row data.
|
||||
* @param array $cache The cache to use.
|
||||
* @param array $result The result to fill.
|
||||
*
|
||||
* @return void
|
||||
*
|
||||
* @throws HydrationException
|
||||
*/
|
||||
protected function hydrateRowData(array $data, array &$cache, array &$result)
|
||||
protected function hydrateRowData(array $data, array &$result)
|
||||
{
|
||||
throw new HydrationException("hydrateRowData() not implemented by this hydrator.");
|
||||
}
|
||||
@ -238,19 +237,18 @@ abstract class AbstractHydrator
|
||||
* the values applied. Scalar values are kept in a specific key 'scalars'.
|
||||
*
|
||||
* @param array $data SQL Result Row.
|
||||
* @param array &$cache Cache for column to field result information.
|
||||
* @param array &$id Dql-Alias => ID-Hash.
|
||||
* @param array &$nonemptyComponents Does this DQL-Alias has at least one non NULL value?
|
||||
*
|
||||
* @return array An array with all the fields (name => value) of the data row,
|
||||
* grouped by their component alias.
|
||||
*/
|
||||
protected function gatherRowData(array $data, array &$cache, array &$id, array &$nonemptyComponents)
|
||||
protected function gatherRowData(array $data, array &$id, array &$nonemptyComponents)
|
||||
{
|
||||
$rowData = array('data' => array());
|
||||
|
||||
foreach ($data as $key => $value) {
|
||||
$cacheKeyInfo = $this->getColumnCacheInfo($key, $cache);
|
||||
$cacheKeyInfo = $this->hydrateColumnInfo($key);
|
||||
|
||||
if ( ! $cacheKeyInfo) {
|
||||
continue;
|
||||
@ -332,16 +330,15 @@ abstract class AbstractHydrator
|
||||
* of elements as before.
|
||||
*
|
||||
* @param array $data
|
||||
* @param array $cache
|
||||
*
|
||||
* @return array The processed row.
|
||||
*/
|
||||
protected function gatherScalarRowData(&$data, &$cache)
|
||||
protected function gatherScalarRowData(&$data)
|
||||
{
|
||||
$rowData = array();
|
||||
|
||||
foreach ($data as $key => $value) {
|
||||
$cacheKeyInfo = $this->getColumnCacheInfo($key, $cache);
|
||||
$cacheKeyInfo = $this->hydrateColumnInfo($key);
|
||||
|
||||
if ( ! $cacheKeyInfo) {
|
||||
continue;
|
||||
@ -379,17 +376,16 @@ abstract class AbstractHydrator
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve column information from cache.
|
||||
* Retrieve column information from ResultSetMapping.
|
||||
*
|
||||
* @param string $key Column name
|
||||
* @param array &$cache Cache for column to field result information.
|
||||
* @param string $key Column name
|
||||
*
|
||||
* @return array|null
|
||||
*/
|
||||
protected function getColumnCacheInfo($key, &$cache)
|
||||
protected function hydrateColumnInfo($key)
|
||||
{
|
||||
if (isset($cache[$key])) {
|
||||
return $cache[$key];
|
||||
if (isset($this->_cache[$key])) {
|
||||
return $this->_cache[$key];
|
||||
}
|
||||
|
||||
switch (true) {
|
||||
@ -398,45 +394,50 @@ abstract class AbstractHydrator
|
||||
$fieldName = $this->_rsm->fieldMappings[$key];
|
||||
$classMetadata = $this->_em->getClassMetadata($this->_rsm->declaringClasses[$key]);
|
||||
|
||||
$cache[$key]['fieldName'] = $fieldName;
|
||||
$cache[$key]['type'] = Type::getType($classMetadata->fieldMappings[$fieldName]['type']);
|
||||
$cache[$key]['isIdentifier'] = $classMetadata->isIdentifier($fieldName);
|
||||
$cache[$key]['dqlAlias'] = $this->_rsm->columnOwnerMap[$key];
|
||||
|
||||
return $cache[$key];
|
||||
return $this->_cache[$key] = array(
|
||||
'isIdentifier' => $classMetadata->isIdentifier($fieldName),
|
||||
'fieldName' => $fieldName,
|
||||
'type' => Type::getType($classMetadata->fieldMappings[$fieldName]['type']),
|
||||
'dqlAlias' => $this->_rsm->columnOwnerMap[$key],
|
||||
);
|
||||
|
||||
case (isset($this->_rsm->newObjectMappings[$key])):
|
||||
// WARNING: A NEW object is also a scalar, so it must be declared before!
|
||||
$mapping = $this->_rsm->newObjectMappings[$key];
|
||||
|
||||
$cache[$key]['isScalar'] = true;
|
||||
$cache[$key]['isNewObjectParameter'] = true;
|
||||
$cache[$key]['fieldName'] = $this->_rsm->scalarMappings[$key];
|
||||
$cache[$key]['type'] = Type::getType($this->_rsm->typeMappings[$key]);
|
||||
$cache[$key]['argIndex'] = $mapping['argIndex'];
|
||||
$cache[$key]['objIndex'] = $mapping['objIndex'];
|
||||
$cache[$key]['class'] = new \ReflectionClass($mapping['className']);
|
||||
|
||||
return $cache[$key];
|
||||
return $this->_cache[$key] = array(
|
||||
'isScalar' => true,
|
||||
'isNewObjectParameter' => true,
|
||||
'fieldName' => $this->_rsm->scalarMappings[$key],
|
||||
'type' => Type::getType($this->_rsm->typeMappings[$key]),
|
||||
'argIndex' => $mapping['argIndex'],
|
||||
'objIndex' => $mapping['objIndex'],
|
||||
'class' => new \ReflectionClass($mapping['className']),
|
||||
);
|
||||
|
||||
case (isset($this->_rsm->scalarMappings[$key])):
|
||||
$cache[$key]['fieldName'] = $this->_rsm->scalarMappings[$key];
|
||||
$cache[$key]['type'] = Type::getType($this->_rsm->typeMappings[$key]);
|
||||
$cache[$key]['isScalar'] = true;
|
||||
|
||||
return $cache[$key];
|
||||
return $this->_cache[$key] = array(
|
||||
'isScalar' => true,
|
||||
'fieldName' => $this->_rsm->scalarMappings[$key],
|
||||
'type' => Type::getType($this->_rsm->typeMappings[$key]),
|
||||
);
|
||||
|
||||
case (isset($this->_rsm->metaMappings[$key])):
|
||||
// Meta column (has meaning in relational schema only, i.e. foreign keys or discriminator columns).
|
||||
$fieldName = $this->_rsm->metaMappings[$key];
|
||||
$classMetadata = $this->_em->getClassMetadata($this->_rsm->aliasMap[$this->_rsm->columnOwnerMap[$key]]);
|
||||
$dqlAlias = $this->_rsm->columnOwnerMap[$key];
|
||||
$classMetadata = $this->_em->getClassMetadata($this->_rsm->aliasMap[$dqlAlias]);
|
||||
$type = isset($this->_rsm->typeMappings[$key])
|
||||
? Type::getType($this->_rsm->typeMappings[$key])
|
||||
: null;
|
||||
|
||||
$cache[$key]['isMetaColumn'] = true;
|
||||
$cache[$key]['fieldName'] = $fieldName;
|
||||
$cache[$key]['dqlAlias'] = $this->_rsm->columnOwnerMap[$key];
|
||||
$cache[$key]['isIdentifier'] = isset($this->_rsm->isIdentifierColumn[$cache[$key]['dqlAlias']][$key]);
|
||||
|
||||
return $cache[$key];
|
||||
return $this->_cache[$key] = array(
|
||||
'isIdentifier' => isset($this->_rsm->isIdentifierColumn[$dqlAlias][$key]),
|
||||
'isMetaColumn' => true,
|
||||
'fieldName' => $fieldName,
|
||||
'type' => $type,
|
||||
'dqlAlias' => $dqlAlias,
|
||||
);
|
||||
}
|
||||
|
||||
// this column is a left over, maybe from a LIMIT query hack for example in Oracle or DB2
|
||||
|
@ -91,10 +91,9 @@ class ArrayHydrator extends AbstractHydrator
|
||||
protected function hydrateAllData()
|
||||
{
|
||||
$result = array();
|
||||
$cache = array();
|
||||
|
||||
while ($data = $this->_stmt->fetch(PDO::FETCH_ASSOC)) {
|
||||
$this->hydrateRowData($data, $cache, $result);
|
||||
$this->hydrateRowData($data, $result);
|
||||
}
|
||||
|
||||
return $result;
|
||||
@ -103,12 +102,12 @@ class ArrayHydrator extends AbstractHydrator
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function hydrateRowData(array $row, array &$cache, array &$result)
|
||||
protected function hydrateRowData(array $row, array &$result)
|
||||
{
|
||||
// 1) Initialize
|
||||
$id = $this->_idTemplate; // initialize the id-memory
|
||||
$nonemptyComponents = array();
|
||||
$rowData = $this->gatherRowData($row, $cache, $id, $nonemptyComponents);
|
||||
$rowData = $this->gatherRowData($row, $id, $nonemptyComponents);
|
||||
|
||||
// 2) Now hydrate the data found in the current row.
|
||||
foreach ($rowData['data'] as $dqlAlias => $data) {
|
||||
|
@ -173,10 +173,9 @@ class ObjectHydrator extends AbstractHydrator
|
||||
protected function hydrateAllData()
|
||||
{
|
||||
$result = array();
|
||||
$cache = array();
|
||||
|
||||
while ($row = $this->_stmt->fetch(PDO::FETCH_ASSOC)) {
|
||||
$this->hydrateRowData($row, $cache, $result);
|
||||
$this->hydrateRowData($row, $result);
|
||||
}
|
||||
|
||||
// Take snapshots from all newly initialized collections
|
||||
@ -351,18 +350,17 @@ class ObjectHydrator extends AbstractHydrator
|
||||
* specified by the FROM clause in a DQL query.
|
||||
*
|
||||
* @param array $row The data of the row to process.
|
||||
* @param array $cache The cache to use.
|
||||
* @param array $result The result array to fill.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function hydrateRowData(array $row, array &$cache, array &$result)
|
||||
protected function hydrateRowData(array $row, array &$result)
|
||||
{
|
||||
// Initialize
|
||||
$id = $this->idTemplate; // initialize the id-memory
|
||||
$nonemptyComponents = array();
|
||||
// Split the row data into chunks of class data.
|
||||
$rowData = $this->gatherRowData($row, $cache, $id, $nonemptyComponents);
|
||||
$rowData = $this->gatherRowData($row, $id, $nonemptyComponents);
|
||||
|
||||
// Hydrate the data chunks
|
||||
foreach ($rowData['data'] as $dqlAlias => $data) {
|
||||
|
@ -39,7 +39,7 @@ class ScalarHydrator extends AbstractHydrator
|
||||
$cache = array();
|
||||
|
||||
while ($data = $this->_stmt->fetch(\PDO::FETCH_ASSOC)) {
|
||||
$this->hydrateRowData($data, $cache, $result);
|
||||
$this->hydrateRowData($data, $result);
|
||||
}
|
||||
|
||||
return $result;
|
||||
@ -48,8 +48,8 @@ class ScalarHydrator extends AbstractHydrator
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function hydrateRowData(array $data, array &$cache, array &$result)
|
||||
protected function hydrateRowData(array $data, array &$result)
|
||||
{
|
||||
$result[] = $this->gatherScalarRowData($data, $cache);
|
||||
$result[] = $this->gatherScalarRowData($data);
|
||||
}
|
||||
}
|
||||
|
@ -42,10 +42,9 @@ class SimpleObjectHydrator extends AbstractHydrator
|
||||
protected function hydrateAllData()
|
||||
{
|
||||
$result = array();
|
||||
$cache = array();
|
||||
|
||||
while ($row = $this->_stmt->fetch(PDO::FETCH_ASSOC)) {
|
||||
$this->hydrateRowData($row, $cache, $result);
|
||||
$this->hydrateRowData($row, $result);
|
||||
}
|
||||
|
||||
$this->_em->getUnitOfWork()->triggerEagerLoads();
|
||||
@ -81,7 +80,7 @@ class SimpleObjectHydrator extends AbstractHydrator
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function hydrateRowData(array $sqlResult, array &$cache, array &$result)
|
||||
protected function hydrateRowData(array $sqlResult, array &$result)
|
||||
{
|
||||
$entityName = $this->class->name;
|
||||
$data = array();
|
||||
@ -103,30 +102,35 @@ class SimpleObjectHydrator extends AbstractHydrator
|
||||
if ( ! isset($discrMap[$sqlResult[$discrColumnName]])) {
|
||||
throw HydrationException::invalidDiscriminatorValue($sqlResult[$discrColumnName], array_keys($discrMap));
|
||||
}
|
||||
|
||||
|
||||
$entityName = $discrMap[$sqlResult[$discrColumnName]];
|
||||
|
||||
unset($sqlResult[$discrColumnName]);
|
||||
}
|
||||
|
||||
foreach ($sqlResult as $column => $value) {
|
||||
// Hydrate column information if not yet present
|
||||
if ( ! isset($cache[$column])) {
|
||||
if (($info = $this->hydrateColumnInfo($entityName, $column)) === null) {
|
||||
continue;
|
||||
}
|
||||
// An ObjectHydrator should be used instead of SimpleObjectHydrator
|
||||
if (isset($this->_rsm->relationMap[$column])) {
|
||||
throw new \Exception(sprintf('Unable to retrieve association information for column "%s"', $column));
|
||||
}
|
||||
|
||||
$cache[$column] = $info;
|
||||
$cacheKeyInfo = $this->hydrateColumnInfo($column);
|
||||
|
||||
if ( ! $cacheKeyInfo) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Convert field to a valid PHP value
|
||||
if (isset($cache[$column]['type'])) {
|
||||
$value = Type::getType($cache[$column]['type'])->convertToPHPValue($value, $this->_platform);
|
||||
if (isset($cacheKeyInfo['type'])) {
|
||||
$type = $cacheKeyInfo['type'];
|
||||
$value = $type->convertToPHPValue($value, $this->_platform);
|
||||
}
|
||||
|
||||
$fieldName = $cacheKeyInfo['fieldName'];
|
||||
|
||||
// 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;
|
||||
if ( ! isset($data[$fieldName]) || $value !== null) {
|
||||
$data[$fieldName] = $value;
|
||||
}
|
||||
}
|
||||
|
||||
@ -139,47 +143,4 @@ class SimpleObjectHydrator extends AbstractHydrator
|
||||
|
||||
$result[] = $entity;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve column information form ResultSetMapping.
|
||||
*
|
||||
* @param string $entityName
|
||||
* @param string $column
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function hydrateColumnInfo($entityName, $column)
|
||||
{
|
||||
|
||||
if (isset($this->_rsm->fieldMappings[$column])) {
|
||||
$name = $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(
|
||||
'name' => $name,
|
||||
'type' => $class->fieldMappings[$name]['type']
|
||||
);
|
||||
}
|
||||
|
||||
if (isset($this->_rsm->metaMappings[$column])) {
|
||||
return array(
|
||||
'name' => $this->_rsm->metaMappings[$column],
|
||||
'type' => (isset($this->_rsm->typeMappings[$column]) ? $this->_rsm->typeMappings[$column] : null)
|
||||
);
|
||||
}
|
||||
|
||||
// An ObjectHydrator should be used instead of SimpleObjectHydrator
|
||||
if (isset($this->_rsm->relationMap[$column])) {
|
||||
throw new \Exception(sprintf('Unable to retrieve association information for column "%s"', $column));
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user