Last night I worked on FLOW3's Object Serializer - it didn't detect recursions in the references of the object tree to be serialized. That's a good opportunity for me to give some insight into FLOW3's session and object serialization capabilities.
In a plain PHP script it's quite easy to store data in a session - all you need to do is starting a session with session_start() and store any data in the super-global $_SESSION. There are, however, limitations to this approach. Circular references in the object tree can become a problem and mechanisms like Dependency Injection or the special approach we take for persisting objects are, of course, not supported by PHP's built-in functions.
Consider the following domain model:
/** * @scope prototype */ class Order { /** * @var integer */ protected $orderNumber; /** * @var \F3\MyApp\Domain\Model\Recipient */ protected $recipient; /** * @var \F3\MyApp\Domain\Model\Article */ protected $article; /** * @inject * @var \F3\MyApp\Domain\Service\OrderNumberGeneratorService */ protected $orderNumberGenerator; /** * Constructs a new order */ public function __construct() { $this->orderNumber = $this->orderNumberGenerator->generate(); } /** * @param \F3\MyApp\Domain\Model\Recipient $recipient * @return void */ public function setRecipient(\F3\MyApp\Domain\Model\Recipient $recipient) { $recipient->addOrder($this); $this->recipient = $recipient; } ... }
There are some challenges you need to take in order to store an instance of this Order class in your session:
- the OrderNumberGeneratorService is a (singleton-scoped) service, injected by the object manager and thus doesn't need to and should not be stored in the session
- on reconstituting data from the session on the next request, we need to re-inject all dependencies which were not persisted
- the Order has a reference to the Recipient which in turn has (for demo purposes) a reference to all its orders - a circular reference
- the Article should not be stored in the session but instead FLOW3 should store the uuid of the already persisted article
- because FLOW3 manages objects centrally, almost all instances are somehow connected to eachother - trying to serialize one of them would serialize all objects in the system
FLOW3 solves these challenges for you - all you need to do is attaching the Order to some object which has a session scope:
/** * @scope session */ class ShoppingSession { /** * @var \F3\MyApp\Domain\Model\Order */ protected $order; /** * @param \F3\MyApp\Domain\Model\Order $order */ public function setOrder(\F3\MyApp\Domain\Model\Order $order) { $this->order = $order; } }
Storing the Order in the ShoppingSession is now a matter of two lines of code:
$shoppingSession = $this->objectManager->get('F3\MyApp\Domain\Service\ShoppingSession'); $shoppingSession->setOrder($order);Of course you can also use Dependency Injection for the retrieval of the ShoppingSession. At the end of the request, FLOW3 analyzes the data attached to session objects. The ObjectSerializer, which is in charge of serializing the object trees, detects that theOrderNumberGeneratorService is of scope Singleton and has been injected - therefore it's omitted during the serialization. At the beginning of the next request, FLOW3 makes sure to re-inject all dependencies which have not been stored in the session data. Because or recipient is declared as an @entity and already exists in the RecipientRepository (i.e. it's not new and has not been modified during the request), it's sufficient to store the object's UUID instead of the whole data. FLOW3's ObjectSerializer automatically creates a reference to the persisted Recipient object. As a consequence, changes to the Recipient data made by someone else will be visible on the next request, because our session doesn't contain the actual Recipient data - only a reference.
Finally if you want to explicitly omit the serialization of certain properties which otherwise would be stored in the session, you can tag them by a "@transient" annotation:
/** * @var sometype * @transient */ protected $propertyWhichShouldNotBeStored;
Anything else you'd like to see in FLOW3's session handling?
Thorsten | 13.02.2012
Hi Robert,
with an eye on the Tx_Extbase_MVC_Controller_FlashMessages class, I tried to implenent this to my controller (via inject, but also tried objectManager->get). At the next reuquest the stored data was not accessible, meaning not stored. When trying to save it with setAndSaveSessionData it works fine, but this is independent of the session scope. Have there been any changes recently? Or might I be missing a major point?
Best,
Thorsten
Thomas | 24.10.2010
Didn't knew about the scope session. Really saved my day.
Thanks for the article.
Greetings,
Thomas
ND | 26.06.2015
Hi Robert,
session scope is great. Will this be part of any future TYPO3 / Extbase version as well? As far as i can see, something like session scope is missing in Extbse 6.2 :(
Greetings, ND
ND | 26.06.2015
Hi Robert,
session scope is great. Will this be part of any future TYPO3 / Extbase version as well? As far as i can see, something like session scope is missing in Extbse 6.2 :(
Greetings, ND
ND | 26.06.2015
Hi Robert,
session scope is great. Will this be part of any future TYPO3 / Extbase version as well? As far as i can see, something like session scope is missing in Extbse 6.2 :(
Greetings, ND
ND | 26.06.2015
...sorry for the triple-comment ;)
ND | 01.10.2019
Thanks for this article. When will @session scope be part of TYPO3 core?