Envoyer un message lorsqu’un formulaire est envoyé via Symfony 5

Le problème exposé dans ce sujet a été résolu.

Bonjour :)

Je travaille sur ma page de profil, pour changer mon adresse courriel, mon mot de passe, etc.

Donc lorsque je me trompe, si je met un mot de passe différent de l’initial, je vais avoir un message d’erreur, si le courriel et < 2 caractères, idem, message d’erreur, etc. mais je ne sais pas comment afficher un message si tout est bon que le courriel a bien été mis à jour.

J’utilise Symfony 5 et PHP 7.

Mes pages :

src/Controller/ProfileController.php

<?php

namespace App\Controller;

use App\Form\ChangeEmailType;
use App\Form\ChangePasswordType;
use Doctrine\ORM\EntityManagerInterface;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Annotation\Route;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\Security\Core\Encoder\UserPasswordEncoderInterface;

class ProfileController extends AbstractController
{
    /**
     * @Route("/profile", name="profile")
     */
    public function index(
        Request $request,
        UserPasswordEncoderInterface $passwordEncoder,
        EntityManagerInterface $entityManager
    ): Response
    {
        $user = $this->getUser();

        $formEmail = $this->createForm(ChangeEmailType::class, $user);
        $formEmail->handleRequest($request);

        $formPassword = $this->createForm(ChangePasswordType::class, $user);
        $formPassword->handleRequest($request);

        if ($formEmail->isSubmitted() && $formEmail->isValid()) {
            $entityManager->flush();
        }

        if ($formPassword->isSubmitted() && $formPassword->isValid()) {
            $user->setPassword(
                $passwordEncoder->encodePassword(
                    $user,
                    $formPassword->get('plainPassword')->getData()
                )
            );

            $entityManager->flush();
        }


        return $this->render('profile/index.html.twig', [
            'emailForm' => $formEmail->createView(),
            'passwordForm' => $formPassword->createView(),
        ]);
    }
}

templates/profile/index.html.twig

{{ form_start(passwordForm) }}
    <div class="block-button inputProfile">
        {{ form_row(passwordForm.plainPassword , {'attr': {'placeholder': 'Mot de passe'}}) }}
    </div>

    <button type="submit" class="btn">Mettre à jour</button>
{{ form_end(passwordForm) }}

Je dois passer par le controller si je suppose, mais je ne sais pas trop comment.

Si vous avez besoin d’autres choses n’hésitez pas :p

Cordialement

+0 -0

Salut

Pourquoi ne pas avoir copié-collé ton code ici ? Il y a tout ce qu’il faut pour bien le présenter et ça nous évite de devoir aller chercher ailleurs les informations. Dans l’idéal, je te conseillerais de le (re-)mettre, quitte à utiliser le bloc masqué autour des pavés de code.

Sinon, en toute logique, si tout va bien, tu rediriges vers une page bien précise. Pourquoi ne pas ajouter un message flash en ce sens dans le contrôleur juste avant la redirection ?

+1 -0

Bonjour,

Tu ne persistes pas ton entité, tu ne fais que flusher.

$entityManager->persist($user); // Sans ça, ton user ne sera pas mis à jour.
$entityManager->flush();

Concernant l’affichage d’un message, Ymox a tout dit.

+1 -0

OK, tu ne rediriges pas, je ne suis pas certain que ça ne risque pas de poser problème (le fameux message qui dit qu’une action sera répétée). Mais quand tu as pu enregistrer les modifications, tu peux ajouter les messages flash, sachant qu’en cas d’erreur, le script sera interrompu au niveau du flush().

@John : il récupère l’utilisateur courant qui est déjà persisté vu qu’il est authentifié, pas besoin d’appeler persist() il me semble.

+0 -0

Je vais essayer les messages flash() mais je ne sais pas trop comment m’en servir encore.

Je souhaite simplement faire mais via Symfony :O

if(isset($_POST['message'])) && !empty($_POST['message'])) {
  echo '<p>Votre message a été envoyé à ' . htmlspecialchars($_POST['email']) . '.</p>';
}

@John : comme l’a dit @Ymox, je récupérer les données de l’utilisateur via $user = $this->getUser(); donc pas besoin d’appeler persist()

+0 -0

Effectivement. Après des années de pratique de Symfony, je ne connaissais pas ce comportement. Comportement que je trouve dangereux, au passage.

@Machou Ce que tu cherches à faire s’appelle les "Flash messages" chez Symfony. Le principe est de mettre en session des messages et, sur toutes les pages, de vérifier si de tels messages existent et le cas échéant de les afficher. Une autre solution consiste à faire une page de confirmation, à part, avec sa propre URL. C’est la solution recommandée lorsqu’on veut facilement mettre en place un tracking sur les formulaires.

+0 -0

J’ai regardé les messages flash() et avec mon collègue, on s’est pas mal amusé a comprendre comment ça fonctionne, je reviendrai vers vous lorsque ce sera assimilé, codé et terminé :p

Par contre je n’ai pas compris ta seconde solution proposée ? Qu’est-ce qu’une page de confirmation ? si t’as un lien ou la documentation ça m’intéresse.

Concernant l’utilisation directement de $user je ne sais pas si c’est dangereux mais c’est un Senior de Symfony qui me l’a recommandé donc du coup je suis perdu à savoir si c’est une bonne pratique ou non :O

