如何在使用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;
}
// ....
}
答案 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;
希望这会对你有所帮助!