Skip to content

Commit

Permalink
Added support for using formatResult on deep attachable associations
Browse files Browse the repository at this point in the history
  • Loading branch information
lorenzo committed Feb 9, 2014
1 parent 7f64c8a commit ec0cc6a
Show file tree
Hide file tree
Showing 4 changed files with 73 additions and 18 deletions.
12 changes: 6 additions & 6 deletions src/ORM/Association.php
Expand Up @@ -430,7 +430,7 @@ public function attachTo(Query $query, array $options = []) {
$query->join([$target->alias() => array_intersect_key($options, $joinOptions)]);

$this->_appendFields($query, $dummy, $options);
$this->_formatAssociationResults($query, $dummy);
$this->_formatAssociationResults($query, $dummy, $options);
$this->_bindNewAssociations($query, $dummy, $options);
}

Expand Down Expand Up @@ -505,15 +505,15 @@ protected function _appendFields($query, $surrogate, $options) {
}
}

protected function _formatAssociationResults($query, $surrogate) {
protected function _formatAssociationResults($query, $surrogate, $options) {
$formatters = $surrogate->formatResults();

if (!$formatters) {
return;
}

$query->formatResults(function($results) use ($formatters) {
$property = $this->property();
$property = $options['propertyPath'];
$query->formatResults(function($results) use ($formatters, $property){
$extracted = $results->extract($property)->compile();
foreach ($formatters as $callable) {
$extracted = new ResultSetDecorator($callable($extracted));
Expand All @@ -534,7 +534,7 @@ protected function _bindNewAssociations($query, $surrogate, $options) {
$loader->attachAssociations($query, $target, $options['includeFields']);
$newBinds = [];
foreach ($contain as $alias => $value) {
$newBinds[$options['path'] . '.' . $alias] = $value;
$newBinds[$options['aliasPath'] . '.' . $alias] = $value;
}
$query->contain($newBinds);
}
Expand Down
21 changes: 14 additions & 7 deletions src/ORM/EagerLoader.php
Expand Up @@ -156,7 +156,7 @@ public function normalized(Table $repository) {
$repository,
$alias,
$options,
$alias
[]
);
}

Expand Down Expand Up @@ -233,7 +233,8 @@ public function attachAssociations(Query $query, Table $repository, $includeFiel

foreach ($this->attachableAssociations($repository) as $options) {
$config = $options['config'] + [
'path' => $options['path'],
'aliasPath' => $options['aliasPath'],
'propertyPath' => $options['propertyPath'],
'includeFields' => $includeFields
];
$options['instance']->attachTo($query, $config);
Expand Down Expand Up @@ -285,11 +286,13 @@ public function externalAssociations(Table $repository) {
* @param Table $parent owning side of the association
* @param string $alias name of the association to be loaded
* @param array $options list of extra options to use for this association
* @param string $path A dot separated string of associations that lead to this `$alias`
* @param array $paths A list of dot separated strings signifying associations that
* lead to this `$alias` and the path to follow in entities to fetch a record of each
* the association
* @return array normalized associations
* @throws \InvalidArgumentException When containments refer to associations that do not exist.
*/
protected function _normalizeContain(Table $parent, $alias, $options, $path) {
protected function _normalizeContain(Table $parent, $alias, $options, $paths) {
$defaults = $this->_containOptions;
$instance = $parent->association($alias);
if (!$instance) {
Expand All @@ -298,20 +301,24 @@ protected function _normalizeContain(Table $parent, $alias, $options, $path) {
);
}

$paths += ['aliasPath' => '', 'propertyPath' => ''];
$paths['aliasPath'] .= '.' . $alias;
$paths['propertyPath'] .= '.' . $instance->property();

$table = $instance->target();

$extra = array_diff_key($options, $defaults);
$config = [
'associations' => [],
'instance' => $instance,
'config' => array_diff_key($options, $extra),
'path' => $path
'aliasPath' => trim($paths['aliasPath'], '.'),
'propertyPath' => trim($paths['propertyPath'], '.'),
];
$config['canBeJoined'] = $instance->canBeJoined($config['config']);

foreach ($extra as $t => $assoc) {
$step = $path . '.' . $t;
$config['associations'][$t] = $this->_normalizeContain($table, $t, $assoc, $step);
$config['associations'][$t] = $this->_normalizeContain($table, $t, $assoc, $paths);
}

return $config;
Expand Down
18 changes: 13 additions & 5 deletions tests/TestCase/ORM/EagerLoaderTest.php
Expand Up @@ -355,19 +355,27 @@ public function testNormalizedPath() {
$loader = new EagerLoader;
$loader->contain($contains);
$normalized = $loader->normalized($this->table);
$this->assertEquals('clients', $normalized['clients']['path']);
$this->assertEquals('clients', $normalized['clients']['aliasPath']);
$this->assertEquals('client', $normalized['clients']['propertyPath']);

$assocs = $normalized['clients']['associations'];
$this->assertEquals('clients.orders', $assocs['orders']['path']);
$this->assertEquals('clients.orders', $assocs['orders']['aliasPath']);
$this->assertEquals('client.order', $assocs['orders']['propertyPath']);

$assocs = $assocs['orders']['associations'];
$this->assertEquals('clients.orders.orderTypes', $assocs['orderTypes']['path']);
$this->assertEquals('clients.orders.stuff', $assocs['stuff']['path']);
$this->assertEquals('clients.orders.orderTypes', $assocs['orderTypes']['aliasPath']);
$this->assertEquals('client.order.order_type', $assocs['orderTypes']['propertyPath']);
$this->assertEquals('clients.orders.stuff', $assocs['stuff']['aliasPath']);
$this->assertEquals('client.order.stuff', $assocs['stuff']['propertyPath']);

$assocs = $assocs['stuff']['associations'];
$this->assertEquals(
'clients.orders.stuff.stuffTypes',
$assocs['stuffTypes']['path']
$assocs['stuffTypes']['aliasPath']
);
$this->assertEquals(
'client.order.stuff.stuff_type',
$assocs['stuffTypes']['propertyPath']
);
}

Expand Down
40 changes: 40 additions & 0 deletions tests/TestCase/ORM/QueryTest.php
Expand Up @@ -1615,5 +1615,45 @@ public function testFormatBelongsToRecords() {
$this->assertEquals($expected, $results);
}

/**
* Tests it is possible to apply formatters to deep relations.
*
* @return void
*/
public function testFormatDeepAssocationRecords() {
$table = TableRegistry::get('ArticlesTags');
$table->belongsTo('Articles');
$table->association('Articles')->target()->belongsTo('Authors');

$builder = function($q) {
return $q
->formatResults(function($results) {
return $results->map(function($result) {
$result->idCopy = $result->id;
return $result;
});
})
->formatResults(function($results) {
return $results->map(function($result) {
$result->idCopy = $result->idCopy + 2;
return $result;
});
});
};
$query = $table->find()
->contain(['Articles' => $builder, 'Articles.Authors' => $builder]);
$query->formatResults(function($results) {
return $results->map(function($row) {
return sprintf(
'%s - %s - %s',
$row->tag_id,
$row->article->idCopy,
$row->article->author->idCopy
);
});
});

$expected = ['1 - 3 - 3', '2 - 3 - 3', '1 - 4 - 5', '3 - 4 - 5'];
$this->assertEquals($expected, $query->toArray());
}
}

0 comments on commit ec0cc6a

Please sign in to comment.