Changed the result from PaginatorInterface to LengthAwarePaginatorInterface for method paginate(). (#2824)

* Changed the result from `PaginatorInterface` to `LengthAwarePaginatorInterface` for method `paginate()` in `Hyperf\Database\Query\Builder`.
* Added method `simplePaginate()` which return `PaginatorInterface` in `Hyperf\Database\Query\Builder`.
* Added test cases .

Co-authored-by: 李铭昕 <715557344@qq.com>
This commit is contained in:
武杰 2020-11-18 18:39:52 +08:00 committed by GitHub
parent a9b3dde8f7
commit 834b582c93
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 184 additions and 20 deletions

View File

@ -1,9 +1,17 @@
# v2.0.20 - TBD # v2.0.20 - TBD
## Added
- [#2824](https://github.com/hyperf/hyperf/pull/2824) Added method `simplePaginate()` which return `PaginatorInterface` in `Hyperf\Database\Query\Builder`.
## Fixed ## Fixed
- [#2820](https://github.com/hyperf/hyperf/pull/2820) Fixed amqp consumer does not works when using fanout exchange. - [#2820](https://github.com/hyperf/hyperf/pull/2820) Fixed amqp consumer does not works when using fanout exchange.
## Changed
- [#2824](https://github.com/hyperf/hyperf/pull/2824) Changed the result from `PaginatorInterface` to `LengthAwarePaginatorInterface` for method `paginate()` in `Hyperf\Database\Query\Builder`.
## Optimized ## Optimized
- [#2821](https://github.com/hyperf/hyperf/pull/2821) Optimized the exceptions thrown by `Json` and `Xml`. - [#2821](https://github.com/hyperf/hyperf/pull/2821) Optimized the exceptions thrown by `Json` and `Xml`.

View File

@ -13,6 +13,7 @@ namespace Hyperf\Database\Query;
use Closure; use Closure;
use DateTimeInterface; use DateTimeInterface;
use Hyperf\Contract\LengthAwarePaginatorInterface;
use Hyperf\Contract\PaginatorInterface; use Hyperf\Contract\PaginatorInterface;
use Hyperf\Database\Concerns\BuildsQueries; use Hyperf\Database\Concerns\BuildsQueries;
use Hyperf\Database\ConnectionInterface; use Hyperf\Database\ConnectionInterface;
@ -1867,13 +1868,31 @@ class Builder
* @param string $pageName * @param string $pageName
* @param null|int $page * @param null|int $page
*/ */
public function paginate($perPage = 15, $columns = ['*'], $pageName = 'page', $page = null): PaginatorInterface public function simplePaginate($perPage = 15, $columns = ['*'], $pageName = 'page', $page = null): PaginatorInterface
{ {
$page = $page ?: Paginator::resolveCurrentPage($pageName); $page = $page ?: Paginator::resolveCurrentPage($pageName);
$this->skip(($page - 1) * $perPage)->take($perPage + 1); $this->skip(($page - 1) * $perPage)->take($perPage + 1);
return $this->paginator($this->get($columns), $perPage, $page, [ return $this->simplePaginator($this->get($columns), $perPage, $page, [
'path' => Paginator::resolveCurrentPath(),
'pageName' => $pageName,
]);
}
/**
* @param int $perPage
* @param string[] $columns
* @param string $pageName
* @param null $page
*/
public function paginate($perPage = 15, $columns = ['*'], $pageName = 'page', $page = null): LengthAwarePaginatorInterface
{
$page = $page ?: Paginator::resolveCurrentPage($pageName);
$total = $this->getCountForPagination();
$results = $total ? $this->forPage($page, $perPage)->get($columns) : collect();
return $this->paginator($results, $total, $perPage, $page, [
'path' => Paginator::resolveCurrentPath(), 'path' => Paginator::resolveCurrentPath(),
'pageName' => $pageName, 'pageName' => $pageName,
]); ]);
@ -2489,18 +2508,6 @@ class Builder
}); });
} }
/**
* Create a new simple paginator instance.
*/
protected function paginator(Collection $items, int $perPage, int $currentPage, array $options)
{
$container = ApplicationContext::getContainer();
if (! method_exists($container, 'make')) {
throw new \RuntimeException('The DI container does not support make() method.');
}
return $container->make(PaginatorInterface::class, compact('items', 'perPage', 'currentPage', 'options'));
}
/** /**
* Creates a subquery and parse it. * Creates a subquery and parse it.
* *
@ -2878,4 +2885,28 @@ class Builder
return ! $binding instanceof Expression; return ! $binding instanceof Expression;
})); }));
} }
/**
* Create a new length-aware paginator instance.
*/
protected function paginator(Collection $items, int $total, int $perPage, int $currentPage, array $options): LengthAwarePaginatorInterface
{
$container = ApplicationContext::getContainer();
if (! method_exists($container, 'make')) {
throw new \RuntimeException('The DI container does not support make() method.');
}
return $container->make(LengthAwarePaginatorInterface::class, compact('items', 'total', 'perPage', 'currentPage', 'options'));
}
/**
* Create a new simple paginator instance.
*/
protected function simplePaginator(Collection $items, int $perPage, int $currentPage, array $options): PaginatorInterface
{
$container = ApplicationContext::getContainer();
if (! method_exists($container, 'make')) {
throw new \RuntimeException('The DI container does not support make() method.');
}
return $container->make(PaginatorInterface::class, compact('items', 'perPage', 'currentPage', 'options'));
}
} }

