vendor/knplabs/knp-components/src/Knp/Component/Pager/Paginator.php line 64

Open in your IDE?
  1. <?php
  2. namespace Knp\Component\Pager;
  3. use Knp\Component\Pager\Exception\PageNumberOutOfRangeException;
  4. use Knp\Component\Pager\Pagination\PaginationInterface;
  5. use Symfony\Component\HttpFoundation\Request;
  6. use Symfony\Component\HttpFoundation\RequestStack;
  7. use Symfony\Contracts\EventDispatcher\EventDispatcherInterface;
  8. /**
  9.  * Paginator uses event dispatcher to trigger pagination
  10.  * lifecycle events. Subscribers are expected to paginate
  11.  * wanted target and finally it generates pagination view
  12.  * which is only the result of paginator
  13.  */
  14. final class Paginator implements PaginatorInterface
  15. {
  16.     /**
  17.      * @var EventDispatcherInterface
  18.      */
  19.     private $eventDispatcher;
  20.     /**
  21.      * Default options of paginator
  22.      *
  23.      * @var array
  24.      */
  25.     private $defaultOptions = [
  26.         self::PAGE_PARAMETER_NAME => 'page',
  27.         self::SORT_FIELD_PARAMETER_NAME => 'sort',
  28.         self::SORT_DIRECTION_PARAMETER_NAME => 'direction',
  29.         self::FILTER_FIELD_PARAMETER_NAME => 'filterParam',
  30.         self::FILTER_VALUE_PARAMETER_NAME => 'filterValue',
  31.         self::DISTINCT => true,
  32.         self::PAGE_OUT_OF_RANGE => self::PAGE_OUT_OF_RANGE_IGNORE,
  33.         self::DEFAULT_LIMIT => self::DEFAULT_LIMIT_VALUE,
  34.     ];
  35.     /**
  36.      * @var RequestStack|null
  37.      */
  38.     private $requestStack;
  39.     public function __construct(EventDispatcherInterface $eventDispatcherRequestStack $requestStack null)
  40.     {
  41.         $this->eventDispatcher $eventDispatcher;
  42.         $this->requestStack $requestStack;
  43.     }
  44.     /**
  45.      * Override the default paginator options
  46.      * to be reused for paginations
  47.      */ 
  48.     public function setDefaultPaginatorOptions(array $options): void
  49.     {
  50.         $this->defaultOptions = \array_merge($this->defaultOptions$options);
  51.     }
  52.     public function paginate($targetint $page 1int $limit null, array $options = []): PaginationInterface
  53.     {
  54.         $limit $limit ?? $this->defaultOptions[self::DEFAULT_LIMIT];
  55.         if ($limit <= || $page <= 0) {
  56.             throw new \LogicException("Invalid item per page number. Limit: $limit and Page: $page, must be positive non-zero integers");
  57.         }
  58.         $offset = ($page 1) * $limit;
  59.         $options = \array_merge($this->defaultOptions$options);
  60.         // normalize default sort field
  61.         if (isset($options[PaginatorInterface::DEFAULT_SORT_FIELD_NAME]) && is_array($options[PaginatorInterface::DEFAULT_SORT_FIELD_NAME])) {
  62.             $options[PaginatorInterface::DEFAULT_SORT_FIELD_NAME] = implode('+'$options[PaginatorInterface::DEFAULT_SORT_FIELD_NAME]);
  63.         }
  64.         $request null === $this->requestStack Request::createFromGlobals() : $this->requestStack->getCurrentRequest();
  65.         // default sort field and direction are set based on options (if available)
  66.         if (isset($options[self::DEFAULT_SORT_FIELD_NAME]) && !$request->query->has($options[self::SORT_FIELD_PARAMETER_NAME])) {
  67.            $request->query->set($options[self::SORT_FIELD_PARAMETER_NAME], $options[self::DEFAULT_SORT_FIELD_NAME]);
  68.             if (!$request->query->has($options[PaginatorInterface::SORT_DIRECTION_PARAMETER_NAME])) {
  69.                 $request->query->set($options[PaginatorInterface::SORT_DIRECTION_PARAMETER_NAME], $options[PaginatorInterface::DEFAULT_SORT_DIRECTION] ?? 'asc');
  70.             }
  71.         }
  72.         // before pagination start
  73.         $beforeEvent = new Event\BeforeEvent($this->eventDispatcher$request);
  74.         $this->eventDispatcher->dispatch($beforeEvent'knp_pager.before');
  75.         // items
  76.         $itemsEvent = new Event\ItemsEvent($offset$limit);
  77.         $itemsEvent->options = &$options;
  78.         $itemsEvent->target = &$target;
  79.         $this->eventDispatcher->dispatch($itemsEvent'knp_pager.items');
  80.         if (!$itemsEvent->isPropagationStopped()) {
  81.             throw new \RuntimeException('One of listeners must count and slice given target');
  82.         }
  83.         if ($page ceil($itemsEvent->count $limit)) {
  84.             $pageOutOfRangeOption $options[PaginatorInterface::PAGE_OUT_OF_RANGE] ?? $this->defaultOptions[PaginatorInterface::PAGE_OUT_OF_RANGE];
  85.             if ($pageOutOfRangeOption === PaginatorInterface::PAGE_OUT_OF_RANGE_FIX && $itemsEvent->count 0) {
  86.                 // replace page number out of range with max page
  87.                 return $this->paginate($target, (int) ceil($itemsEvent->count $limit), $limit$options);
  88.             }
  89.             if ($pageOutOfRangeOption === self::PAGE_OUT_OF_RANGE_THROW_EXCEPTION && $page 1) {
  90.                 throw new PageNumberOutOfRangeException(
  91.                     sprintf('Page number: %d is out of range.'$page),
  92.                     (int) ceil($itemsEvent->count $limit)
  93.                 );
  94.             }
  95.         }
  96.         // pagination initialization event
  97.         $paginationEvent = new Event\PaginationEvent;
  98.         $paginationEvent->target = &$target;
  99.         $paginationEvent->options = &$options;
  100.         $this->eventDispatcher->dispatch($paginationEvent'knp_pager.pagination');
  101.         if (!$paginationEvent->isPropagationStopped()) {
  102.             throw new \RuntimeException('One of listeners must create pagination view');
  103.         }
  104.         // pagination class can be different, with different rendering methods
  105.         $paginationView $paginationEvent->getPagination();
  106.         $paginationView->setCustomParameters($itemsEvent->getCustomPaginationParameters());
  107.         $paginationView->setCurrentPageNumber($page);
  108.         $paginationView->setItemNumberPerPage($limit);
  109.         $paginationView->setTotalItemCount($itemsEvent->count);
  110.         $paginationView->setPaginatorOptions($options);
  111.         $paginationView->setItems($itemsEvent->items);
  112.         // after
  113.         $afterEvent = new Event\AfterEvent($paginationView);
  114.         $this->eventDispatcher->dispatch($afterEvent'knp_pager.after');
  115.         return $paginationView;
  116.     }
  117. }