master

laravel/framework

Last updated at: 29/12/2023 09:24

PhpRedisConnector.php

TLDR

The file PhpRedisConnector.php provides a PHP class PhpRedisConnector that is used to create a new connection to Redis using the PhpRedis extension. It implements the Connector interface and includes methods to connect to a single Redis server and a Redis cluster.

Methods

connect

This method accepts an array of configuration options and creates a new connection to a single Redis server. It returns an instance of PhpRedisConnection.

connectToCluster

This method accepts an array of configuration options and creates a new connection to a Redis cluster. It returns an instance of PhpRedisClusterConnection.

buildClusterConnectionString

This protected method accepts an array representing a single Redis server in a cluster and builds a connection string for that server.

createClient

This protected method creates a new Redis client instance using the PhpRedis extension. It accepts an array of configuration options and initializes the client with these options.

establishConnection

This protected method establishes a connection with the Redis host using the PhpRedis extension. It accepts a Redis client instance and an array of configuration options.

createRedisClusterInstance

This protected method creates a new Redis cluster instance using the PhpRedis extension. It accepts an array of Redis servers and an array of configuration options.

formatHost

This protected method formats the host using the scheme if available. It accepts an array of options and returns the formatted host.

Classes

No classes are defined in this file.

<?php

namespace Illuminate\Redis\Connectors;

use Illuminate\Contracts\Redis\Connector;
use Illuminate\Redis\Connections\PhpRedisClusterConnection;
use Illuminate\Redis\Connections\PhpRedisConnection;
use Illuminate\Support\Arr;
use Illuminate\Support\Facades\Redis as RedisFacade;
use Illuminate\Support\Str;
use LogicException;
use Redis;
use RedisCluster;

class PhpRedisConnector implements Connector
{
    /**
     * Create a new connection.
     *
     * @param  array  $config
     * @param  array  $options
     * @return \Illuminate\Redis\Connections\PhpRedisConnection
     */
    public function connect(array $config, array $options)
    {
        $formattedOptions = Arr::pull($config, 'options', []);

        if (isset($config['prefix'])) {
            $formattedOptions['prefix'] = $config['prefix'];
        }

        $connector = function () use ($config, $options, $formattedOptions) {
            return $this->createClient(array_merge(
                $config, $options, $formattedOptions
            ));
        };

        return new PhpRedisConnection($connector(), $connector, $config);
    }

    /**
     * Create a new clustered PhpRedis connection.
     *
     * @param  array  $config
     * @param  array  $clusterOptions
     * @param  array  $options
     * @return \Illuminate\Redis\Connections\PhpRedisClusterConnection
     */
    public function connectToCluster(array $config, array $clusterOptions, array $options)
    {
        $options = array_merge($options, $clusterOptions, Arr::pull($config, 'options', []));

        return new PhpRedisClusterConnection($this->createRedisClusterInstance(
            array_map([$this, 'buildClusterConnectionString'], $config), $options
        ));
    }

    /**
     * Build a single cluster seed string from an array.
     *
     * @param  array  $server
     * @return string
     */
    protected function buildClusterConnectionString(array $server)
    {
        return $this->formatHost($server).':'.$server['port'].'?'.Arr::query(Arr::only($server, [
            'database', 'password', 'prefix', 'read_timeout',
        ]));
    }

