How to keep your session data
Introduction
Sometimes you need to temporarily store information per same user, which means handling his session data, in previous version of drupal it was easy and more like handling it in PHP programming, but with drupal 8, since the desire was to do everything in OOP strategy it changed.
This article will review some of the options to handle session date which are available on drupal8.
First lets remember how it was done with drupal7: using the $_SESSION in module file during the hooking implementation
In Drupal 8 there's two services to handle session data:
- use
user.private_tempstore for temporarily storing user-specific data.
- use
user.shared_tempstore
for temporarily storing non-user-specific data.
Method - Drupal Service
use: \drupal::service();
Statically calling user.private_tempstore
is simple and easy to use from just about anywhere within your application.
It is especially useful for accessing the user.private_tempstore
service from within procedural code (i.e. any hook implementation or simple function in your application).
To set temporary data:
// For "mymodule_name," any unique namespace will do. // I'd probably use "mymodule_name" most of the time. $tempstore = \Drupal::service('user.private_tempstore')->get('mymodule_name'); $tempstore->set('my_variable_name', $some_data);
To read temporary data:
$tempstore = \Drupal::service('user.private_tempstore')->get('mymodule_name'); $some_data = $tempstore->get('my_variable_name');
Method - Dependency Injection
Use Dependency Injection
Within controller or plugin classes, use dependency injection and Symfony's ContainerInterface to inject user.private_tempstore
as a dependency.
Here's how to use dependency injection in a Drupal 8 controller:
namespace Drupal\my_module; use Drupal\Core\Controller\ControllerBase; use Drupal\user\PrivateTempStoreFactory; //remark: // \Drupal\user\PrivateTempStoreFactory is deprecated since 8.5.x and // it will be removed before 9.0.0 // use \Drupal\Core\TempStore\PrivateTempStoreFactory instead. class MyModuleController extends ControllerBase { protected $tempStore; // Pass the dependency to the object constructor public function __construct(PrivateTempStoreFactory $temp_store_factory) { // For "mymodule_name," any unique namespace will do $this->tempStore = $temp_store_factory->get('mymodule_name'); } // Uses Symfony's ContainerInterface to declare dependency to be passed to constructor public static function create(ContainerInterface $container) { return new static( $container->get('user.private_tempstore') ); } // Save some temporary data public function index() { $this->tempStore->set('my_variable_name', $some_data); // Do other stuff, return a render array, etc... } // Read some temporary data public function listPage() { $visited = $this->tempStore->get('my_variable_name'); // Do other stuff, return a render array, etc... } }
Method - Session
use the session variable
// Save the data: $_SESSION['mymodule_name']['my_variable_name'] = $somedata; // Get the data: $somedata = $_SESSION['mymodule_name']['my_variable_name'];
But (and it's an important but) using Drupal 8 services provides needed abstraction and structure for interacting with a global construct. It's part of an overall architecture that allows developers to build and extend complex applications sustainably.
Private Temporary Storage <> Session Storage
PrivateTempStore and a typical user session are not the same thing.
The differences are very important though in terms of UX and security.
The PrivateTempStore persists beyond the PHP/Drupal session i.e. after explicit logout or the session lifetime.
Also it is actually shared between PHP/Drupal sessions--the same user account logged into 2 separate sessions in different browsers on different machines will be able to access and edit the same PrivateTempStore (though there is a rudimentary locking system that prevents simultaneous editing).
Stuff stored in the PrivateTempStore expires after one week, by default, and is intended for temporary storage, like progress in a multi-step form/process.
The private temporary storage differs from session storage in very significant ways and it is not intended as a replacement of it.
- For logged in users, sessions are completely irrelevant, the data stored in the temporary storage is shared among all sessions of a given user, current and future.
- Only for an anonymous user are sessions relevant: should their sessions expire, the contents is not retrievable any more because it is tied to the session ID. But the data is not stored in the session storage for anonymous users either, only the session ID is relevant.
- The data expires after a time set on the container parameter called
tempstore.expire
which has nothing to do with the session cookie lifetime (nor is the latter relevant for logged in users). - There is metadata associated with each piece of data: the owner (either the logged in user id or a session id) and the updated time.
- The durability expectations completely differ. Sessions are fundamentally ephemeral. Many places will tie sessions to IP addresses. It is certainly tied to a browser and as such, to a device. As a corollary, if clients can't expect sesssions to last, there's no reason for the server to cling to them heavily: putting the session storage on fast but less durable storage (say, memcached etc) is a completely valid speedup strategy. However, the private temporary storage is durable -- within expire, of course. A typical thing to store in a session is a "flash" message -- the one you set with
drupal_set_message
. If you set one such and then the session gets lost, oh well. Yeah, informing the user would've been nice but oh well. I certainly wouldn't expect to see a flash message follow me across browsers and devices. - In theory, a typical thing to store in the private temp storage would be a shopping cart. In practice, this is not done because a) carts, if not for the end user but for the back office are valuable, not temporary data b) when a user logs in, their session data is migrated but their private temp storage is not. Whether this is a bug is debatetable, at the time of this writeup I can't find a core issue about this. This is a possible downside. So a Views UI like complex edit is one possible use case but note the Views UI itself uses the shared temporary storage facility, not the private one. In fact, the only usage I can find are node previews.