All Articles

Interacting with Redis Using Symfony

Hi, and welcome to another blog post related to Symfony 😃

Let’s start with a fact :

In a big project, there is often some data that is not frequently changing and required to be loaded after being logged in. When the number of users and the number of data increases, this may cause some performance issues and might be annoying for end users.

In these situations, many paths of optimizations are available:

Optimizing application code.

Optimizing database (indexes, …)

…

Caching which we are going to focus on in this post.

There are many ways of caching:

Web caching:

It consists of caching a response for a defined amount of time, which can be done on the client-side(i.e: browser cache) or in the server-side. [Details]

Data caching:

Data caching can avoid unnecessary repeated trips back to the database, it can be handy if the data is not changing frequently and the application is querying for the same data all the time. Some databases like MySQL and MariaDB have caching solutions that help speed up the process.

Application caching:

This type of caching is useful when your program uses a method that is very slow, application caching consists of storing the result of the slow method somewhere and use it for the upcoming requests which will speed up the processing time significantly.

Key-Value data caching:

This way of caching relies on the same concept as application cache but it comes with the advantage of not losing data upon reboots or server failure.

Among the popular key-value data caching databases, there is Redis and Memcached which are both in-memory databases.

As you have noticed in the title of this post, we are going to interact with Redis using a Symfony 3.4 application, so let’s get started 😃.

Project setup

Create a blank Symfony project :

composer create-project symfony/framework-standard-edition RedisSymfony3 "3.4.*"

Adding redis-bundle

composer require snc/redis-bundle

After installing the bundle we need to enable it by adding the bundle class in the bundles array in AppKernel class:

$bundles = [
    ....
    new Snc\RedisBundle\SncRedisBundle(),
];

Enabling the bundle is not enough, a little configuration is required in order to communicate with Redis from our application.

For that we need to add below code in our app/config/config.yml file :

snc_redis:
        clients:
            default:
                type: phpredis
                alias: default
                dsn: redis://hostname # (*)
                logging: '%kernel.debug%'

(*): The hostname must be accessible within the network.

We are all set now, we can fetch and store data in Redis.

Communicating with Redis

By installing redis-bundle, we get access to a Redis client class Snc\RedisBundle\Client\Phpredis\Client which contains various methods (get, set, flush, …).

Fetching all Redis keys.

In order to get all the keys stored in Redis, we use the keys method with * as an argument.

Sample Code :

<?php

namespace AppBundle\Controller;

use Snc\RedisBundle\Client\Phpredis\Client;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Annotation\Route;

class DefaultController extends Controller
{
    /** @var  Client */
    private $redisClient;

    public function __construct(Client $client)
    {
        $this->redisClient = $client;
    }

    /**
     * @Route("/keys", name="keys")
     */
    public function indexAction()
    {
        $redisKeys = $this->redisClient->keys('*');
        return $this->json(['keys' => $redisKeys]);
    }
}

Adding key/value pairs in Redis.

For setting a new key/value pair, there is the set method :

set(key, value)

Sample Code :

<?php

namespace AppBundle\Controller;

use Snc\RedisBundle\Client\Phpredis\Client;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Annotation\Route;

class DefaultController extends Controller
{
    /** @var  Client */
    private $redisClient;

    public function __construct(Client $client)
    {
        $this->redisClient = $client;
    }


    /**
     * @param $key
     * @param $value
     *
     * @Route("/create/{key}/{value}", name="create_key", methods={"GET"})
     * @return JsonResponse
     */
    public function createKeyAction($key, $value) {

        $this->redisClient->set($key, $value);
        return $this->json([
            "status" => Response::HTTP_OK
        ]);
    }
}

Deleting a key/value pair from Redis.

For deleting a key, there is a delete method that accepts the key as the argument.

Sample code :

<?php

namespace AppBundle\Controller;

use Snc\RedisBundle\Client\Phpredis\Client;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Annotation\Route;

class DefaultController extends Controller
{
    /** @var  Client */
    private $redisClient;

    public function __construct(Client $client)
    {
        $this->redisClient = $client;
    }

    /**
     * @param $key
     * @Route("/delete/{key}", name="delete_key", methods={"GET"})
     *
     * @return JsonResponse
     */
    public function deleteKeyAction($key) {
        $this->redisClient->delete($key);
        return $this->json([
            "status" => Response::HTTP_OK
        ]);
    }
}

There is also the possibility to remove a set of keys by a pattern like this :

$this->redisClient->delete($this->redisClient->keys($key."*"));

Sample code :

<?php

namespace AppBundle\Controller;

use Snc\RedisBundle\Client\Phpredis\Client;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Annotation\Route;

class DefaultController extends Controller
{
    /** @var  Client */
    private $redisClient;

    public function __construct(Client $client)
    {
        $this->redisClient = $client;
    }

    /**
     * @param $key
     * @Route("/delete/like/{key}", name="delete_like_key", methods={"GET"})
     *
     * @return JsonResponse
     */
    public function deleteKeyLikeAction($key) {
        $this->redisClient->delete($this->redisClient->keys($key."*"));
        return $this->json([
            "status" => Response::HTTP_OK
        ]);
    }
}

That was it for this post, the full code is available here.

Cheers 😄