Imaginons un projet sous Symfony 5 ou 6 avec EasyAdmin (3 ou 4) installé et une entité User possédant plusieurs champs : id, email, roles, password, prenom, nom, avatar, isActive, etc.
Les utilisateurs peuvent se connecter, possèdent des "droits" (rôles) et sont autorisés à faire certaines tâches.
Une fois connectés, les utilisateurs ayant un role admin, par exemple, peuvent naviguer jusqu'à la page d'accueil du Dashboard (EasyAdmin) et pourquoi pas aller changer leur email, avatar, etc.
Mais qu'en est-il du mot de passe ?
Certes, il existe un excellent bundle symfonycasts/reset-password-bundle (https://github.com/symfonycasts/reset-password-bundle) qui permet aux utilisateurs de régénérer un mot de passe en cas de perte.
Mais si on veut permettre à l'utilisateur connecté de changer son propre mot de passe depuis EasyAdmin, comment faire ?
Et bien cela est relativement simple et ça se passe en 2 étapes :
1/ EasyAdmin UserCrudController.php
Dans EasyAdmin vous avez surement généré un Crud controller pour votre entité User (src/Controller/Admin/UserCrudController.php)
Dans ce fichier, insérez la partie relative au mot de passe :
Field::new('password', 'Changer le mot de passe ?')
->setColumns(2)
->onlyOnForms()
->setFormType(PasswordType::class),
Ici, j'utilise Field (n'oubliez pas d'importer la class use EasyCorp\Bundle\EasyAdminBundle\Field\Field)
Je lui dis, pour des questions esthétiques, de ne s'afficher que sur 2 col (Bootstrap), de ne s'afficher que sur les formulaires (pas en page Index, ni dans Details) et j'utilise le setFormType avec PasswordType::class (n'oubliez pas d'importer la class), tout comme dans les Form classiques de Symfony. Cela permettra d'avoir un champ qui remplace les caractères par des points, etc.
2/ EasyAdmin EventSubscriber
La deuxième (et dernière) étape consiste à créer un EventSubscriber (src/EventSubscriber/EasyAdminSubscriberUserPasswordChange.php). L'eventSubscriber est une classe qui définit une ou plusieurs méthodes qui écoutent un ou plusieurs événements.
Aussi notre EventSubsciber va "capter" ou "écouter" ce qui se passe sur la partie User d'EasyAdmin, et notamment la partie mot de passe.
Il s'agira de définir à quel moment écouter et quoi écouter.
Ici, on va écouter tout ce qui concerne l'ajout de l'utilisateur mais aussi l'update éventuel de données de l'utilisateurs grâce à BeforeEntityPersistedEvent et BeforeEntityUpdatedEvent.
Voici donc ci-dessous le fichier en question. En gros, il va "écouter" s'il s'agit d'une création ou d'un update et agir selon le contexte, soit en settant directement le mot de passe, soit en récupérant le mot de passe pour le "hasher" et l'enregistrer dans la base de données : persist() et flush()
<?php
namespace App\EventSubscriber;
use App\Entity\User;
use Doctrine\ORM\EntityManagerInterface;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use EasyCorp\Bundle\EasyAdminBundle\Event\BeforeEntityUpdatedEvent;
use EasyCorp\Bundle\EasyAdminBundle\Event\BeforeEntityPersistedEvent;
use Symfony\Component\PasswordHasher\Hasher\UserPasswordHasherInterface;
class EasyAdminSubscriberUserPasswordChange implements EventSubscriberInterface
{
private EntityManagerInterface $entityManager;
private UserPasswordHasherInterface $passwordHasher;
public function __construct(EntityManagerInterface $entityManager, UserPasswordHasherInterface $passwordHasher)
{
$this->entityManager = $entityManager;
$this->passwordHasher = $passwordHasher;
}
public static function getSubscribedEvents(): array
{
return [
BeforeEntityPersistedEvent::class => ['addUser'],
BeforeEntityUpdatedEvent::class => ['updateUser'],
];
}
public function updateUser(BeforeEntityUpdatedEvent $event): void
{
$entity = $event->getEntityInstance();
if (!($entity instanceof User)) {
return;
}
$this->setPassword($entity);
}
public function addUser(BeforeEntityPersistedEvent $event): void
{
$entity = $event->getEntityInstance();
if (!($entity instanceof User)) {
return;
}
$this->setPassword($entity);
}
public function setPassword(User $entity): void
{
$pass = $entity->getPassword();
$entity->setPassword(
$this->passwordHasher->hashPassword(
$entity,
$pass
)
);
$this->entityManager->persist($entity);
$this->entityManager->flush();
}
}
Olivier Prieur
Geek quinqua nivernais fan d'ovalie, de musique, de linuxeries et de Net.
Portfolio : https://www.olivierprieur.fr
Il n'y a actuellement aucun commentaire pour cet article