+0 -0

Effectivement. Après des années de pratique de Symfony, je ne connaissais pas ce comportement. Comportement que je trouve dangereux, au passage.

@John je reprends Symfony doucement et ça m’intéresse de comprendre pourquoi ne pas persister un objet qui l’a déjà été est un comportement dangereux ? Je ne suis pas certain d’avoir bien compris le fonctionnement du persist.

Je ne suis pas certain que c’est la même idée qu’un prepare, si tu regardes l’implémentation de cette méthode dans l’entityManager tu vois qu’elle est utilisée dans un objet UnitOfWork qui semble suivre les changements d’état de l’entity.

Si je ne dis pas n’importe quoi, ça permet de "dire" à doctrine qu’un nouveau objet a été créé et suivre son évolution. Le flush va permettre ensuite d’appliquer les modifications que l’objet à subit depuis le flush précédent.

À confirmer je te dis ça en ayant regardé rapidement comment c’était foutu j’ai peut-être rien compris :D

persist(…) dit à Doctrine que l’objet passé en paramètre devra à un moment être persisté afin qu’il "survive", en base de données en l’occurrence. Selon le dictionnaire Le Robert, persister veut aussi dire « durer, rester malgré tout », tout comme to persist en anglais.

Maintenant, à l’interne, Doctrine ne fait qu’ajouter l’objet à une liste de ceux qu’il faudra gérer lors du flush()1. C’est cette dernière méthode qui fait que les diverses opérations en base (insertion, suppression et mise à jour) sont réellement effectuées.

La différence entre un objet qui vient de la base de données et un nouvel objet est que Doctrine, quand un objet auparavant persisté est récupéré depuis la base, ajoute automatiquement cet objet précédemment persisté à la liste de ceux qu’il devra gérer lors d’un flush() à venir. C’est donc ce qui fait qu’il n’y a pas besoin de faire de persist(…) explicitement sur des objets qui viennent de la base de données, et que flush() semble magiquement enregistrer les modifications sur ces objets.

Pour éviter ce comportement, il y a(-vait ?) detach(…) qui supprimait l’entité de la liste, permettant ainsi d’appeler flush() sans que les modifications ne soient enregistrées. Cependant, la "réciproque" pour ajouter l’entité dans la liste n’est pas persist(…), mais merge(…)2. Ces deux méthodes ne sont plus conseillées sinon dépréciées, et pourraient bien ne pas être disponibles dans Doctrine ORM 3.x.


  1. Dans le jargon anglophone de Doctrine, ils parlent de managed entities pour désigner celles qui sont dans cette liste.
  2. Même si, probablement pour éviter des surprises, persist($uneEntiteVenantDeLaBaseDeDonnes) et persist($uneEntiteAuparavantDetachee) ne posent pas de problème actuellement
+1 -0

Merci Ymox !

Suite aux messages, j’ai réussi à faire mes messages flash, ça rend super :)

Aussi, j’ai injecté User $user dans la méthode index de mon contrôleur pour éviter un $this->getUser(); comme conseillé par @John :P

Merci à vous ;)

+0 -0

Ah, @John a proposé ça ? C’est pertinent, mais je ne vois pas où c’est mentionné…

Ymox

non il a conseillé que ce n’était pas très bien de faire ça, donc j’ai fait autrement :P

+0 -0

Effectivement. Après des années de pratique de Symfony, je ne connaissais pas ce comportement. Comportement que je trouve dangereux, au passage.

@John je reprends Symfony doucement et ça m’intéresse de comprendre pourquoi ne pas persister un objet qui l’a déjà été est un comportement dangereux ? Je ne suis pas certain d’avoir bien compris le fonctionnement du persist.

Upa

Pour moi, une entité déjà en BDD, et qui serait modifiée, n’a pas obligatoirement vocation à être mise à jour en BDD. Les cas sont sans doute rares, mais ce n’est même pas le soucis pour moi. De mon point de vue, persist indique à l’ORM qu’on souhaite enregistrer l’entité, flush rend effectif cet enregistrement. Ça prend à peine quelques secondes à écrire, et on est sûr de ce que ça fait.

Merci Ymox !

Suite aux messages, j’ai réussi à faire mes messages flash, ça rend super :)

Aussi, j’ai injecté User $user dans la méthode index de mon contrôleur pour éviter un $this->getUser(); comme conseillé par @John :P

Merci à vous ;)

Machou

Ah, @John a proposé ça ? C’est pertinent, mais je ne vois pas où c’est mentionné…

Ymox

Je n’ai effectivement pas préconisé ça, pour ma part c’est du pareil au même (à moins de gérer des profils via l’URL, c’est à dire de pouvoir modifier le profil d’un autre utilisateur (en tant qu’admin par exemple) où, là, cela a vraiment du sens). Ce qui m’a fait tiquer, c’est le fait de ne pas devoir utiliser persist, qu’un simple flush suffise. Mais ici dans ton cas, cela n’a pas d’impact, car ton but est effectivement d’enregistrer l’entité dans la BDD.

+0 -0
Connectez-vous pour pouvoir poster un message.
Connexion

Pas encore membre ?

Créez un compte en une minute pour profiter pleinement de toutes les fonctionnalités de Zeste de Savoir. Ici, tout est gratuit et sans publicité.
Créer un compte