Skip to content

Commit

Permalink
Bringing back dot notation for contain(), I feel this improves the
Browse files Browse the repository at this point in the history
experience fetching depely nested associations
  • Loading branch information
lorenzo committed Jan 2, 2014
1 parent 6e5051c commit 98df11f
Show file tree
Hide file tree
Showing 2 changed files with 78 additions and 7 deletions.
38 changes: 31 additions & 7 deletions Cake/ORM/Query.php
Expand Up @@ -298,7 +298,7 @@ public function contain($associations = null, $override = false) {
}

$old = $this->_containments->getArrayCopy();
$associations = array_merge($old, $this->_reformatContain($associations));
$associations = $this->_reformatContain($associations, $old);
$this->_containments->exchangeArray($associations);
$this->_normalizedContainments = null;
$this->_dirty();
Expand All @@ -307,22 +307,46 @@ public function contain($associations = null, $override = false) {

/**
* Formats the containments array so that associations are always set as keys
* in the array.
* in the array. This funciton merges the original associations array with
* the new associations provided
*
* @param array $associations user provided containments array
* @param array $original The original containments array to merge
* with the new one
* @return array
*/
protected function _reformatContain($associations) {
$result = [];
protected function _reformatContain($associations, $original) {
$result = $original;

foreach ((array)$associations as $table => $options) {
$pointer =& $result;
if (is_int($table)) {
$table = $options;
$options = [];
} elseif (is_array($options) && !isset($this->_containOptions[$table])) {
$options = $this->_reformatContain($options);
}
$result[$table] = $options;

if (isset($this->_containOptions[$table])) {
$pointer[$table] = $options;
continue;
}

if (strpos($table, '.')) {
$path = explode('.', $table);
$table = array_pop($path);
foreach ($path as $t) {
$pointer += [$t => []];
$pointer =& $pointer[$t];
}
}

if (is_array($options)) {
$options = $this->_reformatContain($options, []);
}

$pointer += [$table => []];
$pointer[$table] = $options + $pointer[$table];
}

return $result;
}

Expand Down
47 changes: 47 additions & 0 deletions Cake/Test/TestCase/ORM/QueryTest.php
Expand Up @@ -196,6 +196,53 @@ public function testContainToJoinsOneLevel() {
->contain($contains)->sql();
}

/**
* Tests setting containments using dot notation, additionaly proves that options
* are not overwritten whn combining dot notation and array notation
*
* @return void
*/
public function testContainDotNotation() {
$contains = [
'clients' => [
'orders' => [
'orderTypes',
'stuff' => ['stuffTypes']
],
'companies' => [
'foreignKey' => 'organization_id',
'categories'
]
]
];
$query = $this->getMock('\Cake\ORM\Query', ['join'], [$this->connection, $this->table]);
$query->contain([
'clients.orders.stuff',
'clients.companies.categories' => ['conditions' => ['a >' => 1]]
]);
$expected = new \ArrayObject([
'clients' => [
'orders' => [
'stuff' => []
],
'companies' => [
'categories' => [
'conditions' => ['a >' => 1]
]
]
]
]);
$this->assertEquals($expected, $query->contain());
$query->contain([
'clients.orders' => ['fields' => ['a', 'b']],
'clients' => ['sort' => ['a' => 'desc']],
]);

$expected['clients']['orders'] += ['fields' => ['a', 'b']];
$expected['clients'] += ['sort' => ['a' => 'desc']];
$this->assertEquals($expected, $query->contain());
}

/**
* Test that fields for contained models are aliased and added to the select clause
*
Expand Down

0 comments on commit 98df11f

Please sign in to comment.