#117067 Доработка редис на yii проектах RedisSentinel
This commit is contained in:
		
							
								
								
									
										402
									
								
								Connection.php
									
									
									
									
									
								
							
							
						
						
									
										402
									
								
								Connection.php
									
									
									
									
									
								
							@@ -3,84 +3,384 @@
 | 
			
		||||
namespace dominion\cache;
 | 
			
		||||
 | 
			
		||||
use Yii;
 | 
			
		||||
use Predis\Client;
 | 
			
		||||
use yii\base\Component;
 | 
			
		||||
use yii\helpers\Inflector;
 | 
			
		||||
use Redis;
 | 
			
		||||
 | 
			
		||||
class Connection extends \yii\redis\Connection
 | 
			
		||||
/**
 | 
			
		||||
 * Работа череез однк ноду
 | 
			
		||||
 * пример конфига
 | 
			
		||||
 *
 | 
			
		||||
 *  [
 | 
			
		||||
 *      'class' => 'dominion\cache\Connection',
 | 
			
		||||
 *      'parameters' => [
 | 
			
		||||
 *          'host' => 'node1.redis.service.optiweb',
 | 
			
		||||
 *          'port' => '6379',
 | 
			
		||||
 *          'prefix' => "prefix",
 | 
			
		||||
 *          'username' => '',
 | 
			
		||||
 *          'password' => 'password',
 | 
			
		||||
 *          'database' => 0,
 | 
			
		||||
 *          'read_timeout' => 0,
 | 
			
		||||
 *          'scan' => ,
 | 
			
		||||
 *          'name' => ,
 | 
			
		||||
 *          'serializer' => ,
 | 
			
		||||
 *          'compression' =>,
 | 
			
		||||
 *          'compression_level' =>
 | 
			
		||||
 *       ]
 | 
			
		||||
 *   ]
 | 
			
		||||
 */
 | 
			
		||||
