Johannes Klauß
Johannes Klauß

Reputation: 11020

Doctrine does not update FOSUserBundle User object

I'm encountered a weird problem.

I'm working on a Symfony 2.1 project with Doctrine 2.2 and the FOSUserBundle for user management.

I added a RequestListener, since the user can change the language of the site and I want to track the last used language of the user.

So I simply added a new property to the User Entity and then want to save the new language if has changed.

So I'm doing this in the request listener:

public function onKernelRequest(GetResponseEvent $event)
{
    if (HttpKernel::MASTER_REQUEST != $event->getRequestType()) {
        return;
    }

    if ($event->getRequest()->getRequestFormat() !== 'html') {
        return;
    }

    if ($this->context->getToken()->getUser() instanceof \Foo\BarBundle\Entity\User) {
        $this->request = $event->getRequest();
        $this->user = $this->context->getToken()->getUser();

        if ($this->user->getCustomer() instanceof \Foo\BarBundle\Entity\Customer) {
            $this->customer = $this->user->getCustomer();

            $permission = $this->permissionService->getPermissionSafely($this->customer);

            $params = $this->request->get('_route_params');

            $language = $this->getLanguage($permission['language']['languages']);
            $locale = (strtolower($this->request->get('_locale')) === 'de') ? 'de_DE' : 'en_US';

            if ($language !== "all" && $this->request->get('_locale') !== $language) {
                $params['_locale'] = $language;

                $redirect = new RedirectResponse($this->router->generate($this->request->get('_route'), $params));

                $event->setResponse($redirect);
            }

            if ($this->user->getLastLanguage() !== $locale) {
                $this->user->setLastLanguage($locale);
                $this->em->flush();
            }
        }
    }
}

private function getLanguage($language)
{
    if (!isset($language['en'])) {
        return 'de';
    }
    if (!isset($language['de'])) {
        return 'en';
    }

    if ($language['en'] && !($language['de'])) {
        return 'en';
    } else if (!$language['en'] && $language['de']) {
        return 'de';
    }

    return 'all';
}

Important is the last if-conditional. If the current $locale is different than the last used, I want to update the user object. So there are three possible values: de_DE, en_US and null.

Now the weird behaviour comes in (and I don't know if it's a bug or what, but I'm confused):

It doesn't matter which value is stored in the database, it always gets updated to en_US.

If a user has visit the page for the first time (value null) and visits the site in german (value de_DE) it gets updated to en_US, but the profiler query says:

UPDATE `user` SET last_language = 'de_DE' WHERE id = 1

If a user has last_language = 'de_DE' and visits the site in german (de_DE) it gets updated to en_US, but the query profiler says, that there wasn't a update query. Which makes sense, because the $locale is the same like $this->user->getLastLanguage().

What the??

I have no idea what is going on here. Has anyone experienced a similar problem? Has this something to do with the fact, that I'm modifying the user object from the security context?

Update: The funny thing is, if I change line

$locale = (strtolower($this->request->get('_locale')) === 'de') ? 'de_DE' : 'en_US';

to

$locale = (strtolower($this->request->get('_locale')) === 'de') ? 'de_DE' : 'es_US';

it gets updated to es_US event if $locale holds de_DE

Upvotes: 0

Views: 832

Answers (1)

Nicolai Fröhlich
Nicolai Fröhlich

Reputation: 52473

Your ternary if statement will always fail because the return value of

$this->request->get('_locale')

will be :

  • de_DE

but never === 'de'. Therefore if you save $locale in your entity after calling

$locale = (strtolower($this->request->get('_locale')) === 'de') ? 'de_DE' : 'en_US';

... the next time this statement fails and puts it back to 'en_US' calling ...

$user->setLastLanguage('en_US');

... in the end. Just do a better comparison like ...

 $locale = (strstr($locale,'de') !== false) ? 'de_DE' : 'en_US';

Have you tried persist before flushing:

$this->user->setLastLanguage($locale);
$this->em->flush();

should be ...

 $this->user->setLastLanguage($locale);
 $this->em->persist($this->user);
 $this->em->flush();

... if your user is newly created and not already managed by doctrine.

Upvotes: 1

Related Questions