c2is/doctrine-cache-invalidation-bundle
Installation
Add the bundle to your composer.json:
composer require c2is/doctrine-cache-invalidation-bundle
Register the bundle in config/bundles.php:
return [
// ...
C2is\DoctrineCacheInvalidationBundle\C2isDoctrineCacheInvalidationBundle::class => ['all' => true],
];
First Use Case Invalidate Doctrine's query cache for a specific entity or query:
use C2is\DoctrineCacheInvalidationBundle\CacheInvalidator;
// In your service/controller
$cacheInvalidator = $this->container->get('c2is.doctrine_cache_invalidation.cache_invalidator');
$cacheInvalidator->invalidateEntityCache('App\Entity\Product', 123); // Invalidate cache for Product with ID 123
Where to Look First
config/packages/c2is_doctrine_cache_invalidation.yaml (if auto-generated).onFlush and postFlush events by default.Manual Cache Invalidation Trigger cache invalidation programmatically in services/controllers:
// Invalidate all cached results for an entity class
$cacheInvalidator->invalidateEntityCache('App\Entity\User');
// Invalidate a specific entity instance
$cacheInvalidator->invalidateEntityCache('App\Entity\User', $userId);
Automatic Invalidation via Events
The bundle hooks into Doctrine lifecycle events (onFlush, postFlush). Extend or override the default behavior:
# config/packages/c2is_doctrine_cache_invalidation.yaml
c2is_doctrine_cache_invalidation:
listeners:
on_flush: true # Default: true
post_flush: true # Default: true
Integration with Custom Logic
Use the CacheInvalidator service in custom event subscribers or commands:
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
class ClearProductCacheCommand extends Command
{
protected function execute(InputInterface $input, OutputInterface $output)
{
$cacheInvalidator = $this->getContainer()->get('c2is.doctrine_cache_invalidation.cache_invalidator');
$cacheInvalidator->invalidateEntityCache('App\Entity\Product');
$output->writeln('Product cache invalidated!');
}
}
Partial Cache Invalidation Invalidate only specific queries or DQL fragments (advanced):
$cacheInvalidator->invalidateQueryCache('SELECT p FROM App\Entity\Product p WHERE p.category = :category');
postUpdate/postRemove: Invalidate cache after entity updates/deletions.$this->getContainer()->get('c2is.doctrine_cache_invalidation.cache_invalidator')
->invalidateEntityCache('App\Entity\TestEntity');
Event Timing Issues
onFlush invalidation fails, switch to postFlush or vice versa.debug:event-dispatcher:
php bin/console debug:event-dispatcher
Cache Driver Mismatch
// Example: Force a specific cache pool
$cacheInvalidator->setCachePool($entityManager->getConfiguration()->getQueryCacheImpl());
Performance Overhead
Entity Metadata Caching
$entityManager->getMetadataFactory()->getMetadataFor('App\Entity\User')->setCacheDriver(null);
Log Invalidation Events
Enable debug logging in config/packages/dev/monolog.yaml:
handlers:
doctrine_cache:
type: stream
path: "%kernel.logs_dir%/doctrine_cache_invalidation.log"
level: debug
channels: ["doctrine"]
Verify Cache State Use Doctrine's built-in cache tools:
php bin/console doctrine:query:sql "SELECT * FROM product WHERE category = ?" --em=default
Check for /* HIT */ or /* MISS */ in logs.
Custom Invalidators
Create a decorator for CacheInvalidator:
use C2is\DoctrineCacheInvalidationBundle\CacheInvalidatorInterface;
class CustomCacheInvalidator implements CacheInvalidatorInterface
{
private $decorated;
public function __construct(CacheInvalidatorInterface $decorated)
{
$this->decorated = $decorated;
}
public function invalidateEntityCache($entityName, $entityId = null)
{
// Custom logic (e.g., log, validate)
$this->decorated->invalidateEntityCache($entityName, $entityId);
}
}
Register as a service:
services:
c2is.doctrine_cache_invalidation.cache_invalidator:
decorates: 'c2is.doctrine_cache_invalidation.cache_invalidator'
arguments: ['@c2is.doctrine_cache_invalidation.cache_invalidator.inner']
Override Default Listeners Disable built-in listeners and implement your own:
c2is_doctrine_cache_invalidation:
listeners:
on_flush: false
post_flush: false
Create a custom subscriber:
use Doctrine\Common\EventSubscriber;
use Doctrine\ORM\Event\OnFlushEventArgs;
class CustomCacheSubscriber implements EventSubscriber
{
public function getSubscribedEvents()
{
return ['onFlush'];
}
public function onFlush(OnFlushEventArgs $args)
{
// Custom invalidation logic
}
}
Multi-EntityManager Support
If using multiple EntityManagers, bind the invalidator to a specific one:
$cacheInvalidator = $this->container->get('c2is.doctrine_cache_invalidation.cache_invalidator');
$cacheInvalidator->setEntityManager($secondEntityManager);
How can I help you explore Laravel packages today?