diff --git a/lib/Doctrine/Hydrator/ArrayDriver.php b/lib/Doctrine/Hydrator/ArrayDriver.php index 0850ed0e2..e1fdc21a9 100644 --- a/lib/Doctrine/Hydrator/ArrayDriver.php +++ b/lib/Doctrine/Hydrator/ArrayDriver.php @@ -89,4 +89,37 @@ public function setLastElement(&$prev, &$coll, $index, $dqlAlias, $oneToOne) } } } -} \ No newline at end of file + + protected function beforeAddingAggregateValue($rowData, $cache, $dqlAlias, $value) + { + $rowData = $this->addSelectedRelationToRowData($rowData, $dqlAlias, $cache); + + $rowData = $this->addIdentifierColumnToRowData($rowData, $cache, $dqlAlias, $value); + + return $rowData; + } + + private function addSelectedRelationToRowData($rowData, $dqlAlias, $cache) + { + if (!isset($rowData[$dqlAlias])) { + if ($cache['isRelation']) { + $rowData[$dqlAlias] = array(); + + foreach ($cache['identifiers'] as $identifierField) { + $rowData[$dqlAlias][$identifierField] = null; + } + } + } + + return $rowData; + } + + private function addIdentifierColumnToRowData($rowData, $cache, $dqlAlias, $value) + { + if ($cache['isIdentifier'] && !isset($rowData[$dqlAlias][$cache['columnName']])) { + $rowData[$dqlAlias][$cache['columnName']] = $value; + } + + return $rowData; + } +} diff --git a/lib/Doctrine/Hydrator/Graph.php b/lib/Doctrine/Hydrator/Graph.php index 8578f4871..f37f7ad49 100644 --- a/lib/Doctrine/Hydrator/Graph.php +++ b/lib/Doctrine/Hydrator/Graph.php @@ -311,11 +311,31 @@ protected function _gatherRowData(&$data, &$cache, &$id, &$nonemptyComponents) $table = $this->_queryComponents[$cache[$key]['dqlAlias']]['table']; $fieldName = $table->getFieldName($last); $cache[$key]['fieldName'] = $fieldName; - if ($table->isIdentifier($fieldName)) { + + $cache[$key]['identifiers'] = (array) $table->getIdentifier(); + + $cache[$key]['isRelation'] = isset($this->_queryComponents[$cache[$key]['dqlAlias']]['relation']); + + if (isset($this->_queryComponents[$cache[$key]['dqlAlias']]['agg'][$fieldName])) { + $cache[$key]['isAgg'] = true; + $cache[$key]['aliasName'] = $this->_queryComponents[$cache[$key]['dqlAlias']]['agg'][$fieldName]; + } else { + $cache[$key]['isAgg'] = false; + $cache[$key]['aliasName'] = $fieldName; + } + + if (isset($this->_queryComponents[$cache[$key]['dqlAlias']]['agg_field'][$last])) { + $cache[$key]['columnName'] = $this->_queryComponents[$cache[$key]['dqlAlias']]['agg_field'][$last]; + } else { + $cache[$key]['columnName'] = $fieldName; + } + + if ($table->isIdentifier($cache[$key]['columnName'])) { $cache[$key]['isIdentifier'] = true; } else { $cache[$key]['isIdentifier'] = false; } + $type = $table->getTypeOfColumn($last); if ($type == 'integer' || $type == 'string') { $cache[$key]['isSimpleType'] = true; @@ -328,12 +348,8 @@ protected function _gatherRowData(&$data, &$cache, &$id, &$nonemptyComponents) $map = $this->_queryComponents[$cache[$key]['dqlAlias']]; $table = $map['table']; $dqlAlias = $cache[$key]['dqlAlias']; - $fieldName = $cache[$key]['fieldName']; - $agg = false; - if (isset($this->_queryComponents[$dqlAlias]['agg'][$fieldName])) { - $fieldName = $this->_queryComponents[$dqlAlias]['agg'][$fieldName]; - $agg = true; - } + $fieldName = $cache[$key]['aliasName']; + $agg = $cache[$key]['isAgg']; if ($cache[$key]['isIdentifier']) { $id[$dqlAlias] .= '|' . $value; @@ -349,7 +365,10 @@ protected function _gatherRowData(&$data, &$cache, &$id, &$nonemptyComponents) // Hydrate aggregates in to the root component as well. // So we know that all aggregate values will always be available in the root component if ($agg) { + $rowData = $this->beforeAddingAggregateValue($rowData, $cache[$key], $dqlAlias, $preparedValue); + $rowData[$this->_rootAlias][$fieldName] = $preparedValue; + if (isset($rowData[$dqlAlias])) { $rowData[$dqlAlias][$fieldName] = $preparedValue; } @@ -365,6 +384,11 @@ protected function _gatherRowData(&$data, &$cache, &$id, &$nonemptyComponents) return $rowData; } + protected function beforeAddingAggregateValue($rowData, $cache, $dqlAlias, $value) + { + return $rowData; + } + abstract public function getElementCollection($component); abstract public function registerCollection($coll); diff --git a/lib/Doctrine/Query.php b/lib/Doctrine/Query.php index 2ae35ee15..a4d0b40f8 100644 --- a/lib/Doctrine/Query.php +++ b/lib/Doctrine/Query.php @@ -480,7 +480,7 @@ public function processPendingFields($componentAlias) } $sql = array(); - foreach ($fields as $fieldAlias => $fieldName) { + foreach ($fields as $fieldName) { $columnName = $table->getColumnName($fieldName); if (($owner = $table->getColumnOwner($columnName)) !== null && $owner !== $table->getComponentName()) { @@ -492,17 +492,10 @@ public function processPendingFields($componentAlias) . ' AS ' . $this->_conn->quoteIdentifier($tableAlias . '__' . $columnName); } else { - // Fix for http://www.doctrine-project.org/jira/browse/DC-585 - // Take the field alias if available - if (isset($this->_aggregateAliasMap[$fieldAlias])) { - $aliasSql = $this->_aggregateAliasMap[$fieldAlias]; - } else { - $columnName = $table->getColumnName($fieldName); - $aliasSql = $this->_conn->quoteIdentifier($tableAlias . '__' . $columnName); - } + $columnName = $table->getColumnName($fieldName); $sql[] = $this->_conn->quoteIdentifier($tableAlias) . '.' . $this->_conn->quoteIdentifier($columnName) . ' AS ' - . $aliasSql; + . $this->_conn->quoteIdentifier($tableAlias . '__' . $columnName); } } @@ -655,14 +648,11 @@ public function parseSelect($dql) $this->_queryComponents[$componentAlias]['agg'][$index] = $alias; - $this->_neededTables[] = $tableAlias; - - // Fix for http://www.doctrine-project.org/jira/browse/DC-585 - // Add selected columns to pending fields if (preg_match('/^([^\(]+)\.(\'?)(.*?)(\'?)$/', $expression, $field)) { - $this->_pendingFields[$componentAlias][$alias] = $field[3]; + $this->_queryComponents[$componentAlias]['agg_field'][$index] = $field[3]; } + $this->_neededTables[] = $tableAlias; } else { $e = explode('.', $terms[0]); diff --git a/lib/Doctrine/Query/Abstract.php b/lib/Doctrine/Query/Abstract.php index 6042ed18e..247886f1c 100644 --- a/lib/Doctrine/Query/Abstract.php +++ b/lib/Doctrine/Query/Abstract.php @@ -206,6 +206,16 @@ abstract class Doctrine_Query_Abstract * * map the name of the column / aggregate value this * component is mapped to a collection + * + * agg_field the field names for each aggregates + * Example: + * DQL: COMPONENT.FIELD as ALIAS + * SQL: TABLE.COLUMN as TABLE__0 + * $_queryComponents + * agg: + * 0: ALIAS + * agg_field: + * 0: FIELD */ protected $_queryComponents = array(); @@ -1259,6 +1269,9 @@ protected function _constructQueryFromCache($cached) if (isset($components['agg'])) { $queryComponents[$alias]['agg'] = $components['agg']; } + if (isset($components['agg_field'])) { + $queryComponents[$alias]['agg_field'] = $components['agg_field']; + } if (isset($components['map'])) { $queryComponents[$alias]['map'] = $components['map']; } @@ -1289,6 +1302,9 @@ public function getCachedForm($customComponent = null) if (isset($components['agg'])) { $componentInfo[$alias]['agg'] = $components['agg']; } + if (isset($components['agg_field'])) { + $componentInfo[$alias]['agg_field'] = $components['agg_field']; + } if (isset($components['map'])) { $componentInfo[$alias]['map'] = $components['map']; }