Navigation Menu

Skip to content

Commit

Permalink
Fix Query::count() failing when fields have expressions.
Browse files Browse the repository at this point in the history
Because we can't easily introspect and remove any bound parameters that
will be unused, we must use a subselect query instead.

Also include additional test coverage for count() with subqueries, and
matching().

Refs #7148
Refs #7272
  • Loading branch information
markstory committed Aug 22, 2015
1 parent 5ff3f8d commit c61c408
Show file tree
Hide file tree
Showing 2 changed files with 65 additions and 3 deletions.
19 changes: 16 additions & 3 deletions src/ORM/Query.php
Expand Up @@ -15,6 +15,7 @@
namespace Cake\ORM;

use ArrayObject;
use Cake\Database\ExpressionInterface;
use Cake\Database\Query as DatabaseQuery;
use Cake\Database\ValueBinder;
use Cake\Datasource\QueryTrait;
Expand Down Expand Up @@ -510,15 +511,27 @@ public function count()
{
$query = $this->cleanCopy();
$counter = $this->_counter;

if ($counter) {
$query->counter(null);
return (int)$counter($query);
}

$complex = (
$query->clause('distinct') ||
count($query->clause('group')) ||
count($query->clause('union'))
);
if (!$complex) {
// Expression fields could have bound parameters.
foreach ($query->clause('select') as $field) {
if ($field instanceof ExpressionInterface) {
$complex = true;
break;
}
}
}

$count = ['count' => $query->func()->count('*')];
$complex = count($query->clause('group')) || $query->clause('distinct');
$complex = $complex || count($query->clause('union'));

if (!$complex) {
$query->eagerLoader()->autoFields(false);
Expand Down
49 changes: 49 additions & 0 deletions tests/TestCase/ORM/QueryTest.php
Expand Up @@ -1458,6 +1458,55 @@ public function testCountWithContain()
$this->assertSame(3, $result);
}

/**
* Test getting counts from queries with contain.
*
* @return void
*/
public function testCountWithSubselect()
{
$table = TableRegistry::get('Articles');
$table->belongsTo('Authors');
$table->hasMany('ArticlesTags');

$counter = $table->ArticlesTags->find();
$counter->select([
'total' => $counter->func()->count('*')
])
->where(['ArticlesTags.tag_id' => 1])
->where(['ArticlesTags.article_id = Articles.id']);

$result = $table->find('all')
->select([
'Articles.title',
'tag_count' => $counter
])
->matching('Authors', function ($q) {
return $q->where(['Authors.id' => 1]);
})
->count();
$this->assertSame(2, $result);
}

/**
* Test getting counts with complex fields.
*
* @return void
*/
public function testCountWithExpressions()
{
$table = TableRegistry::get('Articles');
$query = $table->find();
$query->select([
'admin' => $query->func()->concat(
['Articles.title' => 'literal', 'test'],
['string']
),
]);
$query->where(['Articles.id' => 1]);
$this->assertCount(1, $query->all());
$this->assertEquals(1, $query->count());
}

/**
* test count with a beforeFind.
Expand Down

0 comments on commit c61c408

Please sign in to comment.