1

I'm trying to make the $_SESSION global available within the controllers of my framework written from scratch. It's not quite MVC, the presentation layer consists of two parent classes with multiple child classes.

Without going into great detail, my views are rendered in class Template

class Template{

    protected $_controller;
    protected $_action;

    function __construct($controller,$action) {
        $this->_controller = $controller;
        $this->_action = $action;
    }

    function render(){
        if (file_exists(APP_ROOT . DS . 'app' . DS . 'view' . DS . $this->_controller . DS . $this->_action . '.php')) {
            include (APP_ROOT . DS . 'app' . DS . 'view' . DS . $this->_controller . DS . $this->_action . '.php');
        }
    }

}

Then I'm calling Template::render() in a destructor within my parent controller after instantiating class Template within a constructor. All classes are being autoloaded.

class CoreController {

    protected $_controller;
    protected $_action;
    protected $_template;

    function __construct($controller, $action) {
        $this->_controller = ucfirst($controller);
        $this->_action = $action;

        $this->_template = new Template($controller,$action);
    }

    function __destruct() {
        $this->_template->render();
    }
} 

My question is how can I make $_SESSION available in CoreController and when exactly is it available during the shutdown sequence? I've tried calling it directly in CoreController as well as within Template::render() and always get undefined variable warnings, however defining $_SESSION within my views works. The reasoning behind this is I would like to set certain variables based off of whether or not the session id is set and I'd like to keep most presentation logic within my controllers. Thanks in advance.

dcd0181
  • 1,493
  • 4
  • 29
  • 52
  • Just call session_start during bootstrap phase of the process and you should be able to get at it over the life of the request – Orangepill May 20 '13 at 12:55
  • Your suggestion works great, thanks again! your server tip the other day was a lifesaver. I wonder if I should do what teresko suggested and use it within the model layer, that would probably involve sending it through the dispatcher which seems like a better approach if I were being picky. – dcd0181 May 20 '13 at 13:26
  • IMHO it belongs in the controller. If you put it in the modal you are creating a dependency between the modal and use pattern that requires session, so utilizing the modal say in a from script wouldn't be possible. – Orangepill May 20 '13 at 13:32
  • @Orangepill, so, just because you do not want to abstract superglobal, you decide to destroy SoC? – tereško May 20 '13 at 13:38
  • 2
    `$_SESSION` is a superglobal, so it is available *everywhere*. And for the shutdown phase, superglobals are killed within, sessions sometime in there closed. There is a nice talk by Johannes Schlüter, see [PHP Shutdown Sequence](https://www.youtube.com/watch?feature=player_detailpage&v=bxxIXPc9IR8#t=1558s) ca. 25:50 – hakre May 20 '13 at 13:55
  • @teresko My proposal was to favor a usage pattern like `$modalObject->performAction($_SESSION["var"])` in the controller over accessing directly the $_SESSION from within the modal. My method decouples the `$_SESSION` superglobal from the modal layer, which is in the spirit of SoC. – Orangepill May 20 '13 at 14:20
  • @tereško reread your comment above. Abstraction of the session concept would be the best approach, I was just trying to steer @dcd018 away from littering his modal with `$_SESSION` calls. Moving the SESSION dependencies to the controller is better then that but your way is the right way so long as the implementation allows for sourcing the session data from somewhere other then the `$_SESSION` superglobal. +1 – Orangepill May 20 '13 at 14:35

1 Answers1

3

Session is a form of storage. Which means, that it should only be used deep within model layer.

Manipulating $_SESSION in presentation layer would be comparable with wring SQL in controllers and/or views. You would be eliminating the last vestiges of SoC ... though you have been already at it by implementing the Rails like "ViewController" monstrosity.

Instead of leaking your storage logic in the presentation layer, you should be using similar mappers like for the sql.

from some service in model layer

public function identify( $parameters )
{

    $user = $this->domainObjectFacctory->create('user');
    $mapper = $this->mapperFactory->create('session');

    if ( $mapper->fetch($user, 'uid') === false )
    {
        $mapper = $this->mapperFactory->create('user');
        $user->setUsername($parameters['login']);
        $user->setPassword($parameters['pass']);

        $mapper->fetch($user);
    }

    $this->currentUser = $user->isValid()
                       ? $user
                       : null;
}

The controller only interacts with services

public function postLogin( $request )
{
    $auth = $this->serviceFactory->create('recognition');
    $auth->identify([
        'login' => $request->getParameter('username'),
        'pass'  => $request->getParameter('password'),
        ]);
}

The service factory would be injected in the controller's (and the accompanying view's) constructor.

Note: the code above is only to illustrate the point and should not be copy-pasted or otherwise grafted on a production code.

Community
  • 1
  • 1
tereško
  • 58,060
  • 25
  • 98
  • 150
  • Thanks for the suggestion, what's the best way to handle this? I was thinking defining $_SESSION within the dispatcher than calling it within the parent model construct. – dcd0181 May 20 '13 at 13:27
  • The initialization of session object (the abstraction for `$_SESSION` usperglobal) should be done in the factory, that creates the [data mappers](http://martinfowler.com/eaaCatalog/dataMapper.html) for the services. The same factory would also ensure that the session object is only created once, without need for singletons or other bad practices. – tereško May 20 '13 at 13:46
  • Ok so from this perspective if I understand, initialize $_SESSION in memory then interact with it through the presentation layer, forgive the shorthand. Seems like the most logical approach. – dcd0181 May 20 '13 at 13:54