Skip to content

[5.1] Fix pagination for group by and having statements #10632

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
41 changes: 23 additions & 18 deletions src/Illuminate/Database/Query/Builder.php
Original file line number Diff line number Diff line change
Expand Up @@ -1461,19 +1461,28 @@ public function getCountForPagination($columns = ['*'])
{
$this->backupFieldsForCount();

$this->aggregate = ['function' => 'count', 'columns' => $columns];

$results = $this->get();
// If the query contains any "group by" or "having" clauses
// we cannot use a simple aggregate function to count the
// results. We will need to create a sub query instead.
if ($this->groups || $this->havings) {
$subQuery = new Expression('('.$this->toSql().') as '.$this->grammar->wrap('aggregate_table'));

$result = $this->newQuery()
->from($subQuery)
->mergeBindings($this)
->count($columns);
}

$this->aggregate = null;
// Otherwise we can simply call the count aggregate function
// on the current query instance. That will give us the
// total number of results we can use for pagination.
else {
$result = $this->count($columns);
}

$this->restoreFieldsForCount();

if (isset($this->groups)) {
return count($results);
}

return isset($results[0]) ? (int) array_change_key_case((array) $results[0])['aggregate'] : 0;
return $result;
}

/**
Expand All @@ -1483,17 +1492,15 @@ public function getCountForPagination($columns = ['*'])
*/
protected function backupFieldsForCount()
{
foreach (['orders', 'limit', 'offset', 'columns'] as $field) {
foreach (['orders', 'limit', 'offset'] as $field) {
$this->backups[$field] = $this->{$field};

$this->{$field} = null;
}

foreach (['order', 'select'] as $key) {
$this->bindingBackups[$key] = $this->bindings[$key];
$this->bindingBackups['order'] = $this->bindings['order'];

$this->bindings[$key] = [];
}
$this->bindings['order'] = [];
}

/**
Expand All @@ -1503,13 +1510,11 @@ protected function backupFieldsForCount()
*/
protected function restoreFieldsForCount()
{
foreach (['orders', 'limit', 'offset', 'columns'] as $field) {
foreach (['orders', 'limit', 'offset'] as $field) {
$this->{$field} = $this->backups[$field];
}

foreach (['order', 'select'] as $key) {
$this->bindings[$key] = $this->bindingBackups[$key];
}
$this->bindings['order'] = $this->bindingBackups['order'];

$this->backups = [];
$this->bindingBackups = [];
Expand Down
17 changes: 16 additions & 1 deletion tests/Database/DatabaseEloquentIntegrationTest.php
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
<?php

use Illuminate\Database\Connection;
use Illuminate\Database\Query\Expression as Raw;
use Illuminate\Database\Eloquent\Model as Eloquent;
use Illuminate\Database\Eloquent\Relations\Relation;
use Illuminate\Pagination\AbstractPaginator as Paginator;
Expand Down Expand Up @@ -41,7 +42,7 @@ public function setUp()
{
$this->schema()->create('users', function ($table) {
$table->increments('id');
$table->string('email')->unique();
$table->string('email');
$table->timestamps();
});

Expand Down Expand Up @@ -164,6 +165,20 @@ public function testCountForPaginationWithGrouping()
$this->assertEquals(3, $query->getCountForPagination());
}

public function testCountForPaginationWithHaving()
{
EloquentTestUser::create(['id' => 1, 'email' => 'taylorotwell@gmail.com']);
EloquentTestUser::create(['id' => 2, 'email' => 'abigailotwell@gmail.com']);
EloquentTestUser::create(['id' => 3, 'email' => 'foo@gmail.com']);
EloquentTestUser::create(['id' => 4, 'email' => 'foo@gmail.com']);
EloquentTestUser::create(['id' => 5, 'email' => 'bar@gmail.com']);
EloquentTestUser::create(['id' => 6, 'email' => 'bar@gmail.com']);

$query = EloquentTestUser::selectRaw('count("id") as total')->groupBy('email')->having('total', '>', new Raw('1'))->getQuery();

$this->assertEquals(2, $query->getCountForPagination());
}

public function testListsRetrieval()
{
EloquentTestUser::create(['id' => 1, 'email' => 'taylorotwell@gmail.com']);
Expand Down