Get in touch
Sessions are used to save informations that are bound to the current website user. In most cases this informations can be transient - meaning they are only relevant for the time where the user visits the website.
A typical example is something like a Basket or informations about the current Marketingcampaign for the visitor.
Therefore in most cases the Session is a relevant concept for your Domain. Imagine a simple BasketController, you may want to use something like this:
class BasketController {
...
public function addItemAction(Product $product) {
$basket = $this->userSession->getBasket();
$basket->addItemByProduct($product);
$this->userSession->saveBasket($basket);
}
}
If you have a look at the attached UML scetch: That means there is a Session Class in the Domain Layer of your application, that should be of scope singleton and defines a well defined Interface for your Domain. (In this example to get the basket Instance, that acts as Aggregate Root for the Items in the basket).
For the actual storage of the Objects in the Session the Persitence Implementation is part of your applications system Layer. Here you can find a sample SessionStorage Implementation that works for TYPO3 4.x:
class Tx_Extkey_System_Session_SessionStorage implements t3lib_Singleton {
const SESSIONNAMESPACE = 'tx_extkey';
/**
* Returns the object stored in the user´s session
* @param string $key
* @return Object the stored object
*/
public function get($key) {
$sessionData = $this->getFrontendUser()->getKey('ses', self::SESSIONNAMESPACE.$key);
if ($sessionData == '') {
throw new LogicException('No value for key found in session '.$key);
}
return $sessionData;
}
/**
* checks if object is stored in the user´s session
* @param string $key
* @return boolean
*/
public function has($key) {
$sessionData = $this->getFrontendUser()->getKey('ses', self::SESSIONNAMESPACE.$key);
if ($sessionData == '') {
return false;
}
return true;
}
/**
* Writes something to storage
* @param string $key
* @param string $value
* @return void
*/
public function set($key,$value) {
$this->getFrontendUser()->setKey('ses', self::SESSIONNAMESPACE.$key, $value);
$this->getFrontendUser()->storeSessionData();
}
/**
* Writes a object to the session if the key is empty it used the classname
* @param object $object
* @param string $key
* @return void
*/
public function storeObject($object,$key=null) {
if (is_null($key)) {
$key = get_class($object);
}
return $this->set($key,serialize($object));
}
/**
* Writes something to storage
* @param string $key
* @return object
*/
public function getObject($key) {
return unserialize($this->get($key));
}
/**
* Cleans up the session: removes the stored object from the PHP session
* @param string $key
* @return void
*/
public function clean($key) {
$this->getFrontendUser()->setKey('ses', self::SESSIONNAMESPACE.$key, NULL);
$this->getFrontendUser()->storeSessionData();
}
/**
* Gets a frontend user which is taken from the global registry or as fallback from TSFE->fe_user.
*
* @return ux_tslib_feUserAuth The current extended frontend user object
* @throws LogicException
*/
protected function getFrontendUser() {
if ($GLOBALS ['TSFE']->fe_user) {
return $GLOBALS ['TSFE']->fe_user;
}
throw new LogicException ( 'No Frontentuser found in session!' );
}
}
And finally this is the sample code for the UserSession Class:
class Tx_Extkey_Domain_UserSession implements t3lib_Singleton {
/**
* @var Tx_Extkey_System_Session_SessionStorage
*/
private $sessionStorage;
...
public function __construct(Tx_Extkey_System_Session_SessionStorage $sessionStorage) {
$this->sessionStorage = $sessionStorage;
}
public function getBasket() {
if ($this->sessionStorage->has('Basket')) {
return $this->sessionStorage->getObject('Basket');
}
else {
return $this->objectManager->create('Basket');
}
}
public function saveBasket(Basket $basket) {
$this->sessionStorage->storeObject($basket);
}
}
The objects are stored in the User Session as serialized string. This can cause several problems:
Thats where you need to think what data should be stored in your serialized objects. PHP5 gives you the possibility to clean up with your data in the __sleep method and to reconstitute them in the __wakeup method. This is where you:
Dependency Injection
There are two ways of injecting objects after deserialization:
public function getBasket() {
if ($this->sessionStorage->has('Basket')) {
$basket = $this->sessionStorage->getObject('Basket');
$basket->injectSomeThing($this->objectManager->get('Something'));
}
else {
return $this->objectManager->create('Basket');
}
}
Well in FLOW3 you don't need to deal with a "SessionStorage" Implementation and think about __sleep and __wakeup... this is all handled by the Framework and the @scope session annotation.
See Roberts Post about this:
robertlemke.de/blog/posts/2010/08/19/session-handling-and-object-serialization