diff --git a/lib/Doctrine/Hydrate.php b/lib/Doctrine/Hydrate.php index 310d8fc24..10d3b66b6 100644 --- a/lib/Doctrine/Hydrate.php +++ b/lib/Doctrine/Hydrate.php @@ -91,6 +91,9 @@ class Doctrine_Hydrate extends Doctrine_Object implements Serializable * parent the alias of the parent * * agg the aggregates of this component + * + * map the name of the column / aggregate value this + * component is mapped to a collection */ protected $_aliasMap = array(); /** @@ -1034,7 +1037,20 @@ class Doctrine_Hydrate extends Doctrine_Object implements Serializable $index = $driver->search($element, $array); if ($index === false) { - $array[] = $element; + $key = $map['map']; + + if (isset($key)) { + if (isset($array[$key])) { + throw new Doctrine_Hydrate_Exception("Couldn't hydrate. Found non-unique key mapping."); + } + + if ( ! isset($element[$key])) { + throw new Doctrine_Hydrate_Exception("Couldn't hydrate. Found a non-existent key."); + } + $array[$element[$key]] = $element; + } else { + $array[] = $element; + } } $this->_setLastElement($prev, $array, $index, $rootAlias, $oneToOne); unset($currData[$rootAlias]); @@ -1050,7 +1066,7 @@ class Doctrine_Hydrate extends Doctrine_Object implements Serializable $relation = $map['relation']; $componentAlias = $map['relation']->getAlias(); - if (!isset($prev[$parent])) { + if ( ! isset($prev[$parent])) { break; } @@ -1065,7 +1081,19 @@ class Doctrine_Hydrate extends Doctrine_Object implements Serializable $index = $driver->search($element, $prev[$parent][$componentAlias]); if ($index === false) { - $prev[$parent][$componentAlias][] = $element; + $key = $map['map']; + + if (isset($key)) { + if (isset($prev[$parent][$componentAlias][$key])) { + throw new Doctrine_Hydrate_Exception("Couldn't hydrate. Found non-unique key mapping."); + } + if ( ! isset($element[$key])) { + throw new Doctrine_Hydrate_Exception("Couldn't hydrate. Found a non-existent key."); + } + $prev[$parent][$componentAlias][$element[$key]] = $element; + } else { + $prev[$parent][$componentAlias][] = $element; + } } } // register collection for later snapshots diff --git a/lib/Doctrine/Query.php b/lib/Doctrine/Query.php index 10d575635..550894dc5 100644 --- a/lib/Doctrine/Query.php +++ b/lib/Doctrine/Query.php @@ -1217,6 +1217,15 @@ class Doctrine_Query extends Doctrine_Query_Abstract implements Countable public function load($path, $loadFields = true) { + $e = Doctrine_Tokenizer::quoteExplode($path, ' MAP '); + + $mapWith = null; + if (count($e) > 1) { + $mapWith = trim($e[1]); + + $path = $e[0]; + } + // parse custom join conditions $e = explode(' ON ', $path); @@ -1286,7 +1295,8 @@ class Doctrine_Query extends Doctrine_Query_Abstract implements Countable $table = $relation->getTable(); $this->_aliasMap[$componentAlias] = array('table' => $table, 'parent' => $parent, - 'relation' => $relation); + 'relation' => $relation, + 'map' => null); if ( ! $relation->isOneToOne()) { $this->needsSubquery = true; } @@ -1405,7 +1415,16 @@ class Doctrine_Query extends Doctrine_Query_Abstract implements Countable } $parent = $prevPath; } + if (isset($mapWith)) { + $e = explode('.', $mapWith); + $table = $this->_aliasMap[$componentAlias]['table']; + + if ( ! $table->hasColumn($e[1])) { + throw new Doctrine_Query_Exception("Couldn't use key mapping. Column " . $e[1] . " does not exist."); + } + $this->_aliasMap[$componentAlias]['map'] = $table->getColumnName($e[1]); + } return $this->_aliasMap[$componentAlias]; } @@ -1435,7 +1454,7 @@ class Doctrine_Query extends Doctrine_Query_Abstract implements Countable $this->parts['from'][] = $queryPart; $this->tableAliases[$tableAlias] = $componentAlias; - $this->_aliasMap[$componentAlias] = array('table' => $table); + $this->_aliasMap[$componentAlias] = array('table' => $table, 'map' => null); return $table; }