2017-01-05 2 views
2

Ich mag würde drupals Kern Session-Management für meine eigenen, die stattdessen speichert die Sitzung zu Redis, anstatt in die Datenbank zu überschreiben.Drupal 8 übergeordnetes Session-Management

Nach googeln gibt es nicht viel, außer dies zu gehen: https://www.drupal.org/project/session_proxy

Das einzige Problem ist, dass nicht kompatibel mit Drupal 8 ist und ich möchte sparen nur so zu Redis Ich brauche keine anderen Handler .

In Symfony ich eine Session-Handler-Dienst erstellt, scheint aber weit komplizierter in Drupal 8.

Vorschläge, wie ich vorgehen sollte?

Danke

Antwort

3

Hier ist, wie ich die einfachste Art und Weise dachte, dieses Problem zu beheben, ohne auf 3rd-Party-Module oder anderen Plugins angewiesen war Drupals Kern SessionHandler Klasse außer Kraft zu setzen.

Zum einen in meinem Modul habe ich eine Klasse Serviceprovider, die den Behälter den Kern SessionHandler Klasse definitio mit meinem eigenen, neu zu definieren anweist. Ich brauchte den Datenbankverbindungsdienst nicht, also stellte ich sicher, dass nur der Anforderungsstapel an den Konstruktor übergeben wurde.

<?php 

namespace Drupal\my_module; 

use Drupal\Core\DependencyInjection\ContainerBuilder; 
use Drupal\Core\DependencyInjection\ServiceProviderBase; 
use Symfony\Component\DependencyInjection\Reference; 

class OoAuthServiceProvider extends ServiceProviderBase 
{ 
    /** 
    * {@inheritdoc} 
    */ 
    public function alter(ContainerBuilder $container) 
    { 
     $container->getDefinition('session_handler.storage') 
      ->setClass('Drupal\my_module\SessionHandler') 
      ->setArguments([ 
       new Reference('request_stack') 
      ]); 
    } 
} 

Ich fuhr dann fort mein eigenes Redis SessionHandler zu erstellen:

<?php 

namespace Drupal\my_module; 

use Drupal\Component\Utility\Crypt; 
use Drupal\Core\DependencyInjection\DependencySerializationTrait; 
use Drupal\Core\Utility\Error; 
use Symfony\Component\HttpFoundation\RequestStack; 
use Symfony\Component\HttpFoundation\Session\Storage\Proxy\AbstractProxy; 

/** 
* Default session handler. 
*/ 
class SessionHandler extends AbstractProxy implements \SessionHandlerInterface { 

    use DependencySerializationTrait; 

    /** 
    * The request stack. 
    * 
    * @var RequestStack 
    */ 
    protected $requestStack; 

    /** 
    * @var \Redis 
    */ 
    protected $redis; 

    /** 
    * SessionHandler constructor. 
    * 
    * @param RequestStack $requestStack 
    */ 
    public function __construct(RequestStack $requestStack) 
    { 
     $this->requestStack = $requestStack; 
     // TODO: Store redis connection details in config. 
     $this->redis = (new PhpRedis())->getClient('redis-host', 6379); 
    } 

    /** 
    * {@inheritdoc} 
    */ 
    public function open($savePath, $name) 
    { 
     return true; 
    } 

    /** 
    * {@inheritdoc} 
    */ 
    public function read($sid) 
    { 
     $data = ''; 

     if (!empty($sid)) { 
      $query = $this->redis->get(Crypt::hashBase64($sid)); 
      $data = unserialize($query); 
     } 

     return (string) $data['session']; 
    } 

    /** 
    * {@inheritdoc} 
    */ 
    public function write($sid, $value) 
    { 
     // The exception handler is not active at this point, so we need to do it 
     // manually. 

     var_dump(['Value', $value]); 
     try { 
      $request = $this->requestStack->getCurrentRequest(); 
      $fields = [ 
       'uid' => $request->getSession()->get('uid', 0), 
       'hostname' => $request->getClientIP(), 
       'session' => $value, 
       'timestamp' => REQUEST_TIME, 
      ]; 

      $this->redis->set(
       Crypt::hashBase64($sid), 
       serialize($fields), 
       (int) ini_get("session.gc_maxlifetime") 
      ); 

      return true; 
     } 
     catch (\Exception $exception) { 
      require_once DRUPAL_ROOT . '/core/includes/errors.inc'; 
      // If we are displaying errors, then do so with no possibility of a 
      // further uncaught exception being thrown. 
      if (error_displayable()) { 
       print '<h1>Uncaught exception thrown in session handler.</h1>'; 
       print '<p>' . Error::renderExceptionSafe($exception) . '</p><hr />'; 
      } 

      return true; 
     } 
    } 

