Caching Data When Session Starts

digitalpoint

Well-known member
I was poking around the XenForo_Session class and didn't see a way to extend it (maybe I missed it)?

What I'm trying to do is store some data about a user that we collect in cache (part of that data is output on every page they view). The data itself changes rarely (never more than hourly), so it seems like a waste to add a query to every page view to fetch it.

A couple ideas...
  • JOIN in the data when we get the user data every page view via User_Model
  • Not all users have the data (it's optional for them), so we can't read it from cache, and populate it if it's not there unless you started caching "dummy" entries... like "false" for people without data.

Not really excited about JOINing the user query run on every page because it would add two JOINs, and like I said... the data never changes more than hourly.

Also not terribly excited about tossing in thousands of cache entries with null data.

It would be nice if there was a way we could extend the XenForo_Session class so we could read the data into cache (or maybe even just store it in the session itself) when the session is first initialized, and then since we are the ones handling the data changing once in awhile, we could handle the updating of it in the cache/session when it's updated.

Anyone have any better ideas?
 
What I've done is extend the XenForo_Model_User::getUserById() method (using the standard class extension xfcp).
Then what you can do is:
Code:
$userData = parent::getUserById($userId, $fetchOptions);
if ( $userData ) {
    if ( XenForo_Application::isRegistered('session') ) {
        $session = XenForo_Application::getSession();
        if ( $session && $session->get('user_id') == $userId ) {
            // IF !$session->isRegistered('myField');
            // Load extra data, queries or whatever
            // $session->set('myField', 'myValue');
            // $session->save();
        }
    }
}
Once the field is set in the session you don't have to run it again on every page load, it should just be there for you to use.

Another way would be to make it part of the visitor_setup code event. Similar set of checks so that you don't process if it's already part of the session (or visitor) and then assign it to the session. Watch out for in this case where it is possible for the visitor_setup event to be fired off more than once per page view.
 
Yeah, that would definitely work, but it's also something I was trying to avoid. Since the extra data is optional, it's not going to be there for all users... and *ideally* didn't want to check if the field is there every page view. Of course, I could set the field to something like "false" for users that don't have the data (just so we know we've already tried to load it into the session). But it's probably the route I'm going to have to take until someday we get a load_class_session event listener. :)
 
So long as you set it to the session it doesn't cost you anything to check if it's there or not. Only that one time you load it and if you're using something like memcached to cache the db queries even that cost is extremely low.

+1 for the load_class_session event listener :)
 
I finally got some time to start on this... and hopefully will finish it up tomorrow.

Just FYI in case it helps others, I ended up making the code that checks if it exists in the session into a controller_pre_dispatch listener. The reason being is the sessions are protected from being saved/edited after they are initially saved, so needed to be able to $session->set() stuff before $session->save() is called normally.

I haven't yet done the part that updates the data hourly via an AJAX request, but it looks like it shouldn't be too hard to do with the $session->regenerate() function.
 
Not sure what I was thinking with the $session->regenerate()... don't need to do that since controller_pre_dispatch passes $action... so I can just do a normal $session->set() if the $action is my AJAX request.

Either way, the guts seem to be working now... just need to clean up some UI stuff now.
 
Top Bottom