class Connection extends Component
 | 
			
		||||
{
 | 
			
		||||
    /**
 | 
			
		||||
     * @var mixed Connection parameters for one or more servers.
 | 
			
		||||
     */
 | 
			
		||||
    public $parameters;
 | 
			
		||||
    /**
 | 
			
		||||
     * @var mixed Options to configure some behaviours of the client.
 | 
			
		||||
     */
 | 
			
		||||
    public $options = [];
 | 
			
		||||
    public $parameters = [];
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * @var Client redis socket connection
 | 
			
		||||
     * @var array List of available redis commands.
 | 
			
		||||
     * @see https://redis.io/commands
 | 
			
		||||
     */
 | 
			
		||||
    private $_socket = false;
 | 
			
		||||
    public $redisCommands = [
 | 
			
		||||
        'APPEND', // Append a value to a key
 | 
			
		||||
        'AUTH', // Authenticate to the server
 | 
			
		||||
        'BGREWRITEAOF', // Asynchronously rewrite the append-only file
 | 
			
		||||
        'BGSAVE', // Asynchronously save the dataset to disk
 | 
			
		||||
        'BITCOUNT', // Count set bits in a string
 | 
			
		||||
        'BITFIELD', // Perform arbitrary bitfield integer operations on strings
 | 
			
		||||
        'BITOP', // Perform bitwise operations between strings
 | 
			
		||||
        'BITPOS', // Find first bit set or clear in a string
 | 
			
		||||
        'BLPOP', // Remove and get the first element in a list, or block until one is available
 | 
			
		||||
        'BRPOP', // Remove and get the last element in a list, or block until one is available
 | 
			
		||||
        'BRPOPLPUSH', // Pop a value from a list, push it to another list and return it; or block until one is available
 | 
			
		||||
        'CLIENT KILL', // Kill the connection of a client
 | 
			
		||||
        'CLIENT LIST', // Get the list of client connections
 | 
			
		||||
        'CLIENT GETNAME', // Get the current connection name
 | 
			
		||||
        'CLIENT PAUSE', // Stop processing commands from clients for some time
 | 
			
		||||
        'CLIENT REPLY', // Instruct the server whether to reply to commands
 | 
			
		||||
        'CLIENT SETNAME', // Set the current connection name
 | 
			
		||||
        'CLUSTER ADDSLOTS', // Assign new hash slots to receiving node
 | 
			
		||||
        'CLUSTER COUNTKEYSINSLOT', // Return the number of local keys in the specified hash slot
 | 
			
		||||
        'CLUSTER DELSLOTS', // Set hash slots as unbound in receiving node
 | 
			
		||||
        'CLUSTER FAILOVER', // Forces a slave to perform a manual failover of its master.
 | 
			
		||||
        'CLUSTER FORGET', // Remove a node from the nodes table
 | 
			
		||||
        'CLUSTER GETKEYSINSLOT', // Return local key names in the specified hash slot
 | 
			
		||||
        'CLUSTER INFO', // Provides info about Redis Cluster node state
 | 
			
		||||
        'CLUSTER KEYSLOT', // Returns the hash slot of the specified key
 | 
			
		||||
        'CLUSTER MEET', // Force a node cluster to handshake with another node
 | 
			
		||||
        'CLUSTER NODES', // Get Cluster config for the node
 | 
			
		||||
        'CLUSTER REPLICATE', // Reconfigure a node as a slave of the specified master node
 | 
			
		||||
        'CLUSTER RESET', // Reset a Redis Cluster node
 | 
			
		||||
        'CLUSTER SAVECONFIG', // Forces the node to save cluster state on disk
 | 
			
		||||
        'CLUSTER SETSLOT', // Bind a hash slot to a specific node
 | 
			
		||||
        'CLUSTER SLAVES', // List slave nodes of the specified master node
 | 
			
		||||
        'CLUSTER SLOTS', // Get array of Cluster slot to node mappings
 | 
			
		||||
        'COMMAND', // Get array of Redis command details
 | 
			
		||||
        'COMMAND COUNT', // Get total number of Redis commands
 | 
			
		||||
        'COMMAND GETKEYS', // Extract keys given a full Redis command
 | 
			
		||||
        'COMMAND INFO', // Get array of specific Redis command details
 | 
			
		||||
        'CONFIG GET', // Get the value of a configuration parameter
 | 
			
		||||
        'CONFIG REWRITE', // Rewrite the configuration file with the in memory configuration
 | 
			
		||||
        'CONFIG SET', // Set a configuration parameter to the given value
 | 
			
		||||
        'CONFIG RESETSTAT', // Reset the stats returned by INFO
 | 
			
		||||
        'DBSIZE', // Return the number of keys in the selected database
 | 
			
		||||
        'DEBUG OBJECT', // Get debugging information about a key
 | 
			
		||||
        'DEBUG SEGFAULT', // Make the server crash
 | 
			
		||||
        'DECR', // Decrement the integer value of a key by one
 | 
			
		||||
        'DECRBY', // Decrement the integer value of a key by the given number
 | 
			
		||||
        'DEL', // Delete a key
 | 
			
		||||
        'DISCARD', // Discard all commands issued after MULTI
 | 
			
		||||
        'DUMP', // Return a serialized version of the value stored at the specified key.
 | 
			
		||||
        'ECHO', // Echo the given string
 | 
			
		||||
        'EVAL', // Execute a Lua script server side
 | 
			
		||||
        'EVALSHA', // Execute a Lua script server side
 | 
			
		||||
        'EXEC', // Execute all commands issued after MULTI
 | 
			
		||||
        'EXISTS', // Determine if a key exists
 | 
			
		||||
        'EXPIRE', // Set a key's time to live in seconds
 | 
			
		||||
        'EXPIREAT', // Set the expiration for a key as a UNIX timestamp
 | 
			
		||||
        'FLUSHALL', // Remove all keys from all databases
 | 
			
		||||
        'FLUSHDB', // Remove all keys from the current database
 | 
			
		||||
        'GEOADD', // Add one or more geospatial items in the geospatial index represented using a sorted set
 | 
			
		||||
        'GEOHASH', // Returns members of a geospatial index as standard geohash strings
 | 
			
		||||
        'GEOPOS', // Returns longitude and latitude of members of a geospatial index
 | 
			
		||||
        'GEODIST', // Returns the distance between two members of a geospatial index
 | 
			
		||||
        'GEORADIUS', // Query a sorted set representing a geospatial index to fetch members matching a given maximum distance from a point
 | 
			
		||||
        'GEORADIUSBYMEMBER', // Query a sorted set representing a geospatial index to fetch members matching a given maximum distance from a member
 | 
			
		||||
        'GET', // Get the value of a key
 | 
			
		||||
        'GETBIT', // Returns the bit value at offset in the string value stored at key
 | 
			
		||||
        'GETRANGE', // Get a substring of the string stored at a key
 | 
			
		||||
        'GETSET', // Set the string value of a key and return its old value
 | 
			
		||||
        'HDEL', // Delete one or more hash fields
 | 
			
		||||
        'HEXISTS', // Determine if a hash field exists
 | 
			
		||||
        'HGET', // Get the value of a hash field
 | 
			
		||||
        'HGETALL', // Get all the fields and values in a hash
 | 
			
		||||
        'HINCRBY', // Increment the integer value of a hash field by the given number
 | 
			
		||||
        'HINCRBYFLOAT', // Increment the float value of a hash field by the given amount
 | 
			
		||||
        'HKEYS', // Get all the fields in a hash
 | 
			
		||||
        'HLEN', // Get the number of fields in a hash
 | 
			
		||||
        'HMGET', // Get the values of all the given hash fields
 | 
			
		||||
        'HMSET', // Set multiple hash fields to multiple values
 | 
			
		||||
        'HSET', // Set the string value of a hash field
 | 
			
		||||
        'HSETNX', // Set the value of a hash field, only if the field does not exist
 | 
			
		||||
        'HSTRLEN', // Get the length of the value of a hash field
 | 
			
		||||
        'HVALS', // Get all the values in a hash
 | 
			
		||||
        'INCR', // Increment the integer value of a key by one
 | 
			
		||||
        'INCRBY', // Increment the integer value of a key by the given amount
 | 
			
		||||
        'INCRBYFLOAT', // Increment the float value of a key by the given amount
 | 
			
		||||
        'INFO', // Get information and statistics about the server
 | 
			
		||||
        'KEYS', // Find all keys matching the given pattern
 | 
			
		||||
        'LASTSAVE', // Get the UNIX time stamp of the last successful save to disk
 | 
			
		||||
        'LINDEX', // Get an element from a list by its index
 | 
			
		||||
        'LINSERT', // Insert an element before or after another element in a list
 | 
			
		||||
        'LLEN', // Get the length of a list
 | 
			
		||||
        'LPOP', // Remove and get the first element in a list
 | 
			
		||||
        'LPUSH', // Prepend one or multiple values to a list
 | 
			
		||||
        'LPUSHX', // Prepend a value to a list, only if the list exists
 | 
			
		||||
        'LRANGE', // Get a range of elements from a list
 | 
			
		||||
        'LREM', // Remove elements from a list
 | 
			
		||||
        'LSET', // Set the value of an element in a list by its index
 | 
			
		||||
        'LTRIM', // Trim a list to the specified range
 | 
			
		||||
        'MGET', // Get the values of all the given keys
 | 
			
		||||
        'MIGRATE', // Atomically transfer a key from a Redis instance to another one.
 | 
			
		||||
        'MONITOR', // Listen for all requests received by the server in real time
 | 
			
		||||
        'MOVE', // Move a key to another database
 | 
			
		||||
        'MSET', // Set multiple keys to multiple values
 | 
			
		||||
        'MSETNX', // Set multiple keys to multiple values, only if none of the keys exist
 | 
			
		||||
        'MULTI', // Mark the start of a transaction block
 | 
			
		||||
        'OBJECT', // Inspect the internals of Redis objects
 | 
			
		||||
        'PERSIST', // Remove the expiration from a key
 | 
			
		||||
        'PEXPIRE', // Set a key's time to live in milliseconds
 | 
			
		||||
        'PEXPIREAT', // Set the expiration for a key as a UNIX timestamp specified in milliseconds
 | 
			
		||||
        'PFADD', // Adds the specified elements to the specified HyperLogLog.
 | 
			
		||||
        'PFCOUNT', // Return the approximated cardinality of the set(s) observed by the HyperLogLog at key(s).
 | 
			
		||||
        'PFMERGE', // Merge N different HyperLogLogs into a single one.
 | 
			
		||||
        'PING', // Ping the server
 | 
			
		||||
        'PSETEX', // Set the value and expiration in milliseconds of a key
 | 
			
		||||
        'PSUBSCRIBE', // Listen for messages published to channels matching the given patterns
 | 
			
		||||
        'PUBSUB', // Inspect the state of the Pub/Sub subsystem
 | 
			
		||||
        'PTTL', // Get the time to live for a key in milliseconds
 | 
			
		||||
        'PUBLISH', // Post a message to a channel
 | 
			
		||||
        'PUNSUBSCRIBE', // Stop listening for messages posted to channels matching the given patterns
 | 
			
		||||
        'QUIT', // Close the connection
 | 
			
		||||
        'RANDOMKEY', // Return a random key from the keyspace
 | 
			
		||||
        'READONLY', // Enables read queries for a connection to a cluster slave node
 | 
			
		||||
        'READWRITE', // Disables read queries for a connection to a cluster slave node
 | 
			
		||||
        'RENAME', // Rename a key
 | 
			
		||||
        'RENAMENX', // Rename a key, only if the new key does not exist
 | 
			
		||||
        'RESTORE', // Create a key using the provided serialized value, previously obtained using DUMP.
 | 
			
		||||
        'ROLE', // Return the role of the instance in the context of replication
 | 
			
		||||
        'RPOP', // Remove and get the last element in a list
 | 
			
		||||
        'RPOPLPUSH', // Remove the last element in a list, prepend it to another list and return it
 | 
			
		||||
        'RPUSH', // Append one or multiple values to a list
 | 
			
		||||
        'RPUSHX', // Append a value to a list, only if the list exists
 | 
			
		||||
        'SADD', // Add one or more members to a set
 | 
			
		||||
        'SAVE', // Synchronously save the dataset to disk
 | 
			
		||||
        'SCARD', // Get the number of members in a set
 | 
			
		||||
        'SCRIPT DEBUG', // Set the debug mode for executed scripts.
 | 
			
		||||
        'SCRIPT EXISTS', // Check existence of scripts in the script cache.
 | 
			
		||||
        'SCRIPT FLUSH', // Remove all the scripts from the script cache.
 | 
			
		||||
        'SCRIPT KILL', // Kill the script currently in execution.
 | 
			
		||||
        'SCRIPT LOAD', // Load the specified Lua script into the script cache.
 | 
			
		||||
        'SDIFF', // Subtract multiple sets
 | 
			
		||||
        'SDIFFSTORE', // Subtract multiple sets and store the resulting set in a key
 | 
			
		||||
        'SELECT', // Change the selected database for the current connection
 | 
			
		||||
        'SET', // Set the string value of a key
 | 
			
		||||
        'SETBIT', // Sets or clears the bit at offset in the string value stored at key
 | 
			
		||||
        'SETEX', // Set the value and expiration of a key
 | 
			
		||||
        'SETNX', // Set the value of a key, only if the key does not exist
 | 
			
		||||
        'SETRANGE', // Overwrite part of a string at key starting at the specified offset
 | 
			
		||||
        'SHUTDOWN', // Synchronously save the dataset to disk and then shut down the server
 | 
			
		||||
        'SINTER', // Intersect multiple sets
 | 
			
		||||
        'SINTERSTORE', // Intersect multiple sets and store the resulting set in a key
 | 
			
		||||
        'SISMEMBER', // Determine if a given value is a member of a set
 | 
			
		||||
        'SLAVEOF', // Make the server a slave of another instance, or promote it as master
 | 
			
		||||
        'SLOWLOG', // Manages the Redis slow queries log
 | 
			
		||||
        'SMEMBERS', // Get all the members in a set
 | 
			
		||||
        'SMOVE', // Move a member from one set to another
 | 
			
		||||
        'SORT', // Sort the elements in a list, set or sorted set
 | 
			
		||||
        'SPOP', // Remove and return one or multiple random members from a set
 | 
			
		||||
        'SRANDMEMBER', // Get one or multiple random members from a set
 | 
			
		||||
        'SREM', // Remove one or more members from a set
 | 
			
		||||
        'STRLEN', // Get the length of the value stored in a key
 | 
			
		||||
        'SUBSCRIBE', // Listen for messages published to the given channels
 | 
			
		||||
        'SUNION', // Add multiple sets
 | 
			
		||||
        'SUNIONSTORE', // Add multiple sets and store the resulting set in a key
 | 
			
		||||
        'SWAPDB', // Swaps two Redis databases
 | 
			
		||||
        'SYNC', // Internal command used for replication
 | 
			
		||||
        'TIME', // Return the current server time
 | 
			
		||||
        'TOUCH', // Alters the last access time of a key(s). Returns the number of existing keys specified.
 | 
			
		||||
        'TTL', // Get the time to live for a key
 | 
			
		||||
        'TYPE', // Determine the type stored at key
 | 
			
		||||
        'UNSUBSCRIBE', // Stop listening for messages posted to the given channels
 | 
			
		||||
        'UNLINK', // Delete a key asynchronously in another thread. Otherwise it is just as DEL, but non blocking.
 | 
			
		||||
        'UNWATCH', // Forget about all watched keys
 | 
			
		||||
        'WAIT', // Wait for the synchronous replication of all the write commands sent in the context of the current connection
 | 
			
		||||
        'WATCH', // Watch the given keys to determine execution of the MULTI/EXEC block
 | 
			
		||||
        'XACK', // Removes one or multiple messages from the pending entries list (PEL) of a stream consumer group
 | 
			
		||||
        'XADD', // Appends the specified stream entry to the stream at the specified key
 | 
			
		||||
        'XCLAIM', // Changes the ownership of a pending message, so that the new owner is the consumer specified as the command argument
 | 
			
		||||
        'XDEL', // Removes the specified entries from a stream, and returns the number of entries deleted
 | 
			
		||||
        'XGROUP', // Manages the consumer groups associated with a stream data structure
 | 
			
		||||
        'XINFO', // Retrieves different information about the streams and associated consumer groups
 | 
			
		||||
        'XLEN', // Returns the number of entries inside a stream
 | 
			
		||||
        'XPENDING', // Fetching data from a stream via a consumer group, and not acknowledging such data, has the effect of creating pending entries
 | 
			
		||||
        'XRANGE', // Returns the stream entries matching a given range of IDs
 | 
			
		||||
        'XREAD', // Read data from one or multiple streams, only returning entries with an ID greater than the last received ID reported by the caller
 | 
			
		||||
        'XREADGROUP', // Special version of the XREAD command with support for consumer groups
 | 
			
		||||
        'XREVRANGE', // Exactly like XRANGE, but with the notable difference of returning the entries in reverse order, and also taking the start-end range in reverse order
 | 
			
		||||
        'XTRIM', // Trims the stream to a given number of items, evicting older items (items with lower IDs) if needed
 | 
			
		||||
        'ZADD', // Add one or more members to a sorted set, or update its score if it already exists
 | 
			
		||||
        'ZCARD', // Get the number of members in a sorted set
 | 
			
		||||
        'ZCOUNT', // Count the members in a sorted set with scores within the given values
 | 
			
		||||
        'ZINCRBY', // Increment the score of a member in a sorted set
 | 
			
		||||
        'ZINTERSTORE', // Intersect multiple sorted sets and store the resulting sorted set in a new key
 | 
			
		||||
        'ZLEXCOUNT', // Count the number of members in a sorted set between a given lexicographical range
 | 
			
		||||
        'ZRANGE', // Return a range of members in a sorted set, by index
 | 
			
		||||
        'ZRANGEBYLEX', // Return a range of members in a sorted set, by lexicographical range
 | 
			
		||||
        'ZREVRANGEBYLEX', // Return a range of members in a sorted set, by lexicographical range, ordered from higher to lower strings.
 | 
			
		||||
        'ZRANGEBYSCORE', // Return a range of members in a sorted set, by score
 | 
			
		||||
        'ZRANK', // Determine the index of a member in a sorted set
 | 
			
		||||
        'ZREM', // Remove one or more members from a sorted set
 | 
			
		||||
        'ZREMRANGEBYLEX', // Remove all members in a sorted set between the given lexicographical range
 | 
			
		||||
        'ZREMRANGEBYRANK', // Remove all members in a sorted set within the given indexes
 | 
			
		||||
        'ZREMRANGEBYSCORE', // Remove all members in a sorted set within the given scores
 | 
			
		||||
        'ZREVRANGE', // Return a range of members in a sorted set, by index, with scores ordered from high to low
 | 
			
		||||
        'ZREVRANGEBYSCORE', // Return a range of members in a sorted set, by score, with scores ordered from high to low
 | 
			
		||||
        'ZREVRANK', // Determine the index of a member in a sorted set, with scores ordered from high to low
 | 
			
		||||
        'ZSCORE', // Get the score associated with the given member in a sorted set
 | 
			
		||||
        'ZUNIONSTORE', // Add multiple sorted sets and store the resulting sorted set in a new key
 | 
			
		||||
        'SCAN', // Incrementally iterate the keys space
 | 
			
		||||
        'SSCAN', // Incrementally iterate Set elements
 | 
			
		||||
        'HSCAN', // Incrementally iterate hash fields and associated values
 | 
			
		||||
        'ZSCAN', // Incrementally iterate sorted sets elements and associated scores
 | 
			
		||||
    ];
 | 
			
		||||
 | 
			
		||||
    public function __call($name, $params)
 | 
			
		||||
    {
 | 
			
		||||
        $redisCommand = strtoupper(Inflector::camel2words($name, false));
 | 
			
		||||
        if (in_array($redisCommand, $this->redisCommands)) {
 | 
			
		||||
            return $this->executeCommand($redisCommand, $params);
 | 
			
		||||
        } else {
 | 
			
		||||
            return parent::__call($name, $params);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    public $redis = false;
 | 
			
		||||
 | 
			
		||||
    public function executeCommand($name, $params = [])
 | 
			
		||||
    {
 | 
			
		||||
        $this->open();
 | 
			
		||||
        Yii::debug("Executing Redis Command: {$name} " . implode(' ', $params), __METHOD__);
 | 
			
		||||
        return $this->_socket->executeCommand(
 | 
			
		||||
            $this->_socket->createCommand($name, $params)
 | 
			
		||||
        );
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Closes the connection when this component is being serialized.
 | 
			
		||||
     * @return array
 | 
			
		||||
     */
 | 
			
		||||
    public function __sleep()
 | 
			
		||||
    {
 | 
			
		||||
        $this->close();
 | 
			
		||||
        return array_keys(get_object_vars($this));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Returns a value indicating whether the DB connection is established.
 | 
			
		||||
     * @return bool whether the DB connection is established
 | 
			
		||||
     */
 | 
			
		||||
    public function getIsActive()
 | 
			
		||||
    {
 | 
			
		||||
        return $this->_socket !== false;
 | 
			
		||||
        return $this->redis !== false;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function open()
 | 
			
		||||
    {
 | 
			
		||||
        if ($this->_socket !== false) {
 | 
			
		||||
            return;
 | 
			
		||||
        if (!$this->isActive)
 | 
			
		||||
        {
 | 
			
		||||
            Yii::debug('Opening redis DB connection: ' . var_export($this->parameters, true), __METHOD__);
 | 
			
		||||
            $this->redis = $this->createClient($this->parameters);
 | 
			
		||||
        }
 | 
			
		||||
        Yii::debug('Opening redis DB connection: ' /*. var_export($this->parameters, true)*/, __METHOD__);
 | 
			
		||||
        $this->_socket = new Client($this->parameters, $this->options);
 | 
			
		||||
        $this->initConnection();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Closes the currently active DB connection.
 | 
			
		||||
     * It does nothing if the connection is already closed.
 | 
			
		||||
     */
 | 
			
		||||
    public function close()
 | 
			
		||||
    {
 | 
			
		||||
        if ($this->_socket !== false) {
 | 
			
		||||
        if ($this->isActive)
 | 
			
		||||
        {
 | 
			
		||||
            Yii::debug('Closing DB connection: ' . var_export($this->parameters, true), __METHOD__);
 | 
			
		||||
            $this->_socket->disconnect();
 | 
			
		||||
            $this->_socket = false;
 | 
			
		||||
            $this->redis->disconnect();
 | 
			
		||||
            $this->redis = false;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function __call($name, $params)
 | 
			
		||||
    {
 | 
			
		||||
        $redisCommand = strtoupper(Inflector::camel2words($name, false));
 | 
			
		||||
        if (in_array($redisCommand, $this->redisCommands))
 | 
			
		||||
        {
 | 
			
		||||
            return $this->executeCommand($redisCommand, $params);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return parent::__call($name, $params);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function executeCommand($name, $params = [])
 | 
			
		||||
    {
 | 
			
		||||
        $this->open();
 | 
			
		||||
        Yii::debug("Executing Redis Command: {$name} " . var_export($params, true), __METHOD__);
 | 
			
		||||
        return $this->redis->{$name}(...$params);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function createClient(array $config): Redis
 | 
			
		||||
    {
 | 
			
		||||
        $client = new Redis;
 | 
			
		||||
        $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']);
 | 
			
		||||
        }
 | 
			
		||||
        return $client;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    protected function establishConnection($client, array $config)
 | 
			
		||||
    {
 | 
			
		||||
        $persistent = $config['persistent'] ?? false;
 | 
			
		||||
 | 
			
		||||
        $parameters = [
 | 
			
		||||
            $config['host'],
 | 
			
		||||
            $config['port'],
 | 
			
		||||
            isset($config['timeout']) ? $config['timeout'] : 0.0,
 | 
			
		||||
            $persistent ? (isset($config['persistent_id']) ? $config['persistent_id'] : null) : null,
 | 
			
		||||
            isset($config['retry_interval']) ? $config['retry_interval'] : 0,
 | 
			
		||||
        ];
 | 
			
		||||
 | 
			
		||||
        if (version_compare(phpversion('redis'), '3.1.3', '>='))
 | 
			
		||||
        {
 | 
			
		||||
            $parameters[] = isset($config['read_timeout']) ? $config['read_timeout'] : 0.0;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (version_compare(phpversion('redis'), '5.3.0', '>=') && !is_null($context = isset($config['context']) ? $config['context'] : null))
 | 
			
		||||
        {
 | 
			
		||||
            $parameters[] = $context;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        $client->{$persistent ? 'pconnect' : 'connect'}(...$parameters);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -52,7 +52,7 @@ class RedisCache
 | 
			
		||||
    {
 | 
			
		||||
        if (!self::$livetime)
 | 
			
		||||
        {
 | 
			
		||||
            self::$livetime = isset(Yii::$app->params['redis'], Yii::$app->params['redis']['livetime']) ? (int) Yii::$app->params['redis']['livetime'] : 300;
 | 
			
		||||
            self::$livetime = isset(Yii::$app->params['redis'], Yii::$app->params['redis']['livetime']) ? (int) Yii::$app->params['redis']['livetime'] : 15*60;
 | 
			
		||||
        }
 | 
			
		||||
        return self::$livetime;
 | 
			
		||||
    }
 | 
			
		||||
@@ -61,16 +61,11 @@ class RedisCache
 | 
			
		||||
    {
 | 
			
		||||
        if (!self::$prefix)
 | 
			
		||||
        {
 | 
			
		||||
            self::$prefix = isset(Yii::$app->params['redis'], Yii::$app->params['redis']['prefix']) ? (string)Yii::$app->params['redis']['prefix'] : '';
 | 
			
		||||
            self::$prefix = isset(Yii::$app->redis->parameters, Yii::$app->redis->parameters['prefix']) ? Yii::$app->redis->parameters['prefix'] : '';
 | 
			
		||||
        }
 | 
			
		||||
        return self::$prefix;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    protected static function calculateKey($key)
 | 
			
		||||
    {
 | 
			
		||||
        return self::prefix() . $key;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public static function hdel($key, $value)
 | 
			
		||||
    {
 | 
			
		||||
        if (self::$setDeleteKey)
 | 
			
		||||
@@ -79,7 +74,7 @@ class RedisCache
 | 
			
		||||
        }
 | 
			
		||||
        else
 | 
			
		||||
        {
 | 
			
		||||
            Yii::$app->redis->hdel(self::calculateKey($key), $value);
 | 
			
		||||
            Yii::$app->redis->hdel($key, $value);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@@ -91,13 +86,13 @@ class RedisCache
 | 
			
		||||
        }
 | 
			
		||||
        else
 | 
			
		||||
        {
 | 
			
		||||
            Yii::$app->redis->del(self::calculateKey($key));
 | 
			
		||||
            Yii::$app->redis->del($key);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public static function hset($key, $field, $value)
 | 
			
		||||
    {
 | 
			
		||||
        return self::getActive() ? Yii::$app->redis->hset(self::calculateKey($key), $field, json_encode($value)) : false;
 | 
			
		||||
        return self::getActive() ? Yii::$app->redis->hset($key, $field, json_encode($value)) : false;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public static function hsetModel($key, $field, $model)
 | 
			
		||||
@@ -137,7 +132,7 @@ class RedisCache
 | 
			
		||||
        $output = false;
 | 
			
		||||
        if(self::getActive())
 | 
			
		||||
        {
 | 
			
		||||
            $output = json_decode(Yii::$app->redis->hget(self::calculateKey($key), $field), true);
 | 
			
		||||
            $output = json_decode(Yii::$app->redis->hget($key, $field), true);
 | 
			
		||||
        }
 | 
			
		||||
        return $output === null ? false : $output;;
 | 
			
		||||
    }
 | 
			
		||||
@@ -201,7 +196,7 @@ class RedisCache
 | 
			
		||||
                foreach ($patterns as $pattern)
 | 
			
		||||
                {
 | 
			
		||||
                    $arKeys = [];
 | 
			
		||||
                    while ($values = Yii::$app->redis->hscan(self::calculateKey($key), $cursor, $pattern))
 | 
			
		||||
                    while ($values = Yii::$app->redis->hscan($key, $cursor, $pattern))
 | 
			
		||||
                    {
 | 
			
		||||
                        foreach ($values as $vkey => $value)
 | 
			
		||||
                        {
 | 
			
		||||
@@ -233,7 +228,7 @@ class RedisCache
 | 
			
		||||
    public static function getKeyTypes()
 | 
			
		||||
    {
 | 
			
		||||
 | 
			
		||||
        $result = Yii::$app->redis->keys(self::calculateKey('*'));
 | 
			
		||||
        $result = Yii::$app->redis->keys('*');
 | 
			
		||||
        $output = ['*'];
 | 
			
		||||
        foreach ($result as $val)
 | 
			
		||||
        {
 | 
			
		||||
@@ -258,7 +253,7 @@ class RedisCache
 | 
			
		||||
        {
 | 
			
		||||
            self::deleteAll($type);
 | 
			
		||||
            $type = $type == "*" ? "*" : "{$type}:*";
 | 
			
		||||
            $result = Yii::$app->redis->keys(self::calculateKey($type));
 | 
			
		||||
            $result = Yii::$app->redis->keys($type);
 | 
			
		||||
            foreach ($result as $val)
 | 
			
		||||
            {
 | 
			
		||||
                self::deleteAll(str_replace(self::prefix(), '', $val));
 | 
			
		||||
@@ -280,7 +275,7 @@ class RedisCache
 | 
			
		||||
            {
 | 
			
		||||
                $options = ['EX' => $options];
 | 
			
		||||
            }
 | 
			
		||||
            Yii::$app->redis->set(self::calculateKey($key), json_encode($value) .' '. implode(' ', $options));
 | 
			
		||||
            Yii::$app->redis->set($key, json_encode($value), $options);
 | 
			
		||||
        }
 | 
			
		||||
        return $result;
 | 
			
		||||
    }
 | 
			
		||||
@@ -313,7 +308,7 @@ class RedisCache
 | 
			
		||||
        $result = false;
 | 
			
		||||
        if (self::getActive())
 | 
			
		||||
        {
 | 
			
		||||
            $result = json_decode(Yii::$app->redis->get(self::calculateKey($key)), true);
 | 
			
		||||
            $result = json_decode(Yii::$app->redis->get($key), true);
 | 
			
		||||
        }
 | 
			
		||||
        return $result === null ? false : $result;
 | 
			
		||||
    }
 | 
			
		||||
@@ -380,14 +375,14 @@ class RedisCache
 | 
			
		||||
     */
 | 
			
		||||
    public static function oldCacheDelete()
 | 
			
		||||
    {
 | 
			
		||||
        $result = Yii::$app->redis->keys(self::calculateKey('del:*'));
 | 
			
		||||
        $result = Yii::$app->redis->keys('del:*');
 | 
			
		||||
        foreach ($result as $val)
 | 
			
		||||
        {
 | 
			
		||||
            $cursor = 0;//null;
 | 
			
		||||
            $key = str_replace(self::prefix(), '', $val);
 | 
			
		||||
            $pattern = '*';
 | 
			
		||||
            $arKeys = [];
 | 
			
		||||
            while ($values = Yii::$app->redis->hscan(self::calculateKey($key), $cursor, $pattern))
 | 
			
		||||
            while ($values = Yii::$app->redis->hscan($key, $cursor, $pattern))
 | 
			
		||||
            {
 | 
			
		||||
                foreach ($values as $vkey => $value)
 | 
			
		||||
                {
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										148
									
								
								SentinelConnection.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										148
									
								
								SentinelConnection.php
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,148 @@
 | 
			
		||||
<?php
 | 
			
		||||
 | 
			
		||||
namespace dominion\cache;
 | 
			
		||||
 | 
			
		||||
use Yii;
 | 
			
		||||
use yii\helpers\Inflector;
 | 
			
		||||
use Redis;
 | 
			
		||||
use RedisException;
 | 
			
		||||
use RedisSentinel;
 | 
			
		||||
 | 
			
		||||
class SentinelConnection extends Connection
 | 
			
		||||
{
 | 
			
		||||
    /**
 | 
			
		||||
     * Команды достапные на любой ноде master или slave
 | 
			
		||||
     * @var array
 | 
			
		||||
     */
 | 
			
		||||
    public $redisSlaveCommands = [
 | 
			
		||||
        'GET',
 | 
			
		||||
        'HGET',
 | 
			
		||||
        //нужно перечислить все, но пока так
 | 
			
		||||
    ];
 | 
			
		||||
 | 
			
		||||
    public $slaves = [];
 | 
			
		||||
 | 
			
		||||
    public function executeCommand($name, $params = [])
 | 
			
		||||
    {
 | 
			
		||||
        $this->open();
 | 
			
		||||
        Yii::debug("Executing Redis Command: {$name} " . var_export($params, true), __METHOD__);
 | 
			
		||||
 | 
			
		||||
        $redis = $this->redis; //мастер
 | 
			
		||||
        $redisCommand = strtoupper(Inflector::camel2words($name, false));
 | 
			
		||||
        if (in_array($redisCommand, $this->redisSlaveCommands))
 | 
			
		||||
        {
 | 
			
		||||
            if(!empty($this->slaves))
 | 
			
		||||
            {
 | 
			
		||||
                //читаем из произвольного раба
 | 
			
		||||
                $redis = $this->slaves[array_rand($this->slaves)];
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return $redis->{$name}(...$params);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    protected function isValidServer(mixed $server): bool
 | 
			
		||||
    {
 | 
			
		||||
        return is_array($server) && isset($server['ip']) && isset($server['port']);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function createClient(array $config): Redis
 | 
			
		||||
    {
 | 
			
		||||
        $service = $config['sentinel_service'] ?? 'mymaster';
 | 
			
		||||
 | 
			
		||||
        $hosts = is_array($config['sentinel_host']) ? $config['sentinel_host'] : [$config['sentinel_host']];
 | 
			
		||||
        foreach ($hosts as $host)
 | 
			
		||||
        {
 | 
			
		||||
            $newConfig = $config;
 | 
			
		||||
            $newConfig['sentinel_host'] = $host;
 | 
			
		||||
            $sentinel = $this->connectToSentinel($newConfig);
 | 
			
		||||
 | 
			
		||||
            if ($sentinel->ping())
 | 
			
		||||
            {
 | 
			
		||||
                break;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        $master = $sentinel->master($service);
 | 
			
		||||
        if (!$this->isValidServer($master))
 | 
			
		||||
        {
 | 
			
		||||
            throw new RedisException(sprintf("No master found for service '%s'.", $service));
 | 
			
		||||
        }
 | 
			
		||||
        $slaves = $sentinel->slaves($service);
 | 
			
		||||
        foreach ($slaves as $slave)
 | 
			
		||||
        {
 | 
			
		||||
            if ($this->isValidServer($slave))
 | 
			
		||||
            {
 | 
			
		||||
                //могут быть проблемв из-за большого количества подключений
 | 
			
		||||
                $this->slaves[] = parent::createClient(array_merge($config, [
 | 
			
		||||
                    'host' => $slave['ip'],
 | 
			
		||||
                    'port' => $slave['port'],
 | 
			
		||||
                ]));
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return parent::createClient(array_merge($config, [
 | 
			
		||||
                'host' => $master['ip'],
 | 
			
		||||
                'port' => $master['port'],
 | 
			
		||||
        ]));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private function connectToSentinel(array $config): RedisSentinel
 | 
			
		||||
    {
 | 
			
		||||
        $host = $config['sentinel_host'] ?? '';
 | 
			
		||||
        $port = $config['sentinel_port'] ?? 26379;
 | 
			
		||||
        $timeout = $config['sentinel_timeout'] ?? 0.2;
 | 
			
		||||
        $persistent = $config['sentinel_persistent'] ?? null;
 | 
			
		||||
        $retryInterval = $config['sentinel_retry_interval'] ?? 0;
 | 
			
		||||
        $readTimeout = $config['sentinel_read_timeout'] ?? 0;
 | 
			
		||||
        $username = $config['sentinel_username'] ?? '';
 | 
			
		||||
        $password = $config['sentinel_password'] ?? '';
 | 
			
		||||
        $ssl = $config['sentinel_ssl'] ?? null;
 | 
			
		||||
 | 
			
		||||
        if (strlen(trim($host)) === 0)
 | 
			
		||||
        {
 | 
			
		||||
            throw new ConfigurationException('No host has been specified for the Redis Sentinel connection.');
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        $auth = null;
 | 
			
		||||
        if (strlen(trim($username)) !== 0 && strlen(trim($password)) !== 0)
 | 
			
		||||
        {
 | 
			
		||||
            $auth = [$username, $password];
 | 
			
		||||
        }
 | 
			
		||||
        elseif (strlen(trim($password)) !== 0)
 | 
			
		||||
        {
 | 
			
		||||
            $auth = $password;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (version_compare(phpversion('redis'), '6.0', '>='))
 | 
			
		||||
        {
 | 
			
		||||
            $options = [
 | 
			
		||||
                'host' => $host,
 | 
			
		||||
                'port' => $port,
 | 
			
		||||
                'connectTimeout' => $timeout,
 | 
			
		||||
                'persistent' => $persistent,
 | 
			
		||||
                'retryInterval' => $retryInterval,
 | 
			
		||||
                'readTimeout' => $readTimeout,
 | 
			
		||||
            ];
 | 
			
		||||
 | 
			
		||||
            if ($auth !== null)
 | 
			
		||||
            {
 | 
			
		||||
                $options['auth'] = $auth;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            if (version_compare(phpversion('redis'), '6.1', '>=') && $ssl !== null)
 | 
			
		||||
            {
 | 
			
		||||
                $options['ssl'] = $ssl;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            return new RedisSentinel($options);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if ($auth !== null)
 | 
			
		||||
        {
 | 
			
		||||
            /** @noinspection PhpMethodParametersCountMismatchInspection */
 | 
			
		||||
            return new RedisSentinel($host, $port, $timeout, $persistent, $retryInterval, $readTimeout, $auth);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return new RedisSentinel($host, $port, $timeout, $persistent, $retryInterval, $readTimeout);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										172
									
								
								Session.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										172
									
								
								Session.php
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,172 @@
 | 
			
		||||
<?php
 | 
			
		||||
/**
 | 
			
		||||
 * @link https://www.yiiframework.com/
 | 
			
		||||
 * @copyright Copyright (c) 2008 Yii Software LLC
 | 
			
		||||
 * @license https://www.yiiframework.com/license/
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
namespace dominion\cache;
 | 
			
		||||
 | 
			
		||||
use Yii;
 | 
			
		||||
use yii\base\InvalidConfigException;
 | 
			
		||||
use yii\di\Instance;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Redis Session implements a session component using [redis](https://redis.io/) as the storage medium.
 | 
			
		||||
 *
 | 
			
		||||
 * Redis Session requires redis version 2.6.12 or higher to work properly.
 | 
			
		||||
 *
 | 
			
		||||
 * It needs to be configured with a redis [[Connection]] that is also configured as an application component.
 | 
			
		||||
 * By default it will use the `redis` application component.
 | 
			
		||||
 *
 | 
			
		||||
 * To use redis Session as the session application component, configure the application as follows,
 | 
			
		||||
 *
 | 
			
		||||
 * ~~~
 | 
			
		||||
 * [
 | 
			
		||||
 *     'components' => [
 | 
			
		||||
 *         'session' => [
 | 
			
		||||
 *             'class' => 'yii\redis\Session',
 | 
			
		||||
 *             'redis' => [
 | 
			
		||||
 *                 'hostname' => 'localhost',
 | 
			
		||||
 *                 'port' => 6379,
 | 
			
		||||
 *                 'database' => 0,
 | 
			
		||||
 *             ]
 | 
			
		||||
 *         ],
 | 
			
		||||
 *     ],
 | 
			
		||||
 * ]
 | 
			
		||||
 * ~~~
 | 
			
		||||
 *
 | 
			
		||||
 * Or if you have configured the redis [[Connection]] as an application component, the following is sufficient:
 | 
			
		||||
 *
 | 
			
		||||
 * ~~~
 | 
			
		||||
 * [
 | 
			
		||||
 *     'components' => [
 | 
			
		||||
 *         'session' => [
 | 
			
		||||
 *             'class' => 'yii\redis\Session',
 | 
			
		||||
 *             // 'redis' => 'redis' // id of the connection application component
 | 
			
		||||
 *         ],
 | 
			
		||||
 *     ],
 | 
			
		||||
 * ]
 | 
			
		||||
 * ~~~
 | 
			
		||||
 *
 | 
			
		||||
 * @property-read bool $useCustomStorage Whether to use custom storage.
 | 
			
		||||
 *
 | 
			
		||||
 * @author Carsten Brandt <mail@cebe.cc>
 | 
			
		||||
 * @since 2.0
 | 
			
		||||
 */
 | 
			
		||||
class Session extends \yii\web\Session
 | 
			
		||||
{
 | 
			
		||||
    /**
 | 
			
		||||
     * @var Connection|string|array the Redis [[Connection]] object or the application component ID of the Redis [[Connection]].
 | 
			
		||||
     * This can also be an array that is used to create a redis [[Connection]] instance in case you do not want do configure
 | 
			
		||||
     * redis connection as an application component.
 | 
			
		||||
     * After the Session object is created, if you want to change this property, you should only assign it
 | 
			
		||||
     * with a Redis [[Connection]] object.
 | 
			
		||||
     */
 | 
			
		||||
    public $redis = 'redis';
 | 
			
		||||
    /**
 | 
			
		||||
     * @var string a string prefixed to every cache key so that it is unique. If not set,
 | 
			
		||||
     * it will use a prefix generated from [[Application::id]]. You may set this property to be an empty string
 | 
			
		||||
     * if you don't want to use key prefix. It is recommended that you explicitly set this property to some
 | 
			
		||||
     * static value if the cached data needs to be shared among multiple applications.
 | 
			
		||||
     */
 | 
			
		||||
    public $keyPrefix;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Initializes the redis Session component.
 | 
			
		||||
     * This method will initialize the [[redis]] property to make sure it refers to a valid redis connection.
 | 
			
		||||
     * @throws InvalidConfigException if [[redis]] is invalid.
 | 
			
		||||
     */
 | 
			
		||||
    public function init()
 | 
			
		||||
    {
 | 
			
		||||
        $this->redis = Instance::ensure($this->redis, Connection::className());
 | 
			
		||||
        if ($this->keyPrefix === null) {
 | 
			
		||||
            $this->keyPrefix = substr(md5(Yii::$app->id), 0, 5);
 | 
			
		||||
        }
 | 
			
		||||
        parent::init();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Returns a value indicating whether to use custom session storage.
 | 
			
		||||
     * This method overrides the parent implementation and always returns true.
 | 
			
		||||
     * @return bool whether to use custom storage.
 | 
			
		||||
     */
 | 
			
		||||
    public function getUseCustomStorage()
 | 
			
		||||
    {
 | 
			
		||||
        return true;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Session open handler.
 | 
			
		||||
     * @internal Do not call this method directly.
 | 
			
		||||
     * @param string $savePath session save path
 | 
			
		||||
     * @param string $sessionName session name
 | 
			
		||||
     * @return bool whether session is opened successfully
 | 
			
		||||
     */
 | 
			
		||||
    public function openSession($savePath, $sessionName)
 | 
			
		||||
    {
 | 
			
		||||
        if ($this->getUseStrictMode()) {
 | 
			
		||||
            $id = $this->getId();
 | 
			
		||||
            if (!$this->redis->exists($this->calculateKey($id))) {
 | 
			
		||||
                //This session id does not exist, mark it for forced regeneration
 | 
			
		||||
                $this->_forceRegenerateId = $id;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return parent::openSession($savePath, $sessionName);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Session read handler.
 | 
			
		||||
     * Do not call this method directly.
 | 
			
		||||
     * @param string $id session ID
 | 
			
		||||
     * @return string the session data
 | 
			
		||||
     */
 | 
			
		||||
    public function readSession($id)
 | 
			
		||||
    {
 | 
			
		||||
        $data = $this->redis->get($this->calculateKey($id));
 | 
			
		||||
 | 
			
		||||
        return $data === false || $data === null ? '' : $data;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Session write handler.
 | 
			
		||||
     * Do not call this method directly.
 | 
			
		||||
     * @param string $id session ID
 | 
			
		||||
     * @param string $data session data
 | 
			
		||||
     * @return bool whether session write is successful
 | 
			
		||||
     */
 | 
			
		||||
    public function writeSession($id, $data)
 | 
			
		||||
    {
 | 
			
		||||
        if ($this->getUseStrictMode() && $id === $this->_forceRegenerateId) {
 | 
			
		||||
            //Ignore write when forceRegenerate is active for this id
 | 
			
		||||
            return true;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return (bool) $this->redis->set($this->calculateKey($id), $data, ['EX' => $this->getTimeout()]);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Session destroy handler.
 | 
			
		||||
     * Do not call this method directly.
 | 
			
		||||
     * @param string $id session ID
 | 
			
		||||
     * @return bool whether session is destroyed successfully
 | 
			
		||||
     */
 | 
			
		||||
    public function destroySession($id)
 | 
			
		||||
    {
 | 
			
		||||
        $this->redis->del($this->calculateKey($id));
 | 
			
		||||
        // @see https://github.com/yiisoft/yii2-redis/issues/82
 | 
			
		||||
        return true;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Generates a unique key used for storing session data in cache.
 | 
			
		||||
     * @param string $id session variable name
 | 
			
		||||
     * @return string a safe cache key associated with the session variable name
 | 
			
		||||
     */
 | 
			
		||||
    protected function calculateKey($id)
 | 
			
		||||
    {
 | 
			
		||||
        return $this->keyPrefix . md5(json_encode([__CLASS__, $id]));
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -11,9 +11,7 @@
 | 
			
		||||
        }
 | 
			
		||||
    ],
 | 
			
		||||
    "require": {
 | 
			
		||||
        "yiisoft/yii2-redis": "~2.0.0",
 | 
			
		||||
        "yiisoft/yii2": "~2.0.0",
 | 
			
		||||
        "predis/predis": "^3.0.1"
 | 
			
		||||
        "yiisoft/yii2": "~2.0.0"
 | 
			
		||||
    },
 | 
			
		||||
    "autoload": {
 | 
			
		||||
        "psr-4": {
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user