diff --git a/docs/source/development/api.rst b/docs/source/development/api.rst index ea807e090..a5fef2372 100644 --- a/docs/source/development/api.rst +++ b/docs/source/development/api.rst @@ -537,6 +537,121 @@ Curl requests: "type": "scope" }' +Deserializing an association where multiple types are allowed +============================================================= + +Sometimes, multiples types are allowed as association to one entity: + +.. code-block:: php + + namespace Chill\PersonBundle\Entity\AccompanyingPeriod; + + use Chill\PersonBundle\Entity\Person; + use Chill\ThirdPartyBundle\Entity\ThirdParty; + use Doctrine\ORM\Mapping as ORM; + + class Resource + { + + + /** + * @ORM\ManyToOne(targetEntity=ThirdParty::class) + * @ORM\JoinColumn(nullable=true) + */ + private $thirdParty; + + /** + * @ORM\ManyToOne(targetEntity=Person::class) + * @ORM\JoinColumn(nullable=true) + */ + private $person; + + + /** + * + * @param $resource Person|ThirdParty + */ + public function setResource($resource): self + { + // ... + } + + + /** + * @return ThirdParty|Person + * @Groups({"read", "write"}) + */ + public function getResource() + { + return $this->person ?? $this->thirdParty; + } + } + +This is not well taken into account by the Symfony serializer natively. + +You must, then, create your own CustomNormalizer. You can help yourself using this: + +.. code-block:: php + + namespace Chill\PersonBundle\Serializer\Normalizer; + + use Chill\PersonBundle\Entity\Person; + use Chill\ThirdPartyBundle\Entity\ThirdParty; + use Chill\PersonBundle\Entity\AccompanyingPeriod\Resource; + use Chill\PersonBundle\Repository\AccompanyingPeriod\ResourceRepository; + use Symfony\Component\Serializer\Normalizer\DenormalizerInterface; + use Symfony\Component\Serializer\Normalizer\DenormalizerAwareInterface; + use Symfony\Component\Serializer\Normalizer\DenormalizerAwareTrait; + use Symfony\Component\Serializer\Normalizer\ObjectToPopulateTrait; + use Symfony\Component\Serializer\Exception; + use Chill\MainBundle\Serializer\Normalizer\DiscriminatedObjectDenormalizer; + + + class AccompanyingPeriodResourceNormalizer implements DenormalizerInterface, DenormalizerAwareInterface + { + use DenormalizerAwareTrait; + use ObjectToPopulateTrait; + + public function __construct(ResourceRepository $repository) + { + $this->repository = $repository; + } + + public function denormalize($data, string $type, string $format = null, array $context = []) + { + // .. snipped for brevity + + if ($resource === NULL) { + $resource = new Resource(); + } + + if (\array_key_exists('resource', $data)) { + $res = $this->denormalizer->denormalize( + $data['resource'], + // call for a "multiple type" + DiscriminatedObjectDenormalizer::TYPE, + $format, + // into the context, we add the list of allowed types: + [ + DiscriminatedObjectDenormalizer::ALLOWED_TYPES => + [ + Person::class, ThirdParty::class + ] + ] + ); + + $resource->setResource($res); + } + + return $resource; + } + + + public function supportsDenormalization($data, string $type, string $format = null) + { + return $type === Resource::class; + } + } Serialization for collection **************************** @@ -578,6 +693,7 @@ In custom actions, this can be achieved quickly by assembling results into a :co } } + .. _api_full_configuration: Full configuration example