I have to bother you quickly with a little issue of serialization. When a
user logs in, the User entity is stored in the session. For this to work,
PHP serializes the User object to a string at the end of the request and
stores it. At the beginning of the request, that string is unserialized and
turned back into the User object.

Note

If you’re feeling really curious, the class that serializes and deserializes
the user information is called ContextListener.

This is great! And it’s obviously working great - we’re surfing around as
Wayne the admin. But there’s a “gotcha” in Doctrine. Sometimes, Doctrine will stick
some extra information onto our entity, like the entity manager: that big
important object we used to save things.

Normally, we don’t care about this, but when the User object is serialized,
having that big object hidden in our entity causes serialization to fail.
The entity manager contains a database connection and other information that
just can’t be serialized.

When the User object is serialized, it’ll call the serialize method
instead of trying to do it automatically. When the string is deserialized,
the unserialize method is called. This may seem odd, but let’s just return
the id, username and password inside an array for serialize.
For unserialize, just put those 3 values back on the object:

If you think about it, this should kinda break everything. When Symfony
gets the User object from the session and deserializes it, our User
will have lost some of its data, like roles and isActive. That’s
not cool!

Clearly that’s not the case: Symfony’s security system is smart enough to
take the id and query for a full fresh copy of the User object on each
request.

We can see this right in the web debug toolbar: once a user is logged in,
each request has a query that grabs the current user from the database.
So, we’re good!

Leave a comment!

Hmm, this looks weird to me - especially because it's random :/. At the end of every request, your User object is serialized to the session (actually, a "token" object is serialized to the session, and this contains your User - but effectively, your User is serialized to the session). Then, at the beginning of the next request, it's deserialized. This error is coming from the line that deserializes the User.

This is super weird - and makes me wonder if your specific PHP version might have a bug in it that's causing this. It basically looks like the serialized user data becomes corrupted, or PHP thinks it's corrupted for some reason.

Yes, this is effectively where the problems start indeed. It's with proxies - the magic way that `$user->getEvents()` is able to work (since in reality, the whole giant Entity manager is inject into User, that can't be serialized, etc etc etc).

It's a big unfortunate side effect of the Doctrine magic. But I don't think that Doctrine can fix it. For them - it's a feature (and they're right). I would love a "smoother" path around this problem, but I can't think of anything...

Cheers!

2015-07-15Richard

Hi Ryan, Doesn't the serialization problem starts when you point the entity Event to the entity User (I mean, when you give them the one-to-many relationship)? Maybe the "Symfony2 Security Manager" doesn't like that.I would like to know, because otherwise the elderlies of Doctrine should fix this.

2015-04-19Łukasz Zaroda

Duh, I sit down to this just now and instantly found out a rouge piece of code in my controller, I had to be literally blind to miss this.

So the first query was an authentication and second was this. I'm embarassed, too sleepy then I guess, but wanted to close this case :) . Thanks for this amazing tutorial, it is what literally allows me to start with symfony2.

2015-04-13weaverryan

Hey Łukasz!Ah, the controller! That's very interesting! Are you doing a security check? And if so, if you remove it, does the extra query go away? If there is a security check, and removing it removes the extra query, then the cause *is* related to Symfony's security system not properly seeing your user as non-refreshed. Let me know what you find.

Cheers!

2015-04-12Łukasz Zaroda

It didn't make it go away. http://i.imgbox.com/gSkc6SR... This is my timeline, it happens during executing controllers as you can see. I'm too sleepy right now (it's about midnight here), but if I will find some time I can try to debug internals for this, to know what is actually happening. :)

2015-04-12weaverryan

Hmm, I'm not sure then. I'm guessing if you check the timeline of the profiler, you'll see bot queries (their 2 little bars) show up way before your controller, probably during the Firewall listener. That would prove that it's an issue with "refreshing" the user.

Another thing you can try: implement EquatableInterface in your User, and just return true. This is related to the "refreshing" step - Symfony tries to see if your user has been modified, and if you implement this interface, it'll call this method, instead of trying to compare certain fields in the serialized user with the one your queried for. If *this* makes the query go away, then we know the issue is related to the user refresh. If the query remains, then we will definitely know my theory is wrong :). And then the next question would be - where does the second query show up during the timeline?

Cheers!

2015-04-12Łukasz Zaroda

Unfortunately, it doesn't seem to be related to custom serialization, as even when I remove "Serialization" interface - the extra query is still there. When I added as serialized, one by one, the rest of fields - the problem also persisted. I'm using the 2.6.5 version of Symfony2. :)

