vendor/knplabs/knp-components/src/Knp/Component/Pager/Event/Subscriber/Sortable/ArraySubscriber.php line 49

Open in your IDE?
  1. <?php
  2. namespace Knp\Component\Pager\Event\Subscriber\Sortable;
  3. use Knp\Component\Pager\Event\ItemsEvent;
  4. use Knp\Component\Pager\PaginatorInterface;
  5. use Symfony\Component\EventDispatcher\EventSubscriberInterface;
  6. use Symfony\Component\HttpFoundation\Request;
  7. use Symfony\Component\PropertyAccess\Exception\UnexpectedTypeException;
  8. use Symfony\Component\PropertyAccess\PropertyAccess;
  9. use Symfony\Component\PropertyAccess\PropertyAccessorInterface;
  10. class ArraySubscriber implements EventSubscriberInterface
  11. {
  12.     /**
  13.      * @var string the field used to sort current object array list
  14.      */
  15.     private $currentSortingField;
  16.     /**
  17.      * @var string the sorting direction
  18.      */
  19.     private $sortDirection;
  20.     /**
  21.      * @var PropertyAccessorInterface
  22.      */
  23.     private $propertyAccessor;
  24.     /**
  25.      * @var Request
  26.      */
  27.     private $request;
  28.     public function __construct(Request $request nullPropertyAccessorInterface $accessor null)
  29.     {
  30.         if (!$accessor && class_exists('Symfony\Component\PropertyAccess\PropertyAccess')) {
  31.             $accessor PropertyAccess::createPropertyAccessorBuilder()->enableMagicCall()->getPropertyAccessor();
  32.         }
  33.         $this->propertyAccessor $accessor;
  34.         // check needed because $request must be nullable, being the second parameter (with the first one nullable)
  35.         if (null === $request) {
  36.             throw new \InvalidArgumentException('Request must be initialized.');
  37.         }
  38.         $this->request $request;
  39.     }
  40.     public function items(ItemsEvent $event): void
  41.     {
  42.         // Check if the result has already been sorted by an other sort subscriber
  43.         $customPaginationParameters $event->getCustomPaginationParameters();
  44.         if (!empty($customPaginationParameters['sorted']) ) {
  45.             return;
  46.         }
  47.         $sortField $event->options[PaginatorInterface::SORT_FIELD_PARAMETER_NAME];
  48.         if (!is_array($event->target) || null === $sortField || !$this->request->query->has($sortField)) {
  49.             return;
  50.         }
  51.         $event->setCustomPaginationParameter('sorted'true);
  52.         if (isset($event->options[PaginatorInterface::SORT_FIELD_WHITELIST])) {
  53.             trigger_deprecation('knplabs/knp-components''2.4.0', \sprintf('%s option is deprecated. Use %s option instead.'PaginatorInterface::SORT_FIELD_WHITELISTPaginatorInterface::SORT_FIELD_ALLOW_LIST));
  54.             $event->options[PaginatorInterface::SORT_FIELD_ALLOW_LIST] = $event->options[PaginatorInterface::SORT_FIELD_WHITELIST];
  55.         }
  56.         if (isset($event->options[PaginatorInterface::SORT_FIELD_ALLOW_LIST]) && !in_array($this->request->query->get($sortField), $event->options[PaginatorInterface::SORT_FIELD_ALLOW_LIST])) {
  57.             throw new \UnexpectedValueException("Cannot sort by: [{$this->request->query->get($sortField)}] this field is not in allow list.");
  58.         }
  59.         $sortFunction = isset($event->options['sortFunction']) ? $event->options['sortFunction'] : [$this'proxySortFunction'];
  60.         $sortField $this->request->query->get($sortField);
  61.         // compatibility layer
  62.         if ($sortField[0] === '.') {
  63.             $sortField substr($sortField1);
  64.         }
  65.         call_user_func_array($sortFunction, [
  66.             &$event->target,
  67.             $sortField,
  68.             $this->getSortDirection($event->options)
  69.         ]);
  70.     }
  71.     private function getSortDirection(array $options): string
  72.     {
  73.         if (!$this->request->query->has($options[PaginatorInterface::SORT_DIRECTION_PARAMETER_NAME])) {
  74.             return 'desc';
  75.         }
  76.         $direction $this->request->query->get($options[PaginatorInterface::SORT_DIRECTION_PARAMETER_NAME]);
  77.         if (strtolower($direction) === 'asc') {
  78.             return 'asc';
  79.         }
  80.         return 'desc';
  81.     }
  82.     private function proxySortFunction(&$target$sortField$sortDirection): bool
  83.     {
  84.         $this->currentSortingField $sortField;
  85.         $this->sortDirection $sortDirection;
  86.         return usort($target, [$this'sortFunction']);
  87.     }
  88.     /**
  89.      * @param mixed $object1 first object to compare
  90.      * @param mixed $object2 second object to compare
  91.      *
  92.      * @return int
  93.      */
  94.     private function sortFunction($object1$object2): int
  95.     {
  96.         if (!$this->propertyAccessor) {
  97.             throw new \UnexpectedValueException('You need symfony/property-access component to use this sorting function');
  98.         }
  99.         if (!$this->propertyAccessor->isReadable($object1$this->currentSortingField) || !$this->propertyAccessor->isReadable($object2$this->currentSortingField)) {
  100.             return 0;
  101.         }
  102.         try {
  103.             $fieldValue1 $this->propertyAccessor->getValue($object1$this->currentSortingField);
  104.         } catch (UnexpectedTypeException $e) {
  105.             return -$this->getSortCoefficient();
  106.         }
  107.         try {
  108.             $fieldValue2 $this->propertyAccessor->getValue($object2$this->currentSortingField);
  109.         } catch (UnexpectedTypeException $e) {
  110.             return $this->getSortCoefficient();
  111.         }
  112.         if (is_string($fieldValue1)) {
  113.             $fieldValue1 mb_strtolower($fieldValue1);
  114.         }
  115.         if (is_string($fieldValue2)) {
  116.             $fieldValue2 mb_strtolower($fieldValue2);
  117.         }
  118.         if ($fieldValue1 === $fieldValue2) {
  119.             return 0;
  120.         }
  121.         return ($fieldValue1 $fieldValue2 : -1) * $this->getSortCoefficient();
  122.     }
  123.     private function getSortCoefficient(): int
  124.     {
  125.         return $this->sortDirection === 'asc' : -1;
  126.     }
  127.     public static function getSubscribedEvents(): array
  128.     {
  129.         return [
  130.             'knp_pager.items' => ['items'1]
  131.         ];
  132.     }
  133. }