m6web/cache-extra-bundle
Symfony bundle that integrates m6web/cache-extra, adding tag-based cache invalidation and namespace support on top of PSR-6/Symfony cache pools. Useful when you need to clear groups of entries without flushing the whole backend; wired via bundle DI configuration.
Reality check first: this bundle is archived (last release 2016-02-11, zero stars, zero dependents). It targets the Symfony 2.x/3.x era, doctrine/annotations, and m6web/cache-bundle as its cache backend. Before you invest time, confirm your project can actually install it — on Symfony 4+ / PHP 7.2+ you will almost certainly hit constraint or API incompatibilities, and the annotation listener relies on the old Controller event flow. Treat it as a reference implementation unless you are maintaining a legacy app that already uses it.
Assuming a compatible legacy stack:
Install and register
composer require m6web/cache-extra-bundle
// app/AppKernel.php
new M6Web\Bundle\CacheExtraBundle\M6WebCacheExtraBundle(),
It depends on m6web/cache-bundle (or an equivalent PSR-6-ish cache service) being configured, since CacheExtraBundle is a thin annotation layer over a cache provider — it does not ship its own storage.
Wire the cache service
# config.yml
m6_web_cache_extra:
cache_service: m6_web_cache # the service id of your configured provider
Verify the exact key name against the bundle's DependencyInjection/Configuration.php — the config surface is small but the option names matter.
Where to look first
Annotation/Cache.php and Annotation/CacheInvalidate.php — these define the actual annotation surface (expiry/TTL, keys, etc.).Listener/CacheAnnotationListener.php and Listener/CacheInvalidateAnnotationListener.php — this is where the real behavior lives: key derivation, read/write on the controller event, and invalidation on the response.First use case — cache a hot, read-only controller action:
use M6Web\Bundle\CacheExtraBundle\Annotation\Cache;
/**
* @Cache(expires=60)
*/
public function listAction()
{
// expensive query
}
Hit the endpoint twice and confirm the second request short-circuits (add a log line or var_dump in the action to verify it is not executed).
Read caching on controller actions. The primary pattern is annotating actions that are expensive and side-effect free. TTL-based expiry is the default lever; the bundle derives a cache key from the request (route + parameters, typically), so identical requests share an entry. Keep cached actions free of session-dependent, user-specific, or Vary-sensitive output unless you are certain the key accounts for it.
Explicit invalidation on writes. Pair every cached read with a @CacheInvalidate annotation on the action that mutates the underlying data:
use M6Web\Bundle\CacheExtraBundle\Annotation\CacheInvalidate;
/**
* @CacheInvalidate(keys={"article_list", "article_42"})
*/
public function updateAction($id) { ... }
The invalidation listener runs on the controller event and removes the named keys before/around the action, so the next read repopulates. This is the bundle's real value: annotation-driven invalidation without hand-writing $cache->delete() calls scattered through controllers.
Design a key namespace up front. Because keys are strings you control via the annotations, adopt a convention ({resource}_{id}, {route}_{hash(params)}) and centralize the list of invalidated keys. This is the single biggest determinant of whether the bundle helps or hurts — ad-hoc keys lead to stale pages that are painful to trace.
Integrate at the provider level. Set cache_service to the same provider used elsewhere (m6web/redis-bundle, an APC provider, etc.) so cache clears, monitoring, and eviction policies apply uniformly. If you also use HTTP caching (HttpCache, FOSHttpCache), decide whether this bundle is the application-layer cache behind your HTTP cache, or whether you should drop it in favor of Cache-Control/ESI — running both without a clear layering story produces confusing stale data.
Testing. The listeners are the seam. In functional tests, either disable the listener for the test environment (so actions always execute) or use an in-memory cache provider and assert on hit/miss behavior explicitly. Unit-test key generation logic by invoking the listener with a mocked request rather than through the kernel.
symfony/cache contracts with a small custom subscriber, or FOSHttpCacheBundle/friendsofsymfony/http-cache for HTTP-layer caching. The 10 lines of annotation parsing you'd save are not worth an unmaintained dependency.doctrine/annotations and the annotations must be in docblocks the reader scans — annotations on inherited or trait methods, or in files not autoloaded the way the reader expects, silently do nothing. If caching "doesn't work," verify the listener is registered and the annotation is actually being read before debugging the cache itself.cache_service or a typo in the annotation name typically produces no error — just no caching. Add a temporary log in the listener to confirm it fires.@CacheInvalidate, and you get permanent stale entries. Keep the key list in one place or generate it from a helper.Vary dimensions are generally not part of the key. User-specific content (auth state, locale via cookie, A/B buckets) will be cross-served. Bake those into the key or exclude the action from caching.redis-cli KEYS 'prefix*'), temporarily set expires very low, and disable the listener in config_test.yml to isolate whether an issue is caching or application logic.kernel.controller / kernel.response yourself than patching this bundle.How can I help you explore Laravel packages today?