    /**
     * Create the Redis client instance.
     *
     * @param  array  $config
     * @return \Redis
     *
     * @throws \LogicException
     */
    protected function createClient(array $config)
    {
        return tap(new Redis, function ($client) use ($config) {
            if ($client instanceof RedisFacade) {
                throw new LogicException(
                    extension_loaded('redis')
                        ? 'Please remove or rename the Redis facade alias in your "app" configuration file in order to avoid collision with the PHP Redis extension.'
                        : 'Please make sure the PHP Redis extension is installed and enabled.'
                );
            }

            $this->establishConnection($client, $config);

            if (! empty($config['password'])) {
                if (isset($config['username']) && $config['username'] !== '' && is_string($config['password'])) {
                    $client->auth([$config['username'], $config['password']]);
                } else {
                    $client->auth($config['password']);
                }
            }

            if (isset($config['database'])) {
                $client->select((int) $config['database']);
            }

            if (! empty($config['prefix'])) {
                $client->setOption(Redis::OPT_PREFIX, $config['prefix']);
            }

            if (! empty($config['read_timeout'])) {
                $client->setOption(Redis::OPT_READ_TIMEOUT, $config['read_timeout']);
            }

            if (! empty($config['scan'])) {
                $client->setOption(Redis::OPT_SCAN, $config['scan']);
            }

            if (! empty($config['name'])) {
                $client->client('SETNAME', $config['name']);
            }

            if (array_key_exists('serializer', $config)) {
                $client->setOption(Redis::OPT_SERIALIZER, $config['serializer']);
            }

            if (array_key_exists('compression', $config)) {
                $client->setOption(Redis::OPT_COMPRESSION, $config['compression']);
            }

            if (array_key_exists('compression_level', $config)) {
                $client->setOption(Redis::OPT_COMPRESSION_LEVEL, $config['compression_level']);
            }
        });
    }

    /**
     * Establish a connection with the Redis host.
     *
     * @param  \Redis  $client
     * @param  array  $config
     * @return void
     */
    protected function establishConnection($client, array $config)
    {
        $persistent = $config['persistent'] ?? false;

        $parameters = [
            $this->formatHost($config),
            $config['port'],
            Arr::get($config, 'timeout', 0.0),
            $persistent ? Arr::get($config, 'persistent_id', null) : null,
            Arr::get($config, 'retry_interval', 0),
        ];

        if (version_compare(phpversion('redis'), '3.1.3', '>=')) {
            $parameters[] = Arr::get($config, 'read_timeout', 0.0);
        }

        if (version_compare(phpversion('redis'), '5.3.0', '>=') && ! is_null($context = Arr::get($config, 'context'))) {
            $parameters[] = $context;
        }

        $client->{$persistent ? 'pconnect' : 'connect'}(...$parameters);
    }

    /**
     * Create a new redis cluster instance.
     *
     * @param  array  $servers
     * @param  array  $options
     * @return \RedisCluster
     */
    protected function createRedisClusterInstance(array $servers, array $options)
    {
        $parameters = [
            null,
            array_values($servers),
            $options['timeout'] ?? 0,
            $options['read_timeout'] ?? 0,
            isset($options['persistent']) && $options['persistent'],
        ];

        if (version_compare(phpversion('redis'), '4.3.0', '>=')) {
            $parameters[] = $options['password'] ?? null;
        }

        if (version_compare(phpversion('redis'), '5.3.2', '>=') && ! is_null($context = Arr::get($options, 'context'))) {
            $parameters[] = $context;
        }

        return tap(new RedisCluster(...$parameters), function ($client) use ($options) {
            if (! empty($options['prefix'])) {
                $client->setOption(Redis::OPT_PREFIX, $options['prefix']);
            }

            if (! empty($options['scan'])) {
                $client->setOption(Redis::OPT_SCAN, $options['scan']);
            }

            if (! empty($options['failover'])) {
                $client->setOption(RedisCluster::OPT_SLAVE_FAILOVER, $options['failover']);
            }

            if (! empty($options['name'])) {
                $client->client('SETNAME', $options['name']);
            }

            if (array_key_exists('serializer', $options)) {
                $client->setOption(Redis::OPT_SERIALIZER, $options['serializer']);
            }

            if (array_key_exists('compression', $options)) {
                $client->setOption(Redis::OPT_COMPRESSION, $options['compression']);
            }

            if (array_key_exists('compression_level', $options)) {
                $client->setOption(Redis::OPT_COMPRESSION_LEVEL, $options['compression_level']);
            }
        });
    }

    /**
     * Format the host using the scheme if available.
     *
     * @param  array  $options
     * @return string
     */
    protected function formatHost(array $options)
    {
        if (isset($options['scheme'])) {
            return Str::start($options['host'], "{$options['scheme']}://");
        }

        return $options['host'];
    }
}