diff --git a/extensions/redis/Cache.php b/extensions/redis/Cache.php index 0dcb18a..2b7e9e1 100644 --- a/extensions/redis/Cache.php +++ b/extensions/redis/Cache.php @@ -40,7 +40,7 @@ use yii\base\InvalidConfigException; * ] * ~~~ * - * Or if you have configured the redis connection as an application component, the following is sufficient: + * Or if you have configured the redis [[Connection]] as an application component, the following is sufficient: * * ~~~ * [ diff --git a/extensions/redis/README.md b/extensions/redis/README.md index f3777e8..a24ca43 100644 --- a/extensions/redis/README.md +++ b/extensions/redis/README.md @@ -1,9 +1,9 @@ -Redis Cache and ActiveRecord for Yii 2 -====================================== +Redis Cache, Session and ActiveRecord for Yii 2 +=============================================== This extension provides the [redis](http://redis.io/) key-value store support for the Yii2 framework. -It includes a `Cache` class and implents the `ActiveRecord` pattern that allows you to store active -records in redis. +It includes a `Cache` and `Session` storage handler and implents the `ActiveRecord` pattern that allows +you to store active records in redis. To use this extension, you have to configure the Connection class in your application configuration: @@ -21,7 +21,31 @@ return [ ]; ``` -To use the `Cache` component, you also have to configure the `cache` component to be `yii\redis\Cache`: +Installation +------------ + +The preferred way to install this extension is through [composer](http://getcomposer.org/download/). + +Either run + +``` +php composer.phar require yiisoft/yii2-redis "*" +``` + +or add + +```json +"yiisoft/yii2-redis": "*" +``` + +to the require section of your composer.json. + + +Using the Cache component +------------------------- + +To use the `Cache` component, in addtition to configuring the connection as described above, +you also have to configure the `cache` component to be `yii\redis\Cache`: ```php return [ @@ -36,7 +60,7 @@ return [ ``` If you only use the redis cache, you can also configure the parameters of the connection within the -cache component: +cache component (no connection application component needs to be configured in this case): ```php return [ @@ -55,26 +79,44 @@ return [ ]; ``` +Using the Session component +--------------------------- -Installation ------------- - -The preferred way to install this extension is through [composer](http://getcomposer.org/download/). +To use the `Session` component, in addtition to configuring the connection as described above, +you also have to configure the `session` component to be `yii\redis\Session`: -Either run - -``` -php composer.phar require yiisoft/yii2-redis "*" +```php +return [ + //.... + 'components' => [ + // ... + 'session' => [ + 'class' => 'yii\redis\Session', + ], + ] +]; ``` -or add +If you only use the redis session, you can also configure the parameters of the connection within the +cache component (no connection application component needs to be configured in this case): -```json -"yiisoft/yii2-redis": "*" +```php +return [ + //.... + 'components' => [ + // ... + 'session' => [ + 'class' => 'yii\redis\Session', + 'redis' => [ + 'hostname' => 'localhost', + 'port' => 6379, + 'database' => 0, + ], + ], + ] +]; ``` -to the require section of your composer.json. - Using the redis ActiveRecord ---------------------------- @@ -92,10 +134,29 @@ The following is an example model called `Customer`: ```php class Customer extends \yii\redis\ActiveRecord { - public function attributes() - { - return ['id', 'name', 'address', 'registration_date']; - } + /** + * @return array the list of attributes for this record + */ + public function attributes() + { + return ['id', 'name', 'address', 'registration_date']; + } + + /** + * @return ActiveRelation defines a relation to the Order record (can be in other database, e.g. elasticsearch or sql) + */ + public function getOrders() + { + return $this->hasMany(Order::className(), ['customer_id' => 'id']); + } + + /** + * Defines a scope that modifies the `$query` to return only active(status = 1) customers + */ + public static function active($query) + { + $query->andWhere(array('status' => 1)); + } } ``` @@ -108,4 +169,16 @@ It supports the same interface and features except the following limitations: (orderBy() is not yet implemented: [#1305](https://github.com/yiisoft/yii2/issues/1305)) - `via`-relations can not be defined via a table as there are not tables in redis. You can only define relations via other records. -It is also possible to define relations from redis ActiveRecords to normal ActiveRecord classes and vice versa. \ No newline at end of file +It is also possible to define relations from redis ActiveRecords to normal ActiveRecord classes and vice versa. + +Usage example: + +```php +$customer = new Customer(); +$customer->attributes = ['name' => 'test']; +$customer->save(); +echo $customer->id; // id will automatically be incremented if not set explicitly + +$customer = Customer::find()->where(['name' => 'test'])->one(); // find by query +$customer = Customer::find()->active()->all(); // find all by query (using the `active` scope) +``` \ No newline at end of file diff --git a/extensions/redis/Session.php b/extensions/redis/Session.php new file mode 100644 index 0000000..09a0dd4 --- /dev/null +++ b/extensions/redis/Session.php @@ -0,0 +1,157 @@ + [ + * '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 boolean $useCustomStorage Whether to use custom storage. This property is read-only. + * + * @author Carsten Brandt + * @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. + * + * To ensure interoperability, only alphanumeric characters should be used. + */ + 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() + { + parent::init(); + if (is_string($this->redis)) { + $this->redis = Yii::$app->getComponent($this->redis); + } else if (is_array($this->redis)) { + if (!isset($this->redis['class'])) { + $this->redis['class'] = Connection::className(); + } + $this->redis = Yii::createObject($this->redis); + } + if (!$this->redis instanceof Connection) { + throw new InvalidConfigException("Session::redis must be either a Redis connection instance or the application component ID of a Redis connection."); + } + if ($this->keyPrefix === null) { + $this->keyPrefix = substr(md5(Yii::$app->id), 0, 5); + } elseif (!ctype_alnum($this->keyPrefix)) { + throw new InvalidConfigException(get_class($this) . '::keyPrefix should only contain alphanumeric characters.'); + } + } + + /** + * Returns a value indicating whether to use custom session storage. + * This method overrides the parent implementation and always returns true. + * @return boolean whether to use custom storage. + */ + public function getUseCustomStorage() + { + return true; + } + + /** + * 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->executeCommand('GET', [$this->calculateKey($id)]); + return $data === false ? '' : $data; + } + + /** + * Session write handler. + * Do not call this method directly. + * @param string $id session ID + * @param string $data session data + * @return boolean whether session write is successful + */ + public function writeSession($id, $data) + { + return (bool) $this->redis->executeCommand('SET', [$this->calculateKey($id), $data, 'EX', $this->getTimeout()]); + } + + /** + * Session destroy handler. + * Do not call this method directly. + * @param string $id session ID + * @return boolean whether session is destroyed successfully + */ + public function destroySession($id) + { + return (bool) $this->redis->executeCommand('DEL', [$this->calculateKey($id)]); + } + + /** + * 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])); + } +} diff --git a/extensions/redis/composer.json b/extensions/redis/composer.json index fb5065b..16807ae 100644 --- a/extensions/redis/composer.json +++ b/extensions/redis/composer.json @@ -1,7 +1,7 @@ { "name": "yiisoft/yii2-redis", - "description": "Redis Cache and ActiveRecord for the Yii framework", - "keywords": ["yii", "redis", "active-record", "cache"], + "description": "Redis Cache, Session and ActiveRecord for the Yii framework", + "keywords": ["yii", "redis", "active-record", "cache", "session"], "type": "yii2-extension", "license": "BSD-3-Clause", "support": { diff --git a/framework/yii/caching/Cache.php b/framework/yii/caching/Cache.php index 41a25b2..371f91a 100644 --- a/framework/yii/caching/Cache.php +++ b/framework/yii/caching/Cache.php @@ -58,7 +58,7 @@ abstract class Cache extends Component implements \ArrayAccess * 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. * - * To ensure interoperability, only use alphanumeric characters should be used. + * To ensure interoperability, only alphanumeric characters should be used. */ public $keyPrefix; /**