vendor/friendsofsymfony/elastica-bundle/src/Subscriber/PaginateElasticaQuerySubscriber.php line 33

Open in your IDE?
  1. <?php
  2. /*
  3. * This file is part of the FOSElasticaBundle package.
  4. *
  5. * (c) FriendsOfSymfony <https://friendsofsymfony.github.com/>
  6. *
  7. * For the full copyright and license information, please view the LICENSE
  8. * file that was distributed with this source code.
  9. */
  10. namespace FOS\ElasticaBundle\Subscriber;
  11. use FOS\ElasticaBundle\Paginator\PaginatorAdapterInterface;
  12. use FOS\ElasticaBundle\Paginator\PartialResultsInterface;
  13. use Knp\Component\Pager\Event\ItemsEvent;
  14. use Symfony\Component\EventDispatcher\EventSubscriberInterface;
  15. use Symfony\Component\HttpFoundation\Request;
  16. use Symfony\Component\HttpFoundation\RequestStack;
  17. class PaginateElasticaQuerySubscriber implements EventSubscriberInterface
  18. {
  19. private RequestStack $requestStack;
  20. public function __construct(RequestStack $requestStack)
  21. {
  22. $this->requestStack = $requestStack;
  23. }
  24. /**
  25. * @return void
  26. */
  27. public function items(ItemsEvent $event)
  28. {
  29. if ($event->target instanceof PaginatorAdapterInterface) {
  30. // Add sort to query
  31. $this->setSorting($event);
  32. /** @var PartialResultsInterface $results */
  33. $results = $event->target->getResults($event->getOffset(), $event->getLimit());
  34. $event->count = $results->getTotalHits();
  35. $event->items = $results->toArray();
  36. $aggregations = $results->getAggregations();
  37. if (null != $aggregations) {
  38. $event->setCustomPaginationParameter('aggregations', $aggregations);
  39. }
  40. $event->stopPropagation();
  41. }
  42. }
  43. public static function getSubscribedEvents(): array
  44. {
  45. return [
  46. 'knp_pager.items' => ['items', 1],
  47. ];
  48. }
  49. /**
  50. * Adds knp paging sort to query.
  51. *
  52. * @return void
  53. */
  54. protected function setSorting(ItemsEvent $event)
  55. {
  56. // Bugfix for PHP 7.4 as options can be null and generate a "Trying to access array offset on value of type null" error
  57. // @phpstan-ignore-next-line
  58. $options = $event->options ?? [];
  59. $sortField = $this->getFromRequest($options['sortFieldParameterName'] ?? null);
  60. if (!$sortField && isset($options['defaultSortFieldName'])) {
  61. $sortField = $options['defaultSortFieldName'];
  62. }
  63. if (!empty($sortField)) {
  64. $event->target->getQuery()->setSort([
  65. $sortField => $this->getSort($sortField, $options),
  66. ]);
  67. }
  68. }
  69. /**
  70. * @param string $sortField
  71. * @param array<string, mixed> $options
  72. *
  73. * @return array<string, mixed>
  74. */
  75. protected function getSort($sortField, array $options = [])
  76. {
  77. $sort = [
  78. 'order' => $this->getSortDirection($sortField, $options),
  79. ];
  80. if (isset($options['sortNestedPath'])) {
  81. $path = \is_callable($options['sortNestedPath']) ?
  82. $options['sortNestedPath']($sortField) : $options['sortNestedPath'];
  83. if (!empty($path)) {
  84. $sort['nested_path'] = $path;
  85. }
  86. }
  87. if (isset($options['sortNestedFilter'])) {
  88. $filter = \is_callable($options['sortNestedFilter']) ?
  89. $options['sortNestedFilter']($sortField) : $options['sortNestedFilter'];
  90. if (!empty($filter)) {
  91. $sort['nested_filter'] = $filter;
  92. }
  93. }
  94. return $sort;
  95. }
  96. /**
  97. * @param string $sortField
  98. * @param array<string, mixed> $options
  99. *
  100. * @return string
  101. */
  102. protected function getSortDirection($sortField, array $options = [])
  103. {
  104. $dir = 'asc';
  105. $sortDirection = $this->getFromRequest($options['sortDirectionParameterName']);
  106. if (empty($sortDirection) && isset($options['defaultSortDirection'])) {
  107. $sortDirection = $options['defaultSortDirection'];
  108. }
  109. if (null !== $sortDirection && 'desc' === \strtolower($sortDirection)) {
  110. $dir = 'desc';
  111. }
  112. // check if the requested sort field is in the sort whitelist
  113. if (isset($options['sortFieldAllowList']) && !\in_array($sortField, $options['sortFieldAllowList'], true)) {
  114. throw new \UnexpectedValueException(\sprintf('Cannot sort by: [%s] this field is not in whitelist', $sortField));
  115. }
  116. return $dir;
  117. }
  118. private function getRequest(): ?Request
  119. {
  120. return $this->requestStack->getCurrentRequest();
  121. }
  122. /**
  123. * @return mixed|null
  124. */
  125. private function getFromRequest(?string $key)
  126. {
  127. if (null !== $key && null !== $request = $this->getRequest()) {
  128. return $request->get($key);
  129. }
  130. return null;
  131. }
  132. }