├── .env.testing ├── .github └── workflows │ └── ci.yml ├── .gitignore ├── README.md ├── _config.php ├── composer.json ├── src └── RedisCacheFactory.php └── tests └── RedisCacheFactoryTest.php /.env.testing: -------------------------------------------------------------------------------- 1 | SS_DATABASE_CHOOSE_NAME="true" 2 | SS_DATABASE_USERNAME="root" 3 | SS_DATABASE_SERVER="127.0.0.1" 4 | -------------------------------------------------------------------------------- /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: CI 2 | 3 | on: [push] 4 | 5 | jobs: 6 | continuous-integration: 7 | name: Tests on PHP ${{ matrix.php }} 8 | runs-on: ubuntu-latest 9 | 10 | env: 11 | MYSQL_ALLOW_EMPTY_PASSWORD: true 12 | MYSQL_DATABASE: SS_test 13 | services: 14 | mariadb: 15 | image: mariadb:10.4 16 | env: 17 | MYSQL_ALLOW_EMPTY_PASSWORD: true 18 | MYSQL_DATABASE: SS_test 19 | ports: 20 | - 3306:3306 21 | redis: 22 | image: redis 23 | ports: 24 | - 6379:6379 25 | strategy: 26 | matrix: 27 | php: [8.0, 8.3] 28 | silverstripe: [4, 5] 29 | exclude: 30 | - php: 8.0 31 | silverstripe: 5 32 | 33 | steps: 34 | - name: Checkout 35 | uses: actions/checkout@v2 36 | 37 | - name: Setup PHP with composer 38 | uses: shivammathur/setup-php@v2 #https://github.com/shivammathur/setup-php 39 | with: 40 | php-version: ${{ matrix.php }} 41 | extensions: mbstring, dom, fileinfo, mysql, libxml, xml, xmlwriter, dom, tokenizer, filter, json, phar, pcre, openssl, pdo, intl, curl 42 | 43 | - name: Get composer cache directory 44 | id: composer-cache 45 | run: echo "::set-output name=dir::$(composer config cache-files-dir)" 46 | 47 | - name: Cache composer dependencies 48 | uses: actions/cache@v1 49 | with: 50 | path: ${{ steps.composer-cache.outputs.dir }} 51 | # With composer.lock use: 52 | # key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.lock') }} 53 | key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.json') }} 54 | restore-keys: ${{ runner.os }}-composer- 55 | 56 | - name: Install Composer dependencies 57 | run: composer install --no-progress --no-suggest --prefer-dist --optimize-autoloader 58 | 59 | - name: Use SilverStripe v${{ matrix.silverstripe }} 60 | run: composer require --with-all-dependencies silverstripe/framework "^${{ matrix.silverstripe }}" 61 | 62 | - name: Setup test environment 63 | run: | 64 | php -r "copy('.env.testing', '.env');" 65 | 66 | - name: Test with phpunit 67 | run: vendor/bin/phpunit tests/RedisCacheFactoryTest.php 68 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /assets 2 | /resources 3 | /public 4 | /vendor 5 | /composer.lock 6 | /.env 7 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Redis Cache for SilverStripe 2 | 3 | Enables usage of redis cache for SilverStripe. 4 | 5 | ![status](https://github.com/pstaender/silverstripe-redis-cache/actions/workflows/ci.yml/badge.svg) 6 | 7 | ## Requirements 8 | 9 | * SilverStripe v4 / v5 10 | * Redis 11 | * Tested on PHP 7.3+ 12 | 13 | ## Pre-install 14 | 15 | Ensure you have redis installed in your environment and configured within your php ini files to ensure PHP knows where to access Redis. 16 | 17 | To install Redis, a quick Google with your OS name and version, your PHP version, and server and it's version that your're working with (E.G. Apache or NGINX) should yield a number of installation instructions such as [this installation instruction example.](https://www.digitalocean.com/community/tutorials/how-to-install-and-secure-redis-on-ubuntu-18-04) 18 | 19 | Add the following to your php.ini or conf.d/{your-custom-php-config-file}.ini to let PHP know where to communicate with Redis to store session data: 20 | **Note:** Missing this step will lead to login issues when working with providers such as AWS where you have your site running on multiple pods but need sessions to be unified across them. 21 | ``` 22 | session.save_handler = redis 23 | session.save_path = {your_redis_url} 24 | ``` 25 | 26 | ## Installation and usage 27 | 28 | Use composer to pull this module into your project: 29 | 30 | ``` 31 | $ composer require pstaender/silverstripe-redis-cache 32 | ``` 33 | 34 | To enable Redis cache in your SilverStripe project, add one or both of the following yaml configs to your project under `/app/_config/` in either their own yaml file, or in an existing file such as `mysite.yml`. 35 | 36 | **Note:** The `REDIS_URL` must be the url of the used redis instance, e.g. `tcp://127.0.0.1:6379`. 37 | 38 | ## Usage in your project 39 | 40 | ```yml 41 | --- 42 | Name: silverstripe-redis-cache 43 | After: 44 | - '#corecache' 45 | - '#assetscache' 46 | Only: 47 | envvarset: REDIS_URL 48 | --- 49 | SilverStripe\Core\Injector\Injector: 50 | RedisClient: 51 | class: Predis\Client 52 | constructor: 53 | 0: '`REDIS_URL`' 54 | RedisCacheFactory: 55 | class: Zeitpulse\RedisCacheFactory 56 | constructor: 57 | client: '%$RedisClient' 58 | SilverStripe\Core\Cache\CacheFactory: '%$RedisCacheFactory' 59 | 60 | # vendor/silverstripe/assets/_config/assetscache.yml 61 | Psr\SimpleCache\CacheInterface.InterventionBackend_Manipulations: 62 | factory: RedisCacheFactory 63 | Psr\SimpleCache\CacheInterface.FileShortcodeProvider: 64 | factory: RedisCacheFactory 65 | Psr\SimpleCache\CacheInterface.ImageShortcodeProvider: 66 | factory: RedisCacheFactory 67 | 68 | # vendor/silverstripe/assets/_config/assetscache.yml 69 | Psr\SimpleCache\CacheInterface.Sha1FileHashingService: 70 | factory: RedisCacheFactory 71 | 72 | # vendor/silverstripe/cms/_config/cache.yml 73 | Psr\SimpleCache\CacheInterface.CMSMain_SiteTreeHints: 74 | factory: RedisCacheFactory 75 | Psr\SimpleCache\CacheInterface.SiteTree_CreatableChildren: 76 | factory: RedisCacheFactory 77 | Psr\SimpleCache\CacheInterface.SiteTree_PageIcons: 78 | factory: RedisCacheFactory 79 | 80 | # vendor/silverstripe/cms/_config/permissions.yml + 81 | # vendor/silverstripe/framework/_config/cache.yml 82 | Psr\SimpleCache\CacheInterface.InheritedPermissions: 83 | factory: RedisCacheFactory 84 | 85 | # vendor/silverstripe/framework/_config/cache.yml 86 | Psr\SimpleCache\CacheInterface.cacheblock: 87 | factory: RedisCacheFactory 88 | Psr\SimpleCache\CacheInterface.VersionProvider_composerlock: 89 | factory: RedisCacheFactory 90 | Psr\SimpleCache\CacheInterface.RateLimiter: 91 | factory: RedisCacheFactory 92 | Psr\SimpleCache\CacheInterface.ThemeResourceLoader: 93 | factory: RedisCacheFactory 94 | Psr\SimpleCache\CacheInterface.DatabaseAdapterRegistry: 95 | factory: RedisCacheFactory 96 | Psr\SimpleCache\CacheInterface.EmbedShortcodeProvider: 97 | factory: RedisCacheFactory 98 | ``` 99 | 100 | ## Usage with flysystem asset storage 101 | 102 | ```yaml 103 | --- 104 | Name: silverstripes3-flysystem-redis 105 | Only: 106 | envvarset: 107 | - REDIS_URL 108 | After: 109 | - '#silverstripes3-flysystem' 110 | --- 111 | SilverStripe\Core\Injector\Injector: 112 | League\Flysystem\Cached\Storage\Memory.public: 113 | class: League\Flysystem\Cached\Storage\Predis 114 | League\Flysystem\Cached\Storage\Adapter.public: 115 | class: League\Flysystem\Cached\Storage\Predis 116 | League\Flysystem\Cached\Storage\Adapter.protected: 117 | class: League\Flysystem\Cached\Storage\Predis 118 | ``` 119 | 120 | ## Licence 121 | 122 | MIT 123 | -------------------------------------------------------------------------------- /_config.php: -------------------------------------------------------------------------------- 1 | redis_client = $redis_client; 18 | } 19 | 20 | public function create($service, array $params = array()) 21 | { 22 | $namespace = isset($params['namespace']) 23 | ? $params['namespace'] . '_' . md5(BASE_PATH) 24 | : md5(BASE_PATH); 25 | 26 | $defaultLifetime = isset($params['defaultLifetime']) 27 | ? $params['defaultLifetime'] 28 | : 0; 29 | 30 | $psr6 = Injector::inst() 31 | ->createWithArgs( 32 | RedisAdapter::class, 33 | [ 34 | $this->redis_client, 35 | $namespace, 36 | $defaultLifetime, 37 | ] 38 | ); 39 | 40 | return Injector::inst()->createWithArgs(Psr16Cache::class, [$psr6]); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /tests/RedisCacheFactoryTest.php: -------------------------------------------------------------------------------- 1 | load([ 15 | 'RedisClient' => [ 16 | 'class' => \Predis\Client::class, 17 | 'constructor' => [ 18 | 'REDIS_URL' 19 | ], 20 | ], 21 | 'RedisCacheFactory' => [ 22 | 'class' => \Zeitpulse\RedisCacheFactory::class, 23 | 'constructor' => [ 24 | 'client' => '%$RedisClient' 25 | ] 26 | ], 27 | ]); 28 | } 29 | 30 | public function testRedisCacheFactory() 31 | { 32 | $cache = Injector::inst()->get('RedisCacheFactory'); 33 | $class = new \ReflectionClass($cache); 34 | $this->assertEquals((array) $class->getProperty('redis_client'), [ 35 | 'name' => 'redis_client', 36 | 'class' => 'Zeitpulse\RedisCacheFactory', 37 | ]); 38 | } 39 | 40 | public function testRedisCacheWithRedisDatabase() 41 | { 42 | 43 | $cache = Injector::inst() 44 | ->createWithArgs(\Symfony\Component\Cache\Psr16Cache::class, [ 45 | Injector::inst() 46 | ->createWithArgs( 47 | \Symfony\Component\Cache\Adapter\RedisAdapter::class, 48 | [ 49 | new \Predis\Client(''), 50 | 'TestRedisCache_' . sha1(BASE_PATH), 51 | 1000, 52 | ] 53 | ) 54 | ]); 55 | $cache->set('foo', 'bar'); 56 | $this->assertEquals($cache->get('foo'), 'bar'); 57 | } 58 | } 59 | --------------------------------------------------------------------------------