symfony / ux

Symfony UX initiative: a JavaScript ecosystem for Symfony

Home Page:https://ux.symfony.com/

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

[LiveComponent] Changing the username of a user in a live form disconnect the user before entering controllre logic

Huluti opened this issue · comments

I have a UserType form that let the user to change the email of his account.
I use dynamic fields with https://github.com/SymfonyCasts/dynamic-forms so I put the form in a Twig component to have a "live form".

The problem I have, is that when I validate the form, the user is instantly logged out even before entering the form handling part.

Here's my controller:

#[Route(path: ['fr' => '/mon-compte', 'en' => '/my-account'], name: 'dashboard')]
public function index(Request $request): Response
{
    $user = $this->userService->getUser();
    $currentEmail = $user->getEmail();

    $form = $this->createForm(UserType::class, $user, [
        'dashboard' => true,
    ]);
    $form->handleRequest($request);

    if ($form->isSubmitted() && $form->isValid()) {
        if ($user->getEmail() !== $currentEmail) {
            // If the user has changed his email, he need to re-verify it
            $user->setIsVerified(false);
            $locale = $this->userService->getLocale($user);
            $this->emailVerifierService->sendEmailConfirmation($user, $locale);
        }

        $this->entityManager->flush();

        $this->addFlash('success', $this->translator->trans('base.changed'));

        // Redirect to refresh the page
        return $this->redirectToRoute('dashboard');
    }

    return $this->render('dashboard/index.html.twig', [
        'form' => $form->createView(),
        'user' => $user,
    ]);
}

My dashboard.html.twig file:

{{ component('DashboardForm', {
    initialFormData: user,
    form: form
}) }}

My DashboardForm.php file:

<?php

declare(strict_types=1);

namespace App\Twig\Components;

use App\Entity\User;
use App\Form\UserType;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\Form\FormInterface;
use Symfony\UX\LiveComponent\Attribute\AsLiveComponent;
use Symfony\UX\LiveComponent\Attribute\LiveProp;
use Symfony\UX\LiveComponent\ComponentWithFormTrait;
use Symfony\UX\LiveComponent\DefaultActionTrait;

#[AsLiveComponent]
class DashboardForm extends AbstractController
{
    use ComponentWithFormTrait;
    use DefaultActionTrait;

    #[LiveProp]
    public ?User $initialFormData = null;

    protected function instantiateForm(): FormInterface
    {
        return $this->createForm(UserType::class, $this->initialFormData, [
            'dashboard' => true,
        ]);
    }
}

My DashboardForm.html.twig form:

<div {{ attributes }}>
    {{ form_start(form, {'attr': {'data-model': 'on(change)|*'}}) }}
        {{ form_errors(form) }}

        <!-- Other fields hided for the issue -->
        
        {{ form_label(form.email) }}
        {{ form_errors(form.email) }}
        {{ form_widget(form.email) }}

        <button class="button mb-0" type="submit">
            {% trans %}base.valid_button{% endtrans %}
        </button>
    {{ form_end(form) }}
</div>

When I click on the submit button, the if ($form->isSubmitted() && $form->isValid()) { part isn't reached and the user instantly logged out with the following logs:


[2024-04-05T15:30:46.252322+00:00] security.DEBUG: Stored the security token in the session. {"key":"_security_main"} []
[2024-04-05T15:30:46.305552+00:00] request.INFO: Matched route "dashboard". {"route":"dashboard","route_parameters":{"_route":"dashboard","_controller":"App\\Controller\\DashboardController::index","_locale":"fr"},"request_uri":"http://localhost/mon-compte","method":"POST"} []

[2024-04-05T15:30:46.306955+00:00] security.DEBUG: Read existing security token from the session.
[2024-04-05T15:30:46.333030+00:00] security.DEBUG: Cannot refresh token because user has changed. {"username":"*****","provider":"Symfony\\Bridge\\Doctrine\\Security\\User\\EntityUserProvider"} []
[2024-04-05T15:30:46.333117+00:00] security.DEBUG: Token was deauthenticated after trying to refresh it. [] []
[2024-04-05T15:30:46.333259+00:00] security.DEBUG: Clearing remember-me cookie. {"name":"REMEMBERME"} []

Do someone have an idea how to fix this behavior? Thanks!

It seems your user has been changed one way or another before the submit, and that forces the logout.
https://symfony.com/doc/current/security.html#loading-the-user-the-user-provider

First thing: did you try without the LiveComponent ? If you look at your profiler, do you see other requests sent to the LiveComponent and/or your controller ?

If that does not help, could you create and share a small reproducer ? It's hard to know what to investigate there :)

(Side note: using the User as LiveProp is not something i would advice. You should probably use some form of DTO here)

Without wrapping the form in a live component it works perfectly. The if ($form->isSubmitted() && $form->isValid()) { part is reached, the user email is changed in db...

I use the User as a LiveProp as documented for any entity in the documentation. This should not be done for the user that's it?
image
Source: https://symfony.com/bundles/ux-live-component/current/index.html#forms

I tried to do the same with the symfony demo but I can't reproduce it outside my project... so I'll close the issue and try to find the issue in my project.

Thanks!