Nouvelle Discussion

A ce stade, si nous utilisons la route POST /discussions avec le payload

{
    "participants": [
        "/api/users/10",
        "/api/users/11", 
        "/api/users/12"
    ]
}

Nous avons comme réponse

{
    "@context": "/api/contexts/Discussion",
    "@id": "/api/discussions/84",
    "@type": "Discussion",
    "id": 84,
    "participants": [
        "/api/users/10",
        "/api/users/11",
        "/api/users/12"
    ],
    "messages": []
}

Mais nous voudrions pouvoir envoyer le premier message dans ce POST et également le retourner lors de la réponse de façon à avoir

{
    "participants": [
        "/api/users/10",
        "/api/users/11", 
        "/api/users/12"
    ],
    "contentMessage" : "Quae amet consequatur quod iusto non facere. Architecto aut molestias ea."
}

DTO CreateDiscussionInput

Pour ce faire, allons dans notre entité Discussion pour rajouter le DTO input

/**
 * @ApiResource(
 *     collectionOperations={
 *          "post"={
 *                "input"=CreateDiscussionInput::class,
 *                "denormalization_context"={"groups"={"discussion:write"}},
 *          },
 *          "get"
 *    },
 *    normalizationContext={"groups"={"discussion:read"}},
 * )
 * @ORM\Entity(repositoryClass=DiscussionRepository::class)
 */
class Discussion

Il nous reste à le créer :

<?php

// src/DTO/CreateDiscussionInput.php

namespace App\DTO;

use App\Entity\User;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection;
use Symfony\Component\Validator\Constraints as Assert;
use Symfony\Component\Serializer\Annotation\Groups;

class CreateDiscussionInput
{
    /**
     * @Groups({"discussion:write"})
     */
    private $participants;

    /**
     * @Assert\NotBlank()
     * @Groups({"discussion:write"})
     */
    public $contentMessage;

    public function __construct()
    {
        $this->participants = new ArrayCollection();
    }

    /**
     * @return Collection|User[]
     */
    public function getParticipants(): Collection
    {
        return $this->participants;
    }

    public function addParticipant(User $participant): self
    {
        if (!$this->participants->contains($participant)) {
            $this->participants[] = $participant;
        }

        return $this;
    }

    public function removeParticipant(User $participant): self
    {
        $this->participants->removeElement($participant);

        return $this;
    }
}

Ainsi que son DataTransformer

<?php

// src/DataTransformer/CreateDiscussionInputDataTransformer.php

namespace App\DataTransformer;

use ApiPlatform\Core\DataTransformer\DataTransformerInterface;
use App\Entity\Discussion;

class CreateDiscussionInputDataTransformer implements DataTransformerInterface
{
    /**
     * {@inheritdoc}
     */
    public function transform($data, string $to, array $context = [])
    {
        return $data;
    }

    /**
     * {@inheritdoc}
     */
    public function supportsTransformation($data, string $to, array $context = []): bool
    {
        // in the case of an input, the value given here is an array (the JSON decoded).
        if ($data instanceof Discussion) {
            return false;
        }

        return (Discussion::class === $to)
            && null !== ($context['input']['class'] ?? null)
            && (array_key_exists('collection_operation_name', $context))
            && $context['collection_operation_name'] === 'post';
    }
}

Nous allons modifier le __construct de Discussion afin de lui envoyer directement la liste des participants

public function __construct($participants = null)
{
    if ($participants) {
        $this->participants = $participants;
    } else {
        $this->participants = new ArrayCollection();
    }
}

Et enfin son DataPersister

<?php

namespace App\DataPersister;

use ApiPlatform\Core\DataPersister\ContextAwareDataPersisterInterface;
use App\DTO\CreateDiscussionInput;
use App\Entity\Discussion;
use App\Entity\Message;
use Doctrine\ORM\EntityManagerInterface;

class DiscussionDataPersister implements ContextAwareDataPersisterInterface
{
    private $entityManager;

    public function __construct(EntityManagerInterface $entityManager) {
        $this->entityManager = $entityManager;
    }

