Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 32 additions & 2 deletions lib/Horde/Core/Factory/Cache.php
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
<?php

use Horde\HashTable\HashTable;
use Horde\Injector\Injector;

/**
Expand Down Expand Up @@ -62,7 +63,11 @@ public function create(Horde_Injector|Injector $injector)
case 'hashtable':
// DEPRECATED
case 'memcache':
$sparams['hashtable'] = $injector->getInstance('Horde_Core_HashTable_Wrapper');
/* Prefer the modern Horde\HashTable\HashTable when available;
* fall back to the legacy Horde_Core_HashTable_Wrapper. The
* Horde_Cache_Storage_Hashtable accepts both and routes to
* Horde\Cache\HashtableStorage when given the modern one. */
$sparams['hashtable'] = $this->_resolveHashTable($injector);
$driver = 'Horde_Cache_Storage_Hashtable';
unset($sparams['driverconfig'], $sparams['umask']);
break;
Expand Down Expand Up @@ -96,7 +101,7 @@ public function create(Horde_Injector|Injector $injector)
$this->_getStorage(
$conf['cache']['use_memorycache'],
[
'hashtable' => $injector->getInstance('Horde_Core_HashTable_Wrapper'),
'hashtable' => $this->_resolveHashTable($injector),
]
),
$storage,
Expand Down Expand Up @@ -158,4 +163,29 @@ protected function _getStorage($driver, $params)
return new $class($params);
}

/**
* Resolve a HashTable instance for the cache storage.
*
* Prefers the modern Horde\HashTable\HashTable interface (which supports
* phpredis as well as Predis); falls back to the legacy
* Horde_Core_HashTable_Wrapper when the modern binding is unavailable.
*
* @param Horde_Injector|Injector $injector
*
* @return HashTable|Horde_HashTable
*/
protected function _resolveHashTable($injector)
{
try {
$modern = $injector->getInstance(HashTable::class);
if ($modern instanceof HashTable) {
return $modern;
}
} catch (Throwable) {
// Fall through to legacy.
}

return $injector->getInstance('Horde_Core_HashTable_Wrapper');
}

}
4 changes: 4 additions & 0 deletions lib/Horde/Core/Factory/HashTable.php
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,10 @@
* @copyright 2013-2017 Horde LLC
* @license http://www.horde.org/licenses/lgpl21 LGPL 2.1
* @package Core
*
* @deprecated Use {@see Horde\Core\Factory\HashTableFactory}, which produces
* instances of the PSR-4 Horde\HashTable\HashTable interface and
* supports phpredis as well as Predis.
*/
class Horde_Core_Factory_HashTable extends Horde_Core_Factory_Injector
{
Expand Down
6 changes: 6 additions & 0 deletions lib/Horde/Core/HashTable/Wrapper.php
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,12 @@
* @internal
* @license http://www.horde.org/licenses/lgpl21 LGPL-2.1
* @package Core
*
* @deprecated Used to bridge serializable wrappers to the legacy
* 'Horde_HashTable' DI binding. New code should depend on the
* PSR-4 {@see Horde\HashTable\HashTable} interface and inject
* the instance directly. Once the legacy binding is removed this
* wrapper can be deleted.
*/
class Horde_Core_HashTable_Wrapper
{
Expand Down
32 changes: 29 additions & 3 deletions src/Factory/SessionHandlerFactory.php
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,14 @@
use Horde\Core\Config\State;
use Horde\Core\Service\HordeDbService;
use Horde\Core\Session\HordeSessionFactory;
use Horde\HashTable\LockableHashTable;
use Horde\SessionHandler\NativePhpSessionSerializer;
use Horde\SessionHandler\SessionHandler;
use Horde\SessionHandler\Storage\BuiltinBackend;
use Horde\SessionHandler\Storage\FileBackend;
use Horde\SessionHandler\Storage\HashtableBackend;
use Horde\SessionHandler\Storage\ModernHashtableBackend;
use Horde\SessionHandler\Storage\SessionStorageBackend;
use Horde\SessionHandler\Storage\SqlBackend;
use Horde\SessionHandler\Storage\StackBackend;
use Horde_HashTable_Base;
Expand Down Expand Up @@ -117,10 +120,33 @@ private function createSqlBackend(Injector $injector, array $params): SqlBackend
}

/**
* Build the HashTable-backed session storage.
*
* Prefers the modern PSR-4 backend when a Horde\HashTable\LockableHashTable
* is bound. Falls back to the legacy backend (Horde_HashTable_Base &
* Horde_HashTable_Lock) for deployments still using the legacy DI binding.
*
* @param array<string, mixed> $params
*/
private function createHashtableBackend(Injector $injector, array $params): HashtableBackend
private function createHashtableBackend(Injector $injector, array $params): SessionStorageBackend
{
$track = (bool) ($params['track'] ?? false);
$trackKey = $params['track_id'] ?? 'horde_sessions_track_ht';

// Prefer modern LockableHashTable if available.
try {
$modern = $injector->getInstance(LockableHashTable::class);
if ($modern instanceof LockableHashTable) {
return new ModernHashtableBackend(
hashTable: $modern,
track: $track,
trackKey: $trackKey,
);
}
} catch (Throwable) {
// Modern interface not bound; fall through to legacy lookup.
}

$ht = $injector->getInstance('Horde_HashTable');

if (!$ht instanceof Horde_HashTable_Base || !$ht instanceof Horde_HashTable_Lock) {
Expand All @@ -131,8 +157,8 @@ private function createHashtableBackend(Injector $injector, array $params): Hash

return new HashtableBackend(
hashTable: $ht,
track: (bool) ($params['track'] ?? false),
trackKey: $params['track_id'] ?? 'horde_sessions_track_ht',
track: $track,
trackKey: $trackKey,
);
}

Expand Down
Loading
Loading