Skip to content

Commit

Permalink
Fix documentation and add exception for foreignKey in contain
Browse files Browse the repository at this point in the history
foreignKey = false in a contain() call for hasMany associations will not
work. While it could be made to work, I really don't think the effort is
justified. In the rare case that someone needs this kind of behavior
they can use the lower level join() API to generate the required
queries.

Refs #5143
  • Loading branch information
markstory committed Jan 4, 2015
1 parent fb2ec09 commit a02af9f
Show file tree
Hide file tree
Showing 3 changed files with 73 additions and 3 deletions.
5 changes: 5 additions & 0 deletions src/ORM/Association/HasMany.php
Expand Up @@ -128,6 +128,11 @@ protected function _linkField($options)
{
$links = [];
$name = $this->alias();
if ($options['foreignKey'] === false) {
$msg = 'Cannot have foreignKey = false for hasMany associations. ' .
'You must provide a foreignKey column.';
throw new \RuntimeException($msg);
}

foreach ((array)$options['foreignKey'] as $key) {
$links[] = sprintf('%s.%s', $name, $key);
Expand Down
7 changes: 4 additions & 3 deletions src/ORM/Query.php
Expand Up @@ -226,7 +226,8 @@ public function eagerLoader(EagerLoader $instance = null)
* options that can be set per association are:
*
* - foreignKey: Used to set a different field to match both tables, if set to false
* no join conditions will be generated automatically
* no join conditions will be generated automatically. `false` can only be used on
* joinable associations and cannot be used with hasMany or belongsToMany associations.
* - fields: An array with the fields that should be fetched from the association
* - queryBuilder: Equivalent to passing a callable instead of an options array
*
Expand All @@ -245,9 +246,9 @@ public function eagerLoader(EagerLoader $instance = null)
* Failing to do so will trigger exceptions.
*
* {{{
* // Use special join conditions for getting an author's hasMany 'likes'
* // Use special join conditions for getting an Articles's belongsTo 'authors'
* $query->contain([
* 'Likes' => [
* 'Authors' => [
* 'foreignKey' => false,
* 'queryBuilder' => function ($q) {
* return $q->where(...); // Add full filtering conditions
Expand Down
64 changes: 64 additions & 0 deletions tests/TestCase/ORM/QueryTest.php
Expand Up @@ -1664,6 +1664,70 @@ public function testContainWithClosure()
$this->assertEquals([1], array_unique($ids));
}

/**
* Integration test to ensure that filtering associations with the queryBuilder
* option works.
*
* @expectedException \RuntimeException
* @return void
*/
public function testContainWithQueryBuilderHasManyError()
{
$table = TableRegistry::get('Authors');
$table->hasMany('Articles');
$query = new Query($this->connection, $table);
$query->select()
->contain([
'Articles' => [
'foreignKey' => false,
'queryBuilder' => function ($q) {
return $q->where(['articles.id' => 1]);
}
]
]);
$query->toArray();
}

/**
* Integration test to ensure that filtering associations with the queryBuilder
* option works.
*
* @return void
*/
public function testContainWithQueryBuilderJoinableAssociation()
{
$table = TableRegistry::get('Authors');
$table->hasOne('Articles');
$query = new Query($this->connection, $table);
$query->select()
->contain([
'Articles' => [
'foreignKey' => false,
'queryBuilder' => function ($q) {
return $q->where(['Articles.id' => 1]);
}
]
]);
$result = $query->toArray();
$this->assertEquals(1, $result[0]->article->id);
$this->assertEquals(1, $result[1]->article->id);

$articles = TableRegistry::get('Articles');
$articles->belongsTo('Authors');
$query = new Query($this->connection, $articles);
$query->select()
->contain([
'Authors' => [
'foreignKey' => false,
'queryBuilder' => function ($q) {
return $q->where(['Authors.id' => 1]);
}
]
]);
$result = $query->toArray();
$this->assertEquals(1, $result[0]->author->id);
}

/**
* Tests the formatResults method
*
Expand Down

0 comments on commit a02af9f

Please sign in to comment.