Issue #3108967 by znerol, andypost, alexpott: Introduce a container tag to register session bags

merge-requests/2419/head
Alex Pott 2020-02-06 09:19:23 +00:00
parent b978479e86
commit d1daa7ec28
No known key found for this signature in database
GPG Key ID: 31905460D4A69276
7 changed files with 237 additions and 0 deletions

View File

@ -2605,5 +2605,29 @@ function hook_validation_constraint_alter(array &$definitions) {
* within contributed and custom code. Reserved attributes include:
* - uid: The user ID for an authenticated user. The value of this attribute
* cannot be modified.
*
* @section sec_custom_session_bags Custom session bags
* Modules can register custom session bags in order to provide type safe
* interfaces on module specific session data. A session bag must implement
* \Symfony\Component\HttpFoundation\Session\SessionBagInterface. Custom session
* bags are registered using a service entry tagged with the session_bag service
* tag. Custom session bags can be accessed through the session retrieved from
* the request object.
*
* Example service definition:
* @code
* session_test.session_bag:
* class: Drupal\session_test\Session\TestSessionBag
* tags:
* - { name: session_bag }
* @endcode
*
* Example of accessing a custom session bag:
* @code
* $bag = $request->getSession()->getBag(TestSessionBag::BAG_NAME);
* $bag->setFlag();
* @endcode
* Session data must be deleted from custom session bags as soon as it is no
* longer needed (see @ref sec_intro above).
* @}
*/

View File

@ -1512,6 +1512,8 @@ services:
session:
class: Symfony\Component\HttpFoundation\Session\Session
arguments: ['@session_manager', '@session.attribute_bag', '@session.flash_bag']
tags:
- { name: service_collector, tag: session_bag, call: registerBag }
session.flash_bag:
class: Symfony\Component\HttpFoundation\Session\Flash\FlashBag
public: false

View File

@ -131,3 +131,33 @@ session_test.set_session:
test_value: '\s+'
requirements:
_permission: 'administer site configuration'
session_test.set_bag_flag:
path: '/session-test/set-bag-flag'
defaults:
_title: 'Sets the test flag in the session test bag'
_controller: '\Drupal\session_test\Controller\SessionTestController::setSessionBagFlag'
options:
no_cache: TRUE
requirements:
_access: 'TRUE'
session_test.clear_bag_flag:
path: '/session-test/clear-bag-flag'
defaults:
_title: 'Clears the test flag in the session test bag'
_controller: '\Drupal\session_test\Controller\SessionTestController::clearSessionBagFlag'
options:
no_cache: TRUE
requirements:
_access: 'TRUE'
session_test.has_bag_flag:
path: '/session-test/has-bag-flag'
defaults:
_title: 'Prints a message if the flag in the session bag is set'
_controller: '\Drupal\session_test\Controller\SessionTestController::hasSessionBagFlag'
options:
no_cache: TRUE
requirements:
_access: 'TRUE'

View File

@ -14,3 +14,7 @@ services:
- { name: session_handler_proxy, priority: 20 }
session_test.session_handler_proxy_trace:
class: ArrayObject
session_test.session_bag:
class: Drupal\session_test\Session\TestSessionBag
tags:
- { name: session_bag }

View File

@ -3,6 +3,7 @@
namespace Drupal\session_test\Controller;
use Drupal\Core\Controller\ControllerBase;
use Drupal\session_test\Session\TestSessionBag;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
@ -195,4 +196,54 @@ class SessionTestController extends ControllerBase {
return new JsonResponse(['session' => $session->all(), 'user' => $this->currentUser()->id()]);
}
/**
* Sets the test flag in the session test bag.
*
* @param \Symfony\Component\HttpFoundation\Request $request
* The request object.
*
* @return \Symfony\Component\HttpFoundation\Response
* The response object.
*/
public function setSessionBagFlag(Request $request) {
/** @var \Drupal\session_test\Session\TestSessionBag */
$bag = $request->getSession()->getBag(TestSessionBag::BAG_NAME);
$bag->setFlag();
return new Response();
}
/**
* Clears the test flag from the session test bag.
*
* @param \Symfony\Component\HttpFoundation\Request $request
* The request object.
*
* @return \Symfony\Component\HttpFoundation\Response
* The response object.
*/
public function clearSessionBagFlag(Request $request) {
/** @var \Drupal\session_test\Session\TestSessionBag */
$bag = $request->getSession()->getBag(TestSessionBag::BAG_NAME);
$bag->clearFlag();
return new Response();
}
/**
* Prints a message if the flag in the session bag is set.
*
* @param \Symfony\Component\HttpFoundation\Request $request
* The request object.
*
* @return \Symfony\Component\HttpFoundation\Response
* The response object.
*/
public function hasSessionBagFlag(Request $request) {
/** @var \Drupal\session_test\Session\TestSessionBag */
$bag = $request->getSession()->getBag(TestSessionBag::BAG_NAME);
return new Response(empty($bag->hasFlag())
? $this->t('Flag is absent from session bag')
: $this->t('Flag is present in session bag')
);
}
}

View File

@ -0,0 +1,96 @@
<?php
namespace Drupal\session_test\Session;
use Symfony\Component\HttpFoundation\Session\SessionBagInterface;
/**
* Test session container.
*/
class TestSessionBag implements SessionBagInterface {
/**
* The bag name.
*/
const BAG_NAME = 'session_test';
/**
* Key used when persisting the session.
*
* @var string
*/
protected $storageKey;
/**
* Storage for data to save.
*
* @var array
*/
protected $attributes = [];
/**
* Constructs a new TestSessionBag object.
*
* @param string $storage_key
* The key used to store test attributes.
*/
public function __construct($storage_key = '_dp_session_test') {
$this->storageKey = $storage_key;
}
/**
* Sets the test flag.
*/
public function setFlag() {
$this->attributes['test_flag'] = TRUE;
}
/**
* Returns TRUE if the test flag is set.
*
* @return bool
* TRUE when flag is set, FALSE otherwise.
*/
public function hasFlag() {
return !empty($this->attributes['test_flag']);
}
/**
* Clears the test flag.
*/
public function clearFlag() {
unset($this->attributes['test_flag']);
}
/**
* {@inheritdoc}
*/
public function getName() {
return self::BAG_NAME;
}
/**
* {@inheritdoc}
*/
public function initialize(array &$attributes) {
$this->attributes = &$attributes;
}
/**
* {@inheritdoc}
*/
public function getStorageKey() {
return $this->storageKey;
}
/**
* {@inheritdoc}
*/
public function clear() {
$return = $this->attributes;
$this->attributes = [];
return $return;
}
}

View File

@ -295,6 +295,36 @@ class SessionTest extends BrowserTestBase {
$this->assertResponse(403, 'An empty session ID is not allowed.');
}
/**
* Test session bag.
*/
public function testSessionBag() {
$this->drupalGet('/session-test/has-bag-flag');
$this->assertSessionCookie(FALSE);
$this->assertSessionEmpty(TRUE);
$this->assertResponse(200, 'Flag is absent from session bag');
$this->drupalGet('/session-test/set-bag-flag');
$this->assertSessionCookie(TRUE);
$this->assertSessionEmpty(TRUE);
$this->assertResponse(200);
$this->drupalGet('/session-test/has-bag-flag');
$this->assertSessionCookie(TRUE);
$this->assertSessionEmpty(FALSE);
$this->assertResponse(200, 'Flag is present in session bag');
$this->drupalGet('/session-test/clear-bag-flag');
$this->assertSessionCookie(FALSE);
$this->assertSessionEmpty(FALSE);
$this->assertResponse(200);
$this->drupalGet('/session-test/has-bag-flag');
$this->assertSessionCookie(FALSE);
$this->assertSessionEmpty(TRUE);
$this->assertResponse(200, 'Flag is absent from session bag');
}
/**
* Reset the cookie file so that it refers to the specified user.
*/