    public function supports($data, array $context = []): bool
    {
        return $data instanceof CreateDiscussionInput;
    }

    public function persist($data, array $context = [])
    {
        $discussion = new Discussion($data->getParticipants());
        $message = new Message();
        $message->setContent($data->contentMessage);
        $message->setDiscussion($discussion);

        $this->entityManager->persist($discussion);
        $this->entityManager->persist($message);

        $this->entityManager->flush();

        return $discussion;
    }

    public function remove($data, array $context = [])
    {
    }

}

C'est dans DiscussionDataPersister que nous créons une nouvelle Discussion avec ses participants grâce à son __construct, puis nous créons un nouveau Message et nous l'attachons à cette Discussion.

En faisant POST /api/discussions

{
    "participants": [
        "/api/users/10",
        "/api/users/11", 
        "/api/users/12"
    ],
    "contentMessage" : "Quae amet consequatur quod iusto non facere. Architecto aut molestias ea."
}

Nous avons comme réponse :

{
    "@context": "/api/contexts/Discussion",
    "@id": "/api/discussions/87",
    "@type": "Discussion",
    "participants": [
        "/api/users/10",
        "/api/users/11",
        "/api/users/12"
    ],
    "messages": []
}

Nous allons créer un DTO output pour pouvoir afficher le message

DTO CreateDiscussionOutput

Dans Discussion rajoutez la ligne output

/**
 * @ApiResource(
 *     collectionOperations={
 *          "post"={
 *                "input"=CreateDiscussionInput::class,
 *                "denormalization_context"={"groups"={"discussion:write"}},
 *                "output"=CreateDiscussionOutput::class
 *          },
 *          "get"
 *    },
 *    normalizationContext={"groups"={"discussion:read"}},
 * )
 * @ORM\Entity(repositoryClass=DiscussionRepository::class)
 */
class Discussion

Maintenant créons notre CreateDiscussionOutput

<?php

namespace App\DTO;

use Symfony\Component\Serializer\Annotation\Groups;

class CreateDiscussionOutput
{
    /**
     * @Groups({"discussion:read"})
     */
    public $participants;

    /**
     * @Groups({"discussion:read"})
     */
    public $contentMessage;
}

Ainsi que son DataTransformer

<?php

namespace App\DataTransformer;

use ApiPlatform\Core\DataTransformer\DataTransformerInterface;
use App\DTO\CreateDiscussionOutput;
use App\Entity\Discussion;
use App\Repository\MessageRepository;

class CreateDiscussionOutputDataTransformer implements DataTransformerInterface
{
    private $messageRepository;

    public function __construct(MessageRepository $messageRepository)
    {
        $this->messageRepository = $messageRepository;
    }

    /**
     * @param Discussion $object
     * @param string $to
     * @param array $context
     * @return CreateDiscussionOutput
     */
    public function transform($object, string $to, array $context = [])
    {
        $output = new CreateDiscussionOutput();

        $output->participants = $object->getParticipants();
        $output->contentMessage = $this->messageRepository->findOneBy(['discussion' => $object->getId()])->getContent();

        return $output;
    }

    public function supportsTransformation($data, string $to, array $context = []): bool
    {
        return CreateDiscussionOutput::class === $to && $data instanceof Discussion;
    }

}

Dans transform nous créons une nouvelle instance de CreateDiscussionOutput et nous associons avec participants et contentMessage

Maintenant, en faisant un POST /api/discussions/

Nous avons comme retour :

{
    "@context": {
        "@vocab": "https://127.0.0.1:8080/api/docs.jsonld#",
        "hydra": "http://www.w3.org/ns/hydra/core#",
        "participants": "CreateDiscussionOutput/participants",
        "contentMessage": "CreateDiscussionOutput/contentMessage"
    },
    "@type": "Discussion",
    "@id": "/api/discussions/91",
    "participants": [
        "/api/users/10",
        "/api/users/11",
        "/api/users/12"
    ],
     "contentMessage" : "Quae amet consequatur quod iusto non facere. Architecto aut molestias ea."
}
prev next

Commentaires

Connectez-vous pour laisser un commentaire