Search code examples
phpzend-framework2zend-session

object variable in session container is always getting null in bootstrap


I have implemented a logic in application module's bootstrap which will redirect users to login page if they are not signed. I have

class Module
{
    public function onBootstrap(MvcEvent $e)
    {
        $eventManager        = $e->getApplication()->getEventManager();
        $moduleRouteListener = new ModuleRouteListener();
        $moduleRouteListener->attach($eventManager);

        $session = new Container('signin');

        if (!isset($session->member)){
           $eventManager->attach(MvcEvent::EVENT_ROUTE, array($this,'routeMatched'), -100);            
        }
    }

    public function routeMatched(MvcEvent $e)
    {
        $match = $e->getRouteMatch();

        // No route match, this is a 404
        if (!$match instanceof RouteMatch) {
            return;
        }
        $list = array('login', 'signin', 'upload');
        // Route is whitelisted
        $name = $match->getMatchedRouteName();
        if (in_array($name, $list)) {
            return;
        }

        // Redirect to the user login page, as an example
        $router   = $e->getRouter();
        $url      = $router->assemble(array(), array(
            'name' => 'signin'
        ));

        $response = $e->getResponse();
        $response->getHeaders()->addHeaderLine('Location', $url);
        $response->setStatusCode(302);

        return $response;        
    }
}

As you can see below code inside onBootstrap will check if the session container doesn't have member variable set or not, if it is not set then the EVENT_ROUTE is attached which internally handles what to do depending on whether current route is a white listed or not.

        $session = new Container('signin');
        if (!isset($session->member)) ...

The problem here is that $session->member is always getting null. I am assigning this variable in the login action inside my controller like this

            if ($data->authenticate($member->email, $member->password)){
                $session = new Container('signin');
                $session->member = $member;
                return $this->redirect()->toRoute('member-control-panel');                    
            }else{
                $view->setVariable('error', 'Could not verify user/password');
            }

What is the problem here?

Update:

I made the modifications as suggested by Wilts in his answer. It still did not work but I modified the code slightly to store the scalar value (email) instead of object (member). Now it is working so the question is why session container is not storing object but only scalar variables?

In my signin action I made changes like this

                $session = new Container('signin');
                //$session->member = $member; //removed
                $session->email= $member->email; //New

In the bootstrap like this

        $session = new Container('signin');

        if (!isset($session->email)){
           $eventManager->attach(MvcEvent::EVENT_ROUTE, array($this,'routeMatched'), -100);            
        }

Solution

  • Handling sessions correctly involves much more then simply dumping your variables into a Container instance. A session cannot store objects without serializing them. It means you have to deserialize them again when resolving them from session.

    Use a SessionManager

    To help you with managing your session storage ZF2 has a SessionManager class I suggest you create a SessionManager to get control over your session variables. You can read more in the the official ZF2 docs on how to handle sessions correctly.

    You bootstrap session like this:

    use Zend\Session\SessionManager;
    use Zend\Session\Container;
    
    class Module
    {
        public function onBootstrap($event)
        {
            $eventManager        = $e->getApplication()->getEventManager();
            $moduleRouteListener = new ModuleRouteListener();
            $moduleRouteListener->attach($eventManager);
            $this->bootstrapSession($event);
        }
    
        public function bootstrapSession($e)
        {
            $session = $e->getApplication()
                         ->getServiceManager()
                         ->get('Zend\Session\SessionManager');
            $session->start();
    
            $container = new Container('signin');
        }
    }
    

    Storing doctrine entities

    If your $member is a doctrine entity I would also suggest reading the Doctrine 2 documentation on storing entities in the session