add a discrimnator type on onbjects

This commit is contained in:
Julien Fastré 2021-05-12 17:51:37 +02:00
parent f7a807473d
commit 91e4d585ff
17 changed files with 236 additions and 109 deletions

View File

@ -49,7 +49,12 @@ Ensure that those lines are present in your file `app/config/routing.yml`:
Create your model Create your model
***************** *****************
Create your model on the usual way: Create your model on the usual way.
If you do not use a `custom normalizer <https://symfony.com/doc/current/serializer/custom_normalizer.html>`_, you must add `annotations to create serialization groups <https://symfony.com/doc/current/components/serializer.html#attributes-groups>`_. Those groups are, by defaults:
* :code:`read` for GET requests;
* :code:`write` for POST, PUT and PATCH requests
.. code-block:: php .. code-block:: php
@ -57,6 +62,7 @@ Create your model on the usual way:
use Chill\PersonBundle\Entity\AccompanyingPeriod\OriginRepository; use Chill\PersonBundle\Entity\AccompanyingPeriod\OriginRepository;
use Doctrine\ORM\Mapping as ORM; use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Serializer\Annotation\Groups;
/** /**
* @ORM\Entity(repositoryClass=OriginRepository::class) * @ORM\Entity(repositoryClass=OriginRepository::class)
@ -68,16 +74,19 @@ Create your model on the usual way:
* @ORM\Id * @ORM\Id
* @ORM\GeneratedValue * @ORM\GeneratedValue
* @ORM\Column(type="integer") * @ORM\Column(type="integer")
* @Groups({"read"})
*/ */
private $id; private $id;
/** /**
* @ORM\Column(type="json") * @ORM\Column(type="json")
* @Groups({"read", "write"})
*/ */
private $label; private $label;
/** /**
* @ORM\Column(type="date_immutable", nullable=true) * @ORM\Column(type="date_immutable", nullable=true)
* @Groups({"read", "write"})
*/ */
private $noActiveAfter; private $noActiveAfter;
@ -215,6 +224,48 @@ You can also define a role for each method. In this case, this role is used for
GET: MY_ROLE_SEE GET: MY_ROLE_SEE
HEAD: MY ROLE_SEE HEAD: MY ROLE_SEE
Edit an entity: PUT and PATCH requests
=======================================
By default, PUT and PATCH requests are not enabled. You may enable it into the configuration:
.. code-block:: yaml
# config/packages/chill_main.yaml
chill_main:
apis:
accompanying_period_origin:
base_path: '/api/1.0/person/bla/bla'
class: 'Chill\PersonBundle\Entity\Blah'
name: bla
actions:
_entity:
methods:
GET: true
HEAD: true
PUT: true
PATCH: true
roles:
GET: MY_ROLE_SEE
HEAD: MY ROLE_SEE
HEAD: MY ROLE_UPDATE
HEAD: MY ROLE_UPDATE
.. note::
PUT and PATCH requests are handled on a similar way. You may use both without difference, although updating a whole object should use a PUT request, and updating part of the object should use a PATCH request.
Those two requests allow natively to update all attributes which are present in :code:`write` group, and relation which are connected in ManyToOne relation (the entity under :code:`class` config must be associated with one entity).
The api will be able to load the associated entity with a simple given :code:`id` and :code:`type`, if
* if the class is an entity, managed by Doctrine;
* if a discriminator map is present;
* if the given data has two keys: the "discriminator map" (:code:`type`) and the id. Example: :code:`{ "type": "person", "id": 2205 }`;
* if the :code:`setter` is type-hinted.
Customize the controller Customize the controller
======================== ========================

View File

