Happyr / SerializerBundle

An easy serializer bundle built on top of Symfony Serializer compnent
21 stars 0 forks source link

Doesn't handle Doctrine Proxy objects #2

Open ostrolucky opened 6 years ago

ostrolucky commented 6 years ago

When mapping doctrine entities, calls such as these

https://github.com/Happyr/SerializerBundle/blob/3231c3631a103dfa207f5478ed8fd42fbcb58b8e/Normalizer/MetadataAwareNormalizer.php#L182 https://github.com/Happyr/SerializerBundle/blob/3231c3631a103dfa207f5478ed8fd42fbcb58b8e/Normalizer/MetadataAwareNormalizer.php#L198

return false, because if metadata contains App\Entity\Country\Country and input is Proxies\__CG__\App\Entity\Country\Country, it won't find that.

But here is the second problem. Even if these returns true, ReflectionPropertyAccess doesn't know how to extract these properties, it will fail on https://github.com/Happyr/SerializerBundle/blob/3231c3631a103dfa207f5478ed8fd42fbcb58b8e/PropertyManager/ReflectionPropertyAccess.php#L46

I suggest to better utilize Symfony code. There is no need to use own Group annotation instead of symfony one. There is also no need to use ReflectionPropertyAccess instead of Symfony's PropertyAccessor. Also use \Doctrine\Common\Util\ClassUtils::getClass if available.

Current workaround is to put Symfony's own Group annotation along the Happyr annotation:

    /**
     * @Happyr\SerializerBundle\Annotation\Expose
     * @Happyr\SerializerBundle\Annotation\Groups("api_output")
     * @Symfony\Component\Serializer\Annotation\Groups("api_output")
     */
    private $name;

This works because Serializer will use next normalizer in line when MetadataAwareNormalizer denies the object.

I was hopeful I could get rid of JMS serializer, but apparently not yet :(

ostrolucky commented 6 years ago

Here is second workaround:

class DoctrineProxyNormalizer implements NormalizerInterface, NormalizerAwareInterface
{
    use NormalizerAwareTrait;

    private $entityManager;

    public function __construct(EntityManagerInterface $entityManager)
    {
        $this->entityManager = $entityManager;
    }
    public function normalize($object, $format = null, array $context = array())
    {
        $this->entityManager->initializeObject($object);

        return $this->normalizer->normalize($object, $format, $context);
    }

    public function supportsNormalization($data, $format = null)
    {
        return $data instanceof Proxy && $data->__getInitializer() !== null;
    }
}
DoctrineProxyNormalizer:
    calls:
        - ['setNormalizer', ['@happyr.serializer.normalizer.metadata_aware']]
    tags:
        - { name: serializer.normalizer }

plus override supportsNormalization and getMetadata of MetadataAwareNormalizer

So you get rid of duplicate annotations. However, you will need to make all properties protected instead of private, due to said limitations of ReflectionPropertyAccess