|
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