Files
kupshop/class/class.Pager.php
2025-08-02 16:30:27 +02:00

279 lines
6.5 KiB
PHP

<?php
use KupShop\KupShopBundle\Pager\PagerExtraItem;
class Pager implements ArrayAccess
{
public const INFINITE_PAGE_COUNT = 999999;
protected $pageSideCount = 1;
protected $pageInsideCount = 3;
public $count;
public $number;
public $total;
public ?int $totalWithExtraItems = null;
public $onPage;
protected $url;
protected $params = [];
protected int $extraItemsOnFirstPage = 0;
/** @var PagerExtraItem[] */
protected array $extraItemsOnEachPage = [];
public function __construct($pageCount = null, $page = null, $objectCount = null)
{
if (!is_null($pageCount)) {
$this->count = max(1, $pageCount);
}
if (!is_null($page)) {
$this->number = $page;
}
}
public function setUrl($url)
{
$parts = parse_url($url);
$this->url = $parts['path'];
if (!empty($parts['query'])) {
parse_str($parts['query'], $this->params);
}
}
/*
* set total number of pages
* $total = total number of records
* $this->count = total number of pages
* */
public function setTotal($total, $onPage = null)
{
// total uz muze mit nejakou hodnotu, napr. pocet banneru v ProductListu (total number of records = bannery + produkty)
$this->total += $total;
if (is_null($this->count)) {
$extraItems = array_sum($this->getExtraItems());
$extraItems += $this->getExtraItemsOnNextPages(
ceil(($this->total + $extraItems) / $this->getOnPage())
);
$this->totalWithExtraItems = $this->total + $extraItems;
$this->count = ceil($this->totalWithExtraItems / $this->getOnPage());
}
if ($onPage) {
$this->onPage = $onPage;
}
}
/**
* @param int $onPage
*
* @return $this
*/
/*
* set number of records on the page
* */
public function setOnPage($onPage)
{
$this->onPage = $onPage;
return $this;
}
/**
* @param int $number
*
* @return $this
*/
public function setPageNumber($number)
{
$this->number = max(1, $number);
return $this;
}
/**
* @param int $pageSideCount
*
* @return $this
*/
public function setPageSide($pageSideCount)
{
$this->pageSideCount = $pageSideCount;
return $this;
}
/**
* @param int $pageInsideCount
*
* @return $this
*/
public function setPageInside($pageInsideCount)
{
$this->pageInsideCount = $pageInsideCount;
return $this;
}
public function getUrl($values)
{
$params = array_merge($this->params, $values);
if (getVal('page', $params, 0) == 1) {
unset($params['page']);
}
$query = http_build_query($params);
return $query ? '?'.$query : '.';
}
public function __get($name)
{
if (method_exists($this, $name)) {
return $this->$name();
}
}
public function first()
{
return $this->insidePagesFrom() > $this->pageSideCount;
}
public function firstDots()
{
return $this->insidePagesFrom() > $this->pageSideCount + 1;
}
public function last()
{
return $this->insidePagesTo() < ($this->count - $this->pageSideCount + 1);
}
public function lastDots()
{
return $this->insidePagesTo() < $this->count - $this->pageSideCount;
}
public function insidePagesFrom()
{
return max(1, $this->number - $this->pageInsideCount);
}
public function insidePagesTo()
{
return min($this->count, $this->number + $this->pageInsideCount);
}
public function to()
{
return min($this->number * $this->getOnPage() - 1, $this->total ?: self::INFINITE_PAGE_COUNT);
}
public function from()
{
return ($this->number - 1) * $this->getOnPage();
}
public function isInfinite(): bool
{
return $this->count === self::INFINITE_PAGE_COUNT;
}
public function getSpec()
{
return function (Query\QueryBuilder $qb) {
[$extraItemsOnThisPage, $extraItemsOnPreviousPages] = $this->getExtraItems();
$onPage = $this->getOnPage() - $extraItemsOnThisPage;
$from = max(0, $this->from() - $extraItemsOnPreviousPages);
$qb->setMaxResults($onPage)
->setFirstResult($from);
return null;
};
}
public function addExtraItems(PagerExtraItem $onEachPage): self
{
$this->extraItemsOnEachPage[] = $onEachPage;
return $this;
}
/**
* Get the extra items for the current and previous pages.
*
* @return array{onThisPage: int, onPreviousPages: int}
*/
public function getExtraItems(): array
{
$extraItemsOnPreviousPages = 0;
$extraItemsOnThisPage = 0;
foreach ($this->extraItemsOnEachPage as $extraItem) {
$extraItemsOnPreviousPages += min($extraItem->countOnPage * ($this->number - 1), $extraItem->getMax());
$extraItemsOnThisPage += min($extraItem->countOnPage, max($extraItem->getMax() - $extraItemsOnPreviousPages, 0));
}
return [$extraItemsOnThisPage, $extraItemsOnPreviousPages];
}
/**
* Get the extra items for the next pages when total pages count is already known.
*/
private function getExtraItemsOnNextPages(int $totalPages): int
{
$extraItemsOnNextPages = 0;
foreach ($this->extraItemsOnEachPage as $extraItem) {
$extraItemsOnNextPages += min(($totalPages - $this->number) * $extraItem->countOnPage, max($extraItem->getMax() - ($extraItem->countOnPage * $this->number), 0));
}
return $extraItemsOnNextPages;
}
/**
* Implements ArrayAccess interface.
*/
public function offsetSet($offset, $value): void
{
$this->{$offset} = $value;
}
public function offsetExists($offset): bool
{
return isset($this->{$offset});
}
public function offsetUnset($offset): void
{
unset($this->{$offset});
}
public function offsetGet($offset): mixed
{
if (method_exists($this, $offset)) {
return $this->$offset();
}
return isset($this->{$offset}) ? $this->{$offset} : null;
}
public function getOnPage()
{
if (empty($this->onPage)) {
return 30;
}
return $this->onPage;
}
}