This tutorial is based on native doctrine/cache package. Memcached needs to be installed in OS and enabled in php.ini. Example below will show us how to use memcached cache to increase application performance. For more information, you can read doctrine caching chapter, memcached cheat sheet and phpMemcachedAdmin browser GUI.


Configuration


# app/config/services.yml
services:
memcached:
class: Memcached
calls:
- [ addServer, ['localhost', 11211] ]

football.doctrine.cache.memcached:
class: Doctrine\Common\Cache\MemcachedCache
calls:
- [ setMemcached, [@memcached] ]

controllers.yml


services:
application_backend.controller.football:
class: Application\BackendBundle\Controller\FootballController
arguments:
- @templating
- @application_backend.repository.league
- @doctrine.orm.entity_manager
- @football.doctrine.cache.memcached

repositories.yml


services:
application_backend.repository.league:
class: Application\BackendBundle\Repository\LeagueRepository
factory: [@doctrine.orm.entity_manager, getRepository]
arguments: [Application\BackendBundle\Entity\League]

Controller


namespace Application\BackendBundle\Controller;

use Application\BackendBundle\Repository\LeagueRepository;
use Doctrine\Common\Cache\MemcachedCache;
use Doctrine\ORM\EntityManagerInterface;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Method;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Bundle\FrameworkBundle\Templating\EngineInterface;

/**
* @Route("football", service="application_backend.controller.football")
*/
class FootballController extends Controller
{
private $templating;
private $leagueRepository;
private $entityManager;
private $memcached;

public function __construct(
EngineInterface $templating,
LeagueRepository $leagueRepository,
EntityManagerInterface $entityManager,
MemcachedCache $memcached
) {
$this->templating = $templating;
$this->leagueRepository = $leagueRepository;
$this->entityManager = $entityManager;
$this->memcached = $memcached;
}

/**
* @Method({"GET"})
* @Route("")
*/
public function indexAction()
{
$cacheId = 'find_all';
if ($this->memcached->contains($cacheId)) {
$result = $this->memcached->fetch($cacheId);
} else {
$result = $this->leagueRepository->findAll();
$this->memcached->save($cacheId, $result, 60);
}

return $this->getTemplate(['result' => $result]);
}

/**
* @param array $parameters
*
* @return Response
*/
private function getTemplate(array $parameters = [])
{
return $this->templating->renderResponse(
'ApplicationBackendBundle:Football:index.html.twig',
$parameters
);
}
}

Repository


namespace Application\BackendBundle\Repository;

use Doctrine\ORM\EntityRepository;

class LeagueRepository extends EntityRepository
{
public function findAll()
{
$qb = $this->createQueryBuilder('l')
->select('l, t, p')
->innerJoin('l.team', 't')
->innerJoin('t.player', 'p')
->orderBy('l.name', 'ASC')
->addOrderBy('t.name', 'ASC')
->addOrderBy('p.name', 'ASC')
->getQuery();

$qb = $qb->getResult();

return $qb;
}
}

Twig


{% extends '::base.html.twig' %}

{% block body %}
{% spaceless %}
{{ dump(result) }}
{% endspaceless %}
{% endblock %}

Test


Current memcached info


Mac:football inanzzz$ telnet 127.0.0.1 11211
Trying 127.0.0.1...
Connected to localhost.
Escape character is '^]'.

# As you can see below, no cache item exists yet
stats items
END

As you can see below, memory %MEM is not used at all.



Start caching


Calling http://football.local/app_dev.php/backend/football. You can use browser based application phpMemcachedAdmin to monitor caching activities.


Benchmark


  Millisecond MB
757 31.8 (*) query run
418 24.2
430 24.2
406 24.2
1580 29.8 (*) query run
408 24.2
416 24.2
424 24.2

New memcached info


Mac:football inanzzz$ telnet 127.0.0.1 11211
Trying 127.0.0.1...
Connected to localhost.
Escape character is '^]'.

# As you can see below, new item 28 has been created
stats items
STAT items:28:number 1
STAT items:28:age 83
STAT items:28:evicted 0
STAT items:28:evicted_nonzero 0
STAT items:28:evicted_time 0
STAT items:28:outofmemory 0
STAT items:28:tailrepairs 0
STAT items:28:reclaimed 0
STAT items:28:expired_unfetched 0
STAT items:28:evicted_unfetched 0
STAT items:28:crawler_reclaimed 0
STAT items:28:crawler_items_checked 0
STAT items:28:lrutail_reflocked 0
END

# As you see below, "find_all" is the cache key.
stats cachedump 28 100
ITEM [find_all][1] [38125 b; 1450478001 s]
END

As you can see below, memory %MEM is now used.