Skip to content

Commit

Permalink
feat: add cache invalidation by tag
Browse files Browse the repository at this point in the history
  • Loading branch information
adrien-chinour committed Apr 2, 2024
1 parent f96b58a commit d8d0289
Show file tree
Hide file tree
Showing 36 changed files with 373 additions and 175 deletions.
2 changes: 0 additions & 2 deletions compose.yml
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
version: '3.7'

services:
web:
container_name: blog.nginx
Expand Down
1 change: 1 addition & 0 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
"ext-iconv": "*",
"ext-intl": "*",
"league/commonmark": "2.4.*",
"symfony/config": "7.0.*",
"symfony/console": "7.0.*",
"symfony/dotenv": "7.0.*",
"symfony/flex": "^2",
Expand Down
2 changes: 1 addition & 1 deletion composer.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 5 additions & 3 deletions config/packages/framework.php
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,9 @@
->app('cache.adapter.filesystem')
->system('cache.adapter.system');

$framework->cache()->pool('messenger.cache')
->tags(true);

/**
* Router Configuration
* @see \Symfony\Config\Framework\RouterConfig
Expand Down Expand Up @@ -125,7 +128,7 @@
'middleware' => array_filter([
$container->env() === 'dev' ? StopwatchMiddleware::class : null,
LoggerMiddleware::class,
$container->env() === 'dev' ? null : CacheMiddleware::class,
CacheMiddleware::class,
]),
]);

Expand All @@ -137,8 +140,7 @@
->limiter('public')
->policy('sliding_window')
->limit(1000)
->interval('60 minutes')
;
->interval('60 minutes');

/**
* Lock Configuration
Expand Down
4 changes: 2 additions & 2 deletions config/packages/security.php
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
->security(false);

$adminFirewall = $security->firewall('admin')
->pattern('^/admin/')
->pattern('^/(admin|webhook)/')
->security(true)
->stateless(true)
->provider(ADMIN_USER_PROVIDER);
Expand All @@ -34,6 +34,6 @@
->lazy(true);

$security->accessControl()
->path('^/admin')
->path('^/(admin|webhook)')
->roles(['ROLE_ADMIN']);
};
4 changes: 4 additions & 0 deletions config/routes.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,10 @@
->prefix('/api')
->namePrefix('api_');

$routes->import('../src/Presentation/Webhook/', 'attribute')
->prefix('/webhook')
->namePrefix('webhook_');

if ($routes->env() === 'dev') {
$routes->import('@WebProfilerBundle/Resources/config/routing/wdt.xml')->prefix('/_wdt');
$routes->import('@WebProfilerBundle/Resources/config/routing/profiler.xml')->prefix('/_profiler');
Expand Down
1 change: 1 addition & 0 deletions http/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
http-client.private.env.json
6 changes: 6 additions & 0 deletions http/admin_cache_invalidation.http
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
# @name Cache Invalidation by tag
GET {{host}}/admin/cache-invalidation?tag[]=article
Content-Type: application/json
Authorization: Bearer {{token}}

###
12 changes: 12 additions & 0 deletions http/api_article.http
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
# @name Get Articles
GET {{host}}/api/articles
Content-Type: application/json

###

# @name Get Article By ID
@id = 6J0hWoFCuiuWQtjp3K1mXn
GET {{host}}/api/articles/{{id}}
Content-Type: application/json

###
107 changes: 107 additions & 0 deletions http/webhook_contentful.http
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
# @name Contentful Webhook : Publish BlogPage
POST {{host}}/webhook/contentful/publish
Content-Type: application/json
Authorization: Bearer {{token}}

{
"metadata": {
"tags": []
},
"fields": {
"title": {
"fr": "Débuter avec Varnish"
},
"slug": {
"fr": "debuter-avec-varnish"
},
"description": {
"fr": "TODO"
},
"content": {
"fr": "TODO"
},
"categories": {
"fr": []
}
},
"sys": {
"type": "Entry",
"id": "1234",
"space": {
"sys": {
"type": "Link",
"linkType": "Space",
"id": "1234"
}
},
"environment": {
"sys": {
"id": "master",
"type": "Link",
"linkType": "Environment"
}
},
"contentType": {
"sys": {
"type": "Link",
"linkType": "ContentType",
"id": "blogPage"
}
},
"createdBy": {
"sys": {
"type": "Link",
"linkType": "User",
"id": "1234"
}
},
"updatedBy": {
"sys": {
"type": "Link",
"linkType": "User",
"id": "1234"
}
},
"revision": 3,
"createdAt": "2023-12-18T19:15:54.485Z",
"updatedAt": "2024-01-14T14:48:10.656Z"
}
}

###

# @name Contentful Webhook : Unpublsih BlogPage
POST {{host}}/webhook/contentful/publish
Content-Type: application/json

{
"sys": {
"type": "DeletedEntry",
"id": "1234",
"space": {
"sys": {
"type": "Link",
"linkType": "Space",
"id": "1234"
}
},
"environment": {
"sys": {
"id": "master",
"type": "Link",
"linkType": "Environment"
}
},
"contentType": {
"sys": {
"type": "Link",
"linkType": "ContentType",
"id": "blogPage"
}
},
"revision": 3,
"createdAt": "2024-01-14T14:48:15.803Z",
"updatedAt": "2024-01-14T14:48:15.803Z",
"deletedAt": "2024-01-14T14:48:15.803Z"
}
}

This file was deleted.

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
<?php

declare(strict_types=1);

namespace App\Application\Command\TagCacheInvalidation;

final readonly class TagCacheInvalidationCommand
{
public function __construct(
public array $tags
) {}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
<?php

declare(strict_types=1);

namespace App\Application\Command\TagCacheInvalidation;

use Symfony\Component\Messenger\Attribute\AsMessageHandler;
use Symfony\Contracts\Cache\TagAwareCacheInterface;

#[AsMessageHandler]
final readonly class TagCacheInvalidationCommandHandler
{
public function __construct(
private TagAwareCacheInterface $messengerCache
) {
}

public function __invoke(TagCacheInvalidationCommand $command): void
{
$this->messengerCache->invalidateTags($command->tags);
}
}
12 changes: 0 additions & 12 deletions src/Application/Query/CacheableQueryInterface.php

This file was deleted.

19 changes: 6 additions & 13 deletions src/Application/Query/GetArticle/GetArticleQuery.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,19 +4,12 @@

namespace App\Application\Query\GetArticle;

use App\Application\Query\CacheableQueryInterface;
use App\Application\Query\QueryCache;

final readonly class GetArticleQuery implements CacheableQueryInterface
#[QueryCache(ttl: 3600, tags: ['get_article', 'article'])]
final class GetArticleQuery
{
public function __construct(public string $identifier, public bool $preview = false) {}

public function getCacheKey(): string
{
return sprintf('article_%s', $this->identifier);
}

public function getCacheTtl(): int
{
return $this->preview ? 0 : 3600;
}
public function __construct(
public string $identifier,
) {}
}
6 changes: 4 additions & 2 deletions src/Application/Query/GetArticle/GetArticleQueryHandler.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,12 @@
#[AsMessageHandler]
final readonly class GetArticleQueryHandler
{
public function __construct(private BlogArticleRepository $blogArticleRepository) {}
public function __construct(
private BlogArticleRepository $blogArticleRepository,
) {}

public function __invoke(GetArticleQuery $query): ?BlogArticle
{
return $this->blogArticleRepository->getById($query->identifier, $query->preview);
return $this->blogArticleRepository->getById($query->identifier);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,19 +4,12 @@

namespace App\Application\Query\GetArticleByFilter;

use App\Application\Query\CacheableQueryInterface;
use App\Application\Query\QueryCache;

final readonly class GetArticleByFilterQuery implements CacheableQueryInterface
#[QueryCache(ttl: 3600, tags: ['get_article', 'article'])]
final readonly class GetArticleByFilterQuery
{
public function __construct(public array $filters) {}

public function getCacheKey(): string
{
return sprintf('article_filters_%s', md5((string)json_encode($this->filters)));
}

public function getCacheTtl(): int
{
return 3600;
}
public function __construct(
public array $filters,
) {}
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,9 @@
#[AsMessageHandler]
final readonly class GetArticleByFilterQueryHandler
{
public function __construct(private BlogArticleRepository $articleRepository) {}
public function __construct(
private BlogArticleRepository $articleRepository,
) {}

public function __invoke(GetArticleByFilterQuery $query): ?BlogArticle
{
Expand Down
15 changes: 3 additions & 12 deletions src/Application/Query/GetArticleList/GetArticleListQuery.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,21 +4,12 @@

namespace App\Application\Query\GetArticleList;

use App\Application\Query\CacheableQueryInterface;
use App\Application\Query\QueryCache;

final readonly class GetArticleListQuery implements CacheableQueryInterface
#[QueryCache(ttl: 3600, tags: ['list_article', 'article'])]
final readonly class GetArticleListQuery
{
public function __construct(
public ?int $limit = null,
) {}

public function getCacheKey(): string
{
return sprintf('articles_%s', $this->limit);
}

public function getCacheTtl(): int
{
return 3600;
}
}
Loading

0 comments on commit d8d0289

Please sign in to comment.