View File

@ -20,6 +20,7 @@ use Hyperf\Database\Query\Grammars\MySqlGrammar;
use Hyperf\Database\Query\Processors\MySqlProcessor; use Hyperf\Database\Query\Processors\MySqlProcessor;
use Hyperf\Database\Query\Processors\Processor; use Hyperf\Database\Query\Processors\Processor;
use Hyperf\Di\Container; use Hyperf\Di\Container;
use Hyperf\Paginator\LengthAwarePaginator;
use Hyperf\Paginator\Paginator; use Hyperf\Paginator\Paginator;
use Hyperf\Utils\ApplicationContext; use Hyperf\Utils\ApplicationContext;
use Hyperf\Utils\Collection; use Hyperf\Utils\Collection;
@ -2633,7 +2634,7 @@ class QueryBuilderTest extends TestCase
$this->assertTrue(true); $this->assertTrue(true);
} }
public function testPaginate() public function testSimplePaginate()
{ {
$perPage = 16; $perPage = 16;
$columns = ['test']; $columns = ['test'];
@ -2660,7 +2661,7 @@ class QueryBuilderTest extends TestCase
return Context::get('path'); return Context::get('path');
}); });
$result = $builder->paginate($perPage, $columns, $pageName, $page); $result = $builder->simplePaginate($perPage, $columns, $pageName, $page);
$this->assertEquals(new Paginator($results, $perPage, $page, [ $this->assertEquals(new Paginator($results, $perPage, $page, [
'path' => $path, 'path' => $path,
@ -2668,7 +2669,44 @@ class QueryBuilderTest extends TestCase
]), $result); ]), $result);
} }
public function testPaginateWithDefaultArguments() public function testPaginate()
{
$perPage = 16;
$columns = ['test'];
$pageName = 'page-name';
$page = 1;
$total = 10;
$builder = $this->getMockQueryBuilder();
$path = 'http://foo.bar?page=3';
$results = collect([['test' => 'foo'], ['test' => 'bar']]);
$builder->shouldReceive('get')->once()->andReturn($results);
$builder->shouldReceive('getCountForPagination')->andReturn($total);
Context::set('path', $path);
if (! defined('BASE_PATH')) {
define('BASE_PATH', __DIR__);
}
$container = Mockery::mock(Container::class);
$container->shouldReceive('make')->once()->andReturnUsing(function ($interface, $args) {
return new LengthAwarePaginator($args['items'], $args['total'], $args['perPage'], $args['currentPage'], $args['options']);
});
ApplicationContext::setContainer($container);
Paginator::currentPathResolver(function () {
return Context::get('path');
});
$result = $builder->paginate($perPage, $columns, $pageName, $page);
$this->assertEquals(new LengthAwarePaginator($results, $total, $perPage, $page, [
'path' => $path,
'pageName' => $pageName,
]), $result);
}
public function testSimplePaginateWithDefaultArguments()
{ {
$perPage = 15; $perPage = 15;
$columns = ['*']; $columns = ['*'];
@ -2701,7 +2739,7 @@ class QueryBuilderTest extends TestCase
return Context::get('path'); return Context::get('path');
}); });
$result = $builder->paginate(); $result = $builder->simplePaginate();
$this->assertEquals(new Paginator($results, $perPage, $page, [ $this->assertEquals(new Paginator($results, $perPage, $page, [
'path' => $path, 'path' => $path,
@ -2709,7 +2747,50 @@ class QueryBuilderTest extends TestCase
]), $result); ]), $result);
} }
public function testPaginateWhenNoResults() public function testPaginateWithDefaultArguments()
{
$perPage = 15;
$columns = ['*'];
$pageName = 'page';
$page = 1;
$total = 10;
$builder = $this->getMockQueryBuilder();
$path = 'http://foo.bar?page=3';
$results = collect([['test' => 'foo'], ['test' => 'bar']]);
$builder->shouldReceive('get')->once()->andReturn($results);
$builder->shouldReceive('getCountForPagination')->andReturn($total);
Context::set('path', $path);
Context::set('page', $page);
if (! defined('BASE_PATH')) {
define('BASE_PATH', __DIR__);
}
$container = Mockery::mock(Container::class);
$container->shouldReceive('make')->once()->andReturnUsing(function ($interface, $args) {
return new LengthAwarePaginator($args['items'], $args['total'], $args['perPage'], $args['currentPage'], $args['options']);
});
ApplicationContext::setContainer($container);
Paginator::currentPageResolver(function () {
return Context::get('page');
});
Paginator::currentPathResolver(function () {
return Context::get('path');
});
$result = $builder->paginate();
$this->assertEquals(new LengthAwarePaginator($results, $total, $perPage, $page, [
'path' => $path,
'pageName' => $pageName,
]), $result);
}
public function testSimplePaginateWhenNoResults()
{ {
$perPage = 15; $perPage = 15;
$pageName = 'page'; $pageName = 'page';
@ -2743,7 +2824,7 @@ class QueryBuilderTest extends TestCase
return Context::get('path'); return Context::get('path');
}); });
$result = $builder->paginate(); $result = $builder->simplePaginate();
$this->assertEquals(new Paginator($results, $perPage, $page, [ $this->assertEquals(new Paginator($results, $perPage, $page, [
'path' => $path, 'path' => $path,
@ -2751,6 +2832,50 @@ class QueryBuilderTest extends TestCase
]), $result); ]), $result);
} }
public function testPaginateWhenNoResults()
{
$perPage = 15;
$pageName = 'page';
$page = 1;
$total = 10;
$builder = $this->getMockQueryBuilder();
$path = 'http://foo.bar?page=3';
$results = collect();
$builder->shouldReceive('get')->once()->andReturn($results);
$builder->shouldReceive('getCountForPagination')->andReturn($total);
Context::set('path', $path);
Context::set('page', $page);
if (! defined('BASE_PATH')) {
define('BASE_PATH', __DIR__);
}
$container = Mockery::mock(Container::class);
$container->shouldReceive('make')->once()->andReturnUsing(function ($interface, $args) {
/** @var Collection $items */
$items = $args['items'];
return new LengthAwarePaginator(collect($items), $args['total'], $args['perPage'], $args['currentPage'], $args['options']);
});
ApplicationContext::setContainer($container);
Paginator::currentPageResolver(function () {
return Context::get('page');
});
Paginator::currentPathResolver(function () {
return Context::get('path');
});
$result = $builder->paginate();
$this->assertEquals(new LengthAwarePaginator($results, $total, $perPage, $page, [
'path' => $path,
'pageName' => $pageName,
]), $result);
}
public function testWhereRowValues() public function testWhereRowValues()
{ {
$builder = $this->getBuilder(); $builder = $this->getBuilder();