diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index b842712..a819f5b 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -16,7 +16,9 @@ jobs: - uses: shivammathur/setup-php@v2 with: php-version: ${{ matrix.php }} - extensions: redis + extensions: redis, igbinary + env: + REDIS_CONFIGURE_OPTS: --enable-redis --enable-redis-igbinary - name: Start Redis uses: supercharge/redis-github-action@1.2.0 diff --git a/src/Kdyby/Redis/DI/Config/ClientSchema.php b/src/Kdyby/Redis/DI/Config/ClientSchema.php index a936862..85c5bb6 100644 --- a/src/Kdyby/Redis/DI/Config/ClientSchema.php +++ b/src/Kdyby/Redis/DI/Config/ClientSchema.php @@ -15,6 +15,10 @@ public function __construct(\Nette\DI\ContainerBuilder $builder) public function normalize($value, \Nette\Schema\Context $context) { + if (\is_bool($value)) { + return $value; + } + $value = $this->getSchema()->normalize($value, $context); if (\array_key_exists('host', $value) && $value['host'][0] === '/') { @@ -36,7 +40,9 @@ public function merge($value, $base) public function complete($value, \Nette\Schema\Context $context) { - $value = $this->expandParameters($value); + if ( ! \is_bool($value)) { + $value = $this->expandParameters($value); + } $value = $this->getSchema()->complete($value, $context); @@ -75,7 +81,7 @@ private function getSchema(): \Nette\Schema\Schema 'lockAcquireTimeout' => \Nette\Schema\Expect::bool(FALSE), 'debugger' => \Nette\Schema\Expect::bool($this->builder->parameters['debugMode']), 'versionCheck' => \Nette\Schema\Expect::bool(TRUE), - ]); + ])->castTo('array'); } } diff --git a/src/Kdyby/Redis/DI/Config/RedisSchema.php b/src/Kdyby/Redis/DI/Config/RedisSchema.php index 1e605ff..c90d43a 100644 --- a/src/Kdyby/Redis/DI/Config/RedisSchema.php +++ b/src/Kdyby/Redis/DI/Config/RedisSchema.php @@ -82,10 +82,15 @@ private function expandParameters(array $config): array private function getSchema(): \Nette\Schema\Schema { if ($this->schema === NULL) { + $storageSchema = \Nette\Schema\Expect::structure([ + 'locks' => \Nette\Schema\Expect::bool(TRUE), + ])->castTo('array'); + $sessionClientSchema = new \Kdyby\Redis\DI\Config\SessionClientSchema($this->builder); + $this->schema = \Nette\Schema\Expect::structure([ 'journal' => \Nette\Schema\Expect::bool(FALSE), - 'storage' => \Nette\Schema\Expect::bool(FALSE), - 'session' => \Nette\Schema\Expect::bool(FALSE), + 'storage' => \Nette\Schema\Expect::anyOf($storageSchema, TRUE, FALSE)->default(FALSE), + 'session' => \Nette\Schema\Expect::anyOf($sessionClientSchema, TRUE, FALSE)->default(FALSE), 'clients' => \Nette\Schema\Expect::arrayOf( new \Kdyby\Redis\DI\Config\ClientSchema($this->builder) )->default([ @@ -103,7 +108,7 @@ private function getSchema(): \Nette\Schema\Schema 'versionCheck' => TRUE, ], ]), - ]); + ])->castTo('array'); } return $this->schema; diff --git a/src/Kdyby/Redis/DI/Config/SessionClientSchema.php b/src/Kdyby/Redis/DI/Config/SessionClientSchema.php new file mode 100644 index 0000000..0b5a719 --- /dev/null +++ b/src/Kdyby/Redis/DI/Config/SessionClientSchema.php @@ -0,0 +1,90 @@ +builder = $builder; + } + + public function normalize($value, \Nette\Schema\Context $context) + { + if (\is_bool($value)) { + return $value; + } + + $value = $this->getSchema()->normalize($value, $context); + + if (\array_key_exists('host', $value) && $value['host'][0] === '/') { + $value['port'] = NULL; // sockets have no ports + + } elseif ( ! \array_key_exists('port', $value)) { + $value['port'] = \Kdyby\Redis\RedisClient::DEFAULT_PORT; + } + + return $value; + } + + + public function merge($value, $base) + { + return \Nette\Schema\Helpers::merge($value, $base); + } + + + public function complete($value, \Nette\Schema\Context $context) + { + if ( ! \is_bool($value)) { + $value = $this->expandParameters($value); + } + + $value = $this->getSchema()->complete($value, $context); + + return $value; + } + + + public function completeDefault(\Nette\Schema\Context $context) + { + + } + + private function expandParameters(array $config): array + { + $params = $this->builder->parameters; + if (isset($config['parameters'])) { + foreach ((array) $config['parameters'] as $k => $v) { + $v = \explode(' ', \is_int($k) ? $v : $k); + $params[\end($v)] = $this->builder::literal('$' . \end($v)); + } + } + return \Nette\DI\Helpers::expand($config, $params); + } + + private function getSchema(): \Nette\Schema\Schema + { + return \Nette\Schema\Expect::structure([ + 'host' => \Nette\Schema\Expect::string('127.0.0.1'), + 'port' => \Nette\Schema\Expect::int()->nullable(), + 'timeout' => \Nette\Schema\Expect::int(10), + 'database' => \Nette\Schema\Expect::int(0), + 'auth' => \Nette\Schema\Expect::string()->nullable(), + 'persistent' => \Nette\Schema\Expect::bool(FALSE), + 'connectionAttempts' => \Nette\Schema\Expect::int(1), + 'lockDuration' => \Nette\Schema\Expect::int(15), + 'lockAcquireTimeout' => \Nette\Schema\Expect::bool(FALSE), + 'debugger' => \Nette\Schema\Expect::bool(FALSE), + 'versionCheck' => \Nette\Schema\Expect::bool(TRUE), + 'native' => \Nette\Schema\Expect::bool(TRUE), + 'prefix' => \Nette\Schema\Expect::string(\Kdyby\Redis\DI\RedisExtension::DEFAULT_SESSION_PREFIX), + 'weight' => \Nette\Schema\Expect::int(1), + ])->castTo('array'); + } + +} diff --git a/src/Kdyby/Redis/DI/RedisExtension.php b/src/Kdyby/Redis/DI/RedisExtension.php index 794cdd6..c0f1e9e 100644 --- a/src/Kdyby/Redis/DI/RedisExtension.php +++ b/src/Kdyby/Redis/DI/RedisExtension.php @@ -19,9 +19,9 @@ class RedisExtension extends \Nette\DI\CompilerExtension private const PANEL_COUNT_MODE = 'count'; /** - * @var array + * @var array> */ - private $configuredClients = []; + private array $configuredClients = []; public function getConfigSchema(): \Nette\Schema\Schema @@ -32,10 +32,11 @@ public function getConfigSchema(): \Nette\Schema\Schema public function loadConfiguration(): void { - $this->configuredClients = []; - $builder = $this->getContainerBuilder(); - $config = (array) $this->getConfig(); + $config = $this->getConfig(); + + // we need to register default client before session is processed + $this->buildClient(NULL, $config['clients']['']); $phpRedisDriverClass = \Kdyby\Redis\Driver\PhpRedisDriver::class; @@ -47,8 +48,9 @@ public function loadConfiguration(): void $this->loadStorage($config); $this->loadSession($config); + unset($config['clients']['']); foreach ($config['clients'] as $name => $clientConfig) { - $this->buildClient($name, (array) $clientConfig); + $this->buildClient($name, $clientConfig); } } @@ -164,19 +166,19 @@ protected function loadSession(array $config): void $clientConfig = $config['clients'][NULL]; $sessionConfig = \Nette\DI\Config\Helpers::merge(\is_array($config['session']) ? $config['session'] : [], [ - 'host' => $clientConfig->host, - 'port' => $clientConfig->port, + 'host' => $clientConfig['host'], + 'port' => $clientConfig['port'], 'weight' => 1, - 'timeout' => $clientConfig->timeout, - 'database' => $clientConfig->database, + 'timeout' => $clientConfig['timeout'], + 'database' => $clientConfig['database'], 'prefix' => self::DEFAULT_SESSION_PREFIX, - 'auth' => $clientConfig->auth, + 'auth' => $clientConfig['auth'], 'native' => TRUE, - 'lockDuration' => $clientConfig->lockDuration, - 'lockAcquireTimeout' => $clientConfig->lockAcquireTimeout, - 'connectionAttempts' => $clientConfig->connectionAttempts, - 'persistent' => $clientConfig->persistent, - 'versionCheck' => $clientConfig->versionCheck, + 'lockDuration' => $clientConfig['lockDuration'], + 'lockAcquireTimeout' => $clientConfig['lockAcquireTimeout'], + 'connectionAttempts' => $clientConfig['connectionAttempts'], + 'persistent' => $clientConfig['persistent'], + 'versionCheck' => $clientConfig['versionCheck'], ]); $sessionConfig['debugger'] = FALSE; diff --git a/tests/KdybyTests/Redis/ExtensionTest.phpt b/tests/KdybyTests/Redis/ExtensionTest.phpt index cdf6dfe..74573a5 100644 --- a/tests/KdybyTests/Redis/ExtensionTest.phpt +++ b/tests/KdybyTests/Redis/ExtensionTest.phpt @@ -133,6 +133,18 @@ class ExtensionTest extends \Tester\TestCase Assert::false($dic->hasService('redis.cacheStorage')); } + public function testSessionConfiguration(): void + { + $config = $this->createConfig(); + $config->addConfig(__DIR__ . '/files/session.neon'); + $dic = $config->createContainer(); + Assert::true($dic->getService('redis.client') instanceof Kdyby\Redis\RedisClient); + Assert::true($dic->hasService('redis.sessionHandler')); + Assert::type(\Kdyby\Redis\RedisSessionHandler::class, $dic->getService('redis.sessionHandler')); + Assert::false($dic->hasService('redis.cacheJournal')); + Assert::false($dic->hasService('redis.cacheStorage')); + } + } (new ExtensionTest())->run(); diff --git a/tests/KdybyTests/Redis/files/session.neon b/tests/KdybyTests/Redis/files/session.neon new file mode 100644 index 0000000..86273bb --- /dev/null +++ b/tests/KdybyTests/Redis/files/session.neon @@ -0,0 +1,7 @@ +redis: + journal: false + storage: false + session: + database: 1 + native: false + versionCheck: false