@ -7,6 +7,7 @@ use Doctrine\Common\Collections\Collection;
use Doctrine\Common\Collections\ArrayCollection; use Doctrine\Common\Collections\ArrayCollection;
use Symfony\Component\Security\Core\User\AdvancedUserInterface; use Symfony\Component\Security\Core\User\AdvancedUserInterface;
use Symfony\Component\Validator\Context\ExecutionContextInterface; use Symfony\Component\Validator\Context\ExecutionContextInterface;
use Symfony\Component\Serializer\Annotation\DiscriminatorMap;
/** /**
* User * User
@ -14,6 +15,9 @@ use Symfony\Component\Validator\Context\ExecutionContextInterface;
* @ORM\Entity(repositoryClass="Chill\MainBundle\Repository\UserRepository") * @ORM\Entity(repositoryClass="Chill\MainBundle\Repository\UserRepository")
* @ORM\Table(name="users") * @ORM\Table(name="users")
* @ORM\Cache(usage="NONSTRICT_READ_WRITE", region="acl_cache_region") * @ORM\Cache(usage="NONSTRICT_READ_WRITE", region="acl_cache_region")
* @DiscriminatorMap(typeProperty="type", mapping={
* "user"=User::class
* })
*/ */
class User implements AdvancedUserInterface { class User implements AdvancedUserInterface {

View File

@ -6,15 +6,21 @@ use Symfony\Component\Serializer\Normalizer\DenormalizerInterface;
use Doctrine\ORM\EntityManagerInterface; use Doctrine\ORM\EntityManagerInterface;
use Symfony\Component\Serializer\Normalizer\AbstractNormalizer; use Symfony\Component\Serializer\Normalizer\AbstractNormalizer;
use Doctrine\ORM\Mapping\ClassMetadata; use Doctrine\ORM\Mapping\ClassMetadata;
use Symfony\Component\Serializer\Mapping\Factory\ClassMetadataFactoryInterface;
use Symfony\Component\Serializer\Mapping\ClassMetadataInterface as SerializerMetadata;
class DoctrineExistingEntityNormalizer implements DenormalizerInterface class DoctrineExistingEntityNormalizer implements DenormalizerInterface
{ {
private EntityManagerInterface $em; private EntityManagerInterface $em;
public function __construct(EntityManagerInterface $em) private ClassMetadataFactoryInterface $serializerMetadataFactory;
public function __construct(EntityManagerInterface $em, ClassMetadataFactoryInterface $serializerMetadataFactory)
{ {
$this->em = $em; $this->em = $em;
$this->serializerMetadataFactory = $serializerMetadataFactory;
} }
public function denormalize($data, string $type, string $format = null, array $context = []) public function denormalize($data, string $type, string $format = null, array $context = [])
@ -29,10 +35,37 @@ class DoctrineExistingEntityNormalizer implements DenormalizerInterface
public function supportsDenormalization($data, string $type, string $format = null) public function supportsDenormalization($data, string $type, string $format = null)
{ {
return \is_array($data) if (FALSE === \is_array($data)) {
&& count($data) === 1 return false;
&& \array_key_exists('id', $data) }
&& $this->em->getClassMetadata($type) instanceof ClassMetadata;
}
if (FALSE === \array_key_exists('id', $data)) {
return false;
}
if (FALSE === $this->em->getClassMetadata($type) instanceof ClassMetadata) {
return false;
}
// does have serializer metadata, and class discriminator ?
if ($this->serializerMetadataFactory->hasMetadataFor($type)) {
$classDiscriminator = $this->serializerMetadataFactory
->getMetadataFor($type)->getClassDiscriminatorMapping();
if ($classDiscriminator) {
$typeProperty = $classDiscriminator->getTypeProperty();
// check that only 2 keys
// that the second key is property
// and that the type match the class for given type property
return count($data) === 2
&& \array_key_exists($typeProperty, $data)
&& $type === $classDiscriminator->getClassForType($data[$typeProperty]);
}
}
// we do not have any class discriminator. Check that the id is the only one key
return count($data) === 1;
}
} }

View File

@ -24,7 +24,7 @@ use Symfony\Component\Serializer\Normalizer\NormalizerInterface;
/** /**
* *
* * @internal we keep this normalizer, because the property 'text' may be replace by a rendering in the future
*/ */
class UserNormalizer implements NormalizerInterface class UserNormalizer implements NormalizerInterface
{ {
@ -32,8 +32,10 @@ class UserNormalizer implements NormalizerInterface
{ {
/** @var User $user */ /** @var User $user */
return [ return [
'type' => 'user',
'id' => $user->getId(), 'id' => $user->getId(),
'username' => $user->getUsername() 'username' => $user->getUsername(),
'text' => $user->getUsername()
]; ];
} }

View File

@ -0,0 +1,51 @@
<?php
namespace Chill\MainBundle\Tests\Serializer\Normalizer;
use Symfony\Bundle\FrameworkBundle\Test\KernelTestCase;
use Chill\MainBundle\Serializer\Normalizer\DoctrineExistingEntityNormalizer;
use Doctrine\ORM\EntityManagerInterface;
use Symfony\Component\Serializer\Mapping\Factory\ClassMetadataFactoryInterface;
use Chill\MainBundle\Entity\User;
class DoctrineExistingEntityNormalizerTest extends KernelTestCase
{
protected DoctrineExistingEntityNormalizer $normalizer;
protected function setUp()
{
self::bootKernel();
$em = self::$container->get(EntityManagerInterface::class);
$serializerFactory = self::$container->get(ClassMetadataFactoryInterface::class);
$this->normalizer = new DoctrineExistingEntityNormalizer($em, $serializerFactory);
}
/**
* @dataProvider dataProviderUserId
*/
public function testGetMappedClass($userId)
{
$data = [ 'type' => 'user', 'id' => $userId];
$supports = $this->normalizer->supportsDenormalization($data, User::class);
$this->assertTrue($supports);
}
public function dataProviderUserId()
{
self::bootKernel();
$userIds = self::$container->get(EntityManagerInterface::class)
->getRepository(User::class)
->createQueryBuilder('u')
->select('u.id')
->setMaxResults(1)
->getQuery()
->getResult()
;
yield [ $userIds[0]['id'] ];
}
}

View File

@ -58,12 +58,12 @@ class AccompanyingCourseApiController extends ApiController
if ($errors->count() > 0) { if ($errors->count() > 0) {
// only format accepted // only format accepted
return $this->json($errors); return $this->json($errors, 422);
} }
$this->getDoctrine()->getManager()->flush(); $this->getDoctrine()->getManager()->flush();
return $this->json($participation); return $this->json($participation, 200, [], ['groups' => [ 'read' ]]);
} }
public function requestorApi($id, Request $request, string $_format): Response public function requestorApi($id, Request $request, string $_format): Response
@ -102,12 +102,12 @@ class AccompanyingCourseApiController extends ApiController
if ($errors->count() > 0) { if ($errors->count() > 0) {
// only format accepted // only format accepted
return $this->json($errors); return $this->json($errors, 422);
} }
$this->getDoctrine()->getManager()->flush(); $this->getDoctrine()->getManager()->flush();
return $this->json($accompanyingPeriod->getRequestor()); return $this->json($accompanyingPeriod->getRequestor(), 200, [], ['groups' => [ 'read']]);
} }
protected function onPostCheckACL(string $action, Request $request, string $_format, $entity): ?Response protected function onPostCheckACL(string $action, Request $request, string $_format, $entity): ?Response