    /** 
    * {@inheritdoc} 
    */ 
    public function close() 
    { 
     return true; 
    } 

    /** 
    * {@inheritdoc} 
    */ 
    public function destroy($sid) 
    { 
     // Delete session data. 
     $this->redis->delete(Crypt::hashBase64($sid)); 

     return true; 
    } 

    /** 
    * {@inheritdoc} 
    */ 
    public function gc($lifetime) 
    { 
     // Redundant method when using Redis. You no longer have to check the session 
     // timestamp as the session.gc_maxlifetime is set as TTL on write. 
     return true; 
    } 

} 

Die PhpRedis in meiner eigenen Implementierung des SessionHandler verwendet nur eine kleine Utility-Klasse ist mit Anschluss an Redis für den Umgang.

<?php 

namespace Drupal\my_module; 

/** 
* Class PhpRedis 
* @package Drupal\oo_auth 
*/ 
class PhpRedis implements ClientInterface 
{ 
    /** 
    * {@inheritdoc} 
    */ 
    public function getClient($host = null, $port = null, $base = null, $password = null) 
    { 
     $client = new \Redis(); 
     $client->connect($host, $port); 

     if (isset($password)) { 
      $client->auth($password); 
     } 

     if (isset($base)) { 
      $client->select($base); 
     } 

     // Do not allow PhpRedis serialize itself data, we are going to do it 
     // oneself. This will ensure less memory footprint on Redis size when 
     // we will attempt to store small values. 
     $client->setOption(\Redis::OPT_SERIALIZER, \Redis::SERIALIZER_NONE); 

     return $client; 
    } 

    /** 
    * {@inheritdoc} 
    */ 
    public function getName() { 
     return 'PhpRedis'; 
    } 
} 

<?php 

namespace Drupal\my_module; 

/** 
* Interface ClientInterface 
* @package Drupal\oo_auth 
*/ 
interface ClientInterface 
{ 
    /** 
    * Get the connected client instance. 
    * 
    * @param null $host 
    * @param null $port 
    * @param null $base 
    * 
    * @return mixed 
    */ 
    public function getClient($host = NULL, $port = NULL, $base = NULL); 

    /** 
    * Get underlying library name used. 
    * 
    * This can be useful for contribution code that may work with only some of 
    * the provided clients. 
    * 
    * @return string 
    */ 
    public function getName(); 
} 

Es gibt keine vorgeschlagenen Dokumentation gibt (dass ich finden konnte), dass Sie ein Beispiel, wie gibt Redis zu verwenden (dies würde in der Tat die Arbeit mit jedem Datenspeicher) als Session-Speicher für Ihre Drupal-Installation. Es gibt Beiträge darüber, wie man es mit anderen Modulen von Drittanbietern einrichten kann, was in Ordnung ist, aber ich wollte den zusätzlichen Fluff nicht.

+0

Hey Kal, würden Sie eine Zip mit Ihrem Modul haben? Ich möchte sehen, ob ich es in meinem Drupal-Projekt implementieren kann. –

+0

Hey André, ich habe leider nicht so wie bei der vorherigen Firma mit der ich war. Wenn Sie Hilfe benötigen, wenden Sie sich bitte an mich und ich werde mein Bestes tun, um zu helfen: [email protected] :) – Kal

2

Es gibt eine Alpha-Version des Redis-Moduls. Wenn es sich bei aktuellen Beschränkungen nicht um Show-Stopper handelt, können Sie dies einfach verwenden und wie dokumentiert konfigurieren. https://www.drupal.org/project/redis

Lesen Sie die Dokumentation für weitere Informationen über Konfigurationseinstellungen, sondern als Starter, nach der Installation des Moduls würden Sie etwas zu Ihrem settings.php

$settings['cache']['default'] = 'cache.backend.redis'; 
$settings['redis.connection']['host'] = '<<redis_host>>'; 
$settings['redis.connection']['port'] = '<<redis_port>>'; 

Wo redis_host 'und ‚redis_port‘ hinzufügen werden gemäß Ihrer Redis-Instanz festgelegt.

+1

Ich weiß es „Cache“ sagen, aber es wäre auch Sitzung in redis bleiben? – Kal

+0

Ich habe das gleiche Problem mit diesem Redis-Modul. Ich habe es mit Redis für den Cache bekommen und es funktioniert super. Aber noch kein Glück zu versuchen, die Sitzungen auch in Redis –

+0

Die aktuelle Version für D8 Redis Modul unterstützt keine Sitzungen zu erhalten, aber es gibt die Arbeit an einem Sub-Modul, das so will. Sehen Sie diesen Thread https://www.drupal.org/project/redis/issues/2876099 –