Skip to content

Instantly share code, notes, and snippets.

@angelov
Last active May 31, 2023 16:46
Show Gist options
  • Save angelov/9f0beae2c415771931ab9221212a1b5f to your computer and use it in GitHub Desktop.
Save angelov/9f0beae2c415771931ab9221212a1b5f to your computer and use it in GitHub Desktop.
<?php declare(strict_types=1);
use PropertyValueResolvers\PropertyValueResolverInterface;
use Symfony\Component\DependencyInjection\Attribute\TaggedIterator;
use Symfony\Component\Serializer\Normalizer\DenormalizerInterface;
use Symfony\Component\Serializer\Normalizer\ObjectNormalizer;
class PropertyValueResolvingDenormalizer implements DenormalizerInterface
{
/** @var array<class-string, object<PropertyValueResolverInterface>> */
private array $resolvers = [];
private ObjectNormalizer $objectNormalizer;
/** @param iterable<PropertyValueResolverInterface> $resolvers */
public function __construct(
#[TaggedIterator(PropertyValueResolverInterface::class)] iterable $resolvers,
ObjectNormalizer $objectNormalizer
){
foreach ($resolvers as $resolver) {
$this->resolvers[$resolver->supportedAttribute()] = $resolver;
}
$this->objectNormalizer = $objectNormalizer;
}
public function denormalize(mixed $data, string $type, string $format = null, array $context = []): mixed
{
$properties = (new ReflectionClass($type))->getProperties();
foreach ($properties as $property) {
$name = $property->getName();
if (!$this->canResolveValueForProperty($property)) {
continue;
}
$data[$name] = $this->resolveValueForProperty($property);
}
return $this->objectNormalizer->denormalize($data, $type, $format, $context);
}
private function resolveValueForProperty(ReflectionProperty $property): mixed
{
$attributes = $property->getAttributes();
foreach ($attributes as $attribute) {
if (array_key_exists($attribute->getName(), $this->resolvers)) {
return $this->resolvers[$attribute->getName()]->resolve($attribute);
}
}
return null;
}
public function supportsDenormalization(mixed $data, string $type, string $format = null): bool
{
$properties = (new ReflectionClass($type))->getProperties();
foreach ($properties as $property) {
if ($this->canResolveValueForProperty($property)) {
return true;
}
}
return false;
}
private function canResolveValueForProperty(ReflectionProperty $property): bool
{
$attributes = $property->getAttributes();
foreach ($attributes as $attribute) {
if (array_key_exists($attribute->getName(), $this->resolvers)) {
return true;
}
}
return false;
}
/** @return array<class-string, bool> */
public function getSupportedTypes(?string $format): array
{
return ['object' => true];
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment