* * 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\JsonApi\Serializer; use ApiPlatform\Metadata\IriConverterInterface; use ApiPlatform\Metadata\Resource\Factory\ResourceMetadataCollectionFactoryInterface; use ApiPlatform\Metadata\ResourceClassResolverInterface; use ApiPlatform\Metadata\Util\ClassInfoTrait; use Symfony\Component\Serializer\Normalizer\NormalizerInterface; /** * Decorates the output with JSON API metadata when appropriate, but otherwise * just passes through to the decorated normalizer. */ final class ObjectNormalizer implements NormalizerInterface { use ClassInfoTrait; public const FORMAT = 'jsonapi'; public function __construct(private readonly NormalizerInterface $decorated, private readonly IriConverterInterface $iriConverter, private readonly ResourceClassResolverInterface $resourceClassResolver, private readonly ResourceMetadataCollectionFactoryInterface $resourceMetadataFactory) { } /** * {@inheritdoc} */ public function supportsNormalization(mixed $data, ?string $format = null, array $context = []): bool { return self::FORMAT === $format && $this->decorated->supportsNormalization($data, $format, $context); } /** * {@inheritdoc} */ public function getSupportedTypes(?string $format): array { return self::FORMAT === $format ? $this->decorated->getSupportedTypes($format) : []; } /** * {@inheritdoc} */ public function normalize(mixed $data, ?string $format = null, array $context = []): array|string|int|float|bool|\ArrayObject|null { if (isset($context['api_resource'])) { $originalResource = $context['api_resource']; unset($context['api_resource']); } $normalizedData = $this->decorated->normalize($data, $format, $context); if (!\is_array($normalizedData) || isset($context['api_attribute'])) { return $normalizedData; } if (isset($originalResource)) { $resourceClass = $this->resourceClassResolver->getResourceClass($originalResource); $resourceData = [ 'id' => $this->iriConverter->getIriFromResource($originalResource), 'type' => $this->resourceMetadataFactory->create($resourceClass)->getOperation()->getShortName(), ]; } else { $resourceData = [ 'id' => $this->iriConverter->getIriFromResource($data), 'type' => (new \ReflectionClass($this->getObjectClass($data)))->getShortName(), ]; } if ($normalizedData) { $resourceData['attributes'] = $normalizedData; } return ['data' => $resourceData]; } }