来自旧版应用程序的Symfony 2和自定义会话变量

Jim*_*mbo 5 php session symfony

我正在设置从Legacy代码库迁移到Symfony代码库的能力,并且我试图在两个应用程序之间共享旧的会话变量。

我目前可以var_dump($_SESSION)进入app_dev.php,并且user_id密钥来自旧版应用程序。但是,当我在控制器中运行以下命令时,没有任何会话变量:

var_dump($request->getSession()->all());
Run Code Online (Sandbox Code Playgroud)

为了明确起见,我目前可以访问$_SESSION['user_id'],因此会话可以在应用程序之间成功共享,但是Symfony会话对象及其参数包不包含旧键。

我的目标:

  • 为了使user_id密钥在$request->getSession()通话中可用
  • 对于所有其他键在这里可用

我的问题:

我已经尝试过PHP Session桥,但我认为这不应该做我想要的事。添加bridge参数不仅在我的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'];
Run Code Online (Sandbox Code Playgroud)

显然是错误的方法,因为我也必须session_start()在那里打电话。

如何将旧$ _SESSION数据迁移到Symfony的Session对象中?Symfony是否有内置的东西可以帮助解决这个问题或可用的捆绑包?如果没有,我可以在哪里将自定义的$_SESSION['_sf2_attributes']“ hack”放在正确的位置以处理所有这些密钥的迁移?

Jak*_*las 3

Symfony 在会话中引入了会话包的概念,因此一切都是命名空间的。没有内置解决方案来访问非命名空间会话属性。

解决方案是使用标量包,就像TheodoEvolutionSessionBundle一样。我不会直接使用它,而是实现一些适合您项目的自定义内容(无论如何,它们只提供 symfony1 和 codeigniter 的集成)。以他们的想法为基础,但根据您的需求进行调整。

或者,您可以实现一个kernel.request监听器,将遗留会话属性重写为 Symfony 会话属性:

if (isset($_SESSION['user_id'])) {
    $event->getRequest()->getSession()->set('user_id', $_SESSION['user_id']);
}
Run Code Online (Sandbox Code Playgroud)

吉姆的编辑

我创建了一个事件侦听器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);
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

正如下面的评论所解释的,这不一定是最好的方法。但它有效。

  • 我不完全确定这是否有效:“会话已经开始时无法注册包。”(Symfony 3.1.2)。` session.legacy: 类: AppBundle\Session\LegacySessionHandler 标签: - { 名称: kernel.event_listener, 事件: kernel.request, 方法: onKernelRequest } ` (2认同)