2017-07-30 8 views
1

ZF3とDoctrineを使用しているときにデータベースでセッションを実装する方法は?Doctrineを使用したzf3のカスタムセッションSaveHandler

マニュアルは言う:

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.

私はこのインタフェースを実装するカスタムクラスを作成しようとしましたが、私は次のエラーを取得:この設定で

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 
} 

これは動作しますが、欠点は教義ストレージのみで利用可能になるということですこのモジュールと私は具体的にそれをそれぞれのreに注入しますクエスト(ブーストラップ)、本当に必要なときではない(ファクトリ)。

**アップデート:**

私は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

? – akond

+0

セッションサービスがセッションマネージャに登録されていると思います。 – takeshin

+0

簡単なSaveHandlerInterface実装で非常に単純なPOCスニペットを作成しました。これまでのところエラーはありません。 – akond

答えて

0

は、私がセッションを管理するためのハンドラ機能を保存して教義を使用していませんでした正直に言うと。しかしのために、Zend\Sessionの各部分がどのように構築されるべきかを教えてください。

SessionArrayStorage::classZend\Session\Storage\StorageInterfaceを実装し、セッションデータの保存にはSessionManager::classを使用します。

実際にZend\Sessionのこの部分は素晴らしいことをします。それは$_SESSIONスーパーグローバルの代わりに動作し、Zend\StdlibArrayObject::classを使用します。プロパティアクセス、メタデータストレージ、ロック、不変性など、これらの機能を使用できるという大きな柔軟性が得られます。 (正直言って私はそれらのすべてを使っていませんでした)。

'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を完全に構成するには、セッション構成、セッション記憶域、およびセーブハンドラの3つを提供する必要があります。例:

$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を設定しました。必要な時にこれを呼び出すことができます。たとえば、ログイン資格情報で確認した後などです。我々は

// 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; 
のような任意のカスタムプロパティとストア値を使用することができるだろうし、次のように Zend\Session部品の Container::class一部を使用することができるだろう。この後

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

次の値を取得する必要がある場合は、その値を取得することができます。

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

//or 
echo $container->remoteAddr; 

これがあなたを少し助けてくれることを願っています!

+0

ありがとうございます。しかし、問題はEntityManagerの依存関係をカスタムセッションストレージクラス(どの名前をglobal.php configで 'type'を変更するかを設定する)に注入して、すべてのアプリケーションモジュールでアクセスできるようにする方法です。今のところ私はModule.phpでストレージインスタンスを取得し、Entity managerを渡します。しかし、この方法では、私は完全なオブジェクトを注入し、工場ではなく、このオブジェクトは現在のモジュールでのみアクセス可能です。 EntityManagerファクトリをセッションマネージャに挿入する方法は? – takeshin

+0

まず、 'Doctrine :: class'と' EntityManager :: class'のためのファクトリを作成する必要があります。次に、ファクトリの作成中に 'Doctrine :: class'のセッターメソッドに' EntityManager :: class'を挿入します。次に、サービスマネージャを使用して必要な場所に呼び出します。ありがとう – unclexo

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(); 
     }, 
    ] 
] 
まさにあなたはこのエラーが出るん
+0

これは 'EntityManager'を挿入することを許可しましたが、' read() 'と' write() 'メソッドを実装すると、エンコードされた値はデータベースに保存されますが、正しく処理されません(セッションコンテナには全く値がありません)。おそらく、データのシリアル化/シリアル化解除に関するいくつかの問題があります。私は現在のコードで質問を更新しました。 – takeshin

関連する問題