Skip to content

Commit 207d9a5

Browse files
authored
feat: add HTTP cache support to RSS feeds (#217)
* feat: add HTTP cache support to RSS feeds --------- Co-authored-by: Florian ALEXANDRE <f.alexandre@novactive.com>
1 parent d2cfa31 commit 207d9a5

File tree

6 files changed

+118
-3
lines changed

6 files changed

+118
-3
lines changed

components/RssFeedBundle/README.md

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -100,4 +100,11 @@ Inside your locale file (example novarss_sites.fr.yaml) put your translation as
100100
```yaml
101101
site_access_identifier: My site
102102
```
103-
Note : This translation is enabled using the default SiteListService
103+
Note : This translation is enabled using the default SiteListService
104+
105+
### HTTP caching
106+
107+
The `NOVAEZRSSFEED_CACHE_TTL` ENV var control the HTTP cache behavior:
108+
- `null` => public + expire at 0h00
109+
- `0` => private
110+
- `<int>` => public + s-maxage of `<int>`

components/RssFeedBundle/src/bundle/Controller/RssFeedViewController.php

Lines changed: 35 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@
1212

1313
namespace Novactive\EzRssFeedBundle\Controller;
1414

15+
use DateTime;
16+
use FOS\HttpCacheBundle\Http\SymfonyResponseTagger;
1517
use Ibexa\Bundle\Core\Controller;
1618
use Ibexa\Contracts\Core\Repository\PermissionResolver;
1719
use Ibexa\Core\Base\Exceptions\UnauthorizedException;
@@ -32,6 +34,15 @@ class RssFeedViewController extends Controller
3234
{
3335
use EntityManagerTrait;
3436

37+
protected SymfonyResponseTagger $responseTagger;
38+
protected ?int $cacheTtl = null;
39+
40+
public function __construct(SymfonyResponseTagger $responseTagger, ?int $cacheTtl)
41+
{
42+
$this->responseTagger = $responseTagger;
43+
$this->cacheTtl = $cacheTtl;
44+
}
45+
3546
/**
3647
* @Route("/{urlSlug}/{site?}", name="rss_feed_view_index")
3748
*/
@@ -76,6 +87,19 @@ public function indexAction(
7687

7788
$response->headers->set('Content-Type', 'application/rss+xml; charset=utf-8');
7889

90+
$response->setPublic();
91+
if (null === $this->cacheTtl) {
92+
$expire = (new DateTime())->modify('+1 day')->setTime(0, 0);
93+
$response->setExpires($expire);
94+
$response->setSharedMaxAge($expire->getTimestamp() - time());
95+
} elseif (0 === $this->cacheTtl) {
96+
$response->setPrivate();
97+
} else {
98+
$response->setSharedMaxAge($this->cacheTtl);
99+
}
100+
$this->responseTagger->addTags(['rssfeed-'.$rssFeed->getId()]);
101+
$this->responseTagger->tagSymfonyResponse($response);
102+
79103
return $response;
80104
}
81105

@@ -105,11 +129,20 @@ public function rssHeadLinkTagsAction(SiteAccess $siteAccess, FactoryInterface $
105129
}
106130
}
107131

108-
return $this->render(
132+
$response = new Response();
133+
$response = $this->render(
109134
'@ibexadesign/rssfeed/meta_links.html.twig',
110135
[
111136
'links' => $links,
112-
]
137+
],
138+
$response
113139
);
140+
141+
$response->setPublic();
142+
$response->setSharedMaxAge(60 * 60 * 24 * 365);
143+
$this->responseTagger->addTags(['rssfeeds']);
144+
$this->responseTagger->tagSymfonyResponse($response);
145+
146+
return $response;
114147
}
115148
}

components/RssFeedBundle/src/bundle/DependencyInjection/EzRssFeedExtension.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ class EzRssFeedExtension extends Extension implements PrependExtensionInterface
3333
public function load(array $configs, ContainerBuilder $container): void
3434
{
3535
$loader = new Loader\YamlFileLoader($container, new FileLocator(__DIR__.'/../Resources/config'));
36+
$loader->load('default_settings.yaml');
3637
$loader->load('services.yml');
3738
$loader->load('PlatformAdminUI/services.yml');
3839
}
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Novactive\EzRssFeedBundle\EventListener;
6+
7+
use Doctrine\ORM\Event\LifecycleEventArgs;
8+
use Ibexa\Contracts\HttpCache\PurgeClient\PurgeClientInterface;
9+
use Novactive\EzRssFeedBundle\Entity\RssFeeds;
10+
11+
class DoctrineEventListener
12+
{
13+
/** @var PurgeClientInterface */
14+
protected $httpCachePurgeClient;
15+
16+
public function __construct(PurgeClientInterface $httpCachePurgeClient)
17+
{
18+
$this->httpCachePurgeClient = $httpCachePurgeClient;
19+
}
20+
21+
public function postPersist(LifecycleEventArgs $args)
22+
{
23+
$this->lifecycleEventHandler($args);
24+
}
25+
26+
public function postUpdate(LifecycleEventArgs $args)
27+
{
28+
$this->lifecycleEventHandler($args);
29+
}
30+
31+
public function postRemove(LifecycleEventArgs $args)
32+
{
33+
$this->lifecycleEventHandler($args);
34+
}
35+
36+
/**
37+
* @throws \Psr\Cache\InvalidArgumentException
38+
*/
39+
protected function lifecycleEventHandler(LifecycleEventArgs $args): void
40+
{
41+
$entity = $args->getEntity();
42+
if ($entity instanceof RssFeeds) {
43+
$tags = ['rssfeed-'.$entity->getId(), 'rssfeeds'];
44+
$this->invalidateTags($tags);
45+
}
46+
}
47+
48+
/**
49+
* @throws \Psr\Cache\InvalidArgumentException
50+
*/
51+
protected function invalidateTags(array $tags): void
52+
{
53+
if (!empty($tags)) {
54+
$this->httpCachePurgeClient->purge($tags);
55+
}
56+
}
57+
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
parameters:
2+
# ~ => public + expire at 0h00
3+
# 0 => private
4+
# <int> => public + s-maxage of `<int>`
5+
env(NOVAEZRSSFEED_CACHE_TTL): "3600"
6+
7+
novaezrssfeed.cache.ttl: '%env(NOVAEZRSSFEED_CACHE_TTL)%'

components/RssFeedBundle/src/bundle/Resources/config/services.yml

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,9 @@ services:
88

99
Novactive\EzRssFeedBundle\Controller\RssFeedViewController:
1010
autowire: true
11+
arguments:
12+
$cacheTtl: '%novaezrssfeed.cache.ttl%'
13+
$responseTagger: '@fos_http_cache.http.symfony_response_tagger'
1114
tags:
1215
- { name: controller.service_arguments }
1316

@@ -43,3 +46,10 @@ services:
4346

4447
Novactive\EzRssFeedBundle\Services\SiteListServiceInterface: '@Novactive\EzRssFeedBundle\Services\SiteListService'
4548

49+
Novactive\EzRssFeedBundle\EventListener\DoctrineEventListener:
50+
arguments:
51+
$httpCachePurgeClient: '@ibexa.http_cache.purge_client'
52+
tags:
53+
- { name: doctrine.event_listener, event: postPersist, lazy: true }
54+
- { name: doctrine.event_listener, event: postUpdate, lazy: true }
55+
- { name: doctrine.event_listener, event: postRemove, lazy: true }

0 commit comments

Comments
 (0)