Skip to content

Commit

Permalink
Support CakePHP 5.x (#48)
Browse files Browse the repository at this point in the history
  • Loading branch information
chitoku-k authored Apr 21, 2024
1 parent 0dc7c1e commit a9f8873
Show file tree
Hide file tree
Showing 18 changed files with 812 additions and 802 deletions.
2 changes: 0 additions & 2 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,6 @@ jobs:
strategy:
matrix:
php:
- 7.4
- 8.0
- 8.1
- 8.2
- 8.3
Expand Down
70 changes: 34 additions & 36 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,20 +13,21 @@ Rapid pagination without using OFFSET

## Requirements

- PHP: ^7.4 || ^8.0
- CakePHP: ^4.5
- PHP: ^8.1
- CakePHP: ^5.0
- [lampager/lampager][]: ^0.4

### Note

- For CakePHP 2.x, use [lampager/lampager-cakephp2][].
- For CakePHP 3.x, use [lampager/lampager-cakephp v1.x][].
- For CakePHP 4.x, use lampager/lampager-cakephp v2.x (this version).
- For CakePHP 4.x, use [lampager/lampager-cakephp v2.x][].
- For CakePHP 5.x, use lampager/lampager-cakephp v3.x (this version).

## Installing

```bash
composer require lampager/lampager-cakephp:^2.0
composer require lampager/lampager-cakephp:^3.0
```

For SQLite users, see [SQLite](#sqlite) to configure.
Expand Down Expand Up @@ -64,8 +65,8 @@ are specific to Lampager such as `forward`, `seekable`, or `cursor`.
```php
$query = $this->Posts
->where(['Posts.type' => 'public'])
->orderDesc('created')
->orderDesc('id')
->orderByDesc('created')
->orderByDesc('id')
->limit(10);

$posts = $this->paginate($query, [
Expand Down Expand Up @@ -121,9 +122,10 @@ $latest = $this->lampager()
->seekable()
->cursor($cursor)
->limit(10)
->orderDesc('Posts.modified')
->orderDesc('Posts.created')
->orderDesc('Posts.id');
->orderByDesc('Posts.modified')
->orderByDesc('Posts.created')
->orderByDesc('Posts.id')
->paginate();

foreach ($latest as $post) {
/** @var \Cake\ORM\Entity $post */
Expand All @@ -144,9 +146,10 @@ $drafts = $this->lampager()
->seekable()
->cursor($cursor)
->limit(10)
->orderDesc($this->selectQuery()->newExpr('modified'))
->orderDesc($this->selectQuery()->newExpr('created'))
->orderDesc($this->selectQuery()->newExpr('id'));
->orderByDesc($this->selectQuery()->newExpr('modified'))
->orderByDesc($this->selectQuery()->newExpr('created'))
->orderByDesc($this->selectQuery()->newExpr('id'))
->paginate();

/** @var \Cake\ORM\Entity $sample */
$sample = $drafts->sample();
Expand All @@ -159,20 +162,16 @@ $count = $drafts->count();

See also: [lampager/lampager][].

| Name | Type | Parent Class<br>Implemented Interface | Description |
|:----------------------------------------------------|:------|:---------------------------------------|:------------------------------------------------------------------------------------|
| Lampager\\Cake\\ORM\\`Query` | Class | Cake\\ORM\\`Query` | Fluent factory implementation for CakePHP |
| Lampager\\Cake\\Model\\Behavior\\`LampagerBehavior` | Class | Cake\\ORM\\`Behavior` | CakePHP behavior which returns Lampager\\Cake\\ORM\\`Query` |
| Lampager\\Cake\\Datasource\\`Paginator` | Class | Cake\\Datasource\\`Paginator` | CakePHP paginatior which delegates to Lampager\\Cake\\ORM\\`Query` |
| Lampager\\Cake\\`Paginator` | Class | Lampager\\`Paginator` | Paginator implementation for CakePHP |
| Lampager\\Cake\\`ArrayProcessor` | Class | Lampager\\`ArrayProcessor` | Processor implementation for CakePHP |
| Lampager\\Cake\\`PaginationResult` | Class | Cake\\Datasource\\`ResultSetInterface` | PaginationResult implementation for CakePHP |
| Lampager\\Cake\\Database\\`SqliteCompiler` | Class | Cake\\Database\\`SqliteCompiler` | Query compiler implementation for SQLite |
| Lampager\\Cake\\Database\\Driver\\`Sqlite` | Class | Cake\\Database\\Driver\\`Sqlite` | Driver implementation which delegates to Lampager\\Cake\\Database\\`SqliteCompiler` |

Note that `\Lampager\Cake\PaginationResult` does not extend
`\Lampager\PaginationResult` as it conflicts with
`\Cake\Datasource\ResultSetInterface`.
| Name | Type | Parent Class<br>Implemented Interface | Description |
|:----------------------------------------------------|:------|:-------------------------------------------------------------------------------|:------------------------------------------------------------------------------------|
| Lampager\\Cake\\ORM\\`Query` | Class | Cake\\ORM\\`Query` | Fluent factory implementation for CakePHP |
| Lampager\\Cake\\Model\\Behavior\\`LampagerBehavior` | Class | Cake\\ORM\\`Behavior` | CakePHP behavior which returns Lampager\\Cake\\ORM\\`Query` |
| Lampager\\Cake\\Datasource\\`Paginator` | Class | Cake\\Datasource\\`Paginator` | CakePHP paginatior which delegates to Lampager\\Cake\\ORM\\`Query` |
| Lampager\\Cake\\`Paginator` | Class | Lampager\\`Paginator` | Paginator implementation for CakePHP |
| Lampager\\Cake\\`ArrayProcessor` | Class | Lampager\\`ArrayProcessor` | Processor implementation for CakePHP |
| Lampager\\Cake\\`PaginationResult` | Class | Lampager\\`PaginationResult`<br>Cake\\Datasource\\Paging\\`PaginatedInterface` | PaginationResult implementation for CakePHP |
| Lampager\\Cake\\Database\\`SqliteCompiler` | Class | Cake\\Database\\`SqliteCompiler` | Query compiler implementation for SQLite |
| Lampager\\Cake\\Database\\Driver\\`Sqlite` | Class | Cake\\Database\\Driver\\`Sqlite` | Driver implementation which delegates to Lampager\\Cake\\Database\\`SqliteCompiler` |

## API

Expand All @@ -192,24 +191,24 @@ Create a new paginator instance. These methods are not intended to be directly
used in your code.

```php
static Paginator::create(\Cake\ORM\Query $builder): static
Paginator::__construct(\Cake\ORM\Query $builder)
static Paginator::create(\Cake\ORM\Query\SelectQuery $builder): static
Paginator::__construct(\Cake\ORM\Query\SelectQuery $builder)
```

### Paginator::transform()

Transform a Lampager query into a CakePHP query.

```php
Paginator::transform(\Lampager\Query $query): \Cake\ORM\Query
Paginator::transform(\Lampager\Query $query): \Cake\ORM\Query\SelectQuery
```

### Paginator::build()

Perform configure + transform.

```php
Paginator::build(\Lampager\Contracts\Cursor|array $cursor = []): \Cake\ORM\Query
Paginator::build(\Lampager\Contracts\Cursor|array $cursor = []): \Cake\ORM\Query\SelectQuery
```

### Paginator::paginate()
Expand Down Expand Up @@ -270,8 +269,7 @@ object(Lampager\Cake\PaginationResult)#1 (6) {
### PaginationResult::\_\_call()

`\Lampager\Cake\PaginationResult` implements
`\Cake\Datasource\ResultSetInterface`. For how to make the best use of the
`PaginationResult`, please refer to the Cookbook: [Working with Result Sets][].
`\Cake\Datasource\Paging\PaginatedInterface`.

## Examples

Expand Down Expand Up @@ -303,8 +301,8 @@ class PostsController extends AppController
// Query expression can be passed to PaginatorComponent::paginate() as normal
$query = $this->Posts
->where(['Posts.type' => 'public'])
->orderDesc('created')
->orderDesc('id')
->orderByDesc('created')
->orderByDesc('id')
->limit(15);

/** @var \Lampager\Cake\PaginationResult<\Cake\ORM\Entity> $posts */
Expand Down Expand Up @@ -415,6 +413,6 @@ return [

[lampager/lampager]: https://github.com/lampager/lampager
[lampager/lampager-cakephp v1.x]: https://github.com/lampager/lampager-cakephp/tree/v1.x
[lampager/lampager-cakephp v2.x]: https://github.com/lampager/lampager-cakephp/tree/v2.x
[lampager/lampager-cakephp2]: https://github.com/lampager/lampager-cakephp2
[Pagination]: https://book.cakephp.org/4/en/controllers/pagination.html
[Working with Result Sets]: https://book.cakephp.org/4/en/orm/retrieving-data-and-resultsets.html#working-with-result-sets
[Pagination]: https://book.cakephp.org/5/en/controllers/pagination.html
8 changes: 4 additions & 4 deletions composer.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "lampager/lampager-cakephp",
"description": "Rapid pagination for CakePHP 4",
"description": "Rapid pagination for CakePHP 5",
"type": "cakephp-plugin",
"license": "MIT",
"authors": [
Expand All @@ -21,12 +21,12 @@
}
},
"require": {
"php": "^7.4 || ^8.0",
"cakephp/cakephp": "^4.5",
"php": "^8.1",
"cakephp/cakephp": "^5.0",
"lampager/lampager": "^0.4"
},
"require-dev": {
"phpunit/phpunit": "^8.0 || ^9.0",
"phpunit/phpunit": "^10.1",
"nilportugues/sql-query-formatter": "^1.2"
},
"scripts": {
Expand Down
13 changes: 8 additions & 5 deletions phpunit.xml.dist
Original file line number Diff line number Diff line change
@@ -1,24 +1,27 @@
<?xml version="1.0" encoding="UTF-8"?>
<phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="https://schema.phpunit.de/9.3/phpunit.xsd"
xsi:noNamespaceSchemaLocation="https://schema.phpunit.de/10.1/phpunit.xsd"
colors="true"
processIsolation="false"
stopOnFailure="false"
bootstrap="tests/bootstrap.php">
<source>
<include>
<directory suffix=".php">src/</directory>
</include>
</source>

<testsuites>
<testsuite name="Lampager CakePHP Test Suite">
<directory>tests/TestCase/</directory>
</testsuite>
</testsuites>

<extensions>
<extension class="\Cake\TestSuite\Fixture\PHPUnitExtension" />
<bootstrap class="\Cake\TestSuite\Fixture\Extension\PHPUnitExtension" />
</extensions>

<coverage>
<include>
<directory suffix=".php">src/</directory>
</include>
<report>
<clover outputFile="build/logs/clover.xml" />
<html outputDirectory="build/coverage" />
Expand Down
4 changes: 3 additions & 1 deletion src/ArrayProcessor.php
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,9 @@ class ArrayProcessor extends BaseArrayProcessor
*/
protected function defaultFormat($rows, array $meta, LampagerQuery $query)
{
return new PaginationResult($rows, $meta);
return new PaginationResult($rows, $meta + [
'limit' => $query->limit(),
]);
}

/**
Expand Down
55 changes: 40 additions & 15 deletions src/Datasource/Paginator.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,13 @@
namespace Lampager\Cake\Datasource;

use Cake\Datasource\Paging\NumericPaginator as CakePaginator;
use Cake\Datasource\Paging\PaginatedInterface;
use Cake\Datasource\QueryInterface;
use Cake\Datasource\ResultSetInterface;
use Exception;
use Lampager\Cake\ORM\Query;
use Lampager\Cake\PaginationResult;
use Lampager\Exceptions\InvalidArgumentException;
use function Cake\Core\triggerWarning;

class Paginator extends CakePaginator
{
Expand All @@ -19,13 +20,13 @@ class Paginator extends CakePaginator
* @throws InvalidArgumentException if the \Lampager\Cake\ORM\Query is given
* @return PaginationResult
*/
public function paginate(object $object, array $params = [], array $settings = []): ResultSetInterface
public function paginate(mixed $target, array $params = [], array $settings = []): PaginatedInterface
{
$query = null;
if ($object instanceof QueryInterface) {
$query = $object;
$object = $query->getRepository();
if ($object === null) {
if ($target instanceof QueryInterface) {
$query = $target;
$target = $query->getRepository();
if ($target === null) {
throw new Exception('No repository set for query.');
}
}
Expand All @@ -34,25 +35,49 @@ public function paginate(object $object, array $params = [], array $settings = [
throw new InvalidArgumentException(Query::class . ' cannot be paginated by ' . __METHOD__ . '()');
}

$alias = $object->getAlias();
$alias = $target->getAlias();
$defaults = $this->getDefaults($alias, $settings);

$validSettings = [
...array_keys($this->_defaultConfig),
'order',
'forward',
'backward',
'exclusive',
'inclusive',
'seekable',
'unseekable',
'cursor',
];
$extraSettings = array_diff_key($defaults, array_flip($validSettings));
if ($extraSettings) {
triggerWarning(
'Passing query options as paginator settings is no longer supported.'
. ' Use a custom finder through the `finder` config or pass a Query instance to paginate().'
. ' Extra keys found are: `' . implode('`, `', array_keys($extraSettings)) . '`.'
);
}

$options = $this->mergeOptions($params, $defaults);
$options = $this->validateSort($object, $options);
$options = $this->validateSort($target, $options);
$options = $this->checkLimit($options);

$options += ['cursor' => [], 'scope' => null];

list($finder, $options) = $this->_extractFinder($options);

if (empty($query)) {
$query = Query::fromQuery($object->find($finder, $options));
} else {
$query = Query::fromQuery($query->applyOptions($options));
if ($query === null) {
$args = [];
$type = $options['finder'] ?? 'all';
if (is_array($type)) {
$args = (array)current($type);
$type = key($type);
}
$query = $target->find($type, ...$args);
}

$query = Query::fromQuery($query->applyOptions($options));
$query->fromArray($options);
$query->cursor($options['cursor']);

return $query->all();
return $query->paginate();
}
}
6 changes: 1 addition & 5 deletions src/Model/Behavior/LampagerBehavior.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,16 +5,12 @@
namespace Lampager\Cake\Model\Behavior;

use Cake\ORM\Behavior;
use Cake\ORM\Table;
use Lampager\Cake\ORM\Query;

class LampagerBehavior extends Behavior
{
public function lampager(): Query
{
$query = new Query($this->table()->getConnection(), $this->table());
$query->select();

return $query;
return new Query($this->table());
}
}
Loading

0 comments on commit a9f8873

Please sign in to comment.