|
20 | 20 | use ApiPlatform\Exception\ItemNotFoundException; |
21 | 21 | use ApiPlatform\Metadata\ApiProperty; |
22 | 22 | use ApiPlatform\Metadata\CollectionOperationInterface; |
23 | | -use ApiPlatform\Metadata\Exception\OperationNotFoundException; |
24 | 23 | use ApiPlatform\Metadata\Property\Factory\PropertyMetadataFactoryInterface; |
25 | 24 | use ApiPlatform\Metadata\Property\Factory\PropertyNameCollectionFactoryInterface; |
26 | 25 | use ApiPlatform\Metadata\Resource\Factory\ResourceMetadataCollectionFactoryInterface; |
@@ -56,6 +55,7 @@ abstract class AbstractItemNormalizer extends AbstractObjectNormalizer |
56 | 55 | use CloneTrait; |
57 | 56 | use ContextTrait; |
58 | 57 | use InputOutputMetadataTrait; |
| 58 | + use OperationContextTrait; |
59 | 59 |
|
60 | 60 | protected PropertyAccessorInterface $propertyAccessor; |
61 | 61 | protected array $localCache = []; |
@@ -134,6 +134,8 @@ public function normalize(mixed $object, string $format = null, array $context = |
134 | 134 | return $this->serializer->normalize($object, $format, $context); |
135 | 135 | } |
136 | 136 |
|
| 137 | + // Never remove this, with `application/json` we don't use our AbstractCollectionNormalizer and we need |
| 138 | + // to remove the collection operation from our context or we'll introduce security issues |
137 | 139 | if (isset($context['operation']) && $context['operation'] instanceof CollectionOperationInterface) { |
138 | 140 | unset($context['operation_name']); |
139 | 141 | unset($context['operation']); |
@@ -586,14 +588,7 @@ protected function getFactoryOptions(array $context): array |
586 | 588 | // This is a hot spot |
587 | 589 | if (isset($context['resource_class'])) { |
588 | 590 | // Note that the groups need to be read on the root operation |
589 | | - $operation = $context['root_operation'] ?? $context['operation'] ?? null; |
590 | | - |
591 | | - if (!$operation && $this->resourceMetadataCollectionFactory && $this->resourceClassResolver->isResourceClass($context['resource_class'])) { |
592 | | - $resourceClass = $this->resourceClassResolver->getResourceClass(null, $context['resource_class']); // fix for abstract classes and interfaces |
593 | | - $operation = $this->resourceMetadataCollectionFactory->create($resourceClass)->getOperation($context['root_operation_name'] ?? $context['operation_name'] ?? null); |
594 | | - } |
595 | | - |
596 | | - if ($operation) { |
| 591 | + if ($operation = ($context['root_operation'] ?? null)) { |
597 | 592 | $options['normalization_groups'] = $operation->getNormalizationContext()['groups'] ?? null; |
598 | 593 | $options['denormalization_groups'] = $operation->getDenormalizationContext()['groups'] ?? null; |
599 | 594 | $options['operation_name'] = $operation->getName(); |
@@ -716,8 +711,7 @@ protected function normalizeRelation(ApiProperty $propertyMetadata, ?object $rel |
716 | 711 | throw new LogicException(sprintf('The injected serializer must be an instance of "%s".', NormalizerInterface::class)); |
717 | 712 | } |
718 | 713 |
|
719 | | - $relatedContext = $context; |
720 | | - unset($relatedContext['force_resource_class']); |
| 714 | + $relatedContext = $this->createOperationContext($context, $resourceClass); |
721 | 715 | $normalizedRelatedObject = $this->serializer->normalize($relatedObject, $format, $relatedContext); |
722 | 716 | if (!\is_string($normalizedRelatedObject) && !\is_array($normalizedRelatedObject) && !$normalizedRelatedObject instanceof \ArrayObject && null !== $normalizedRelatedObject) { |
723 | 717 | throw new UnexpectedValueException('Expected normalized relation to be an IRI, array, \ArrayObject or null'); |
@@ -883,29 +877,4 @@ private function setValue(object $object, string $attributeName, mixed $value): |
883 | 877 | // Properties not found are ignored |
884 | 878 | } |
885 | 879 | } |
886 | | - |
887 | | - private function createOperationContext(array $context, string $resourceClass = null): array |
888 | | - { |
889 | | - if (isset($context['operation']) && !isset($context['root_operation'])) { |
890 | | - $context['root_operation'] = $context['operation']; |
891 | | - $context['root_operation_name'] = $context['operation_name']; |
892 | | - } |
893 | | - |
894 | | - unset($context['iri'], $context['uri_variables']); |
895 | | - if (!$resourceClass) { |
896 | | - return $context; |
897 | | - } |
898 | | - |
899 | | - unset($context['operation'], $context['operation_name']); |
900 | | - $context['resource_class'] = $resourceClass; |
901 | | - if ($this->resourceMetadataCollectionFactory) { |
902 | | - try { |
903 | | - $context['operation'] = $this->resourceMetadataCollectionFactory->create($resourceClass)->getOperation(); |
904 | | - $context['operation_name'] = $context['operation']->getName(); |
905 | | - } catch (OperationNotFoundException) { |
906 | | - } |
907 | | - } |
908 | | - |
909 | | - return $context; |
910 | | - } |
911 | 880 | } |
0 commit comments