├── .codeclimate.yml ├── .editorconfig ├── .gitignore ├── .travis.yml ├── Cache.php ├── Connection.php ├── README.md ├── Session.php ├── composer.json ├── phpredis-vs-yii-redis.png ├── phpunit.xml.dist └── tests ├── CacheTest.php ├── ConnectionTest.php ├── SessionTest.php ├── TestCase.php ├── bootstrap.php ├── config.php └── performance.php /.codeclimate.yml: -------------------------------------------------------------------------------- 1 | --- 2 | engines: 3 | duplication: 4 | enabled: true 5 | config: 6 | languages: 7 | - php 8 | fixme: 9 | enabled: true 10 | phpcodesniffer: 11 | enabled: true 12 | phpmd: 13 | enabled: true 14 | ratings: 15 | paths: 16 | - "**.php" 17 | exclude_paths: 18 | - tests/ 19 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | # Unix-style newlines with a newline ending every file 4 | [*] 5 | end_of_line = lf 6 | insert_final_newline = true 7 | charset = utf-8 8 | 9 | [*.php] 10 | indent_style = space 11 | indent_size = 4 12 | trim_trailing_whitespace = true 13 | 14 | [*.json] 15 | indent_style = space 16 | indent_size = 2 17 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /vendor 2 | /composer.lock 3 | *.swp 4 | /.idea 5 | /tests/config-local.php 6 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: php 2 | 3 | php: 4 | - '5.4' 5 | - '5.5' 6 | - '5.6' 7 | - '7.0' 8 | - '7.1' 9 | 10 | services: 11 | - redis-server 12 | 13 | before_install: v=$(phpenv version-name); if [ ${v:0:1} -lt 7 ]; then pecl install igbinary ; yes | pecl install redis; else echo "extension = redis.so" >> ~/.phpenv/versions/$(phpenv version-name)/etc/php.ini; fi 14 | 15 | install: 16 | - composer global require --prefer-dist "fxp/composer-asset-plugin:^1.2.0" 17 | - composer require codeclimate/php-test-reporter --dev --prefer-dist 18 | - composer install --no-progress --no-interaction --prefer-dist 19 | 20 | script: 21 | - ./vendor/bin/phpunit --coverage-clover build/logs/clover.xml 22 | 23 | addons: 24 | code_climate: 25 | repo_token: 255db28eb13c47dff54362135d879145fc97afff3eb91d97158608818bb4d1a9 26 | 27 | after_script: 28 | - vendor/bin/test-reporter 29 | -------------------------------------------------------------------------------- /Cache.php: -------------------------------------------------------------------------------- 1 | redis = Instance::ensure($this->redis, Connection::className()); 27 | $this->redis->open(); 28 | } 29 | 30 | 31 | /** 32 | * @inheritdoc 33 | */ 34 | public function exists($key) 35 | { 36 | $key = $this->buildKey($key); 37 | 38 | return (bool)$this->redis->exists($key); 39 | } 40 | 41 | /** 42 | * @inheritdoc 43 | */ 44 | protected function getValue($key) 45 | { 46 | return $this->redis->get($key); 47 | } 48 | 49 | /** 50 | * @inheritdoc 51 | */ 52 | protected function getValues($keys) 53 | { 54 | $response = $this->redis->mget($keys); 55 | $result = []; 56 | $i = 0; 57 | foreach ($keys as $key) { 58 | $result[$key] = $response[$i++]; 59 | } 60 | 61 | return $result; 62 | } 63 | 64 | /** 65 | * @inheritdoc 66 | */ 67 | protected function setValue($key, $value, $expire) 68 | { 69 | if ($expire == 0) { 70 | return (bool)$this->redis->set($key, $value); 71 | } else { 72 | return (bool)$this->redis->setEx($key, $expire, $value); 73 | } 74 | } 75 | 76 | /** 77 | * @inheritdoc 78 | */ 79 | protected function setValues($data, $expire) 80 | { 81 | $failedKeys = []; 82 | if ($expire == 0) { 83 | $this->redis->mSet($data); 84 | } else { 85 | $expire = (int)$expire; 86 | $this->redis->multi(); 87 | $this->redis->mSet($data); 88 | $index = []; 89 | foreach ($data as $key => $value) { 90 | $this->redis->expire($key, $expire); 91 | $index[] = $key; 92 | } 93 | $result = $this->redis->exec(); 94 | array_shift($result); 95 | foreach ($result as $i => $r) { 96 | if ($r != 1) { 97 | $failedKeys[] = $index[$i]; 98 | } 99 | } 100 | } 101 | 102 | return $failedKeys; 103 | } 104 | 105 | 106 | /** 107 | * @inheritdoc 108 | */ 109 | protected function addValue($key, $value, $expire) 110 | { 111 | if ($expire == 0) { 112 | return (bool)$this->redis->setNx($key, $value); 113 | } 114 | 115 | return (bool)$this->redis->rawCommand('SET', $key, $value, 'EX', $expire, 'NX'); 116 | } 117 | 118 | /** 119 | * @inheritdoc 120 | */ 121 | protected function deleteValue($key) 122 | { 123 | return (bool)$this->redis->del($key); 124 | } 125 | 126 | /** 127 | * @inheritdoc 128 | */ 129 | protected function flushValues() 130 | { 131 | return $this->redis->flushdb(); 132 | } 133 | } 134 | -------------------------------------------------------------------------------- /Connection.php: -------------------------------------------------------------------------------- 1 | unixSocket !== null) { 91 | $isConnected = $this->connect($this->unixSocket); 92 | } else { 93 | if(is_null($host)){ 94 | $host = $this->hostname; 95 | } 96 | if(is_null($port)){ 97 | $port = $this->port; 98 | } 99 | if(is_null($timeout)){ 100 | $timeout = $this->connectionTimeout; 101 | } 102 | $isConnected = $this->connect($host, $port, $timeout, null, $retry_interval); 103 | } 104 | 105 | if ($isConnected === false) { 106 | throw new RedisException('Connect to redis server error.'); 107 | } 108 | 109 | if ($this->password !== null) { 110 | $this->auth($this->password); 111 | } 112 | 113 | if ($this->database !== null) { 114 | $this->select($this->database); 115 | } 116 | } 117 | 118 | /** 119 | * @return bool 120 | */ 121 | public function ping() 122 | { 123 | return parent::ping() === '+PONG'; 124 | } 125 | 126 | public function flushdb() 127 | { 128 | return parent::flushDB(); 129 | } 130 | } 131 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Redis Cache and Session for Yii2 2 | ====================== 3 | This extension provides the [redis](http://redis.io/) key-value store support for the [Yii framework 2.0](http://www.yiiframework.com). 4 | 5 | It includes a `Cache` and `Session` storage handler in redis. 6 | 7 | 8 | [![Build Status](https://travis-ci.org/dcb9/yii2-phpredis.svg?branch=master)](https://travis-ci.org/dcb9/yii2-phpredis) 9 | [![Code Climate](https://codeclimate.com/github/dcb9/yii2-phpredis/badges/gpa.svg)](https://codeclimate.com/github/dcb9/yii2-phpredis) 10 | [![Test Coverage](https://codeclimate.com/github/dcb9/yii2-phpredis/badges/coverage.svg)](https://codeclimate.com/github/dcb9/yii2-phpredis/coverage) 11 | [![Issue Count](https://codeclimate.com/github/dcb9/yii2-phpredis/badges/issue_count.svg)](https://codeclimate.com/github/dcb9/yii2-phpredis) 12 | [![Latest Stable Version](https://poser.pugx.org/dcb9/yii2-phpredis/version)](https://packagist.org/packages/dcb9/yii2-phpredis) 13 | [![Total Downloads](https://poser.pugx.org/dcb9/yii2-phpredis/downloads)](https://packagist.org/packages/dcb9/yii2-phpredis) 14 | [![License](https://poser.pugx.org/dcb9/yii2-phpredis/license)](https://packagist.org/packages/dcb9/yii2-phpredis) 15 | 16 | **Notice: THIS REPO DOES NOT SUPPORT ACTIVE RECORD.** 17 | 18 | Requirements 19 | ------------ 20 | 21 | - PHP >= 5.4.0 22 | - Redis >= 2.6.12 23 | - ext-redis >= 2.2.7 24 | - Yii2 ~2.0.4 25 | 26 | Installation 27 | ------------ 28 | 29 | The preferred way to install this extension is through [composer](http://getcomposer.org/download/). 30 | 31 | Either run 32 | 33 | ``` 34 | php composer.phar require --prefer-dist dcb9/yii2-phpredis 35 | ``` 36 | 37 | or add 38 | 39 | ```json 40 | "dcb9/yii2-phpredis": "~1.0" 41 | ``` 42 | 43 | to the require section of your composer.json. 44 | 45 | 46 | Configuration 47 | ------------- 48 | 49 | To use this extension, you have to configure the Connection class in your application configuration: 50 | 51 | ```php 52 | return [ 53 | //.... 54 | 'components' => [ 55 | 'redis' => [ 56 | 'class' => 'dcb9\redis\Connection', 57 | 'hostname' => 'localhost', 58 | 'port' => 6379, 59 | 'database' => 0, 60 | ], 61 | ] 62 | ]; 63 | ``` 64 | 65 | Run unit test 66 | ------------- 67 | 68 | You can specific your redis config 69 | 70 | ``` 71 | $ cp tests/config.php tests/config-local.php 72 | $ vim tests/config-local.php 73 | ``` 74 | 75 | and Run 76 | 77 | ``` 78 | $ ./vendor/bin/phpunit 79 | PHPUnit 5.6.1 by Sebastian Bergmann and contributors. 80 | 81 | ............ 12 / 12 (100%) 82 | 83 | Time: 600 ms, Memory: 10.00MB 84 | 85 | OK (12 tests, 50 assertions) 86 | ``` 87 | 88 | Performance test 89 | ------------------ 90 | 91 | ``` 92 | $ php tests/performance.php 93 | ``` 94 | 95 | ![phpredis-vs-yii-redis](./phpredis-vs-yii-redis.png) 96 | -------------------------------------------------------------------------------- /Session.php: -------------------------------------------------------------------------------- 1 | [ 21 | * 'session' => [ 22 | * 'class' => 'dcb9\redis\Session', 23 | * 'redis' => [ 24 | * 'hostname' => 'localhost', 25 | * 'port' => 6379, 26 | * 'database' => 0, 27 | * ] 28 | * ], 29 | * ], 30 | * ] 31 | * ~~~ 32 | * 33 | * Or if you have configured the redis [[Connection]] as an application component, the following is sufficient: 34 | * 35 | * ~~~ 36 | * [ 37 | * 'components' => [ 38 | * 'session' => [ 39 | * 'class' => 'dcb9\redis\Session', 40 | * // 'redis' => 'redis' // id of the connection application component 41 | * ], 42 | * ], 43 | * ] 44 | * ~~~ 45 | * 46 | * @property boolean $useCustomStorage Whether to use custom storage. This property is read-only. 47 | * 48 | * @author Bob chengbin 49 | */ 50 | class Session extends \yii\web\Session 51 | { 52 | /** 53 | * @var Connection|string|array the Redis [[Connection]] object or the application component ID of the Redis [[Connection]]. 54 | * This can also be an array that is used to create a redis [[Connection]] instance in case you do not want do configure 55 | * redis connection as an application component. 56 | * After the Session object is created, if you want to change this property, you should only assign it 57 | * with a Redis [[Connection]] object. 58 | */ 59 | public $redis = 'redis'; 60 | 61 | /** 62 | * @var string a string prefixed to every cache key so that it is unique. If not set, 63 | * it will use a prefix generated from [[Application::id]]. You may set this property to be an empty string 64 | * if you don't want to use key prefix. It is recommended that you explicitly set this property to some 65 | * static value if the cached data needs to be shared among multiple applications. 66 | */ 67 | public $keyPrefix; 68 | 69 | /** 70 | * Initializes the redis Session component. 71 | * This method will initialize the [[redis]] property to make sure it refers to a valid redis connection. 72 | * @throws InvalidConfigException if [[redis]] is invalid. 73 | */ 74 | public function init() 75 | { 76 | if (is_string($this->redis)) { 77 | $this->redis = Yii::$app->get($this->redis); 78 | } elseif (is_array($this->redis)) { 79 | if (!isset($this->redis['class'])) { 80 | $this->redis['class'] = Connection::className(); 81 | } 82 | $this->redis = Yii::createObject($this->redis); 83 | } 84 | if (!$this->redis instanceof Connection) { 85 | throw new InvalidConfigException("Session::redis must be either a Redis connection instance or the application component ID of a Redis connection."); 86 | } 87 | if ($this->keyPrefix === null) { 88 | $this->keyPrefix = substr(md5(Yii::$app->id), 0, 5); 89 | } 90 | $this->redis->open(); 91 | 92 | parent::init(); 93 | } 94 | 95 | /** 96 | * Returns a value indicating whether to use custom session storage. 97 | * This method overrides the parent implementation and always returns true. 98 | * @return boolean whether to use custom storage. 99 | */ 100 | public function getUseCustomStorage() 101 | { 102 | return true; 103 | } 104 | 105 | /** 106 | * Session read handler. 107 | * Do not call this method directly. 108 | * @param string $id session ID 109 | * @return string the session data 110 | */ 111 | public function readSession($id) 112 | { 113 | $data = $this->redis->get($this->calculateKey($id)); 114 | 115 | return $data === false || $data === null ? '' : $data; 116 | } 117 | 118 | /** 119 | * Session write handler. 120 | * Do not call this method directly. 121 | * @param string $id session ID 122 | * @param string $data session data 123 | * @return boolean whether session write is successful 124 | */ 125 | public function writeSession($id, $data) 126 | { 127 | return (bool)$this->redis->setex($this->calculateKey($id), $this->getTimeout(), $data); 128 | } 129 | 130 | /** 131 | * Session destroy handler. 132 | * Do not call this method directly. 133 | * @param string $id session ID 134 | * @return boolean whether session is destroyed successfully 135 | */ 136 | public function destroySession($id) 137 | { 138 | return (bool)$this->redis->del($this->calculateKey($id)); 139 | } 140 | 141 | /** 142 | * Generates a unique key used for storing session data in cache. 143 | * @param string $id session variable name 144 | * @return string a safe cache key associated with the session variable name 145 | */ 146 | protected function calculateKey($id) 147 | { 148 | return $this->keyPrefix . md5(json_encode([__CLASS__, $id])); 149 | } 150 | } 151 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "dcb9/yii2-phpredis", 3 | "description": "yii2 with phpredis", 4 | "minimum-stability": "stable", 5 | "license": "BSD", 6 | "authors": [ 7 | { 8 | "name": "Bob Chengbin", 9 | "email": "bob@phpor.me" 10 | } 11 | ], 12 | "require": { 13 | "yiisoft/yii2": "~2.0.4", 14 | "ext-redis": ">=2.2.7", 15 | "php": ">=5.4.0" 16 | }, 17 | "autoload": { 18 | "psr-4": { 19 | "dcb9\\redis\\": "" 20 | } 21 | }, 22 | "require-dev": { 23 | "phpunit/phpunit": "<6.0", 24 | "yiisoft/yii2-redis": "^2.0" 25 | }, 26 | "config": { 27 | "fxp-asset": { 28 | "vcs-driver-options": { 29 | "github-no-api": true 30 | }, 31 | "pattern-skip-version": "(-build|-patch)" 32 | } 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /phpredis-vs-yii-redis.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dcb9/yii2-phpredis/836f9ff24562d614b608cda1fc1a2aea18782f9b/phpredis-vs-yii-redis.png -------------------------------------------------------------------------------- /phpunit.xml.dist: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 | 10 | ./tests 11 | 12 | 13 | 14 | 15 | ./Cache.php 16 | ./Connection.php 17 | ./Session.php 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /tests/CacheTest.php: -------------------------------------------------------------------------------- 1 | mockApplication(['components' => ['redis' => $connection]]); 20 | if ($this->_cacheInstance === null) { 21 | $this->_cacheInstance = new Cache(); 22 | } 23 | 24 | return $this->_cacheInstance; 25 | } 26 | 27 | /** 28 | * Store a value that is 2 times buffer size big 29 | * https://github.com/yiisoft/yii2/issues/743 30 | */ 31 | public function testLargeData() 32 | { 33 | $cache = $this->getCacheInstance(); 34 | $data = str_repeat('XX', 8192); // http://www.php.net/manual/en/function.fread.php 35 | $key = 'bigdata1'; 36 | $this->assertFalse($cache->get($key)); 37 | $cache->set($key, $data); 38 | $this->assertTrue($cache->get($key) === $data); 39 | // try with multibyte string 40 | $data = str_repeat('ЖЫ', 8192); // http://www.php.net/manual/en/function.fread.php 41 | $key = 'bigdata2'; 42 | $this->assertFalse($cache->get($key)); 43 | $cache->set($key, $data); 44 | $this->assertTrue($cache->get($key) === $data); 45 | } 46 | 47 | /** 48 | * Store a megabyte and see how it goes 49 | * https://github.com/yiisoft/yii2/issues/6547 50 | */ 51 | public function testReallyLargeData() 52 | { 53 | $cache = $this->getCacheInstance(); 54 | $keys = []; 55 | for ($i = 1; $i < 16; $i++) { 56 | $key = 'realbigdata' . $i; 57 | $data = str_repeat('X', 100 * 1024); // 100 KB 58 | $keys[$key] = $data; 59 | // $this->assertTrue($cache->get($key) === false); // do not display 100KB in terminal if this fails :) 60 | $cache->set($key, $data); 61 | } 62 | $values = $cache->mget(array_keys($keys)); 63 | foreach ($keys as $key => $value) { 64 | $this->assertArrayHasKey($key, $values); 65 | $this->assertTrue($values[$key] === $value); 66 | } 67 | } 68 | 69 | public function testMultiByteGetAndSet() 70 | { 71 | $cache = $this->getCacheInstance(); 72 | $data = ['abc' => 'ежик', 2 => 'def']; 73 | $key = 'data1'; 74 | $this->assertFalse($cache->get($key)); 75 | $cache->set($key, $data); 76 | $this->assertTrue($cache->get($key) === $data); 77 | } 78 | 79 | public function testFlushValues() 80 | { 81 | $cache = $this->getCacheInstance(); 82 | $key = 'data'; 83 | $cache->set($key, 'val'); 84 | $cache->flush(); 85 | $this->assertFalse($cache->get($key)); 86 | } 87 | 88 | public function testMultiSet() 89 | { 90 | $cache = $this->getCacheInstance(); 91 | $items = [ 92 | 'k1' => 'v1', 93 | 'k2' => 'v2', 94 | 'k3' => 'v3', 95 | ]; 96 | $this->assertEquals([], $cache->multiSet($items, 1)); 97 | $this->assertEquals('v1', $cache->get('k1')); 98 | $this->assertEquals('v2', $cache->get('k2')); 99 | $this->assertEquals('v3', $cache->get('k3')); 100 | sleep(1); 101 | $this->assertFalse($cache->get('k1')); 102 | $this->assertFalse($cache->get('k2')); 103 | $this->assertFalse($cache->get('k3')); 104 | 105 | $this->assertFalse($cache->exists('k1')); 106 | $this->assertFalse($cache->exists('k2')); 107 | $this->assertFalse($cache->exists('k3')); 108 | 109 | $cache->multiSet($items); 110 | sleep(2); 111 | $this->assertEquals('v1', $cache->get('k1')); 112 | $this->assertEquals('v2', $cache->get('k2')); 113 | $this->assertEquals('v3', $cache->get('k3')); 114 | } 115 | 116 | public function testSetGet() 117 | { 118 | $cache = $this->getCacheInstance(); 119 | $cache->set('key', 'val', 1); 120 | $this->assertEquals('val', $cache->get('key')); 121 | sleep(1); 122 | $this->assertFalse($cache->get('key')); 123 | $this->assertFalse($cache->exists('key')); 124 | 125 | $cache->set('key', 'val'); 126 | $this->assertTrue($cache->delete('key')); 127 | $this->assertFalse($cache->exists('key')); 128 | 129 | } 130 | 131 | public function testMultiAdd() 132 | { 133 | $cache = $this->getCacheInstance(); 134 | $items = [ 135 | 'k1' => 'v1', 136 | 'k2' => 'v2', 137 | 'k3' => 'v3', 138 | ]; 139 | $cache->multiSet($items); 140 | $this->assertEquals(['k2'], $cache->multiAdd([ 141 | 'k2' => 'vv22', 142 | 'k4' => 'vv44', 143 | ])); 144 | 145 | $this->assertEquals('v2', $cache->get('k2')); 146 | $this->assertEquals('vv44', $cache->get('k4')); 147 | 148 | $this->assertEquals(['k1'], $cache->multiAdd([ 149 | 'k5' => 'vv55', 150 | 'k1' => 'v1', 151 | ], 1)); 152 | $this->assertEquals('vv55', $cache->get('k5')); 153 | sleep(1); 154 | $this->assertFalse($cache->exists('k5')); 155 | $this->assertTrue($cache->exists('k1')); 156 | } 157 | } 158 | -------------------------------------------------------------------------------- /tests/ConnectionTest.php: -------------------------------------------------------------------------------- 1 | getConnection(false); 13 | $database = $db->database; 14 | $db->open(); 15 | $this->assertTrue($db->ping()); 16 | $db->set('YIITESTKEY', 'YIITESTVALUE'); 17 | $db->close(); 18 | 19 | $db = $this->getConnection(false); 20 | $db->database = $database; 21 | $db->open(); 22 | $this->assertEquals('YIITESTVALUE', $db->get('YIITESTKEY')); 23 | $db->close(); 24 | 25 | $db = $this->getConnection(false); 26 | $db->database = 1; 27 | $db->open(); 28 | $this->assertFalse($db->get('YIITESTKEY')); 29 | $db->close(); 30 | } 31 | 32 | /** 33 | * tests whether close cleans up correctly so that a new connect works 34 | */ 35 | public function testReConnect() 36 | { 37 | $db = $this->getConnection(false); 38 | $db->open(); 39 | $this->assertTrue($db->ping()); 40 | $db->close(); 41 | $db->open(); 42 | $this->assertTrue($db->ping()); 43 | $db->close(); 44 | } 45 | 46 | public function keyValueData() 47 | { 48 | return [ 49 | [123], 50 | [-123], 51 | [0], 52 | ['test'], 53 | ["test\r\ntest"], 54 | [''], 55 | ]; 56 | } 57 | 58 | /** 59 | * @dataProvider keyValueData 60 | */ 61 | public function testStoreGet($data) 62 | { 63 | $db = $this->getConnection(true); 64 | $db->set('hi', $data); 65 | $this->assertEquals($data, $db->get('hi')); 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /tests/SessionTest.php: -------------------------------------------------------------------------------- 1 | mockApplication([ 15 | 'components' => [ 16 | 'redis' => $params, 17 | 'session' => 'dcb9\\redis\\Session', 18 | ] 19 | ]); 20 | 21 | $sessionId = 'sessionId'; 22 | $session = Yii::$app->session; 23 | $session->setTimeout(1); 24 | $sessionData = json_encode([ 25 | 'sessionId' => $sessionId, 26 | 'username' => 'bob', 27 | ]); 28 | $session->writeSession($sessionId, $sessionData); 29 | $this->assertEquals($sessionData, $session->readSession($sessionId)); 30 | $this->assertTrue($session->destroySession($sessionId)); 31 | $this->assertEquals('', $session->readSession($sessionId)); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /tests/TestCase.php: -------------------------------------------------------------------------------- 1 | destroyApplication(); 42 | } 43 | 44 | /** 45 | * Populates Yii::$app with a new application 46 | * The application will be destroyed on tearDown() automatically. 47 | * @param array $config The application configuration, if needed 48 | * @param string $appClass name of the application class to create 49 | */ 50 | protected function mockApplication($config = [], $appClass = '\yii\console\Application') 51 | { 52 | new $appClass(ArrayHelper::merge([ 53 | 'id' => 'testapp', 54 | 'basePath' => __DIR__, 55 | 'vendorPath' => dirname(__DIR__) . '/vendor', 56 | ], $config)); 57 | } 58 | 59 | protected function mockWebApplication($config = [], $appClass = '\yii\web\Application') 60 | { 61 | new $appClass(ArrayHelper::merge([ 62 | 'id' => 'testapp', 63 | 'basePath' => __DIR__, 64 | 'vendorPath' => dirname(__DIR__) . '/vendor', 65 | 'components' => [ 66 | 'request' => [ 67 | 'cookieValidationKey' => 'wefJDF8sfdsfSDefwqdxj9oq', 68 | 'scriptFile' => __DIR__ . '/index.php', 69 | 'scriptUrl' => '/index.php', 70 | ], 71 | ] 72 | ], $config)); 73 | } 74 | 75 | /** 76 | * Destroys application in Yii::$app by setting it to null. 77 | */ 78 | protected function destroyApplication() 79 | { 80 | Yii::$app = null; 81 | Yii::$container = new Container(); 82 | } 83 | 84 | protected function setUp() 85 | { 86 | $params = self::getParam(); 87 | if ($params === null) { 88 | $this->markTestSkipped('No redis server connection configured.'); 89 | } 90 | $connection = new Connection($params); 91 | $this->mockApplication(['components' => ['redis' => $connection]]); 92 | 93 | parent::setUp(); 94 | } 95 | 96 | /** 97 | * @param boolean $reset whether to clean up the test database 98 | * @return Connection 99 | */ 100 | public function getConnection($reset = true) 101 | { 102 | $params = self::getParam(); 103 | $db = new Connection($params); 104 | if ($reset) { 105 | $db->open(); 106 | $db->flushdb(); 107 | } 108 | 109 | return $db; 110 | } 111 | } 112 | -------------------------------------------------------------------------------- /tests/bootstrap.php: -------------------------------------------------------------------------------- 1 | 'localhost', 5 | 'port' => 6379, 6 | 'database' => 0, 7 | 'password' => null, 8 | ]; 9 | -------------------------------------------------------------------------------- /tests/performance.php: -------------------------------------------------------------------------------- 1 | 'test-performance-app', 16 | 'basePath' => __DIR__, 17 | 'vendorPath' => dirname(__DIR__) . '/vendor', 18 | 'components' => [ 19 | 'phpRedis' => $phpRedisConfig, 20 | 'yiiRedis' => $yiiRedisConfig, 21 | ], 22 | ]); 23 | 24 | $count = 10000; 25 | echo "phpredis run SET $count times in"; 26 | $start = microtime(true); 27 | /* @var $phpRedis \dcb9\redis\Connection */ 28 | $phpRedis = Yii::$app->phpRedis; 29 | $phpRedis->open(); 30 | $phpRedis->flushdb(); 31 | for ($i = 0; $i < $count; $i++) { 32 | $phpRedis->set('php_redis_prefix' . $i, $i); 33 | } 34 | echo " " . ((microtime(true) - $start) * 1000) . " micro seconds.\n"; 35 | 36 | echo "yii redis run SET $count times in"; 37 | $start = microtime(true); 38 | /* @var $yiiRedis \yii\redis\Connection */ 39 | $yiiRedis = Yii::$app->yiiRedis; 40 | $yiiRedis->flushdb(); 41 | for ($i = 0; $i < $count; $i++) { 42 | $yiiRedis->set('yii_redis_prefix' . $i, $i); 43 | } 44 | echo " " . ((microtime(true) - $start) * 1000) . " micro seconds.\n"; 45 | 46 | echo "phpredis run GET $count times in"; 47 | $start = microtime(true); 48 | for ($i = 0; $i < $count; $i++) { 49 | $phpRedis->get('php_redis_prefix' . $i); 50 | } 51 | echo " " . ((microtime(true) - $start) * 1000) . " micro seconds.\n"; 52 | 53 | echo "yii redis run GET $count times in"; 54 | $start = microtime(true); 55 | for ($i = 0; $i < $count; $i++) { 56 | $yiiRedis->get('yii_redis_prefix' . $i); 57 | } 58 | echo " " . ((microtime(true) - $start) * 1000) . " micro seconds.\n"; 59 | --------------------------------------------------------------------------------