diff --git a/src/Illuminate/Database/Eloquent/Builder.php b/src/Illuminate/Database/Eloquent/Builder.php index f0f535981300..726209fa4983 100755 --- a/src/Illuminate/Database/Eloquent/Builder.php +++ b/src/Illuminate/Database/Eloquent/Builder.php @@ -864,7 +864,7 @@ public function pluck($column, $key = null) /** * Paginate the given query. * - * @param int|null $perPage + * @param int|null|callable $perPage * @param array $columns * @param string $pageName * @param int|null $page @@ -876,11 +876,16 @@ public function paginate($perPage = null, $columns = ['*'], $pageName = 'page', { $page = $page ?: Paginator::resolveCurrentPage($pageName); - $perPage = $perPage ?: $this->model->getPerPage(); + $total = $this->toBase()->getCountForPagination(); + + $perPage = ($perPage instanceof Closure + ? $perPage($total) + : $perPage + ) ?: $this->model->getPerPage(); - $results = ($total = $this->toBase()->getCountForPagination()) - ? $this->forPage($page, $perPage)->get($columns) - : $this->model->newCollection(); + $results = $total + ? $this->forPage($page, $perPage)->get($columns) + : $this->model->newCollection(); return $this->paginator($results, $total, $perPage, $page, [ 'path' => Paginator::resolveCurrentPath(), diff --git a/src/Illuminate/Database/Query/Builder.php b/src/Illuminate/Database/Query/Builder.php index 0652f45b4d3a..2321df80cc9d 100755 --- a/src/Illuminate/Database/Query/Builder.php +++ b/src/Illuminate/Database/Query/Builder.php @@ -2634,7 +2634,7 @@ protected function runSelect() /** * Paginate the given query into a simple paginator. * - * @param int $perPage + * @param int|callable $perPage * @param array $columns * @param string $pageName * @param int|null $page @@ -2646,6 +2646,8 @@ public function paginate($perPage = 15, $columns = ['*'], $pageName = 'page', $p $total = $this->getCountForPagination(); + $perPage = $perPage instanceof Closure ? $perPage($total) : $perPage; + $results = $total ? $this->forPage($page, $perPage)->get($columns) : collect(); return $this->paginator($results, $total, $perPage, $page, [ diff --git a/tests/Database/DatabaseEloquentIntegrationTest.php b/tests/Database/DatabaseEloquentIntegrationTest.php index 1a5451f95659..bf20260dd436 100644 --- a/tests/Database/DatabaseEloquentIntegrationTest.php +++ b/tests/Database/DatabaseEloquentIntegrationTest.php @@ -269,6 +269,69 @@ public function testPaginatedModelCollectionRetrieval() $this->assertSame('foo@gmail.com', $models[0]->email); } + public function testPaginatedModelCollectionRetrievalUsingCallablePerPage() + { + EloquentTestUser::create(['id' => 1, 'email' => 'taylorotwell@gmail.com']); + EloquentTestUser::create(['id' => 2, 'email' => 'abigailotwell@gmail.com']); + EloquentTestUser::create(['id' => 3, 'email' => 'foo@gmail.com']); + + Paginator::currentPageResolver(function () { + return 1; + }); + $models = EloquentTestUser::oldest('id')->paginate(function ($total) { + return $total <= 3 ? 3 : 2; + }); + + $this->assertCount(3, $models); + $this->assertInstanceOf(LengthAwarePaginator::class, $models); + $this->assertInstanceOf(EloquentTestUser::class, $models[0]); + $this->assertInstanceOf(EloquentTestUser::class, $models[1]); + $this->assertInstanceOf(EloquentTestUser::class, $models[2]); + $this->assertSame('taylorotwell@gmail.com', $models[0]->email); + $this->assertSame('abigailotwell@gmail.com', $models[1]->email); + $this->assertSame('foo@gmail.com', $models[2]->email); + + Paginator::currentPageResolver(function () { + return 2; + }); + $models = EloquentTestUser::oldest('id')->paginate(function ($total) { + return $total <= 3 ? 3 : 2; + }); + + $this->assertCount(0, $models); + $this->assertInstanceOf(LengthAwarePaginator::class, $models); + + EloquentTestUser::create(['id' => 4, 'email' => 'bar@gmail.com']); + + Paginator::currentPageResolver(function () { + return 1; + }); + $models = EloquentTestUser::oldest('id')->paginate(function ($total) { + return $total <= 3 ? 3 : 2; + }); + + $this->assertCount(2, $models); + $this->assertInstanceOf(LengthAwarePaginator::class, $models); + $this->assertInstanceOf(EloquentTestUser::class, $models[0]); + $this->assertInstanceOf(EloquentTestUser::class, $models[1]); + $this->assertSame('taylorotwell@gmail.com', $models[0]->email); + $this->assertSame('abigailotwell@gmail.com', $models[1]->email); + + Paginator::currentPageResolver(function () { + return 2; + }); + $models = EloquentTestUser::oldest('id')->paginate(function ($total) { + return $total <= 3 ? 3 : 2; + }); + + $this->assertCount(2, $models); + $this->assertInstanceOf(LengthAwarePaginator::class, $models); + $this->assertInstanceOf(EloquentTestUser::class, $models[0]); + $this->assertInstanceOf(EloquentTestUser::class, $models[1]); + $this->assertSame('foo@gmail.com', $models[0]->email); + $this->assertSame('bar@gmail.com', $models[1]->email); + } + public function testPaginatedModelCollectionRetrievalWhenNoElements() { Paginator::currentPageResolver(function () {