Installation:
composer require ibexa/http-cache
Requires Ibexa DXP (formerly eZ Platform Enterprise) as a base.
Configuration:
Add the bundle to config/bundles.php:
Ibexa\HttpCache\IbexaHttpCacheBundle::class => ['all' => true],
Varnish Configuration:
Ensure your Varnish instance is configured with the provided .vcl templates (e.g., varnish6.vcl). The bundle includes default configurations for Varnish 6/7.
First Use Case:
Enable caching for a controller by adding the Cacheable trait or annotation:
use Ibexa\HttpCache\Attribute\Cacheable;
#[Cacheable]
public function show(Content $content): Response
{
return new Response($content->getContent());
}
config/packages/ibexa_http_cache.yaml (default configuration)src/Attribute/Cacheable.php (annotation-based caching)src/Listener/ResponseTaggerListener.php (response tagging logic)Use the #[Cacheable] attribute on controller methods to enable HTTP caching:
#[Cacheable(
ttl: 3600,
varyBy: ['content_language', 'content_version'],
tags: ['content/{content_id}']
)]
public function show(Content $content): Response
{
return new Response($content->render());
}
ttl: Time-to-live in seconds (default: 300).varyBy: Array of request attributes to vary cache by (e.g., ['content_language']).tags: Cache tags for invalidation (e.g., ['content/123']).Invalidate cache tags programmatically (e.g., after content updates):
use Ibexa\HttpCache\CacheInvalidator;
public function updateContent(Content $content): void
{
$this->cacheInvalidator->invalidateTags(['content/' . $content->id]);
}
Inject CacheInvalidator via dependency injection.
Dynamically add Vary headers for multi-language or multi-site setups:
use Ibexa\HttpCache\EventSubscriber\VaryHeaderSubscriber;
// Configure in services.yaml:
Ibexa\HttpCache\EventSubscriber\VaryHeaderSubscriber:
tags:
- { name: kernel.event_subscriber }
Use ConditionalGetListener to support If-None-Match/If-Modified-Since:
# config/packages/ibexa_http_cache.yaml
ibexa_http_cache:
conditional_get: true
varnish6.vcl or varnish7.vcl to your Varnish instance.VarnishPurger service to purge URLs or tags:
$this->varnishPurger->purge(['/path/to/page', '/another/path']);
Middleware Integration:
Add the bundle’s middleware to your app/Http/Kernel.php:
protected $middlewareGroups = [
'web' => [
// ...
\Ibexa\HttpCache\Middleware\CacheMiddleware::class,
],
];
Symfony Event Dispatcher: The bundle leverages Symfony’s event system. Extend existing listeners or create custom ones:
use Ibexa\HttpCache\Event\CacheEvent;
public function onCacheEvent(CacheEvent $event): void
{
if ($event->isCacheable()) {
$event->setTtl(7200); // Override TTL
}
}
Custom Response Taggers:
Extend ResponseTaggerInterface to add custom tags:
use Ibexa\HttpCache\ResponseTagger\ResponseTaggerInterface;
class CustomResponseTagger implements ResponseTaggerInterface
{
public function getTags(Request $request, Response $response): array
{
return ['custom/' . $request->get('param')];
}
}
Register the service with the ibexa.http_cache.response_tagger tag.
content_language tags.content_version in varyBy to cache different content versions separately.Cookie Handling:
ibexa-).session_id) are excluded or prefixed correctly.ConditionallyRemoveVaryHeaderListener if Vary: Cookie appears unexpectedly.Varnish Configuration Mismatches:
500 errors, verify:
.vcl file is correctly deployed.ibexa_http_cache.varnish config in config/packages/ibexa_http_cache.yaml aligns with your Varnish version.varnishlog to debug Varnish requests.Cache Invalidation Race Conditions:
purge() for critical paths (e.g., admin actions):
$this->varnishPurger->purge(['/admin/*'], true); // Force sync purge
TTL Too Aggressive:
< 60s) may cause Varnish to flood your backend with requests.ttl: 300 and adjust based on traffic.Symfony 7+ Compatibility:
composer.json constraints align:
"require": {
"php": "^8.3",
"symfony/*": "^7.3"
}
Enable Debug Headers:
Add to config/packages/ibexa_http_cache.yaml:
ibexa_http_cache:
debug: true
This adds X-Ibexa-Cache headers to responses (e.g., X-Ibexa-Cache: HIT).
Log Cache Events:
Configure Monolog to log Ibexa\HttpCache\Event\CacheEvent:
monolog:
handlers:
cache:
type: stream
path: "%kernel.logs_dir%/cache.log"
channels: ["ibexa_http_cache"]
Check Response Tags:
Use dd($response->headers->get('X-Ibexa-Cache-Tags')) to verify tags are applied correctly.
Varnish Debugging:
varnishd -C -f /path/to/varnish.vcl.varnishstat to monitor hit/miss ratios.Custom Cache Keys:
Override the cache key generation in CacheKeyGeneratorInterface:
class CustomCacheKeyGenerator implements CacheKeyGeneratorInterface
{
public function generate(Request $request): string
{
return md5($request->getPathInfo() . $request->get('custom_param'));
}
}
Register as a service with the ibexa.http_cache.cache_key_generator tag.
Dynamic TTL:
Implement TtlResolverInterface to set TTLs based on runtime logic:
class DynamicTtlResolver implements TtlResolverInterface
{
public function resolve(Request $request, Response $response): int
{
return $request->get('is_premium') ? 86400 : 3600;
}
}
Edge-Side Includes (ESI):
Use #[Cacheable(esi: true)] to enable ESI for partial responses:
#[Cacheable(esi: true, ttl: 60)]
public function partial(): Response
{
return new Response('<esi:include src="/partial-path" />');
How can I help you explore Laravel packages today?