php - zf3 中使用 Doctrine 的自定义 session SaveHandler

标签 php session doctrine-orm zend-framework3

使用ZF3和Doctrine时如何在数据库中实现 session ?

手册说:

There may be cases where you want to create a save handler where a save handler currently does not exist. Creating a custom save handler is much like creating a custom PHP save handler. All save handlers must implement Zend\Session\SaveHandler\SaveHandlerInterface. Generally if your save handler has options you will create another options class for configuration of the save handler.

我尝试创建实现此接口(interface)的自定义类,但出现以下错误:

需要一个实现 Zend\Session\Storage\StorageInterface' 的类

使用此配置:

 'session_storage' => [
//        'type' => SessionArrayStorage::class (with array storage works ok)
        'type' => \Application\Session\SaveHandler\Doctrine::class (tried to implement suggested interface)
    ],

请注意,手册建议使用SaveHandlerInterface,但需要StorageInterface

有什么例子可以做到这一点吗?

编辑:

我当前的实现。

global.php中:

  'session_config' => [
        // Session cookie will expire in 1 hour.
        'cookie_lifetime' => 60*60*1,
        // Session data will be stored on server maximum for 30 days.
        'gc_maxlifetime'     => 60*60*24*30,
    ],
    // Session manager configuration.
    'session_manager' => [
        // Session validators (used for security).
        'validators' => [
            RemoteAddr::class,
            HttpUserAgent::class,
        ]
    ],
    // Session storage configuration.
    'session_storage' => [
        'type' => \Application\Session\Storage\Doctrine::class,
    ],
    'session_containers' => [
        'UserSession'
    ]

Module.php中:

/**
     * This method is called once the MVC bootstrapping is complete.
     */
    public function onBootstrap(MvcEvent $event)
    {
        $application = $event->getApplication();
        $serviceManager = $application->getServiceManager();



        // The following line instantiates the SessionManager and automatically
        // makes the SessionManager the 'default' one
        /** @var SessionManager $sessionManager */
        $sessionManager = $serviceManager->get(SessionManager::class);

        $entityManager =  $serviceManager->get('doctrine.entitymanager.orm_default');

        /** @var Doctrine $storage */
        $storage = $sessionManager->getStorage();
        $storage->setEntityManager($        
    }

Application\Session\Storage\Doctrine.php中:

class Doctrine implements
    IteratorAggregate,
    StorageInterface,
    StorageInitializationInterface
{
    public function setEntityManager($em) {  
        $this->entityManager = $em;
    }

    // ...
    // other functions as required by interfaces
}

这可行,但缺点是 Doctrine Storage 仅在该模块中可用,并且我专门在每个请求(Boostrap)上注入(inject)它,而不是在真正需要它时(Factory)注入(inject)它。

**更新:**

我编写了SaveHandler,但看起来值在请求后没有保留。

代码如下:

    class Doctrine extends ArrayStorage implements SaveHandlerInterface {

    /**
     * @param string $session_id
     * @return string Encdoded session data string
     */
    public function read($session_id)
    {
        $entity = $this->getEntity($session_id);
        if ($entity) {
            return $entity->getSessionData();
//          sample output:
//          string '__ZF|a:2:{s:20:"_REQUEST_ACCESS_TIME";d:1501933765.497678;s:6:"_VALID";a:3:{s:25:"Zend\Session\Validator\Id";s:26:"3kr15rhi6ijhneu7rruro9gr76";s:33:"Zend\Session\Validator\RemoteAddr";s:9:"127.0.0.1";s:36:"Zend\Session\Validator\HttpUserAgent";s:133:"Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Ubuntu Chromium/57.0.2987.98 Chrome/57.0.2987.98 Safari/537.36";}}FlashMessenger|C:23:"Zend\Stdlib\ArrayObject":205:{a:4:{s:7:"storage";a:0:{}s:4:"flag";i:2;s:13:"iteratorClass";s:13:"ArrayI'... (length=645)
//          note that counter is not present            
        }
    }

    /**
     * @param string $session_id
     * @param string $session_data Encoded session data string
     * @return bool
     */
    public function write($session_id, $session_data)
    {
//        sample input ($session_data):
//        string '__ZF|a:2:{s:20:"_REQUEST_ACCESS_TIME";d:1501934933.9573331;s:6:"_VALID";a:3:{s:25:"Zend\Session\Validator\Id";s:26:"3kr15rhi6ijhneu7rruro9gr76";s:33:"Zend\Session\Validator\RemoteAddr";s:9:"127.0.0.1";s:36:"Zend\Session\Validator\HttpUserAgent";s:133:"Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Ubuntu Chromium/57.0.2987.98 Chrome/57.0.2987.98 Safari/537.36";}}UserSession|C:23:"Zend\Stdlib\ArrayObject":223:{a:4:{s:7:"storage";a:1:{s:7:"counter";i:1;}s:4:"flag";i:2;s:13:"iteratorCla'... (length=918)
//        (note that counter variable is set)

        $entity = $this->getEntity($session_id);

        $entity->setSessionData($session_data);
        $entity->setLifetime($this->getLifeTime());

        $this->getEntityManager()->persist($entity);
        $this->getEntityManager()->flush($entity);

        return true;
    }

    /**
     * @param string $session_id
     * @return Entity|null
     */
    public function getEntity($session_id)
    {
        $this->entity = $this->getRepository()->find($session_id);

        if (!$this->entity) {
            $this->entity = new $this->entityName;
            $this->entity->setId($session_id);
        }

        return $this->entity;
    }

    //  ....

 }

最佳答案

实际上,您需要实现这些接口(interface),因为 PHP 需要 SaveHandlerInterface,ZF3 需要 StorageInterface。您的存储处理程序是它们之间的网关。

这应该有效。您可以在工厂内注入(inject)所有依赖项。

Application/src/DoctrineSaveHandler.php

namespace Application;

use Zend\Session\SaveHandler\SaveHandlerInterface;
use Zend\Session\Storage\ArrayStorage;

class DoctrineSaveHandler extends ArrayStorage implements SaveHandlerInterface
{
    public function close () {}
    public function destroy ($session_id) {}
    public function gc ($maxlifetime) {}
    public function open ($save_path, $name)  {}
    public function read ($session_id)  {}
    public function write ($session_id, $session_data)  {}
}

config/autoload/global.php

"service_manager" => [
    'aliases' => [
        \Zend\Session\SaveHandler\SaveHandlerInterface::class => \Zend\Session\Storage\StorageInterface::class
    ],
    'factories' => [
        \Zend\Session\Storage\StorageInterface::class => function () {
            // -------------------------------
            // YOU NEED A PROPER FACTORY HERE!
            // -------------------------------
            return new DoctrineSaveHandler();
        },
    ]
]

关于php - zf3 中使用 Doctrine 的自定义 session SaveHandler,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45404933/

相关文章:

php - Doctrine 2 : selecting entity fields, 包括相关字段

php - sql left join 不工作

php - 寻找一段时间内活跃/不活跃用户的策略

php - AJAX 与 HTML?

php - 从数组中删除重复项(数组按键唯一)

php - 如何在每个页面上验证用户 session

php - 如果数据长度可能超过 BLOB 大小,如何存储 CodeIgniter session 数据?

php - Doctrine 不会更新简单的数组类型字段

php - LEFT 主义 mysql 函数

php - 如何将用户名变量传递到第三个 php 页面?