我正在设置从Legacy代码库迁移到Symfony代码的能力,并且我尝试在两个应用程序之间共享遗留会话变量。
我目前var_dump($_SESSION)
app_dev.php
,user_id
密钥来自遗留应用程序。但是,当我在控制器中运行以下内容时,我没有得到任何会话变量:
var_dump($request->getSession()->all());
所以要澄清,我目前可以访问$_SESSION['user_id']
,因此会话在应用程序之间成功共享,但Symfony会话对象及其参数包不包含传统密钥。
我的目标:
user_id
调用$request->getSession()
密钥
我的问题:
我尝试了PHP Session bridge,但我不认为这应该按照我的意愿行事。添加bridge参数不仅不会在我的Symfony应用程序中执行任何操作,而且还可以在其他遗留应用程序中以某种方式使用此类read,而不是symfony中。
Symfony会话将特殊数据中的数据存储在特殊的' Bags'它使用$ _SESSION超全局中的一个键。这意味着Symfony会话无法访问可能由遗留应用程序设置的$ _SESSION中的任意键,尽管保存会话时将保存所有$ _SESSION内容。 [来自Integrating with legacy sessions]
我还看了TheodoEvolutionSessionBundle,但这已经过时了,没有得到积极的支持或工作,也没有与Symfony 3合作。
我注意到Symfony将其会话数据存储在$_SESSION['_sf2_attributes']
下,所以我最初的想法是在app_dev.php
中执行此操作:
$_SESSION['_sf2_attributes']['user_id'] = $_SESSION['user_id'];
这显然是 这样做的错误方法,因为我也必须在那里调用session_start()
。
如何将旧的$ _SESSION数据迁移到Symfony的Session对象中? Symfony内置了哪些内容可以帮助解决这个问题或捆绑问题?如果没有, 可以放置我的自定义$_SESSION['_sf2_attributes']
' hack'在正确的位置处理所有这些键的迁移?
答案 0 :(得分:3)
Symfony在会话中引入了会话包的概念,因此所有内容都是命名空间。在访问非命名空间的会话属性的解决方案中没有构建。
解决方案是使用标量包,就像TheodoEvolutionSessionBundle一样。我不会直接使用它,但实现一些适用于你项目的自定义项目(它们只提供symfony1和codeigniter的集成)。基于他们的想法,但根据您的需求进行调整。
或者,您可以实现一个kernel.request
侦听器,它将遗留的会话属性重写为Symfony:
if (isset($_SESSION['user_id'])) {
$event->getRequest()->getSession()->set('user_id', $_SESSION['user_id']);
}
Jim编辑
我在kernel.request
上创建了一个事件监听器 - 每个请求都会进入,我们遍历$_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);
}
}
}
正如下面的评论中所解释的,这不一定是最好的方法。但它确实有效。
答案 1 :(得分:1)
会话变量是否有任何复杂的生命周期?或者,一旦您登录到您的应用程序,它们主要是只读的?
如果后者适用,您可以将“hack”添加到事件订阅者中。该订阅者将监听Interactive Login Event,它可能看起来像:
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']);
...
}
}
希望这有帮助