sfRedisPlugin - 1.0.2

Redis for symfony

You are currently browsing
the website for symfony 1

Visit the Symfony2 website


« Back to the Plugins Home

Signin


Forgot your password?
Create an account

Tools

Stats

advanced search
Information Readme Releases Changelog Contribute
Show source

sfRedisPlugin

The sfRedis plugin provides redis support to symfony (through Predis).

Installation

You can install this plugin the usual way (RTFM), or if you want to work with the trunk:

$ cd plugins
$ svn co http://svn.symfony-project.com/plugins/sfRedisPlugin/trunk/ sfRedisPlugin

Then activate the plugin in the config/ProjectConfiguration.class.php file.

Configuration

Edit config/redis.yml to suit your redis installation :

all:
  connections:
    local:
      host: 127.0.0.1
      port: 6379

You can also use URL based notation :

all:
  connections:
    local: redis://127.0.0.1:6379

By default, there is a connection named "default" which targets a local redis server.

All available parameters :

all:
  connections:
    local:
      host: 127.0.0.1
      port: 6379
      database: 0
      password: secret
      connection_timeout: 5
      read_write_timeout: 30

You can also use Predis cluster feature :

all:
  connections:
    myshard:
      - redis://192.168.0.1:6379
      - redis://192.168.0.2:6379

Get a predis client

To create a connection, use sfRedis::getClient() with the connection name as parameter :

$redis = sfRedis::getClient('myshard');

Or empty to use "default" connection:

$redis = sfRedis::getClient();

Then follow Predis API to query the database

$redis->set('name', 'value');
$value = $redis->get('name');

Symfony cache

The sfRedisPlugin provides a sfRedisCache class to use for view and/or i18n symfony cache.

To enable it, edit config/factories.yml :

all:
  view_cache:
    class: sfRedisCache
    param:
      connection: default
      prefix: view:%SF_APP%:%SF_ENVIRONMENT%

The parameter "connection" is the key defined in config/redis.yml. The parameter "prefix" is adjusted in this example.

Doctrine cache

The sfRedisPlugin provides a Doctrine cache backend.

To enable it, edit ProjectConfiguration::configureDoctrine with :

$cacheDriver = new Doctrine_Cache_Redis(array('server' => 'redis://127.0.0.1:6379', 'prefix' => 'dql:'));
$manager->setAttribute(Doctrine::ATTR_QUERY_CACHE, $cacheDriver);

The option "prefix" is recommended to keep redis server keys clean.

You can also pass a Predis_Client object as an option:

$redis = Predis_Client::create(...);
$cacheDriver = new Doctrine_Cache_Redis(array('redis' => $redis));
$manager->setAttribute(Doctrine::ATTR_QUERY_CACHE, $cacheDriver);

Since sfRedis::getClient returns a Predis_Client, you can use configuration from your config/redis.yml:

$cacheDriver = new Doctrine_Cache_Redis(array('redis' => sfRedis::getClient('local'), 'prefix' => 'dql:'));
$manager->setAttribute(Doctrine::ATTR_QUERY_CACHE, $cacheDriver);

Please note, you need to enable the sfRedisPlugin before the sfDoctrinePlugin to make the previous snippet work.

Redis sfPager

The plugin provides two types of pager, one for redis lists and one for sorted sets.

Lists: imagine you populate a redis list :

$client = sfRedis::getClient();
$key = 'mylist';
$client->rpush($key, 'a');
$client->rpush($key, 'b');
// ...
$client->rpush($key, 'z');

To get a pager on this list, use the following code :

// signature : __construct($redisKey, $maxPerPage)
$pager = new sfRedisListPager('mylist', 10);
$pager->setPage($page);
$pager->init();
// use it as any sfPager
foreach ($pager as $element)
{
  echo $element; // = 'a', 'b', ..., 'j'
}

Sorted sets: let's setup a "movies-by-year" set with year as score :

$client = sfRedis::getClient();
$key = 'movies-by-year';
$client->zadd($key, 2007, 'Rocky Balboa');
$client->zadd($key, 1990, 'Rocky V');
$client->zadd($key, 1986, 'Rocky IV');
$client->zadd($key, 1982, 'Rocky III');
$client->zadd($key, 1979, 'Rocky II');
$client->zadd($key, 1976, 'Rocky');

The corresponding pager is :

// signature : __construct($redisKey, $maxPerPage)
$pager = new sfRedisZsetPager('movies-by-year', 10);
$pager->setPage($page);
$pager->init();
// use it as any sfPager
foreach ($pager as $element)
{
  echo $element; // = 'Rocky', 'Rocky II', 'Rocky III', ...
  echo $client->zscore($key, $element); // = 1976, 1979, 1982, ...
}

Note: the results are ordered by "score" ascending. As the ZREVRANGEBYSCORE command does not yet exists in redis, there is only one ordering possible. If you want reverse order, you have to store scores negative.

If you want to filter results by year, set parameters "min" and/or "max" :

$pager = new sfRedisZsetPager('movies', 10);
$pager->setParameter('min', 1980);
$pager->setParameter('max', 2000);
// ...

sfRedisZsetDoctrinePager = sfPager + Redis + Doctrine

The sfRedisZsetDoctrinePager allows you to paginate on redis sorted sets with Doctrine record as pager objects.

Take this schema.yml example :

Movie:
  columns:
    year:   integer(2)
    title:  string(200)

And fixtures :

Movie:
  rocky:   { year: 1976, title: 'Rocky' }
  rocky_2: { year: 1979, title: 'Rocky II' }
  # ...

Imagine you sync somehow in Redis key 'movie:year' a set sorted by year with record id as member :

sfRedis::getClient()->zadd('movie:year', $movie->year, $movie->id);

You can then paginate on movies objects sorted by year with this code :

// signature : __construct($modelName, $redisKey, $maxPerPage)
$pager = new sfRedisZsetDoctrinePager('Movie', 'movie:year', 10);
$pager->setPage($page);
$pager->init();
 
foreach ($pager as $movie)
{
  // each iteration calls Doctrine_core::getTable('Movie')->find($element)
  // so $movie is an instance of Movie
  echo link_to($movie->title, 'movie_show', $movie);
}

Each iteration on the pager makes a "find" query, so this makes as many queries as items per page. But it's much more efficient to do many "WHERE id = const" queries than doing a WHERE IN + ORDER BY FIELD(), the order is already done by redis so you don't need to tell your DB to order the found records in a temporary buffer, and those queries are more cacheable.

You can also go further by using a custom tableMethod :

// Custom find with cache enabled
class MovieTable
{
  public function findUseCache($id)
  {
    return $this->createQuery()->where('id = ?', $id)->useResultCache(true, 3600, 'movie_'.$id)->fetchOne();
  }
}
 
$pager = new sfRedisZsetDoctrinePager('Movie', 'movie:year', 10);
$pager->setParameter('tableMethod', 'findUseCache');
$pager->setPage($page);
$pager->init();

Now you have a sortable pager on Doctrine records without (almost) querying the database, taking advantage of redis sort speed.

TODO

  • implement a pager for SORT commands
  • work with nginx HTTP redis module

LINKS

  • Predis http://github.com/nrk/predis
  • redis http://code.google.com/p/redis/