We use the Symfony2 framework and FOSUserBundle for our users. So We have our own UserBundle that inherits from FOSUserBundle. The problem is : When we send the form for editing a user with a wrong password, the app.user.username that is displayed in the header changes when it shouldn't since the form isn't correct. Then when we reload the page, the app.user.username has the normal username (since it hasn't changed in the database). The question is, why does the app.user.username changes temporarily for the value of the form (edit user) that we just sent with a wrong password ?
we use the normal routing from FOSUser :
fos_user_security:
resource: "@FOSUserBundle/Resources/config/routing/security.xml"
fos_user_profile:
resource: "@FOSUserBundle/Resources/config/routing/profile.xml"
prefix: /profile
fos_user_register:
resource: "@FOSUserBundle/Resources/config/routing/registration.xml"
prefix: /register
fos_user_resetting:
resource: "@FOSUserBundle/Resources/config/routing/resetting.xml"
prefix: /resetting
fos_user_change_password:
resource: "@FOSUserBundle/Resources/config/routing/change_password.xml"
prefix: /profile
And the default Controller from FOSUser :
public function editAction(Request $request)
{
$user = $this->getUser();
if (!is_object($user) || !$user instanceof UserInterface) {
throw new AccessDeniedException('This user does not have access to this section.');
}
/** @var $dispatcher \Symfony\Component\EventDispatcher\EventDispatcherInterface */
$dispatcher = $this->get('event_dispatcher');
$event = new GetResponseUserEvent($user, $request);
$dispatcher->dispatch(FOSUserEvents::PROFILE_EDIT_INITIALIZE, $event);
if (null !== $event->getResponse()) {
return $event->getResponse();
}
/** @var $formFactory \FOS\UserBundle\Form\Factory\FactoryInterface */
$formFactory = $this->get('fos_user.profile.form.factory');
$form = $formFactory->createForm();
$form->setData($user);
$form->handleRequest($request);
if ($form->isValid()) {
/** @var $userManager \FOS\UserBundle\Model\UserManagerInterface */
$userManager = $this->get('fos_user.user_manager');
$event = new FormEvent($form, $request);
$dispatcher->dispatch(FOSUserEvents::PROFILE_EDIT_SUCCESS, $event);
$userManager->updateUser($user);
if (null === $response = $event->getResponse()) {
$url = $this->generateUrl('fos_user_profile_show');
$response = new RedirectResponse($url);
}
$dispatcher->dispatch(FOSUserEvents::PROFILE_EDIT_COMPLETED, new FilterUserResponseEvent($user, $request, $response));
return $response;
}
return $this->render('FOSUserBundle:Profile:edit.html.twig', array(
'form' => $form->createView()
));
}
Here is the part of code that is displayed in the header that should NOT change when submitting the form with a wrong password. (app.user.username)
<ul class="nav navbar-nav navbar-right">
{% if is_granted("IS_AUTHENTICATED_REMEMBERED") %}
<li>
<a href="{{ path('fos_user_profile_show') }}">{{ app.user.username }}
</a>
</li>
<li>
<a href="{{ path('fos_user_security_logout') }}">
{{ 'layout.logout'|trans({}, 'FOSUserBundle') }}
</a>
</li>
{% else %}
<li>
<a href="{{ path('fos_user_registration_register') }}">{{ 'layout.register'|trans({}, 'FOSUserBundle') }}</a>
</li>
<li>
<a href="{{ path('fos_user_security_login') }}">{{ 'layout.login'|trans({}, 'FOSUserBundle') }}</a>
</li>
{% endif %}
</ul>
And Here is the code of the formulaire that is displayed :
<div class="well">
{{ form_start(form, {'attr': {'class': 'form-horizontal'}}) }}
{{ form_errors(form) }}
<div class="form-group">
{# Génération du label username. #}
{{ form_label(form.username, 'register.form.username'|trans, {'label_attr': {'class': 'col-sm-3 control-label'}}) }}
{# Affichage des erreurs pour ce champ précis. #}
{{ form_errors(form.username) }}
<div class="col-sm-4">
{{ form_widget(form.username, {'attr': {'class': 'form-control'}}) }}
</div>
</div>
<div class="form-group">
{# Génération du label adresse. #}
{{ form_label(form.address, 'register.form.address'|trans, {'label_attr': {'class': 'col-sm-3 control-label'}}) }}
{# Affichage des erreurs pour ce champ précis. #}
{{ form_errors(form.address) }}
<div class="col-sm-4">
{{ form_widget(form.address, {'attr': {'class': 'form-control'}}) }}
</div>
</div>
<div class="form-group">
{# Génération du label nom du contact. #}
{{ form_label(form.contactName, 'register.form.contact_name'|trans, {'label_attr': {'class': 'col-sm-3 control-label'}}) }}
{# Affichage des erreurs pour ce champ précis. #}
{{ form_errors(form.contactName) }}
<div class="col-sm-4">
{{ form_widget(form.contactName, {'attr': {'class': 'form-control'}}) }}
</div>
</div>
<div class="form-group">
{# Génération du label email. #}
{{ form_label(form.email, 'register.form.email'|trans, {'label_attr': {'class': 'col-sm-3 control-label'}}) }}
{# Affichage des erreurs pour ce champ précis. #}
{{ form_errors(form.email) }}
<div class="col-sm-4">
{{ form_widget(form.email, {'attr': {'class': 'form-control'}}) }}
</div>
</div>
<div class="form-group">
{# Génération du label numéro de téléphone. #}
{{ form_label(form.phone, 'register.form.phone'|trans, {'label_attr': {'class': 'col-sm-3 control-label'}}) }}
{# Affichage des erreurs pour ce champ précis. #}
{{ form_errors(form.phone) }}
<div class="col-sm-4">
{{ form_widget(form.phone, {'attr': {'class': 'form-control'}}) }}
</div>
</div>
<div class="form-group">
{# Génération du label mot de passe. #}
{{ form_label(form.current_password, 'register.form.password'|trans, {'label_attr': {'class': 'col-sm-3 control-label'}}) }}
{# Affichage des erreurs pour ce champ précis. #}
{{ form_errors(form.current_password) }}
<div class="col-sm-4">
{{ form_widget(form.current_password, {'attr': {'class': 'form-control'}}) }}
</div>
</div>
{# Pour le bouton, pas de label ni d'erreur, on affiche juste le widget #}
{{ form_widget(form.saveButton, {'attr': {'class': 'btn btn-primary'}, 'label': 'profile.edit.submit'|trans }) }}
{# Génération automatique des champs pas encore écrits.
Dans cet exemple, ce serait le champ CSRF (géré automatiquement par Symfony !)
et tous les champs cachés (type « hidden »). #}
{{ form_rest(form) }}
{# Fermeture de la balise <form> du formulaire HTML #}
{{ form_end(form) }}
</div>
And here is the FormType that we user for this particular form :
public function buildForm(FormBuilderInterface $builder, array $options)
{
// add your custom field
$builder->add('contactName', 'text')
->add('phone', 'text')
->add('address', 'text')
->add('saveButton', 'submit');
}
The FormType inherits from ProfileFormType (Default in FOSUserBundle) thanks to a getParent() function.
Thank you for your help figuring out what is wrong. We don't understand why the app.user.username changes in the header since the form is sent with a wrong password and the data in the database isn't changed and sorry for the comments that are in French in the code :).
This works for me:
1) Add currentUsername property and lifecycle callbacks into User entity class
namespace AppBundle\Entity;
use FOS\UserBundle\Model\User as BaseUser;
use Doctrine\ORM\Mapping as ORM;
/**
* Class User
* @package AppBundle\Entity
*
* @ORM\Entity(repositoryClass="AppBundle\Repositories\User")
* @ORM\Table(name="site_user")
* @ORM\HasLifecycleCallbacks()
*/
class User extends BaseUser
{
/**
* @var int
*
* @ORM\Column(type="integer", nullable=false)
* @ORM\Id()
* @ORM\GeneratedValue()
*/
protected $id;
/**
* @var string
*/
public $currentUsername;
/**
* @ORM\PostLoad()
* @ORM\PostUpdate()
* @ORM\PostPersist()
*/
public function syncCurrentUsername()
{
$this->currentUsername = $this->username;
}
/**
* @return string
*/
public function getCurrentUsername()
{
return $this->currentUsername;
}
}
2) And then in template use:
{{ app.user.getCurrentUsername() }}
3) In some cases maybe you should need to override serialize and deserialize methods and add new property (currentUsername) to it.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With