16/09/2018 - MEMCACHED, SYMFONY, REDIS
This example shows us how we can use Memcached as "cache pool" in Symfony applications. You can clear all caches in given pool in one go without touching cache items that present in other pools. There is a non-pool version as well but this is the preferred approach.
If you want to use Redis instead, all you have to do is add config below. Afterwards run sudo apt-get install redis-server
and sudo apt-get install php7.2-redis
commands and restart your web/php services.
framework:
cache:
default_redis_provider: 'redis://localhost:6379'
pools:
app.cache.countries:
adapter: cache.adapter.redis
public: false
default_lifetime: 60
$ sudo apt-get install memcached
$ sudo apt-get install -y libapache2-mod-php
$ sudo apt-get install -y php7.2-memcached
$ sudo systemctl restart nginx
$ sudo service php7.2-fpm restart
$ composer require symfony/cache
# Clear cache for given pool only in terminal
$ bin/console cache:pool:clear app.cache.countries
$ bin/console cache:pool:clear app.cache.products
# Delete a cache from given pool in terminal
$ bin/console cache:pool:delete app.cache.countries key
framework:
cache:
default_memcached_provider: 'memcached://localhost:11211'
pools:
app.cache.countries:
adapter: cache.adapter.memcached
public: false
default_lifetime: 60
app.cache.products:
adapter: cache.adapter.memcached
public: false
default_lifetime: 120
services:
App\Controller\CountryController:
arguments:
$cachePool: '@app.cache.countries'
tags: ['controller.service_arguments']
App\Controller\ProductController:
arguments:
$cachePool: '@app.cache.products'
tags: ['controller.service_arguments']
declare(strict_types=1);
namespace App\Controller;
use App\Util\CacheInterface;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
use Symfony\Component\Cache\Adapter\MemcachedAdapter;
use Symfony\Component\HttpFoundation\JsonResponse;
/**
* @Route("/countries")
*/
class CountryController
{
private $cachePool;
private $cacheUtil;
public function __construct(
MemcachedAdapter $cachePool,
CacheInterface $cacheUtil
) {
$this->cachePool = $cachePool;
$this->cacheUtil = $cacheUtil;
}
/**
* @Route("/save-item", methods={"GET"})
*/
public function saveItem(): JsonResponse
{
return new JsonResponse($this->cacheUtil->saveItem($this->cachePool, 'key', 'country'));
}
/**
* @Route("/get-item", methods={"GET"})
*/
public function getItem(): JsonResponse
{
return new JsonResponse($this->cacheUtil->getItem($this->cachePool, 'key'));
}
/**
* @Route("/delete-item", methods={"GET"})
*/
public function deleteItem(): JsonResponse
{
return new JsonResponse($this->cacheUtil->deleteItem($this->cachePool, 'key'));
}
/**
* @Route("/delete-all", methods={"GET"})
*/
public function deleteAll(): JsonResponse
{
return new JsonResponse($this->cacheUtil->deleteAll($this->cachePool));
}
}
declare(strict_types=1);
namespace App\Controller;
use App\Util\CacheInterface;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
use Symfony\Component\Cache\Adapter\MemcachedAdapter;
use Symfony\Component\HttpFoundation\JsonResponse;
/**
* @Route("/products")
*/
class ProductController
{
private $cachePool;
private $cacheUtil;
public function __construct(
MemcachedAdapter $cachePool,
CacheInterface $cacheUtil
) {
$this->cachePool = $cachePool;
$this->cacheUtil = $cacheUtil;
}
/**
* @Route("/save-item", methods={"GET"})
*/
public function saveItem(): JsonResponse
{
return new JsonResponse($this->cacheUtil->saveItem($this->cachePool, 'key', 'product'));
}
/**
* @Route("/get-item", methods={"GET"})
*/
public function getItem(): JsonResponse
{
return new JsonResponse($this->cacheUtil->getItem($this->cachePool, 'key'));
}
/**
* @Route("/delete-item", methods={"GET"})
*/
public function deleteItem(): JsonResponse
{
return new JsonResponse($this->cacheUtil->deleteItem($this->cachePool, 'key'));
}
/**
* @Route("/delete-all", methods={"GET"})
*/
public function deleteAll(): JsonResponse
{
return new JsonResponse($this->cacheUtil->deleteAll($this->cachePool));
}
}
declare(strict_types=1);
namespace App\Util;
use Symfony\Component\Cache\Adapter\MemcachedAdapter;
interface CacheInterface
{
public function saveItem(MemcachedAdapter $cachePool, string $key, string $value): bool;
public function getItem(MemcachedAdapter $cachePool, string $key): ?string;
public function deleteItem(MemcachedAdapter $cachePool, string $key): bool;
public function deleteAll(MemcachedAdapter $cachePool): bool;
}
declare(strict_types=1);
namespace App\Util;
use App\Exception\CacheException;
use Psr\Cache\CacheItemInterface;
use Psr\Cache\InvalidArgumentException;
use Symfony\Component\Cache\Adapter\MemcachedAdapter;
class MemcachedUtil implements CacheInterface
{
public function saveItem(MemcachedAdapter $cachePool, string $key, string $value): bool
{
$item = $this->fetch($cachePool, $key);
$item->set($value);
return $cachePool->save($item);
}
public function getItem(MemcachedAdapter $cachePool, string $key): ?string
{
$result = null;
$item = $this->fetch($cachePool, $key);
if ($item->isHit()) {
$result = $item->get();
}
return $result;
}
public function deleteItem(MemcachedAdapter $cachePool, string $key): bool
{
return $cachePool->deleteItem($key);
}
public function deleteAll(MemcachedAdapter $cachePool): bool
{
return $cachePool->clear();
}
private function fetch(MemcachedAdapter $cachePool, string $key): CacheItemInterface
{
try {
return $cachePool->getItem($key);
} catch (InvalidArgumentException $e) {
throw new CacheException($e->getMessage());
}
}
}
declare(strict_types=1);
namespace App\Exception;
use RuntimeException;
class CacheException extends RuntimeException
{
}