FabRiviere / Livre_Or_Symfony

Développement du projet concernant un livre d'or sur les conférences. Projet du livre Symfony 6.
0 stars 0 forks source link

Asynchrone - Avec le composant Messenger #38

Closed FabRiviere closed 1 year ago

FabRiviere commented 1 year ago
FabRiviere commented 1 year ago

Installation du package Messenger :

symfony composer req doctrine-messenger

Lorsqu'une action doit être exécutée de manière asynchrone, envoyer un message à un bus messager . Le bus stocke le message dans un fichier d'attente et rend immédiatement la main pour permettre au flux des opérations de reprise aussi vite que possible.

Codage d'un gestionnaire de messages :

Création de la classe CommentMessage.php :

<?php

namespace App\Message;

class CommentMessage
{
    public function __construct(private int $id, private array $context = [],)
    {        
    }

    public function getId(): int
    {
        return $this->id;
    }

    public function getContext(): array
    {{
        return $this->context;
    }}
}

Dans le monde de Messenger, nous n'avons pas de contrôleurs, mais des gestionnaires de messages.

Création de la classe CommentMessageHandler.php :

Sous un nouvel espace de noms App\MessageHandler, créez une classe CommentMessageHandlerqui saura comment gérer les messages CommentMessage:

<?php

namespace App\MessageHandler;

use App\Message\CommentMessage;
use App\Repository\CommentRepository;
use App\Service\SpamChecker;
use Doctrine\ORM\EntityManagerInterface;
use Symfony\Component\Messenger\Attribute\AsMessageHandler;

#[AsMessageHandler]
class CommentMessageHandler
{
    public function __construct(
        private EntityManagerInterface $entityManager,
        private SpamChecker $spamChecker,
        private CommentRepository $commentRepository,
    ) {        
    }

    public function __invoke(CommentMessage $message)
    {
        $comment = $this->commentRepository->find($message->getId());
        if (!$comment) {
            return;
        }

        if (2 === $this->spamChecker->getSpamScore($comment, $message->getContext())) {
            $comment->setState('spam');
        } else {
            $comment->setState('published');
        }

        $this->entityManager->flush();
    }
}

Modification du ConferenceController.php :

public function __construct(private EntityManagerInterface $entityManager, private MessageBusInterface $bus)
    {        
    }
#[Route('/conference/{slug}', name: 'conference')]
    public function show(Request $request, Conference $conference, CommentRepository $commentRepository,
                            #[Autowire('%photo_dir%')] string $photoDir): Response
    {
        $comment = new Comment();
        $formComment = $this->createForm(CommentType::class, $comment);
        $formComment->handleRequest($request);

        if ($formComment->isSubmitted() && $formComment->isValid()) {
            $comment->setConference($conference);

            //! Traitement des photos
            if ($photo = $formComment['photo']->getData()) {
                $filename = bin2hex(random_bytes(6)).'.'.$photo->guessExtension();
                $photo->move($photoDir, $filename);
                $comment->setPhotoFilename($filename);
            }

            $this->entityManager->persist($comment);
            $this->entityManager->flush();

            //! vérification si présence de spam avant de stocker les commentaires en DB
            $context = [
                'user_ip' => $request->getClientIp(),
                'user_agent' => $request->headers->get('user-agent'),
                'referrer' => $request->headers->get('referer'),
                'permalink' => $request->getUri(),
            ];
            // ! mis en commentaire pour utilisation du MessageBusInterface à la place de SpamChecker
            // if (2 === $spamChecker->getSpamScore($comment, $context)) {
            //     throw new \RuntimeException('Blatant spam, go away !! 😵‍💫😟');
            // }

            // $this->entityManager->flush();
            // ! Utilisation du MessageBusInterface
            $this->bus->dispatch(new CommentMessage($comment->getId(), $context));

            return $this->redirectToRoute('conference', ['slug' => $conference->getSlug()]);
        }

        $offset = max(0, $request->query->getInt('offset', 0));
        $paginator = $commentRepository->getCommentPaginator($conference, $offset);

        return $this->render('conference/show.html.twig', [
            'conference' => $conference,
            'comments' => $paginator,
            'previous' => $offset - CommentRepository::PAGINATOR_PER_PAGE,
            'next' => min(count($paginator), $offset + CommentRepository::PAGINATOR_PER_PAGE),
            'comment_form' => $formComment,
        ]);
    }

Au lieu de dépendre du SpamChecker, nous envoyons maintenant un message dans le bus. Le gestionnaire décide alors ce qu'il en fait.

Modification du fichier config/packages/messenger.yaml :

 ```
   # Route your messages to the transports
        'App\Message\CommentMessage': async