Renvoyer un nouveau code
Nous allons refaire une route POST resend-activation-code
sur l'entité User, et qui demandera un email valide en payload.
/**
* @ORM\Entity(repositoryClass=UserRepository::class)
* @ApiResource(
* normalizationContext={"groups"={"user:read"}},
* denormalizationContext={"groups"={"user:write"}},
* collectionOperations={
* "get",
* "post",
* "activationCode"={
* "method"="POST",
* "path"="activation-code",
* "input": ActivationCodeInput::class,
* "denormalization_context"={"groups"={"activation:write"}}
* },
* "resendActivationCode"={
* "method"="POST",
* "path"="resend-activation-code",
* "input": ResendActivationCodeInput::class,
* "denormalization_context"={"groups"={"activation:write"}}
* }
* }
* )
*/
class User implements UserInterface
Voici notre input qui vérifie si notre input est valide
<?php
// src/DTO/ResendActivationCodeInput.php
namespace App\DTO;
use App\Validator\Constraint\IsEmailExist;
use Symfony\Component\Validator\Constraints as Assert;
use Symfony\Component\Serializer\Annotation\Groups;
class ResendActivationCodeInput
{
/**
* @Assert\NotBlank()
* @Assert\Email()
* @Groups({"activation:write"})
*/
public $email;
}
Nous créons un DataTransformer
<?php
// src/DataTransformer/ResendActivationCodeDataTransformer.php
namespace App\DataTransformer;
use ApiPlatform\Core\DataTransformer\DataTransformerInterface;
use App\Entity\ActivationCode;
use App\Entity\User;
final class ResendActivationCodeDataTransformer 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 User) {
return false;
}
return (User::class === $to) && null !== ($context['input']['class'] ?? null) && (array_key_exists('collection_operation_name', $context) && $context['collection_operation_name'] === 'resendActivationCode');
}
}
Dans la méthode transform
nous vérifions si l'email est présent en base de données. Si oui nous générons un nouveau.
Nous allons factoriser la partie suivante
$activationCode = ActivationCodeService::generateNewCode();
$user->setActivationCode($activationCode['code']);
$user->setActivationCodeExpiresAt($activationCode['expirationDate']);
$this->entityManager->persist($user);
$this->entityManager->flush();
car elle est également dans UserDataPersister.
dans src/Security/ActivationCodeService.php
rajoutons la méthode generateCodeAndSendByMail
:
<?php
namespace App\Security;
use App\Entity\User;
use Symfony\Component\Mailer\MailerInterface;
use Symfony\Component\Mime\Email;
use Twig\Environment;
class ActivationCodeService
{
private $mailer;
private $twig;
public function __construct(
MailerInterface $mailer,
Environment $twig
) {
$this->mailer = $mailer;
$this->twig = $twig;
}
const VALIDATION_HOURS = 2;
public static function generateNewCode()
{
return
[
'code' => random_int(100000, 999999),
'expirationDate' => new \DateTime('+ ' . self::VALIDATION_HOURS . 'hour')
];
}
public function generateCodeAndSendByMail(User $user) {
$activationCode = self::generateNewCode();
$user->setActivationCode($activationCode['code']);
$user->setActivationCodeExpiresAt($activationCode['expirationDate']);
$email = (new Email())
->from('hello@example.com')
->to($user->getEmail())
->subject('Activez votre mail')
->html(
$this->twig->render('emails/registration.html.twig', [
'activationCode' => $activationCode
])
)
;
$this->mailer->send($email);
return $user;
}
}
Maintenant nous créons ResendActivationCodeDataPersister
qui est appelé quand on arrive de ResendActivationCodeInput
et nous envoyons le nouveau code par mail avec la méthode generateCodeAndSendByMail
<?php
// src/DataPersister/ResendActivationCodeDataPersister.php
namespace App\DataPersister;
use ApiPlatform\Core\DataPersister\ContextAwareDataPersisterInterface;
use App\DTO\ResendActivationCodeInput;
use App\Repository\UserRepository;
use App\Security\ActivationCodeService;
use Doctrine\ORM\EntityManagerInterface;
use Symfony\Component\HttpFoundation\JsonResponse;
class ResendActivationCodeDataPersister implements ContextAwareDataPersisterInterface
{
private $userRepository;
private $entityManager;
private $activationCodeService;
public function __construct(UserRepository $userRepository, EntityManagerInterface $entityManager, ActivationCodeService $activationCodeService)
{
$this->userRepository = $userRepository;
$this->entityManager = $entityManager;
$this->activationCodeService = $activationCodeService;
}
public function supports($data, array $context = []): bool
{
return $data instanceof ResendActivationCodeInput;
}
public function persist($data, array $context = [])
{
$user = $this->userRepository->findOneBy(['email' => $data->email]);
if ($user) {
$this->activationCodeService->generateCodeAndSendByMail($user);
$this->entityManager->persist($user);
$this->entityManager->flush();
}
return new JsonResponse(['message' => 'A new code has been sent to you'], 200);
}
public function remove($data, array $context = [])
{
}
}
et dans UserDataPersister
nous appelons également generateCodeAndSendByMail
:
public function persist($data, array $context = [])
{
if ($data->getId() === null) {
if ($data->getPlainPassword()) {
$data->setPassword(
$this->userPasswordEncoder->encodePassword($data, $data->getPlainPassword())
);
$data->eraseCredentials();
}
$this->activationCodeService->generateCodeAndSendByMail($data);
}
return $this->decorated->persist($data, $context);
}
prev
next
Commentaires
Connectez-vous pour laisser un commentaire