来自遗留应用程序

时间:2016-02-24 12:01:35

标签: php symfony session

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

我目前var_dump($_SESSION) app_dev.phpuser_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'在正确的位置处理所有这些键的迁移?

2 个答案:

答案 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']);
        ...
    }
}

希望这有帮助