vendor/api-platform/core/src/Hydra/Serializer/PartialCollectionViewNormalizer.php line 50
<?php/** This file is part of the API Platform project.** (c) Kévin Dunglas <dunglas@gmail.com>** For the full copyright and license information, please view the LICENSE* file that was distributed with this source code.*/declare(strict_types=1);namespace ApiPlatform\Hydra\Serializer;use ApiPlatform\Core\Metadata\Resource\Factory\ResourceMetadataFactoryInterface;use ApiPlatform\Metadata\Resource\Factory\ResourceMetadataCollectionFactoryInterface;use ApiPlatform\State\Pagination\PaginatorInterface;use ApiPlatform\State\Pagination\PartialPaginatorInterface;use ApiPlatform\Util\IriHelper;use Symfony\Component\PropertyAccess\PropertyAccess;use Symfony\Component\PropertyAccess\PropertyAccessorInterface;use Symfony\Component\Serializer\Exception\UnexpectedValueException;use Symfony\Component\Serializer\Normalizer\CacheableSupportsMethodInterface;use Symfony\Component\Serializer\Normalizer\NormalizerAwareInterface;use Symfony\Component\Serializer\Normalizer\NormalizerInterface;/*** Adds a view key to the result of a paginated Hydra collection.** @author Kévin Dunglas <dunglas@gmail.com>* @author Samuel ROZE <samuel.roze@gmail.com>*/final class PartialCollectionViewNormalizer implements NormalizerInterface, NormalizerAwareInterface, CacheableSupportsMethodInterface{private $collectionNormalizer;private $pageParameterName;private $enabledParameterName;private $resourceMetadataFactory;private $propertyAccessor;public function __construct(NormalizerInterface $collectionNormalizer, string $pageParameterName = 'page', string $enabledParameterName = 'pagination', $resourceMetadataFactory = null, PropertyAccessorInterface $propertyAccessor = null){$this->collectionNormalizer = $collectionNormalizer;$this->pageParameterName = $pageParameterName;$this->enabledParameterName = $enabledParameterName;$this->resourceMetadataFactory = $resourceMetadataFactory;if (!$resourceMetadataFactory instanceof ResourceMetadataCollectionFactoryInterface) {trigger_deprecation('api-platform/core', '2.7', sprintf('Use "%s" instead of "%s".', ResourceMetadataCollectionFactoryInterface::class, ResourceMetadataFactoryInterface::class));}$this->propertyAccessor = $propertyAccessor ?? PropertyAccess::createPropertyAccessor();}/*** {@inheritdoc}** @return array|string|int|float|bool|\ArrayObject|null*/public function normalize($object, $format = null, array $context = []){$data = $this->collectionNormalizer->normalize($object, $format, $context);if (!\is_array($data)) {throw new UnexpectedValueException('Expected data to be an array');}if (isset($context['api_sub_level'])) {return $data;}$currentPage = $lastPage = $itemsPerPage = $pageTotalItems = null;if ($paginated = ($object instanceof PartialPaginatorInterface)) {if ($object instanceof PaginatorInterface) {$paginated = 1. !== $lastPage = $object->getLastPage();} else {$itemsPerPage = $object->getItemsPerPage();$pageTotalItems = (float) \count($object);}$currentPage = $object->getCurrentPage();}$parsed = IriHelper::parseIri($context['request_uri'] ?? '/', $this->pageParameterName);$appliedFilters = $parsed['parameters'];unset($appliedFilters[$this->enabledParameterName]);if (!$appliedFilters && !$paginated) {return $data;}$isPaginatedWithCursor = false;$cursorPaginationAttribute = null;if ($this->resourceMetadataFactory instanceof ResourceMetadataFactoryInterface && isset($context['resource_class']) && $paginated) {$metadata = $this->resourceMetadataFactory->create($context['resource_class']);$isPaginatedWithCursor = null !== $cursorPaginationAttribute = $metadata->getCollectionOperationAttribute($context['collection_operation_name'] ?? $context['subresource_operation_name'], 'pagination_via_cursor', null, true);} elseif ($this->resourceMetadataFactory instanceof ResourceMetadataCollectionFactoryInterface && isset($context['resource_class']) && $paginated) {$operation = $this->resourceMetadataFactory->create($context['resource_class'])->getOperation($context['operation_name'] ?? null);$isPaginatedWithCursor = [] !== $cursorPaginationAttribute = ($operation->getPaginationViaCursor() ?? []);}$data['hydra:view'] = ['@id' => null, '@type' => 'hydra:PartialCollectionView'];if ($isPaginatedWithCursor) {return $this->populateDataWithCursorBasedPagination($data, $parsed, $object, $cursorPaginationAttribute);}$data['hydra:view']['@id'] = IriHelper::createIri($parsed['parts'], $parsed['parameters'], $this->pageParameterName, $paginated ? $currentPage : null);if ($paginated) {return $this->populateDataWithPagination($data, $parsed, $currentPage, $lastPage, $itemsPerPage, $pageTotalItems);}return $data;}/*** {@inheritdoc}*/public function supportsNormalization($data, $format = null, array $context = []): bool{return $this->collectionNormalizer->supportsNormalization($data, $format, $context);}/*** {@inheritdoc}*/public function hasCacheableSupportsMethod(): bool{return $this->collectionNormalizer instanceof CacheableSupportsMethodInterface && $this->collectionNormalizer->hasCacheableSupportsMethod();}/*** {@inheritdoc}*/public function setNormalizer(NormalizerInterface $normalizer){if ($this->collectionNormalizer instanceof NormalizerAwareInterface) {$this->collectionNormalizer->setNormalizer($normalizer);}}private function cursorPaginationFields(array $fields, int $direction, $object){$paginationFilters = [];foreach ($fields as $field) {$forwardRangeOperator = 'desc' === strtolower($field['direction']) ? 'lt' : 'gt';$backwardRangeOperator = 'gt' === $forwardRangeOperator ? 'lt' : 'gt';$operator = $direction > 0 ? $forwardRangeOperator : $backwardRangeOperator;$paginationFilters[$field['field']] = [$operator => (string) $this->propertyAccessor->getValue($object, $field['field']),];}return $paginationFilters;}private function populateDataWithCursorBasedPagination(array $data, array $parsed, \Traversable $object, $cursorPaginationAttribute): array{$objects = iterator_to_array($object);$firstObject = current($objects);$lastObject = end($objects);$data['hydra:view']['@id'] = IriHelper::createIri($parsed['parts'], $parsed['parameters']);if (false !== $lastObject && \is_array($cursorPaginationAttribute)) {$data['hydra:view']['hydra:next'] = IriHelper::createIri($parsed['parts'], array_merge($parsed['parameters'], $this->cursorPaginationFields($cursorPaginationAttribute, 1, $lastObject)));}if (false !== $firstObject && \is_array($cursorPaginationAttribute)) {$data['hydra:view']['hydra:previous'] = IriHelper::createIri($parsed['parts'], array_merge($parsed['parameters'], $this->cursorPaginationFields($cursorPaginationAttribute, -1, $firstObject)));}return $data;}private function populateDataWithPagination(array $data, array $parsed, ?float $currentPage, ?float $lastPage, ?float $itemsPerPage, ?float $pageTotalItems): array{if (null !== $lastPage) {$data['hydra:view']['hydra:first'] = IriHelper::createIri($parsed['parts'], $parsed['parameters'], $this->pageParameterName, 1.);$data['hydra:view']['hydra:last'] = IriHelper::createIri($parsed['parts'], $parsed['parameters'], $this->pageParameterName, $lastPage);}if (1. !== $currentPage) {$data['hydra:view']['hydra:previous'] = IriHelper::createIri($parsed['parts'], $parsed['parameters'], $this->pageParameterName, $currentPage - 1.);}if ((null !== $lastPage && $currentPage < $lastPage) || (null === $lastPage && $pageTotalItems >= $itemsPerPage)) {$data['hydra:view']['hydra:next'] = IriHelper::createIri($parsed['parts'], $parsed['parameters'], $this->pageParameterName, $currentPage + 1.);}return $data;}}class_alias(PartialCollectionViewNormalizer::class, \ApiPlatform\Core\Hydra\Serializer\PartialCollectionViewNormalizer::class);