<?php
namespace App\Util;
use Doctrine\ORM\AbstractQuery;
use Doctrine\ORM\Query;
use Doctrine\ORM\QueryBuilder;
use Doctrine\ORM\Tools\Pagination\Paginator;
final class Pagination
{
public const PAGE_LIMIT = 12;
public const PAGE_START = 0;
public const PAGE_VAR = 'pagination';
/**
* @param int|null $limit
* @return int
*/
static public function limit(?int $limit = null): int
{
return (((int) $limit) <= 0) ? self::PAGE_LIMIT : $limit;
}
/**
* @param int $page
* @return int
*/
static public function page(int $page = self::PAGE_START): int
{
return ($page < self::PAGE_START) ? self::PAGE_START : $page;
}
/**
* @param int $page
* @param int $limit
* @return int
*/
static public function offset(int $page, int $limit = self::PAGE_LIMIT): int
{
return (self::page($page) * self::limit($limit));
}
/**
* @param QueryBuilder|Query $query
* @param int|null $limit
* @param int|null $offset
* @return QueryBuilder|Query
*/
static public function paginate($query, ?int $limit = null, ?int $offset = null)
{
if ($limit !== null || $offset !== null) {
$query
->setMaxResults(self::limit($limit))
->setFirstResult($offset ?? 0);
}
return $query;
}
/**
* @param QueryBuilder|Query $query
* @return iterable|array|Paginator
*/
static function query($query): iterable
{
if ($query instanceof QueryBuilder) {
$query = $query->getQuery();
}
if ( ! $query instanceof Query) {
throw new \Exception();
}
if ($query->getFirstResult() !== null && $query->getMaxResults() !== null) {
return new Paginator($query);
}
return $query->getResult($query->getHydrationMode() ?: AbstractQuery::HYDRATE_OBJECT);
}
/**
* @param QueryBuilder|Query $query
* @param int|null $limit
* @param int|null $offset
* @return iterable|array|Paginator
*/
static public function paginateThenQuery($query, ?int $limit = null, ?int $offset = null): iterable
{
return self::query(
self::paginate($query, $limit, $offset)
);
}
/**
* @param QueryBuilder $qb
* @return int
*/
static public function count(QueryBuilder $qb): int
{
return $qb
->resetDQLParts([
'select',
'orderBy',
])
->select(sprintf(
'COUNT(%s)',
$qb->getRootAliases()[0]
))
->getQuery()
->getSingleScalarResult()
;
}
/**
* @param mixed $objects
* @param int $max
* @param int $page
* @param int $limit
* @return array
*/
static public function controller($objects, int $max, int $page, int $limit = self::PAGE_LIMIT): array
{
return array_merge(
self::stats($objects, $max, $page, $limit),
[
'results' => $objects,
]
);
}
/**
* @param mixed $objects
* @param int $max
* @param int $page
* @param int $limit
* @return array
*/
static public function stats($objects, int $max, int $page, int $limit = self::PAGE_LIMIT): array
{
return [
'results_count' => count($objects),
'results_max' => $max,
'page_prev' => max(self::PAGE_START, $page - 1),
'page' => $page,
'limit' => self::limit($limit),
'page_next' => min(self::maxPage($objects, $limit), $page + 1),
'pages_min' => self::PAGE_START,
'pages_max' => self::maxPage($objects, $limit),
];
}
/**
* @param mixed $objects
* @param int $page
* @param int $limit
* @return bool
*/
static public function outOfBounds($objects, int $page, int $limit = self::PAGE_LIMIT): bool
{
return (self::page($page) > self::maxPage($objects, $limit));
}
/**
* @param mixed $objects
* @param int $limit
* @return int
*/
static public function maxPage($objects, int $limit = self::PAGE_LIMIT): int
{
return max((intval(ceil(count($objects) / self::limit($limit))) - 1), 0);
}
}