2015-04-12weaverryan

Hey Łukasz!

I don't know immediately, but maybe we can figure it out :). I recognize the first as the query Symfony runs early when it's trying to "refresh" the user (i.e. take the user "id" stored in the session, and query for a new one). The second query is interesting, it's the one that *we* wrote that should be used on initial login - where it queries for username OR email. There is some weird behavior/a bug in Symfony, that I bet this might be hitting (btw, I can't repeat this behavior locally on my version of this project, which uses an older Symfony - 2.4.2). Specifically, the first query works, but the user appears "modified", which causes a second query. If I'm right, then the extra query will go away when/if you add the AdvancedUserInterface fields your serialize and unserialize methods. For us, specifically, we need to add isActive (just like we do in the docs here: http://symfony.com/doc/curr....

I believe that should fix it - but let me know :). Basically, without these fields, the user looks like it is not quite the same one between requests, and does the extra query. It honestly needs to be handled a little better in the Symfony core - it's been on my list for awhile.

Cheers!

2015-04-12Łukasz Zaroda

Hmm, anyone have any idea why after login there run TWO queries, fetching our user? I mean:

"SELECT t0.id AS id1, t0.username AS username2, t0.email AS email3, t0.password AS password4, t0.roles AS roles5, t0.isActive AS isActive6 FROM yoda_user t0 WHERE t0.id = 7"

AND:

"SELECT y0_.id AS id0, y0_.username AS username1, y0_.email AS email2, y0_.password AS password3, y0_.roles AS roles4, y0_.isActive AS isActive5 FROM yoda_user y0_ WHERE y0_.username = 'darth@deathstar.com' OR y0_.email ='darth@deathstar.com'"

Both queries are basically always return the same things. Any ideas? :)

2015-03-26Dizzy Bryan High

Found the issue, i'd used phpstorm to override the methods, but had initially inserted into the wrong place, i had deleted the functions but had missed out deleting the annotations so i had:

1) You should serialize the password, username salt AND all the values from the AdvancedUserInterface (isEnabled, isAccountNonExpired, etc). I'm not showing this exactly in the tutorial, and it causes this weird behavior. But it's not a big deal.

2) When Symfony loads, it checks to see if the user in the session "has changed". I won't go into details why (it's complex and I'm not sure I totally understand it). If It *has* changed (meaning any of the properties in (1) are different... or you didn't serialize one of them, so things look different), then the user becomes "not authenticated".

3) A few parts in Symfony - one of them being the part executes the `access_control` areas - re-authenticate the user if the user looks "not authenticated". This makes everything "green" and ok again.

So what you're seeing is a cause of not serializing all the fields in (1) and an idiosyncrasy of Symfony. But, as far as I know (and I've seen a lot of Symfony sites), it's harmless, and it's probably something we should fix in core. The takeaway is to (a) add the extra fields to serialize in (1) and (b) not worry about it :).

Cheers!

2015-03-10two_mart_toe

To add, authenticated green and yes only appears for the paths defined in access_control

2015-03-10two_mart_toe

I have the same problem. Strange. If i add $is_active = true, no problem. If it's just $is_active; (in the user model) then I get the yellow, logged in ok, authenticated no. Some voodoo is going on here. I dont think removing access control is the answer

2015-01-23Diego Aguiar

Actually you are right! I just removed my access_control entirely, cleared cache and tried again. It worked

I don't know what were causing it, but anyway thanks for your help ;]

2015-01-23weaverryan

Hey Diego!

That's odd! It doesn't make sense to me .... Usually, "Authenticated: No" happens only when you have a firewall that doesn't cover the URL that you're going to. Adding the `access_control` shouldn't make a difference. Did you have any other `access_control` entries?

But overall, I wouldn't worry about it - this seems like one of those times when something is *barely* wrong, and you might sink a lot of time into finding out what it is, only to find out it was some silly configuration issue. If it works, cool :).

Cheers!

2015-01-23Diego Aguiar

Oh God!

You need to specify this in order to get Authenticated no matter what.