<?php declare(strict_types=1); namespace App\Services\Search; use App\Models\Role; use Illuminate\Container\Container; use Illuminate\Database\Eloquent\Builder; use Illuminate\Database\Eloquent\Relations\Relation; use Illuminate\Pagination\CursorPaginator; use Illuminate\Pagination\LengthAwarePaginator; use Illuminate\Pagination\Paginator; use Illuminate\Support\Collection; use App\Contracts\Search as SearchContract; final readonly class Search implements SearchContract { public function __construct( private Relation|Builder $query ) { } public function all(): Collection { return $this->query->get(); } public function get(int $limit): Collection { return $this->query->limit($limit)->get(); } public function pagination(int $limit, int $page = 1): LengthAwarePaginator { if ($page > 100) { return $this->paginationPerfomance($limit, $page); } return $this->query->paginate($limit, page: $page)->withQueryString(); } public function cursorPaginate(int $limit): CursorPaginator { return $this->query->cursorPaginate($limit); } private function paginationPerfomance(int $limit, int $page = 1): LengthAwarePaginator { $total = $this->query->clone()->count(); $options = [ 'path' => Paginator::resolveCurrentPath(), 'pageName' => 'page', ]; $result = collect(); if ($total > 0) { $result = $this->subQuery($limit, $page); } $pagination = Container::getInstance()->makeWith(LengthAwarePaginator::class, [ 'items' => $result, 'total' => $total, 'perPage' => $limit, 'currentPage' => $page, 'options' => $options ]); return $pagination->withQueryString(); } private function subQuery(int $limit, int $page): Collection { $table = $this->query->getModel()->getTable(); return $this->query->getModel()::query() ->select($table.'.*') ->with($this->query->getEagerLoads()) ->from( clone $this->query->select('id')->forPage($page, $limit), 'q' )->join($table.' as '.$table, $table.'.id', '=', 'q.id') ->get(); } }