View File

@ -34,12 +34,16 @@ use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Validator\Context\ExecutionContextInterface; use Symfony\Component\Validator\Context\ExecutionContextInterface;
use Chill\MainBundle\Entity\User; use Chill\MainBundle\Entity\User;
use Symfony\Component\Serializer\Annotation\Groups; use Symfony\Component\Serializer\Annotation\Groups;
use Symfony\Component\Serializer\Annotation\DiscriminatorMap;
/** /**
* AccompanyingPeriod Class * AccompanyingPeriod Class
* *
* @ORM\Entity(repositoryClass="Chill\PersonBundle\Repository\AccompanyingPeriodRepository") * @ORM\Entity(repositoryClass="Chill\PersonBundle\Repository\AccompanyingPeriodRepository")
* @ORM\Table(name="chill_person_accompanying_period") * @ORM\Table(name="chill_person_accompanying_period")
* @DiscriminatorMap(typeProperty="type", mapping={
* "accompanying_period"=AccompanyingPeriod::class
* })
*/ */
class AccompanyingPeriod class AccompanyingPeriod
{ {
@ -156,6 +160,7 @@ class AccompanyingPeriod
/** /**
* @var string * @var string
* @ORM\Column(type="string", length=32, nullable=true) * @ORM\Column(type="string", length=32, nullable=true)
* @Groups({"read"})
*/ */
private $step = self::STEP_DRAFT; private $step = self::STEP_DRAFT;
@ -532,7 +537,7 @@ class AccompanyingPeriod
return $this->requestorPerson; return $this->requestorPerson;
} }
public function setRequestorPerson(Person $requestorPerson = null): self private function setRequestorPerson(Person $requestorPerson = null): self
{ {
$this->requestorPerson = $requestorPerson; $this->requestorPerson = $requestorPerson;
@ -544,7 +549,7 @@ class AccompanyingPeriod
return $this->requestorThirdParty; return $this->requestorThirdParty;
} }
public function setRequestorThirdParty(ThirdParty $requestorThirdParty = null): self private function setRequestorThirdParty(ThirdParty $requestorThirdParty = null): self
{ {
$this->requestorThirdParty = $requestorThirdParty; $this->requestorThirdParty = $requestorThirdParty;
@ -567,10 +572,10 @@ class AccompanyingPeriod
* The requestor is either an instance of ThirdParty, or an * The requestor is either an instance of ThirdParty, or an
* instance of Person * instance of Person
* *
* @param $requestor Person|ThirdParty * param $requestor Person|ThirdParty
* @return self * @return self
* @throw UnexpectedValueException if the requestor is not a Person or ThirdParty * @throw UnexpectedValueException if the requestor is not a Person or ThirdParty
* * @Groups({"write"})
*/ */
public function setRequestor($requestor): self public function setRequestor($requestor): self
{ {

View File

@ -26,6 +26,8 @@ use Chill\PersonBundle\Repository\AccompanyingPeriodParticipationRepository;
use Chill\PersonBundle\Entity\AccompanyingPeriod; use Chill\PersonBundle\Entity\AccompanyingPeriod;
use Chill\PersonBundle\Entity\Person; use Chill\PersonBundle\Entity\Person;
use Doctrine\ORM\Mapping as ORM; use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Serializer\Annotation\Groups;
use Symfony\Component\Serializer\Annotation\DiscriminatorMap;
/** /**
* AccompanyingPeriodParticipation Class * AccompanyingPeriodParticipation Class
@ -33,6 +35,9 @@ use Doctrine\ORM\Mapping as ORM;
* @package Chill\PersonBundle\Entity * @package Chill\PersonBundle\Entity
* @ORM\Entity(repositoryClass=AccompanyingPeriodParticipationRepository::class) * @ORM\Entity(repositoryClass=AccompanyingPeriodParticipationRepository::class)
* @ORM\Table(name="chill_person_accompanying_period_participation") * @ORM\Table(name="chill_person_accompanying_period_participation")
* @DiscriminatorMap(typeProperty="type", mapping={
* "accompanying_period_participation"=AccompanyingPeriodParticipation::class
* })
*/ */
class AccompanyingPeriodParticipation class AccompanyingPeriodParticipation
{ {
@ -40,12 +45,14 @@ class AccompanyingPeriodParticipation
* @ORM\Id * @ORM\Id
* @ORM\GeneratedValue * @ORM\GeneratedValue
* @ORM\Column(type="integer") * @ORM\Column(type="integer")
* @Groups({"read"})
*/ */
private $id; private $id;
/** /**
* @ORM\ManyToOne(targetEntity=Person::class, inversedBy="accompanyingPeriodParticipations") * @ORM\ManyToOne(targetEntity=Person::class, inversedBy="accompanyingPeriodParticipations")
* @ORM\JoinColumn(name="person_id", referencedColumnName="id", nullable=false) * @ORM\JoinColumn(name="person_id", referencedColumnName="id", nullable=false)
* @Groups({"read"})
*/ */
private $person; private $person;
@ -57,11 +64,13 @@ class AccompanyingPeriodParticipation
/** /**
* @ORM\Column(type="date", nullable=false) * @ORM\Column(type="date", nullable=false)
* @Groups({"read"})
*/ */
private $startDate; private $startDate;
/** /**
* @ORM\Column(type="date", nullable=true) * @ORM\Column(type="date", nullable=true)
* @Groups({"read"})
*/ */
private $endDate = null; private $endDate = null;

View File

@ -34,6 +34,7 @@ use Doctrine\Common\Collections\Collection;
use Doctrine\Common\Collections\ArrayCollection; use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Criteria; use Doctrine\Common\Collections\Criteria;
use Symfony\Component\Validator\Context\ExecutionContextInterface; use Symfony\Component\Validator\Context\ExecutionContextInterface;
use Symfony\Component\Serializer\Annotation\DiscriminatorMap;
/** /**
* Person Class * Person Class
@ -45,6 +46,9 @@ use Symfony\Component\Validator\Context\ExecutionContextInterface;
* columns={"firstName", "lastName"} * columns={"firstName", "lastName"}
* )}) * )})
* @ORM\HasLifecycleCallbacks() * @ORM\HasLifecycleCallbacks()
* @DiscriminatorMap(typeProperty="type", mapping={
* "person"=Person::class
* })
*/ */
class Person implements HasCenterInterface class Person implements HasCenterInterface
{ {

View File

@ -41,6 +41,7 @@ class AccompanyingPeriodParticipationNormalizer implements NormalizerInterface,
public function supportsNormalization($data, string $format = null): bool public function supportsNormalization($data, string $format = null): bool
{ {
return false;
return $data instanceof AccompanyingPeriodParticipation; return $data instanceof AccompanyingPeriodParticipation;
} }

View File

@ -26,6 +26,7 @@ use Chill\PersonBundle\Repository\PersonRepository;
use Symfony\Component\Serializer\Exception\RuntimeException; use Symfony\Component\Serializer\Exception\RuntimeException;
use Symfony\Component\Serializer\Exception\UnexpectedValueException; use Symfony\Component\Serializer\Exception\UnexpectedValueException;
use Chill\MainBundle\Templating\Entity\ChillEntityRenderExtension; use Chill\MainBundle\Templating\Entity\ChillEntityRenderExtension;
use Symfony\Component\Serializer\Normalizer\AbstractNormalizer;
/** /**
* Serialize a Person entity * Serialize a Person entity
@ -33,21 +34,15 @@ use Chill\MainBundle\Templating\Entity\ChillEntityRenderExtension;
*/ */
class PersonNormalizer implements class PersonNormalizer implements
NormalizerInterface, NormalizerInterface,
NormalizerAwareInterface, NormalizerAwareInterface
DenormalizerInterface
{ {
protected NormalizerInterface $normalizer; protected NormalizerInterface $normalizer;
protected PersonRepository $repository;
private ChillEntityRenderExtension $render; private ChillEntityRenderExtension $render;
public const GET_PERSON = 'get_person'; public function __construct(ChillEntityRenderExtension $render)
public function __construct(PersonRepository $repository, ChillEntityRenderExtension $render)
{ {
$this->repository = $repository;
$this->render = $render; $this->render = $render;
} }
@ -56,7 +51,7 @@ class PersonNormalizer implements
/** @var Person $person */ /** @var Person $person */
return [ return [
'type' => 'person', 'type' => 'person',
'person_id' => $person->getId(), 'id' => $person->getId(),
'text' => $this->render->renderString($person), 'text' => $this->render->renderString($person),
'firstName' => $person->getFirstName(), 'firstName' => $person->getFirstName(),
'lastName' => $person->getLastName(), 'lastName' => $person->getLastName(),
@ -80,33 +75,11 @@ class PersonNormalizer implements
} }
public function denormalize($data, string $type, string $format = null, array $context = []): Person
{
if ($context[self::GET_PERSON] ?? true) {
$id = $data['person_id'] ?? null;
if (NULL === $id) {
throw new RuntimeException("missing person_id into person object");
}
}
/** var Person $person */
$person = $this->repository->findOneById($id);
if (NULL === $person) {
throw new UnexpectedValueException("person id not found");
}
return $person;
}
public function supportsNormalization($data, string $format = null): bool public function supportsNormalization($data, string $format = null): bool
{ {
return $data instanceof Person; return $data instanceof Person;
} }
public function supportsDenormalization($data, string $type, ?string $format = NULL): bool
{
return Person::class === $type;
}
public function setNormalizer(NormalizerInterface $normalizer) public function setNormalizer(NormalizerInterface $normalizer)
{ {

View File

@ -100,14 +100,14 @@ class AccompanyingCourseApiControllerTest extends WebTestCase
[], // parameters [], // parameters
[], // files [], // files
[], // server parameters [], // server parameters
\json_encode([ 'person_id' => $personId ]) \json_encode([ 'type' => 'person', 'id' => $personId ])
); );
$response = $this->client->getResponse(); $response = $this->client->getResponse();
$data = \json_decode($response->getContent(), true); $data = \json_decode($response->getContent(), true);
$this->assertEquals(200, $response->getStatusCode()); $this->assertEquals(200, $response->getStatusCode());
$this->assertArrayHasKey('person_id', $data); $this->assertArrayHasKey('id', $data);
$this->assertEquals($personId, $data['person_id']); $this->assertEquals($personId, $data['id']);
// check into database // check into database
$period = $em->getRepository(AccompanyingPeriod::class) $period = $em->getRepository(AccompanyingPeriod::class)
@ -122,14 +122,14 @@ class AccompanyingCourseApiControllerTest extends WebTestCase
[], // parameters [], // parameters
[], // files [], // files
[], // server parameters [], // server parameters
\json_encode([ 'thirdparty_id' => $thirdPartyId ]) \json_encode([ 'type' => 'thirdparty', 'id' => $thirdPartyId ])
); );
$response = $this->client->getResponse(); $response = $this->client->getResponse();
$data = \json_decode($response->getContent(), true); $data = \json_decode($response->getContent(), true);
$this->assertEquals(200, $response->getStatusCode()); $this->assertEquals(200, $response->getStatusCode());
$this->assertArrayHasKey('thirdparty_id', $data); $this->assertArrayHasKey('id', $data);
$this->assertEquals($thirdPartyId, $data['thirdparty_id']); $this->assertEquals($thirdPartyId, $data['id']);
// check into database // check into database
$period = $em->getRepository(AccompanyingPeriod::class) $period = $em->getRepository(AccompanyingPeriod::class)
@ -152,6 +152,36 @@ class AccompanyingCourseApiControllerTest extends WebTestCase
$this->assertNull($period->getRequestor()); $this->assertNull($period->getRequestor());
} }
/**
*
* @dataProvider dataGenerateRandomAccompanyingCourse
*/
public function testAccompanyingPeriodPatch(int $personId, AccompanyingPeriod $period)
{
$initialValueEmergency = $period->isEmergency();
$em = self::$container->get(EntityManagerInterface::class);
$this->client->request(
Request::METHOD_PATCH,
sprintf('/api/1.0/person/accompanying-course/%d.json', $period->getId()),
[], // parameters
[], // files
[], // server parameters
\json_encode([ 'type' => 'accompanying_period', 'emergency' => !$initialValueEmergency ])
);
$response = $this->client->getResponse();
$this->assertEquals(200, $response->getStatusCode());
$period = $em->getRepository(AccompanyingPeriod::class)
->find($period->getId());
$em->refresh($period);
$this->assertEquals(!$initialValueEmergency, $period->isEmergency());
// restore the initial valud
$period->setEmergency($initialValueEmergency);
$em->flush();
}
public function dataGenerateRandomRequestorValidData(): \Iterator public function dataGenerateRandomRequestorValidData(): \Iterator
{ {
$dataLength = 2; $dataLength = 2;
@ -208,7 +238,7 @@ class AccompanyingCourseApiControllerTest extends WebTestCase
[], // parameters [], // parameters
[], // files [], // files
[], // server parameters [], // server parameters
\json_encode([ 'person_id' => $personId ]) \json_encode([ 'type' => 'person', 'id' => $personId ])
); );
$response = $this->client->getResponse(); $response = $this->client->getResponse();
$data = \json_decode($response->getContent(), true); $data = \json_decode($response->getContent(), true);
@ -227,7 +257,7 @@ class AccompanyingCourseApiControllerTest extends WebTestCase
// check that the person id is contained // check that the person id is contained
$participationsPersonsIds = \array_map( $participationsPersonsIds = \array_map(
function($participation) { return $participation->person->person_id; }, function($participation) { return $participation->person->id; },
$data->participations); $data->participations);
$this->assertContains($personId, $participationsPersonsIds); $this->assertContains($personId, $participationsPersonsIds);
@ -239,7 +269,7 @@ class AccompanyingCourseApiControllerTest extends WebTestCase
[], // parameters [], // parameters
[], // files [], // files
[], // server parameters [], // server parameters
\json_encode([ 'person_id' => $personId ]) \json_encode([ 'type' => 'person', 'id' => $personId ])
); );
$response = $this->client->getResponse(); $response = $this->client->getResponse();
$data = \json_decode($response->getContent(), true); $data = \json_decode($response->getContent(), true);

View File

@ -17,6 +17,9 @@ components:
AccompanyingPeriod: AccompanyingPeriod:
type: object type: object
properties: properties:
type:
type: string
x-fixed-value: 'accompanying_period'
id: id:
type: integer type: integer
requestorAnonymous: requestorAnonymous:

View File

@ -2,7 +2,11 @@ parameters:
# cl_chill_person.example.class: Chill\PersonBundle\Example # cl_chill_person.example.class: Chill\PersonBundle\Example
services: services:
Chill\PersonBundle\Serializer\Normalizer\:
resource: '../Serializer/Normalizer/'
autowire: true
tags:
- { name: 'serializer.normalizer', priority: 64 }
chill.person.form.type.select2maritalstatus: chill.person.form.type.select2maritalstatus:
class: Chill\PersonBundle\Form\Type\Select2MaritalStatusType class: Chill\PersonBundle\Form\Type\Select2MaritalStatusType

View File

@ -1,12 +1,3 @@
--- ---
services: services:
Chill\PersonBundle\Serializer\Normalizer\PersonNormalizer: # note: normalizers are loaded from ../services.yaml
arguments:
$repository: '@Chill\PersonBundle\Repository\PersonRepository'
$render: '@Chill\MainBundle\Templating\Entity\ChillEntityRenderExtension'
tags:
- { name: 'serializer.normalizer', priority: 64 }
Chill\PersonBundle\Serializer\Normalizer\AccompanyingPeriodParticipationNormalizer:
tags:
- { name: 'serializer.normalizer', priority: 64 }

View File

@ -28,6 +28,7 @@ use Doctrine\Common\Collections\ArrayCollection;
use Chill\MainBundle\Entity\Center; use Chill\MainBundle\Entity\Center;
use Symfony\Component\Validator\Constraints as Assert; use Symfony\Component\Validator\Constraints as Assert;
use Chill\MainBundle\Entity\Address; use Chill\MainBundle\Entity\Address;
use Symfony\Component\Serializer\Annotation\DiscriminatorMap;
/** /**
* ThirdParty is a party recorded in the database. * ThirdParty is a party recorded in the database.
@ -38,7 +39,9 @@ use Chill\MainBundle\Entity\Address;
* *
* @ORM\Table(name="chill_3party.third_party") * @ORM\Table(name="chill_3party.third_party")
* @ORM\Entity(repositoryClass="Chill\ThirdPartyBundle\Repository\ThirdPartyRepository") * @ORM\Entity(repositoryClass="Chill\ThirdPartyBundle\Repository\ThirdPartyRepository")
* * @DiscriminatorMap(typeProperty="type", mapping={
* "thirdparty"=ThirdParty::class
*})
*/ */
class ThirdParty class ThirdParty
{ {

View File

@ -6,31 +6,19 @@ use Chill\ThirdPartyBundle\Entity\ThirdParty;
use Symfony\Component\Serializer\Normalizer\NormalizerAwareInterface; use Symfony\Component\Serializer\Normalizer\NormalizerAwareInterface;
use Symfony\Component\Serializer\Normalizer\NormalizerAwareTrait; use Symfony\Component\Serializer\Normalizer\NormalizerAwareTrait;
use Symfony\Component\Serializer\Normalizer\NormalizerInterface; use Symfony\Component\Serializer\Normalizer\NormalizerInterface;
use Symfony\Component\Serializer\Normalizer\DenormalizerInterface;
use Symfony\Component\Serializer\Exception\RuntimeException;
use Symfony\Component\Serializer\Exception\UnexpectedValueException;
use Symfony\Component\Serializer\Normalizer\AbstractNormalizer;
use Chill\ThirdPartyBundle\Repository\ThirdPartyRepository;
class ThirdPartyNormalizer implements NormalizerInterface, DenormalizerInterface, NormalizerAwareInterface class ThirdPartyNormalizer implements NormalizerInterface, NormalizerAwareInterface
{ {
private ThirdPartyRepository $repository;
use NormalizerAwareTrait; use NormalizerAwareTrait;
public function __construct(ThirdPartyRepository $repository)
{
$this->repository= $repository;
}
public function normalize($thirdParty, string $format = null, array $context = []) public function normalize($thirdParty, string $format = null, array $context = [])
{ {
/** @var $thirdParty ThirdParty */ /** @var $thirdParty ThirdParty */
$data['type'] = 'thirdparty'; $data['type'] = 'thirdparty';
// TODO should be replaced by a "render entity" // TODO should be replaced by a "render entity"
$data['text'] = $thirdParty->getName(); $data['text'] = $thirdParty->getName();
$data['thirdparty_id'] = $thirdParty->getId(); $data['id'] = $thirdParty->getId();
$data['address'] = $this->normalizer->normalize($thirdParty->getAddress(), $format, $data['address'] = $this->normalizer->normalize($thirdParty->getAddress(), $format,
[ 'address_rendering' => 'short' ]); [ 'address_rendering' => 'short' ]);
@ -42,29 +30,4 @@ class ThirdPartyNormalizer implements NormalizerInterface, DenormalizerInterface
return $data instanceof ThirdParty; return $data instanceof ThirdParty;
} }
public function denormalize($data, string $type, string $format = null, array $context = [])
{
$thirdParty = $context[AbstractNormalizer::OBJECT_TO_POPULATE] ?? NULL;
if (NULL === $thirdParty) {
$id = $data['thirdparty_id'] ?? NULL;
if (NULL === $id) {
throw new RuntimeException("mission thirdparty_id into body");
}
$thirdParty = $this->repository->findOneById($id);
if (NULL === $thirdParty) {
throw new UnexpectedValueException("thirdparty not found");
}
}
return $thirdParty;
}
public function supportsDenormalization($data, string $type, string $format = null)
{
return ThirdParty::class === $type;
}
} }