Skip to content

Commit c9217e8

Browse files
committed
Add paginator service for pagination logic
1 parent 5c75b61 commit c9217e8

6 files changed

Lines changed: 134 additions & 31 deletions

File tree

src/Shared/Base/Entity.php

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
namespace Ivy\Shared\Base;
44

55
use Illuminate\Database\Eloquent\Model;
6+
use Ivy\Shared\Domain\Collection\EntityCollection;
67

78
/**
89
* @method static static where(string $column, mixed $value = null)
@@ -19,5 +20,17 @@
1920
*/
2021
abstract class Entity extends Model
2122
{
23+
public function newCollection(array $models = []): EntityCollection
24+
{
25+
$collection = new EntityCollection($models);
2226

27+
if (
28+
method_exists(static::class, 'pagination') &&
29+
static::pagination()
30+
) {
31+
$collection->setPagination(static::pagination());
32+
}
33+
34+
return $collection;
35+
}
2336
}
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
<?php
2+
3+
namespace Ivy\Shared\Domain\Collection;
4+
5+
use Illuminate\Database\Eloquent\Collection;
6+
use Ivy\Shared\Domain\Data\PaginationResult;
7+
8+
class EntityCollection extends Collection
9+
{
10+
protected ?PaginationResult $pagination = null;
11+
12+
public function setPagination(PaginationResult $pagination): static
13+
{
14+
$this->pagination = $pagination;
15+
16+
return $this;
17+
}
18+
19+
public function pagination(): ?PaginationResult
20+
{
21+
return $this->pagination;
22+
}
23+
}
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
<?php
2+
3+
namespace Ivy\Shared\Domain\Data;
4+
5+
use Illuminate\Support\Collection;
6+
7+
class PaginationResult
8+
{
9+
public function __construct(
10+
public readonly int $currentPage,
11+
public readonly int $perPage,
12+
public readonly int $total,
13+
public readonly int $lastPage,
14+
public array $perPageOptions = [5, 10, 25, 50, 100],
15+
) {}
16+
17+
public function pages(): array
18+
{
19+
return range(1, $this->lastPage);
20+
}
21+
22+
public function from(): int
23+
{
24+
return ($this->currentPage - 1) * $this->perPage + 1;
25+
}
26+
27+
public function to(): int
28+
{
29+
return min($this->currentPage * $this->perPage, $this->total);
30+
}
31+
32+
public function hasNext(): bool
33+
{
34+
return $this->currentPage < $this->lastPage;
35+
}
36+
37+
public function hasPrevious(): bool
38+
{
39+
return $this->currentPage > 1;
40+
}
41+
}

src/Shared/Infrastructure/Service/PaginationService.php

Lines changed: 17 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -3,37 +3,35 @@
33
namespace Ivy\Shared\Infrastructure\Service;
44

55
use Illuminate\Database\Eloquent\Builder;
6+
use Ivy\Shared\Domain\Data\PaginationResult;
67
use Symfony\Component\HttpFoundation\Request;
78

89
class PaginationService
910
{
10-
public function paginate(
11+
public function apply(
1112
Builder $query,
1213
Request $request,
1314
int $perPage = 25
14-
): array {
15+
): Builder {
1516

1617
$page = max(1, (int) $request->query->get('page', 1));
18+
$perPage = max(1, (int) $request->query->get('per_page', $perPage));
1719

1820
$total = (clone $query)->count();
1921

20-
$items = $query
22+
$modelClass = get_class($query->getModel());
23+
24+
$modelClass::setPagination(
25+
new PaginationResult(
26+
currentPage: $page,
27+
perPage: $perPage,
28+
total: $total,
29+
lastPage: (int) ceil($total / $perPage),
30+
)
31+
);
32+
33+
return $query
2134
->offset(($page - 1) * $perPage)
22-
->limit($perPage)
23-
->get();
24-
25-
$lastPage = (int) ceil($total / $perPage);
26-
27-
return [
28-
'data' => $items,
29-
'meta' => [
30-
'current_page' => $page,
31-
'per_page' => $perPage,
32-
'total' => $total,
33-
'last_page' => $lastPage,
34-
'has_next' => $page < $lastPage,
35-
'has_prev' => $page > 1,
36-
],
37-
];
35+
->limit($perPage);
3836
}
3937
}
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
<?php
2+
3+
namespace Ivy\Shared\Traits;
4+
5+
use Illuminate\Container\Container;
6+
use Illuminate\Database\Eloquent\Builder;
7+
use Ivy\Shared\Domain\Data\PaginationResult;
8+
use Ivy\Shared\Infrastructure\Service\PaginationService;
9+
use Symfony\Component\HttpFoundation\Request;
10+
11+
trait HasPagination
12+
{
13+
protected static ?PaginationResult $pagination = null;
14+
15+
public static function pagination(): ?PaginationResult
16+
{
17+
return static::$pagination;
18+
}
19+
20+
public static function setPagination(PaginationResult $pagination): void
21+
{
22+
static::$pagination = $pagination;
23+
}
24+
25+
public function scopePaged(
26+
Builder $query,
27+
Request $request,
28+
): Builder {
29+
30+
return Container::getInstance()->get(PaginationService::class)->apply($query, $request);
31+
}
32+
}

src/Template/Presentation/View/Engine/LatteEngine.php

Lines changed: 8 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -178,21 +178,17 @@ private function registerFunctions(): void
178178
$key ?? $default
179179
);
180180

181-
$this->latte->addFunction('sortUrl', function (string $column) {
181+
$this->latte->addFunction('queryUrl', function (array $replace = [], array $remove = []) {
182182

183183
$query = $this->request->query->all();
184184

185-
$currentSort = $query['sort'] ?? null;
186-
$currentDirection = $query['direction'] ?? 'asc';
185+
foreach ($replace as $key => $value) {
186+
$query[$key] = $value;
187+
}
187188

188-
$query['sort'] = $column;
189-
190-
$query['direction'] =
191-
($currentSort === $column && $currentDirection === 'asc')
192-
? 'desc'
193-
: 'asc';
194-
195-
unset($query['page']);
189+
foreach ($remove as $key) {
190+
unset($query[$key]);
191+
}
196192

197193
return '?' . http_build_query($query);
198194
});
@@ -205,6 +201,6 @@ private function registerExtensions(): void
205201

206202
private function registerProviders(): void
207203
{
208-
204+
209205
}
210206
}

0 commit comments

Comments
 (0)