vendor/contao/core-bundle/src/EventListener/UserSessionListener.php line 63

Open in your IDE?
  1. <?php
  2. declare(strict_types=1);
  3. /*
  4.  * This file is part of Contao.
  5.  *
  6.  * (c) Leo Feyer
  7.  *
  8.  * @license LGPL-3.0-or-later
  9.  */
  10. namespace Contao\CoreBundle\EventListener;
  11. use Contao\CoreBundle\Routing\ScopeMatcher;
  12. use Contao\User;
  13. use Doctrine\DBAL\Connection;
  14. use Symfony\Component\EventDispatcher\EventDispatcherInterface;
  15. use Symfony\Component\HttpFoundation\Request;
  16. use Symfony\Component\HttpFoundation\Session\Attribute\AttributeBagInterface;
  17. use Symfony\Component\HttpFoundation\Session\SessionBagInterface;
  18. use Symfony\Component\HttpKernel\Event\RequestEvent;
  19. use Symfony\Component\HttpKernel\Event\ResponseEvent;
  20. use Symfony\Component\HttpKernel\KernelEvents;
  21. use Symfony\Component\Security\Core\Security;
  22. /**
  23.  * @internal
  24.  */
  25. class UserSessionListener
  26. {
  27.     /**
  28.      * @var Connection
  29.      */
  30.     private $connection;
  31.     /**
  32.      * @var Security
  33.      */
  34.     private $security;
  35.     /**
  36.      * @var ScopeMatcher
  37.      */
  38.     private $scopeMatcher;
  39.     /**
  40.      * @var EventDispatcherInterface
  41.      */
  42.     private $eventDispatcher;
  43.     public function __construct(Connection $connectionSecurity $securityScopeMatcher $scopeMatcherEventDispatcherInterface $eventDispatcher)
  44.     {
  45.         $this->connection $connection;
  46.         $this->security $security;
  47.         $this->scopeMatcher $scopeMatcher;
  48.         $this->eventDispatcher $eventDispatcher;
  49.     }
  50.     /**
  51.      * Replaces the current session data with the stored session data.
  52.      */
  53.     public function __invoke(RequestEvent $event): void
  54.     {
  55.         if (!$this->scopeMatcher->isContaoMasterRequest($event)) {
  56.             return;
  57.         }
  58.         $user $this->security->getUser();
  59.         if (!$user instanceof User) {
  60.             return;
  61.         }
  62.         $session $user->session;
  63.         if (\is_array($session)) {
  64.             /** @var AttributeBagInterface $sessionBag */
  65.             $sessionBag $this->getSessionBag($event->getRequest());
  66.             $sessionBag->replace($session);
  67.         }
  68.         // Dynamically register the kernel.response listener (see #1293)
  69.         $this->eventDispatcher->addListener(KernelEvents::RESPONSE, [$this'write']);
  70.     }
  71.     /**
  72.      * Writes the current session data to the database.
  73.      */
  74.     public function write(ResponseEvent $event): void
  75.     {
  76.         if (!$this->scopeMatcher->isContaoMasterRequest($event)) {
  77.             return;
  78.         }
  79.         $user $this->security->getUser();
  80.         if (!$user instanceof User) {
  81.             return;
  82.         }
  83.         /** @var AttributeBagInterface $sessionBag */
  84.         $sessionBag $this->getSessionBag($event->getRequest());
  85.         $data $sessionBag->all();
  86.         $this->connection->update($user->getTable(), ['session' => serialize($data)], ['id' => $user->id]);
  87.     }
  88.     /**
  89.      * Returns the session bag.
  90.      *
  91.      * @throws \RuntimeException
  92.      */
  93.     private function getSessionBag(Request $request): SessionBagInterface
  94.     {
  95.         if (!$request->hasSession()) {
  96.             throw new \RuntimeException('The request did not contain a session.');
  97.         }
  98.         $name 'contao_frontend';
  99.         if ($this->scopeMatcher->isBackendRequest($request)) {
  100.             $name 'contao_backend';
  101.         }
  102.         return $request->getSession()->getBag($name);
  103.     }
  104. }