Skip to content

Commit

Permalink
Adding the ability to register a callback funciton to override the
Browse files Browse the repository at this point in the history
results of Query::count()
  • Loading branch information
lorenzo committed Jan 24, 2014
1 parent 9f8505f commit d96d155
Show file tree
Hide file tree
Showing 2 changed files with 57 additions and 1 deletion.
37 changes: 36 additions & 1 deletion src/ORM/Query.php
Expand Up @@ -143,6 +143,14 @@ class Query extends DatabaseQuery {
*/
protected $_cache;

/**
* A callable function that can be used to calculate the total amount of
* records this query will match when not using `limit`
*
* @var callable
*/
protected $_counter;

/**
* Constuctor
*
Expand Down Expand Up @@ -873,19 +881,46 @@ public function first() {
public function count() {
$query = clone $this;
$query->limit(null);
$query->offset(null);
$counter = $this->_counter;

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

// Forcing at least one field to be selected
$query->select($query->newExpr()->add('1'));
$statement = $this->connection()->newQuery()
->select(['count' => $query->func()->count('*')])
->from(['source' => $query])
->from(['count_source' => $query])
->execute();
$result = $statement->fetch('assoc')['count'];

$statement->closeCursor();
return (int)$result;
}

/**
* Registers a callable function that will be executed when the `count` method in
* this query is called. The return value for the function will be set as the
* return value of the `count` method.
*
* This is particularly useful when you need to optimize a query for returning the
* count, for example removing unnecessary joins, removing group by or just return
* an estimated number of rows.
*
* The callback will receive as first argument a clone of this query and not this
* query itself.
*
* @param callable $counter
* @return Cake\ORM\Query
*/
public function counter($counter) {
$this->_counter = $counter;
return $this;
}

/**
* Toggle hydrating entites.
*
Expand Down
21 changes: 21 additions & 0 deletions tests/TestCase/ORM/QueryTest.php
Expand Up @@ -1515,6 +1515,27 @@ public function testCountWithGroup() {
$this->assertEquals(2, $result);
}

/**
* Tests that it is possible to provide
*
* @return void
*/
public function testCountWuthCustomCounter() {
$table = TableRegistry::get('articles');
$query = $table->find('all');
$query
->select(['author_id', 's' => $query->func()->sum('id')])
->where(['id >' => 2])
->group(['author_id'])
->counter(function($q) use ($query) {
$this->assertNotSame($q, $query);
return $q->select([], true)->group([], true)->count();
});

$result = $query->count();
$this->assertEquals(1, $result);
}

/**
* Test update method.
*
Expand Down

0 comments on commit d96d155

Please sign in to comment.