使用Doctrine

时间:2017-07-30 21:36:17

标签: php session doctrine-orm zend-framework3

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

手册说:

  

在某些情况下,您可能希望创建一个保存处理程序   保存处理程序当前不存在。创建自定义保存处理程序   就像创建自定义PHP保存处理程序一样。所有保存处理程序   必须实现Zend \ Session \ SaveHandler \ SaveHandlerInterface。   通常如果您的保存处理程序有选项,您将创建另一个   用于配置保存处理程序的选项类。

我尝试创建实现此接口的自定义类,但是我收到以下错误:

expects a class implementing 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)上专门注入它,而不是在它真正需要的时候(工厂)。

**更新:**

我写了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;
    }

    //  ....

 }

2 个答案:

答案 0 :(得分:1)

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

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

<强>应用/ 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)  {}
}

<强>配置/自动加载/ 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();
        },
    ]
]

答案 1 :(得分:0)

说实话,我没有使用带有保存处理程序功能的doctrine来管理会话。但是,让我告诉你应该如何构建Zend\Session的每个部分,特别是SessionManager::class

SessionArrayStorage::class实现Zend\Session\Storage\StorageInterface,用于存储会话数据以支持SessionManager::class

实际上Zend\Session的这一部分做得很棒。它可以替代$_SESSION超全局,并使用ArrayObject::class中的Zend\Stdlib。它将为您提供极大的灵活性,这意味着您将能够使用这些功能:属性访问,元数据存储,锁定和不变性。 (老实说,我没有使用所有这些)。

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

现在重点是您使用的是自定义保存处理程序而不是不正确的存储。因为保存处理程序没有实现Zend\Session\Storage\StorageInterface。这就是你得到那种错误的原因。

保存处理程序通常用于在数据库,文件或缓存系统中存储会话数据。在制作自定义保存处理程序时意味着您正在实现Zend\Session\SaveHandler\SaveHandlerInterface。因此,您必须使用open($savePath, $name)read($id)write($id, $data)destroy($id)等等。

因此,要完全配置SessionManager::class以管理会话,您需要提供三个内容:会话配置,会话存储和保存处理程序。例如

$sessionManager = new SessionManager(
    $sessionConfig,
    $sessionStorage,
    // provide your save handler here
    $sessionSaveHandler
);

// this keeps this configuration in mind in later calls of 'Container::class'
Container::setDefaultManager($sessionManager);
return $sessionManager;

现在我们配置了SessionManager::class。我们可以在需要时调用它。例如,在使用一个人的登录凭证进行验证后。

$session = $e->getApplication()
    ->getServiceManager()
    ->get(SessionManager::class);
$session->start();

在此之后,我们可以使用Container::class部分的Zend\Session部分,如下所示

// this would use the above configuration 
$container = new Container('initialized');

$session->getSaveHandler()->open('path', 'session-name');

// Write data to db, files etc
// "$contents" must be serialized data; coentents can be: id, email etc
$session->getSaveHandler()->write($session->getId(), $contents);

// Read data
$storedData = $session->getSaveHandler()->read($session->getId());

现在我们可以使用任何自定义属性和存储值,如

$container->storedData = $storedData;
$container->remoteAddr = 127.0.0.1;

接下来我们需要检索这些值,我们就可以得到它们

$container = new Container('initialized');
print_r($container->storedData);

//or
echo $container->remoteAddr;

希望这会对你有所帮助!