Я в процессе настройки возможности перехода из кодовой базы Legacy на Symfony, и я пытаюсь использовать устаревшие переменные сеанса между двумя приложениями.
В настоящее время я могу var_dump($_SESSION)
в app_dev.php
а ключ app_dev.php
из user_id
приложения. Однако, когда я запускаю следующее в контроллере, я не получаю никаких переменных сеанса:
var_dump($request->getSession()->all());
Поэтому, чтобы уточнить , у меня в настоящее время есть доступ к $_SESSION['user_id']
, поэтому сеанс распределяется между приложениями успешно, но объект сеанса Symfony и его пакеты параметров не содержат устаревших ключей.
Моя цель:
user_id
был доступен в вызове $request->getSession()
Мои проблемы:
Я пробовал мост PHP Session, но я не думаю, что это должно делать то, что я хочу. Не только добавление параметра моста ничего не делает в моем приложении Symfony, но из того, что я прочитал, это должно использоваться как-то в другом унаследованном приложении, а не в Symfony.
В сеансах Symfony хранятся данные, такие как атрибуты в специальных «сумочках», которые используют ключ в суперзвезде $ _SESSION. Это означает, что сеанс Symfony не может получить доступ к произвольным ключам в $ _SESSION, которые могут быть установлены устаревшим приложением, хотя все содержимое $ _SESSION будет сохранено при сохранении сеанса. [От интеграции с предыдущими сеансами ]
Я также посмотрел на TheodoEvolutionSessionBundle , но он старый, не активно поддерживается или работает и не работает с Symfony 3.
Я заметил, что Symfony хранит данные сеанса в $_SESSION['_sf2_attributes']
, поэтому моя первоначальная мысль заключалась в том, чтобы сделать это в app_dev.php
:
$_SESSION['_sf2_attributes']['user_id'] = $_SESSION['user_id'];
Очевидно, это неправильный способ сделать это, так как мне также нужно вызвать session_start()
.
Как переносить устаревшие данные $ _SESSION в объект Session Symfony? Есть ли что-то встроенное в Symfony, чтобы помочь с этим или пакетом? Если этого не происходит, где я могу поместить свой пользовательский $_SESSION['_sf2_attributes']
'hack' в $_SESSION['_sf2_attributes']
место, чтобы обработать миграцию всех этих ключей?
Symfony вводит концепцию сессионных мешков в сессию, поэтому все пространство имен. Там нет встроенного решения для доступа к атрибутам сеанса, не связанным с именами.
Решение заключается в использовании скалярных пакетов, как это делает TheodoEvolutionSessionBundle . Я бы не использовал его напрямую, а реализовал что-то индивидуальное, которое будет работать для вас проекта (они только обеспечивают интеграцию для symfony1 и codeigniter в любом случае). Основывайте их на своей идее, но приспосабливайте ее к вашим потребностям.
Кроме того, вы можете реализовать прослушиватель kernel.request
, который переписывал бы устаревшие атрибуты сеанса на Symfony:
if (isset($_SESSION['user_id'])) { $event->getRequest()->getSession()->set('user_id', $_SESSION['user_id']); }
Редактирование Джима
Я создал прослушиватель событий на kernel.request
– каждый запрос, который приходит, мы прокручиваем все устаревшие сессии vars в $_SESSION
и помещаем их в сумку для сессии Symfony. Вот слушатель:
namespace AppBundle\Session; use Symfony\Component\HttpFoundation\Session\Attribute\NamespacedAttributeBag, Symfony\Component\EventDispatcher\EventSubscriberInterface, Symfony\Component\HttpKernel\Event\GetResponseEvent, Symfony\Component\HttpKernel\KernelEvents; class LegacySessionHandler implements EventSubscriberInterface { /** * @var string The name of the bag name containing all the brunel values */ const LEGACY_SESSION_BAG_NAME = 'old_app'; /** * {@inheritdoc} */ public static function getSubscribedEvents() { return [ KernelEvents::REQUEST => 'onKernelRequest' ]; } /** * Transfer all the legacy session variables into a session bag, so $_SESSION['user_id'] will be accessible * via $session->getBag('old_app')->get('user_id'). The first bag name is defined as the class constant above * * @param GetResponseEvent $event */ public function onKernelRequest(GetResponseEvent $event) { /** There might not be a session, in the case of the profiler / wdt (_profiler, _wdt) **/ if (!isset($_SESSION)) { return; } $session = $event->getRequest()->getSession(); /** Only create the old_app bag if it doesn't already exist **/ try { $bag = $session->getBag(self::LEGACY_SESSION_BAG_NAME); } catch (\InvalidArgumentException $e) { $bag = new NamespacedAttributeBag(self::LEGACY_SESSION_BAG_NAME); $bag->setName(self::LEGACY_SESSION_BAG_NAME); $session->registerBag($bag); } foreach ($_SESSION as $key => $value) { /** Symfony prefixes default session vars with an underscore thankfully, so ignore these **/ if (substr($key, 0, 1) === '_' && $key !== self::LEGACY_SESSION_BAG_NAME) { continue; } $bag->set($key, $value); } } }
Как поясняется в комментариях ниже, это не обязательно лучший способ сделать это. Но это работает.
Существует ли какой-либо сложный жизненный цикл для ваших переменных сеанса? Или они в основном доступны для чтения только после входа в ваше приложение?
Если последнее применимо, вы можете добавить этот «взлом» в подписчика событий. Этот абонент будет прослушивать интерактивное входное событие , и он может выглядеть примерно так:
class PortSessionHandler implements EventSubscriberInterface { private $session; public function __construct(SessionInterface $session) { $this->session = $session; } public static function getSubscribedEvents() { return [ SecurityEvents::INTERACTIVE_LOGIN => [ ['portLegacySession'] ] ]; } public function portLegacySession(InteractiveLoginEvent $event) { //here you could populate SF2 session with legacy session $this->session->set('user_id', $_SESSION['user_id']); ... } }
Надеюсь это поможет