Update session variable on page load

In my PagesController, I write a few session and config variables, depending on which page the user is on. The config values come from my app_local.php file. The module session variable controls some menu items and a few other background settings. Here’s an example:

    $session = $this->getRequest()->getSession();
    if ($page == 'nc' && Configure::read('NC.installed')) { 
        $session->write('module', 'nc');
        $modname = Configure::read('headertitle') . ": " . Configure::read('NC.name') . " Module";
        Configure::write('headertitle', $modname); 
    } else if ($page == 'pm' && Configure::read('PM.installed')) {
        $session->write('module', 'pm');
        $modname = Configure::read('headertitle') . ": " . Configure::read('PM.name') . " Module";
        Configure::write('headertitle', $modname);

… and so on for each module installed in my project. The menu system is loaded from my AppController and relies on the current value of module to correctly load menu items.

Problem: When the user moves between pages in my project, the module variable only refreshes if the page is refreshed manually. For example: If the current value of module is nc and I navigate to pm, I want the value of module to update from nc to pm when the page loads, but it remains at nc until I do a manual refresh. After that, my menus display properly. Can I force a refresh of the module session variable upon page load?

So if you simply navigate from one page to another, the module is not changed?

That sounds like it might be a problem caused by the browser caching your page (or part of it) and not bothering with an actual request?

I’m out of my depth here so this is just guess work and speculation.

If it is true, aren’t there headers on the page that can effect browser caching-behavior? The Pages controller is designed for the delivery of ‘static’ pages and it may be setting some header telling the browser to use cached data if it is available.

If that is the case, then finding a way to fix this header, or delivering your pages through a different controller might solve the problem.

When I go from one page to another, things like the headertitle (which is configured via Configure::write in app_local and read by PagesController) change correctly, but yeah, the module session variable does not update without a refresh. Oddly, if I move my menu logic (a private setMenu() function) into PagesController, then module does update correctly. But that causes other issues in my app, like the menubar not appearing on any page not served directly by PagesController, so I haven’t pursued that as a solution yet. Header manipulation might be the way to go. In my pre-framework days, I did a lot of that.

It seems an odd detail that PagesController can see it when it is external but other controllers cannot. Is it possible access to that method is playing a part?

Changing it from private to protected or public could reveal if that is a factor.

I’m just spitballing and may not be thinking clearly :slight_smile:

I’m confused about the distinction you’re drawing between “navigate to” and “manually refresh”. Both of those terms mean, to me, that you are loading the page in your browser. The latter is just loading the same page that you’re already on instead of loading a different page. If this is right, then I’d guess that it’s some sort of order-of-operations issue, where some code is incorrectly running before you update your session.

When I click on a menu item in my project, a page loads. The value of session variable module associated with that page should update when the page loads. Instead, I have to refresh the page to get the session variable to update.

For example:

  1. I log into my site and start a new session. Default value of module is all.
  2. I click on a menu item, such as ‘ML Module.’ Expected behavior is that the value of module will change to ‘ml’, but it doesn’t. If I refresh the ‘ML Module’ page, then the value of module changes to ‘ml’.

I’m trying to figure out why a refresh is necessary. The value of module is written in the PagesController, and apart from the refresh, is doing what it’s supposed to do.

You have shown very little context around your code. My guess is still that what’s happening is that the stuff (menus?) that is generated based on the session value is happening before your code for updating the session runs.

So, it’s not the refresh that’s making it update, it’s that it gets updated after you use it, so that the visible effects you’re expecting don’t show up until the next page load.

Try adding some output or logging in both locations and see what order it’s happening in.

1 Like

Maybe this will help: I did some further debugging, and it turns out that the module variable is updating in my PagesController, but the update is not reflected in my AppController.

When I debug module in both controllers, I get two different values, unless I refresh the page. Here’s the workflow:

// Set in PagesController via $session->write() 
// Value changes whenever I click on a different menu item; 'ml' given as example
$module = $session->write('module', 'ml');  

// setMenu() called in beforeFilter of AppController
$this->setMenu();   

// 'module' session variable read in AppController::setMenu();
$module = $session->read('module');

// value of 'module' used in $conditions to make sure proper menu options load
$conditions = ['OR' => [
            ['group_prefix' => 'all'], 
            ['module' => $module],
        ]];    

Result of debugging ‘module’ in both controllers, after I have left ‘doc’ page and loaded ‘ml’ page:

 APP/Controller/AppController.php (line 176)
'doc'

APP/Controller/PagesController.php (line 112)
'ml'

The value of module in AppController is the module I was in before I clicked on ‘doc’ in my menu. Once I have the ‘doc’ page displayed, I have to refresh the page in order for the value of module to update to ‘doc’. I had assumed that, since module is a session variable, it would update across my app as it changed. So what I need is for it to update in my AppController at the same time it updates in my PagesController. But I’m guessing it updates in the latter correctly because it’s actually written there?

I would say @Zuluru was right when he suggested

beforeFilter() is too early to look at the session. It runs during Controller initialization.

Try the later running event beforeRender().

1 Like

Thanks. That was the missing link. It’s working now.

Oddly, I’d tried using beforeRender() earlier and got a boatload of error messages back when I tried to load my menu. I’ll comb through my commits to see what I misconfigured back then so I don’t do it again.

Thanks, both of you!