Web Technical Leader
AptusHealth
@jderusse
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Cache;
/**
* @Cache(smaxage="3600")
*/
public function indexAction()
{
// ...
}
Advanced usage with FriendsOfSymfony/FOSHttpCacheBundle
There are only two hard things in Computer Science: cache invalidation and naming things.
Phil Karlton
In the real world
In the real world
curl "http://varnish.myapp.com"
curl \
-X "BAN" \
-H "X-Cache-Tags: Foo" \
"http://varnish.myapp.com"
HTTP/1.1 200 OK
Cache-Control: public, s-maxage=3600
X-Cache-Tags: Foo,Bar
HTTP/1.1 200 OK
Cache-Control: public, s-maxage=3600
X-Cache-Tags: Foo
HTTP/1.1 200 OK
Cache-Control: public, s-maxage=3600
X-Cache-Tags: Bar,Qux
curl "http://varnish.myapp.com/posts/42"
HTTP/1.1 200 OK
Cache-Control: public, s-maxage=86400
X-Cache-Tags: Post42,Author:12,Comment:314,Comment:1337
{
"id": 42,
"title": "My blog post.",
"body": "Lorem Ipsum.",
"author": {
"id": 12,
"username": "jderusse"
},
"comments": [
{
"id": 314,
"message": "Wow such post"
},
{
"id": 1337,
"message": "much performance"
}
]
}
Tagging Response - 1. Collect displayed entities
namespace App\EventListener;
use JMS\Serializer\EventDispatcher\Events;
use JMS\Serializer\EventDispatcher\EventSubscriberInterface;
use JMS\Serializer\EventDispatcher\ObjectEvent;
class SerializationTagListener implements EventSubscriberInterface
{
public function onPostSerialize(ObjectEvent $event)
{
$entity = $event->getObject();
// TODO
}
public static function getSubscribedEvents()
{
return [
[
'event' => Events::POST_SERIALIZE,
'format' => 'json',
'method' => 'onPostSerialize',
],
];
}
}
Tagging Response - 2. Generate resource identifier
namespace App\EventListener;
use App\Tag\TagExtractorInterface;
use FOS\HttpCacheBundle\Handler\TagHandler;
use JMS\Serializer\EventDispatcher\EventSubscriberInterface;
use JMS\Serializer\EventDispatcher\ObjectEvent;
class SerializationTagListener implements EventSubscriberInterface
{
private $tagExtractor;
public function __construct(TagExtractorInterface $tagExtractor)
{
$this->tagExtractor = $tagExtractor;
}
public function onPostSerialize(ObjectEvent $event): void
{
$tags = $this->tagExtractor->extract($event->getObject());
}
//...
}
Tagging Response - 3. Tag response
namespace App\EventListener;
use App\Tag\TagExtractorInterface;
use FOS\HttpCacheBundle\Handler\TagHandler;
use JMS\Serializer\EventDispatcher\EventSubscriberInterface;
use JMS\Serializer\EventDispatcher\ObjectEvent;
class SerializationTagListener implements EventSubscriberInterface
{
private $tagExtractor;
private $tagHandler;
public function __construct(TagExtractorInterface $tagExtractor, TagHandler $tagHandler)
{
$this->tagExtractor = $tagExtractor;
$this->tagHandler = $tagHandler;
}
public function onPostSerialize(ObjectEvent $event): void
{
$tags = $this->tagExtractor->extract($event->getObject());
$this->tagHandler->addTags($tags);
}
//...
}
Invalidate Cache - 1. Listen changes
namespace App\EventListener;
use Doctrine\Common\EventSubscriber;
use Doctrine\ORM\Event\OnFlushEventArgs;
use Doctrine\ORM\Events;
class DoctrineInvalidationTagListener implements EventSubscriber
{
public function getSubscribedEvents()
{
return [Events::onFlush];
}
public function onFlush(OnFlushEventArgs $eventArgs)
{
$uow = $eventArgs->getEntityManager()->getUnitOfWork();
foreach ($uow->getScheduledEntityUpdates() as $entity) {
// TODO
}
foreach ($uow->getScheduledEntityDeletions() as $entity) {
// TODO
}
}
}
Invalidate Cache - 2. Generate resource identifier
namespace App\EventListener;
use App\Tag\TagExtractorInterface;
use Doctrine\Common\EventSubscriber;
class DoctrineInvalidationTagListener implements EventSubscriber
{
private $tagExtractor;
public function __construct(TagExtractorInterface $tagExtractor)
{
$this->tagExtractor = $tagExtractor;
}
public function onFlush(OnFlushEventArgs $eventArgs)
{
$uow = $eventArgs->getEntityManager()->getUnitOfWork();
$tags = [];
foreach ($uow->getScheduledEntityUpdates() as $entity) {
$tags += $this->tagExtractor->extract($entity);
}
foreach ($uow->getScheduledEntityDeletions() as $entity) {
$tags += $this->tagExtractor->extract($entity);
}
}
}
Invalidate Cache - 3. Call varnish
namespace App\EventListener;
use App\Tag\TagExtractorInterface;
use Doctrine\Common\EventSubscriber;
use FOS\HttpCache\Handler\TagHandler;
class DoctrineInvalidationTagListener implements EventSubscriber
{
private $tagExtractor;
public function __construct(TagExtractorInterface $tagExtractor, TagHandler $tagHandler)
{
$this->tagExtractor = $tagExtractor;
$this->tagHandler = $tagHandler;
}
public function onFlush(OnFlushEventArgs $eventArgs)
{
// ...
$this->tagHandler->invalidateTags(array_keys($tags));
}
}