Storing Session Data with Drupal 8

Justin Toupin

I recently needed to temporarily store information associated with a user's session in Drupal 8. In past versions of Drupal, I might have just thrown the data in $_SESSION. In Drupal 8 there's a service for that; actually, two services: use user.private_tempstore and user.shared_tempstore for temporarily storing user-specific and non-user-specific data, respectively.

Background Reading

If you're new to Drupal 8, there are a number of OOP principles and specific Symfony concepts worth getting to know. This post does not directly address those. Here I'll just briefly address storing temporary data (aka writing to $_SESSION). For more background, the following are a few good resources about OOP, dependency injection and services in Drupal 8 (or skip ahead directly to writing $_SESSION variables in Drupal 8):

Method One: 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 Two: 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;
 
 
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...
  }
 
}

For a real life example of a Drupal 8 class that uses dependency injection, check out \Drupal\user\Form\UserMultipleCancelConfirm in Drupal core.

Both methods are roughly equivalent to:

// 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.


About the Author

Justin is CEO and founding partner at Aten. He started the company back in 2000 with a passion for technology and communications, a desire to do meaningful work, and an aspiration to help build a place where people love what they do.

Read More