I\'m in the process of setting up the ability to migrate from a Legacy codebase to a Symfony one, and I\'m trying to share legacy session variables between the two applicati
Symfony introduces a concept of session bags into the session, so everything is namespaced. There's no build in solution to access non-namespaced session attributes.
The solution is to use scalar bags, just like TheodoEvolutionSessionBundle does. I wouldn't use it directly, but implement something custom that will work for you project (they only provide integrations for symfony1 and codeigniter anyway). Base it on their idea, but adapt it to your needs.
Alternatively, you could implement a kernel.request
listener that would rewrite legacy session attributes to the Symfony one:
if (isset($_SESSION['user_id'])) {
$event->getRequest()->getSession()->set('user_id', $_SESSION['user_id']);
}
Jim's edit
I created an event listener on kernel.request
- every request that comes in, we loop through all the legacy session vars in $_SESSION
and place them in Symfony's session bag. Here's the listener:
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);
}
}
}
As explained in the comments below, this isn't necessarily the best way of doing this. But it works.
Is there any complicated life-cycle for your session variables? Or they are mainly read-only once you're logged in into your application?
If the latter applies, you might be able to add that "hack" into an event subscriber. This subscriber would listen for the Interactive Login Event, and it could look something like:
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']);
...
}
}
Hope this helps