Created
January 1, 2021 01:50
-
-
Save lpj145/dd251bceed38ea711ebef50005dccd00 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
declare(strict_types=1); | |
namespace Api2Bundle\Service; | |
use Doctrine\ORM\AbstractQuery; | |
use Doctrine\ORM\QueryBuilder; | |
use Doctrine\ORM\Tools\Pagination\Paginator; | |
use Symfony\Component\HttpFoundation\ParameterBag; | |
use Symfony\Component\HttpFoundation\Request; | |
class PaginateService | |
{ | |
const DEFAULT_PAGE_SIZE = 20; | |
/** | |
* @var QueryBuilder | |
*/ | |
private $query; | |
private function __construct(QueryBuilder $query) { | |
$this->query = $query; | |
} | |
public function paginate(Request $request, ?callable $hydrateCallback = null): array | |
{ | |
$params = $request->query; | |
if ($params->has('no_page')) { | |
return is_callable($hydrateCallback) | |
? $hydrateCallback($this->mountData()) | |
: $this->mountData(); | |
} | |
$currentPage = $params->get('page', 1); | |
$pageSize = $params->get('size', self::DEFAULT_PAGE_SIZE); | |
if (!is_numeric($currentPage)) { | |
$currentPage = 1; | |
} | |
if (!is_numeric($pageSize)) { | |
$pageSize = self::DEFAULT_PAGE_SIZE; | |
} | |
$this->query->setFirstResult($pageSize * ($currentPage - 1)); | |
$this->query->setMaxResults($pageSize); | |
$data = $this->mountData(); | |
return [ | |
'data' => is_callable($hydrateCallback) ? $hydrateCallback($data) : $data, | |
'meta' => $this->mountMeta( | |
$this->getBaseUrl($request), | |
$params, | |
count($data), | |
(int)$currentPage, | |
(int)$pageSize | |
) | |
]; | |
} | |
protected function mountData(): array | |
{ | |
return $this->query | |
->getQuery() | |
->getResult(AbstractQuery::HYDRATE_ARRAY); | |
} | |
protected function mountMeta( | |
string $baseUrl, | |
ParameterBag $params, | |
int $itemsCount, | |
?int $currentPage = 1, | |
?int $pageSize = 0 | |
): array | |
{ | |
$paginator = new Paginator($this->query); | |
$resultCount = $paginator->count(); | |
$lastPage = (int)ceil($resultCount / $pageSize); | |
$lastPage = $lastPage > 0 ? $lastPage : 1; | |
$toRecordsNumber = $this->calculateToRecordNumber($resultCount, $pageSize, $currentPage, $lastPage); | |
$nextPageUrl = null; | |
$prevPageUrl = null; | |
if ($resultCount > $pageSize && $currentPage < $lastPage) { | |
$nextPageUrl = $this->getUrlWithPageQuery($baseUrl, $params->all(), $currentPage + 1); | |
} | |
if ($currentPage > 1 && $resultCount > $pageSize) { | |
$prevPageUrl = $this->getUrlWithPageQuery($baseUrl, $params->all(), $currentPage - 1); | |
} | |
return [ | |
'total'=> $resultCount, | |
'per_page' => $pageSize, | |
'current_page' => $currentPage, | |
'last_page' => $lastPage, | |
'first_page_url' => $this->getUrlWithPageQuery($baseUrl, $params->all(), 1), | |
'last_page_url' => $this->getUrlWithPageQuery($baseUrl, $params->all(), $lastPage), | |
'next_page_url' => $nextPageUrl, | |
'prev_page_url' => $prevPageUrl, | |
'items_count' => $itemsCount, | |
'from' => $this->calculateFromRecordNumber($itemsCount, $toRecordsNumber), | |
'to' => $toRecordsNumber | |
]; | |
} | |
private function calculateFromRecordNumber(int $itemsCount, int $toNumber): int | |
{ | |
return $toNumber === 0 ? 0 : $toNumber === $itemsCount ? 1 : $toNumber - $itemsCount; | |
} | |
private function calculateToRecordNumber($resultCount, $pageSize, $currentPage, $lastPage): int | |
{ | |
return $currentPage === $lastPage | |
? $resultCount | |
: $pageSize * $currentPage; | |
} | |
private function getBaseUrl(Request $request): string | |
{ | |
return $request->getUriForPath($request->getPathInfo()); | |
} | |
private function getUrlWithPageQuery(string $url, array $params, int $page): string | |
{ | |
$params['page'] = $page; | |
return $url.'?'.http_build_query($params); | |
} | |
public static function factory(QueryBuilder $query): PaginateService | |
{ | |
return new static($query); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment