diff --git a/components/http_foundation.rst b/components/http_foundation.rst index 23d8e9a6809..e00f9dabb7b 100644 --- a/components/http_foundation.rst +++ b/components/http_foundation.rst @@ -247,7 +247,8 @@ Accessing the Session ~~~~~~~~~~~~~~~~~~~~~ If you have a session attached to the request, you can access it via the -:method:`Symfony\\Component\\HttpFoundation\\Request::getSession` method; +:method:`Symfony\\Component\\HttpFoundation\\Request::getSession` method or the +:method:`Symfony\\Component\\HttpFoundation\\RequestStack::getSession` method; the :method:`Symfony\\Component\\HttpFoundation\\Request::hasPreviousSession` method tells you if the request contains a session which was started in one of diff --git a/controller.rst b/controller.rst index 212d0a2b509..a5017452832 100644 --- a/controller.rst +++ b/controller.rst @@ -394,7 +394,7 @@ Request object. Managing the Session -------------------- -Symfony provides a session service that you can use to store information +Symfony provides a session object that you can use to store information about the user between requests. Session is enabled by default, but will only be started if you read or write from it. diff --git a/logging/processors.rst b/logging/processors.rst index 8ba965327b2..c0a3eb33bbf 100644 --- a/logging/processors.rst +++ b/logging/processors.rst @@ -19,30 +19,33 @@ using a processor:: // src/Logger/SessionRequestProcessor.php namespace App\Logger; - use Symfony\Component\HttpFoundation\Session\SessionInterface; + use Symfony\Component\HttpFoundation\Exception\SessionNotFoundException; + use Symfony\Component\HttpFoundation\RequestStack; class SessionRequestProcessor { - private $session; - private $sessionId; + private $requestStack; - public function __construct(SessionInterface $session) + public function __construct(RequestStack $requestStack) { - $this->session = $session; + $this->requestStack = $requestStack; } // this method is called for each log record; optimize it to not hurt performance public function __invoke(array $record) { - if (!$this->session->isStarted()) { + try { + $session = $requestStack->getSession(); + } catch (SessionNotFoundException $e) { + return; + } + if (!$session->isStarted()) { return $record; } - if (!$this->sessionId) { - $this->sessionId = substr($this->session->getId(), 0, 8) ?: '????????'; - } + $sessionId = substr($session->getId(), 0, 8) ?: '????????'; - $record['extra']['token'] = $this->sessionId.'-'.substr(uniqid('', true), -8); + $record['extra']['token'] = $sessionId.'-'.substr(uniqid('', true), -8); return $record; } diff --git a/quick_tour/the_architecture.rst b/quick_tour/the_architecture.rst index d88bb5d32ed..e3b388a0bc4 100644 --- a/quick_tour/the_architecture.rst +++ b/quick_tour/the_architecture.rst @@ -72,9 +72,6 @@ What other possible classes or interfaces could you use? Find out by running: Request stack that controls the lifecycle of requests. Symfony\Component\HttpFoundation\RequestStack (request_stack) - Interface for the session. - Symfony\Component\HttpFoundation\Session\SessionInterface (session) - RouterInterface is the interface that all Router classes must implement. Symfony\Component\Routing\RouterInterface (router.default) diff --git a/security/access_denied_handler.rst b/security/access_denied_handler.rst index 42ee7fe5dd9..2a7566fafed 100644 --- a/security/access_denied_handler.rst +++ b/security/access_denied_handler.rst @@ -28,7 +28,6 @@ unauthenticated user tries to access a protected resource:: use Symfony\Component\HttpFoundation\RedirectResponse; use Symfony\Component\HttpFoundation\Request; - use Symfony\Component\HttpFoundation\Session\SessionInterface; use Symfony\Component\Routing\Generator\UrlGeneratorInterface; use Symfony\Component\Security\Core\Exception\AuthenticationException; use Symfony\Component\Security\Http\EntryPoint\AuthenticationEntryPointInterface; @@ -36,18 +35,16 @@ unauthenticated user tries to access a protected resource:: class AuthenticationEntryPoint implements AuthenticationEntryPointInterface { private $urlGenerator; - private $session; - public function __construct(UrlGeneratorInterface $urlGenerator, SessionInterface $session) + public function __construct(UrlGeneratorInterface $urlGenerator) { $this->urlGenerator = $urlGenerator; - $this->session = $session; } public function start(Request $request, AuthenticationException $authException = null): RedirectResponse { // add a custom flash message and redirect to the login page - $this->session->getFlashBag()->add('note', 'You have to login in order to access this page.'); + $request->getSession()->getFlashBag()->add('note', 'You have to login in order to access this page.'); return new RedirectResponse($this->urlGenerator->generate('security_login')); } diff --git a/security/form_login_setup.rst b/security/form_login_setup.rst index c7ea359c459..1d269eba380 100644 --- a/security/form_login_setup.rst +++ b/security/form_login_setup.rst @@ -477,7 +477,6 @@ whenever the user browses a page:: namespace App\EventSubscriber; use Symfony\Component\EventDispatcher\EventSubscriberInterface; - use Symfony\Component\HttpFoundation\Session\SessionInterface; use Symfony\Component\HttpKernel\Event\RequestEvent; use Symfony\Component\HttpKernel\KernelEvents; use Symfony\Component\Security\Http\Util\TargetPathTrait; @@ -486,13 +485,6 @@ whenever the user browses a page:: { use TargetPathTrait; - private $session; - - public function __construct(SessionInterface $session) - { - $this->session = $session; - } - public function onKernelRequest(RequestEvent $event): void { $request = $event->getRequest(); @@ -504,7 +496,7 @@ whenever the user browses a page:: return; } - $this->saveTargetPath($this->session, 'main', $request->getUri()); + $this->saveTargetPath($request->getSession(), 'main', $request->getUri()); } public static function getSubscribedEvents() diff --git a/service_container.rst b/service_container.rst index e3db328033b..98fb5e61318 100644 --- a/service_container.rst +++ b/service_container.rst @@ -62,9 +62,6 @@ What other services are available? Find out by running: Request stack that controls the lifecycle of requests. Symfony\Component\HttpFoundation\RequestStack (request_stack) - Interface for the session. - Symfony\Component\HttpFoundation\Session\SessionInterface (session) - RouterInterface is the interface that all Router classes must implement. Symfony\Component\Routing\RouterInterface (router.default) @@ -80,7 +77,7 @@ in the container. .. tip:: There are actually *many* more services in the container, and each service has - a unique id in the container, like ``session`` or ``router.default``. For a full + a unique id in the container, like ``request_stack`` or ``router.default``. For a full list, you can run ``php bin/console debug:container``. But most of the time, you won't need to worry about this. See :ref:`services-wire-specific-service`. See :doc:`/service_container/debug`. @@ -283,9 +280,6 @@ type-hints by running: Request stack that controls the lifecycle of requests. Symfony\Component\HttpFoundation\RequestStack (request_stack) - Interface for the session. - Symfony\Component\HttpFoundation\Session\SessionInterface (session) - RouterInterface is the interface that all Router classes must implement. Symfony\Component\Routing\RouterInterface (router.default) diff --git a/session.rst b/session.rst index 394cfece78b..3ccf47460b6 100644 --- a/session.rst +++ b/session.rst @@ -127,25 +127,26 @@ Check out the Symfony config reference to learn more about the other available Basic Usage ----------- -Symfony provides a session service that is injected in your services and +The sessions is available througth the Request and the RequestStack. +Symfony provides a request_stack service that is injected in your services and controllers if you type-hint an argument with -:class:`Symfony\\Component\\HttpFoundation\\Session\\SessionInterface`:: +:class:`Symfony\\Component\\HttpFoundation\\RequestStack`:: - use Symfony\Component\HttpFoundation\Session\SessionInterface; + use Symfony\Component\HttpFoundation\RequestStack; class SomeService { - private $session; + private $requestStack; - public function __construct(SessionInterface $session) + public function __construct(RequestStack $requestStack) { - $this->session = $session; + $this->requestStack = $requestStack; } public function someMethod() { // stores an attribute in the session for later reuse - $this->session->set('attribute-name', 'attribute-value'); + $this->requestStack->getSession()->set('attribute-name', 'attribute-value'); // gets an attribute by name $foo = $this->session->get('foo'); @@ -157,10 +158,10 @@ controllers if you type-hint an argument with } } -.. tip:: +.. deprecated:: 5.3 - Every ``SessionInterface`` implementation is supported. If you have your - own implementation, type-hint this in the argument instead. + The ``SessionInterface`` and ``session`` service are deprecated since + Symfony 5.3. Inject a request stack instead. Stored attributes remain in the session for the remainder of that user's session. By default, session attributes are key-value pairs managed with the @@ -175,22 +176,44 @@ class. If your application needs are complex, you may prefer to use :ref:`namespaced session attributes ` which are managed with the :class:`Symfony\\Component\\HttpFoundation\\Session\\Attribute\\NamespacedAttributeBag` -class. Before using them, override the ``session`` service definition to replace -the default ``AttributeBag`` by the ``NamespacedAttributeBag``: +class. Before using them, override the ``session_listener`` service definition to build +your ``Session`` object with the default ``AttributeBag`` by the ``NamespacedAttributeBag``: .. configuration-block:: .. code-block:: yaml # config/services.yaml - session: - public: true - class: Symfony\Component\HttpFoundation\Session\Session - arguments: ['@session.storage', '@session.namespacedattributebag'] + session_listener: + autoconfigure: true + class: App\EventListener\SessionListener + arguments: + - !service_locator + logger: '@?logger' + session_collector: '@?data_collector.request.session_collector' + session_storage: '@session.storage' + session_attributes: '@session.namespacedattributebag' + - '%kernel.debug%' session.namespacedattributebag: class: Symfony\Component\HttpFoundation\Session\Attribute\NamespacedAttributeBag +.. code-block:: php + + namespace App\EventListener; + + use Symfony\Component\HttpFoundation\Session\Session; + use Symfony\Component\HttpFoundation\Session\SessionInterface; + use Symfony\Component\HttpKernel\EventListener\AbstractSessionListener; + + class SessionListener extends AbstractSessionListener + { + protected function getSession(): ?SessionInterface + { + return new Session($this->container->get('session_storage'), $this->container->get('session_attributes')); + } + } + .. _session-avoid-start: Avoid Starting Sessions for Anonymous Users diff --git a/session/locale_sticky_session.rst b/session/locale_sticky_session.rst index 056f2a674cb..13d620381aa 100644 --- a/session/locale_sticky_session.rst +++ b/session/locale_sticky_session.rst @@ -146,7 +146,7 @@ event:: namespace App\EventSubscriber; use Symfony\Component\EventDispatcher\EventSubscriberInterface; - use Symfony\Component\HttpFoundation\Session\SessionInterface; + use Symfony\Component\HttpFoundation\RequestStack; use Symfony\Component\Security\Http\Event\InteractiveLoginEvent; use Symfony\Component\Security\Http\SecurityEvents; @@ -156,11 +156,11 @@ event:: */ class UserLocaleSubscriber implements EventSubscriberInterface { - private $session; + private $requestStack; - public function __construct(SessionInterface $session) + public function __construct(RequestStack $requestStack) { - $this->session = $session; + $this->requestStack = $requestStack; } public function onInteractiveLogin(InteractiveLoginEvent $event) @@ -168,7 +168,7 @@ event:: $user = $event->getAuthenticationToken()->getUser(); if (null !== $user->getLocale()) { - $this->session->set('_locale', $user->getLocale()); + $this->requestStack->getSession()->set('_locale', $user->getLocale()); } }