vendor/api-platform/core/src/GraphQl/Serializer/ItemNormalizer.php line 66

  1. <?php
  2. /*
  3.  * This file is part of the API Platform project.
  4.  *
  5.  * (c) Kévin Dunglas <dunglas@gmail.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. declare(strict_types=1);
  11. namespace ApiPlatform\GraphQl\Serializer;
  12. use ApiPlatform\Api\IdentifiersExtractorInterface;
  13. use ApiPlatform\Api\IriConverterInterface;
  14. use ApiPlatform\Api\ResourceClassResolverInterface;
  15. use ApiPlatform\Metadata\ApiProperty;
  16. use ApiPlatform\Metadata\Property\Factory\PropertyMetadataFactoryInterface;
  17. use ApiPlatform\Metadata\Property\Factory\PropertyNameCollectionFactoryInterface;
  18. use ApiPlatform\Metadata\Resource\Factory\ResourceMetadataCollectionFactoryInterface;
  19. use ApiPlatform\Metadata\Util\ClassInfoTrait;
  20. use ApiPlatform\Serializer\ItemNormalizer as BaseItemNormalizer;
  21. use ApiPlatform\Symfony\Security\ResourceAccessCheckerInterface;
  22. use Psr\Log\LoggerInterface;
  23. use Psr\Log\NullLogger;
  24. use Symfony\Component\PropertyAccess\PropertyAccessorInterface;
  25. use Symfony\Component\Serializer\Exception\UnexpectedValueException;
  26. use Symfony\Component\Serializer\Mapping\Factory\ClassMetadataFactoryInterface;
  27. use Symfony\Component\Serializer\NameConverter\NameConverterInterface;
  28. /**
  29.  * GraphQL normalizer.
  30.  *
  31.  * @author Kévin Dunglas <dunglas@gmail.com>
  32.  */
  33. final class ItemNormalizer extends BaseItemNormalizer
  34. {
  35.     use ClassInfoTrait;
  36.     public const FORMAT 'graphql';
  37.     public const ITEM_RESOURCE_CLASS_KEY '#itemResourceClass';
  38.     public const ITEM_IDENTIFIERS_KEY '#itemIdentifiers';
  39.     public function __construct(PropertyNameCollectionFactoryInterface $propertyNameCollectionFactoryPropertyMetadataFactoryInterface $propertyMetadataFactoryIriConverterInterface $iriConverter, private readonly IdentifiersExtractorInterface $identifiersExtractorResourceClassResolverInterface $resourceClassResolverPropertyAccessorInterface $propertyAccessor nullNameConverterInterface $nameConverter nullClassMetadataFactoryInterface $classMetadataFactory nullLoggerInterface $logger nullResourceMetadataCollectionFactoryInterface $resourceMetadataCollectionFactory nullResourceAccessCheckerInterface $resourceAccessChecker null)
  40.     {
  41.         parent::__construct($propertyNameCollectionFactory$propertyMetadataFactory$iriConverter$resourceClassResolver$propertyAccessor$nameConverter$classMetadataFactory$logger ?: new NullLogger(), $resourceMetadataCollectionFactory$resourceAccessChecker);
  42.     }
  43.     /**
  44.      * {@inheritdoc}
  45.      */
  46.     public function supportsNormalization(mixed $datastring $format null, array $context = []): bool
  47.     {
  48.         return self::FORMAT === $format && parent::supportsNormalization($data$format$context);
  49.     }
  50.     /**
  51.      * {@inheritdoc}
  52.      *
  53.      * @param array<string, mixed> $context
  54.      *
  55.      * @throws UnexpectedValueException
  56.      */
  57.     public function normalize(mixed $objectstring $format null, array $context = []): array|string|int|float|bool|\ArrayObject|null
  58.     {
  59.         $resourceClass $this->getObjectClass($object);
  60.         if ($this->getOutputClass($context)) {
  61.             $context['graphql_identifiers'] = [
  62.                 self::ITEM_RESOURCE_CLASS_KEY => $context['operation']->getClass(),
  63.                 self::ITEM_IDENTIFIERS_KEY => $this->identifiersExtractor->getIdentifiersFromItem($object$context['operation'] ?? null),
  64.             ];
  65.             return parent::normalize($object$format$context);
  66.         }
  67.         unset($context['operation_name'], $context['operation']);
  68.         $data parent::normalize($object$format$context);
  69.         if (!\is_array($data)) {
  70.             throw new UnexpectedValueException('Expected data to be an array.');
  71.         }
  72.         if (isset($context['graphql_identifiers'])) {
  73.             $data += $context['graphql_identifiers'];
  74.         } elseif (!($context['no_resolver_data'] ?? false)) {
  75.             $data[self::ITEM_RESOURCE_CLASS_KEY] = $resourceClass;
  76.             $data[self::ITEM_IDENTIFIERS_KEY] = $this->identifiersExtractor->getIdentifiersFromItem($object$context['operation'] ?? null);
  77.         }
  78.         return $data;
  79.     }
  80.     /**
  81.      * {@inheritdoc}
  82.      */
  83.     protected function normalizeCollectionOfRelations(ApiProperty $propertyMetadataiterable $attributeValuestring $resourceClass, ?string $format, array $context): array
  84.     {
  85.         // to-many are handled directly by the GraphQL resolver
  86.         return [];
  87.     }
  88.     /**
  89.      * {@inheritdoc}
  90.      */
  91.     public function supportsDenormalization(mixed $datastring $typestring $format null, array $context = []): bool
  92.     {
  93.         return self::FORMAT === $format && parent::supportsDenormalization($data$type$format$context);
  94.     }
  95.     /**
  96.      * {@inheritdoc}
  97.      */
  98.     protected function getAllowedAttributes(string|object $classOrObject, array $contextbool $attributesAsString false): array|bool
  99.     {
  100.         $allowedAttributes parent::getAllowedAttributes($classOrObject$context$attributesAsString);
  101.         if (($context['api_denormalize'] ?? false) && \is_array($allowedAttributes) && false !== ($indexId array_search('id'$allowedAttributestrue))) {
  102.             $allowedAttributes[] = '_id';
  103.             array_splice($allowedAttributes, (int) $indexId1);
  104.         }
  105.         return $allowedAttributes;
  106.     }
  107.     /**
  108.      * {@inheritdoc}
  109.      */
  110.     protected function setAttributeValue($object$attribute$value$format null, array $context = []): void
  111.     {
  112.         if ('_id' === $attribute) {
  113.             $attribute 'id';
  114.         }
  115.         parent::setAttributeValue($object$attribute$value$format$context);
  116.     }
  117. }