Ajouter un message a une discussion
Sur notre entité Discussion rajoutons une nouvelle route
/**
* @ApiResource(
* collectionOperations={
* "post"={
* "input"=CreateDiscussionInput::class,
* "denormalization_context"={"groups"={"discussion:write"}},
* "output"=CreateDiscussionOutput::class
* },
* "createNewMessage"={
* "method"="POST",
* "path"="discussions/{id}/messages",
* "input"=CreateMessageInput::class,
* "denormalization_context"={"groups"={"message:write"}},
* },
* "get"
* },
* normalizationContext={"groups"={"discussion:read"}},
* )
* @ORM\Entity(repositoryClass=DiscussionRepository::class)
*/
class Discussion
Nous créons le DTO input CreateMessageInput
<?php
// src/DTO/CreateMessageInput.php
namespace App\DTO;
use Symfony\Component\Validator\Constraints as Assert;
use Symfony\Component\Serializer\Annotation\Groups;
class CreateMessageInput
{
/**
* @Assert\NotBlank()
* @Groups({"message:write"})
*/
public $contentMessage;
}
Son DataTransformer
<?php
// src/DataTransformer/CreateMessageInputDataTransformer.php
namespace App\DataTransformer;
use ApiPlatform\Core\DataTransformer\DataTransformerInterface;
use App\Entity\Discussion;
use App\Entity\Message;
class CreateMessageInputDataTransformer implements DataTransformerInterface
{
/**
* {@inheritdoc}
*/
public function transform($data, string $to, array $context = [])
{
$message = new Message();
$message->setContent($data->contentMessage);
return $message;
}
/**
* {@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'] === 'createNewMessage';;
}
}
Et enfin notre DataPersister. Notez qu'on regarde si on est sur une instance Message alors que dans notre DataTransformer on regardait si on était sur Discussion. C'est parce que notre DataTransformer retourne une nouvelle instance de Message.
Dans notre DataPersister on récupère la discussion car on connait son id avec le path "path"="discussions/{id}/messages"
<?php
// src/DataPersister/CreateMessageInputDataPersister.php
namespace App\DataPersister;
use ApiPlatform\Core\DataPersister\ContextAwareDataPersisterInterface;
use App\Entity\Message;
use App\Repository\DiscussionRepository;
use Doctrine\ORM\EntityManagerInterface;
use Symfony\Component\HttpFoundation\RequestStack;
class CreateMessageInputDataPersister implements ContextAwareDataPersisterInterface
{
/**
* @var RequestStack
*/
private $requestStack;
/**
* @var DiscussionRepository
*/
private $discussionRepository;
/**
* @var EntityManagerInterface
*/
private $entityManager;
public function __construct(
RequestStack $requestStack,
DiscussionRepository $discussionRepository,
EntityManagerInterface $entityManager
)
{
$this->requestStack = $requestStack;
$this->discussionRepository = $discussionRepository;
$this->entityManager = $entityManager;
}
public function supports($data, array $context = []): bool
{
return $data instanceof Message
&& (array_key_exists('collection_operation_name', $context)
&& $context['collection_operation_name'] === 'createNewMessage');
}
/**
* @param Message $data
* @param array $context
* @return void
*/
public function persist($data, array $context = [])
{
$id = $this->requestStack->getMasterRequest()->attributes->get('id');
$discusssion = $this->discussionRepository->find($id);
$data->setDiscussion($discusssion);
$this->entityManager->persist($data);
$this->entityManager->flush();
return $data;
}
public function remove($data, array $context = [])
{
}
}
A cet instant, si on fait un POST /api/discussions/{id}/messages
avec comme payload
{
"contentMessage": "Facilis nisi mollitia ut necessitatibus explicabo veniam. Eligendi ratione sunt voluptas est consequatur expedita fuga ut. Officia necessitatibus maiores cumque."
}
On à comme réponse []
car notre entité Message n'est pas déclaré comme une ressource ApiPlatform, voici les modifications à apporter :
use ApiPlatform\Core\Annotation\ApiResource;
use App\Repository\MessageRepository;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Serializer\Annotation\Groups;
/**
* @ApiResource()
* @ORM\Entity(repositoryClass=MessageRepository::class)
*/
class Message
Et à l'attribut content
nous rajoutons le groupe discussion:read
car nous arrivons de cette entité.
/**
* @ORM\Column(type="text")
* @Groups({"discussion:read"})
*/
private $content;
Maintenant en refaisant un POST /api/discussions/{id}/messages
avec comme payload
{
"contentMessage": "Facilis nisi mollitia ut necessitatibus explicabo veniam. Eligendi ratione sunt voluptas est consequatur expedita fuga ut. Officia necessitatibus maiores cumque."
}
nous avons la réponse :
{
"@context": "/api/contexts/Message",
"@id": "/api/messages/92",
"@type": "Message",
"content": "Facilis nisi mollitia ut necessitatibus explicabo veniam. Eligendi ratione sunt voluptas est consequatur expedita fuga ut. Officia necessitatibus maiores cumque."
}
prev
next
Commentaires
Connectez-vous pour laisser un commentaire