From 71903c28a8d19d792ca17728aa588694e5337a9b Mon Sep 17 00:00:00 2001 From: fabios Date: Wed, 23 Oct 2013 15:46:45 -0400 Subject: [PATCH] Region cache clear commands --- .../ORM/Cache/Region/DefaultRegion.php | 2 +- .../ClearCache/CollectionRegionCommand.php | 134 ++++++++++++++++++ .../ClearCache/EntityRegionCommand.php | 132 +++++++++++++++++ .../Command/ClearCache/QueryRegionCommand.php | 124 ++++++++++++++++ tests/Doctrine/Tests/Mocks/CacheEntryMock.php | 3 + tests/Doctrine/Tests/Mocks/CacheKeyMock.php | 8 ++ .../Doctrine/Tests/Mocks/CacheRegionMock.php | 42 +++++- .../Tests/Mocks/ConcurrentRegionMock.php | 54 ++++++- .../Tests/Mocks/TimestampRegionMock.php | 5 + .../ClearCacheCollectionRegionCommandTest.php | 94 ++++++++++++ .../ClearCacheEntityRegionCommandTest.php | 91 ++++++++++++ .../ClearCacheQueryRegionCommandTest.php | 90 ++++++++++++ tools/sandbox/bootstrap.php | 14 ++ tools/sandbox/doctrine.php | 3 + 14 files changed, 792 insertions(+), 4 deletions(-) create mode 100644 lib/Doctrine/ORM/Tools/Console/Command/ClearCache/CollectionRegionCommand.php create mode 100644 lib/Doctrine/ORM/Tools/Console/Command/ClearCache/EntityRegionCommand.php create mode 100644 lib/Doctrine/ORM/Tools/Console/Command/ClearCache/QueryRegionCommand.php create mode 100644 tests/Doctrine/Tests/ORM/Tools/Console/Command/ClearCacheCollectionRegionCommandTest.php create mode 100644 tests/Doctrine/Tests/ORM/Tools/Console/Command/ClearCacheEntityRegionCommandTest.php create mode 100644 tests/Doctrine/Tests/ORM/Tools/Console/Command/ClearCacheQueryRegionCommandTest.php diff --git a/lib/Doctrine/ORM/Cache/Region/DefaultRegion.php b/lib/Doctrine/ORM/Cache/Region/DefaultRegion.php index b4b5b1b1d..ab518ff65 100644 --- a/lib/Doctrine/ORM/Cache/Region/DefaultRegion.php +++ b/lib/Doctrine/ORM/Cache/Region/DefaultRegion.php @@ -72,7 +72,7 @@ class DefaultRegion implements Region } /** - * @return \Doctrine\Common\Cache\Cache + * @return \Doctrine\Common\Cache\CacheProvider */ public function getCache() { diff --git a/lib/Doctrine/ORM/Tools/Console/Command/ClearCache/CollectionRegionCommand.php b/lib/Doctrine/ORM/Tools/Console/Command/ClearCache/CollectionRegionCommand.php new file mode 100644 index 000000000..80df37a64 --- /dev/null +++ b/lib/Doctrine/ORM/Tools/Console/Command/ClearCache/CollectionRegionCommand.php @@ -0,0 +1,134 @@ +. + */ + +namespace Doctrine\ORM\Tools\Console\Command\ClearCache; + +use Symfony\Component\Console\Command\Command; +use Symfony\Component\Console\Input\InputOption; +use Symfony\Component\Console\Input\InputArgument; +use Symfony\Component\Console\Input\InputInterface; +use Symfony\Component\Console\Output\OutputInterface; +use Doctrine\ORM\Cache\Region\DefaultRegion; +use Doctrine\ORM\Cache; + +/** + * Command to clear a collection cache region. + * + * @since 2.5 + * @author Fabio B. Silva + */ +class CollectionRegionCommand extends Command +{ + /** + * {@inheritdoc} + */ + protected function configure() + { + $this + ->setName('orm:clear-cache:region:collection') + ->setDescription('Clear a second-level cache collection region.') + ->addArgument('owner-class', InputArgument::OPTIONAL, 'The owner entity name.') + ->addArgument('association', InputArgument::OPTIONAL, 'The association collection name.') + ->addArgument('owner-id', InputArgument::OPTIONAL, 'The owner identifier.') + ->addOption('all', null, InputOption::VALUE_NONE, 'If defined, all entity regions will be deleted/invalidated.') + ->addOption('flush', null, InputOption::VALUE_NONE,'If defined, all cache entries will be flushed.'); + + + $this->setHelp(<<%command.name% command is meant to clear a second-level cache collection regions for an associated Entity Manager. +It is possible to delete/invalidate all collection region, a specific collection region or flushes the cache provider. + +The execution type differ on how you execute the command. +If you want to invalidate all entries for an collection region this command would do the work: + +%command.name% 'Entities\MyEntity' 'collectionName' + +To invalidate a specific entry you should use : + +%command.name% 'Entities\MyEntity' 'collectionName' 1 + +If you want to invalidate all entries for the all collection regions: + +%command.name% --all + +Alternatively, if you want to flush the configured cache provider for an collection region use this command: + +%command.name% 'Entities\MyEntity' 'collectionName' --flush + +Finally, be aware that if --flush option is passed, +not all cache providers are able to flush entries, because of a limitation of its execution nature. +EOT + ); + } + + /** + * {@inheritdoc} + */ + protected function execute(InputInterface $input, OutputInterface $output) + { + $em = $this->getHelper('em')->getEntityManager(); + $ownerClass = $input->getArgument('owner-class'); + $assoc = $input->getArgument('association'); + $ownerId = $input->getArgument('owner-id'); + $cache = $em->getCache(); + + if ( ! $cache instanceof Cache) { + throw new \InvalidArgumentException('No second-level cache is configured on the given EntityManager.'); + } + + if ( (! $ownerClass || ! $assoc) && ! $input->getOption('all')) { + throw new \InvalidArgumentException('Missing arguments "--owner-class" "--association"'); + } + + if ($input->getOption('flush')) { + $collectionRegion = $cache->getCollectionCacheRegion($ownerClass, $assoc); + + if ( ! $collectionRegion instanceof DefaultRegion) { + throw new \InvalidArgumentException(sprintf( + 'The option "--flush" expects a "Doctrine\ORM\Cache\Region\DefaultRegion", but got "%s".', + is_object($collectionRegion) ? get_class($collectionRegion) : gettype($collectionRegion) + )); + } + + $collectionRegion->getCache()->flushAll(); + + $output->writeln(sprintf('Flushing cache provider configured for "%s#%s"', $ownerClass, $assoc)); + + return; + } + + if ($input->getOption('all')) { + $output->writeln('Clearing all second-level cache collection regions'); + + $cache->evictEntityRegions(); + + return; + } + + if ($ownerId) { + $output->writeln(sprintf('Clearing second-level cache entry for collection "%s#%s" owner entity identified by "%s"', $ownerClass, $assoc, $ownerId)); + $cache->evictCollection($ownerClass, $assoc, $ownerId); + + return; + } + + $output->writeln(sprintf('Clearing second-level cache for collection "%s#%s"', $ownerClass, $assoc)); + $cache->evictCollectionRegion($ownerClass, $assoc); + } +} \ No newline at end of file diff --git a/lib/Doctrine/ORM/Tools/Console/Command/ClearCache/EntityRegionCommand.php b/lib/Doctrine/ORM/Tools/Console/Command/ClearCache/EntityRegionCommand.php new file mode 100644 index 000000000..21f6e9de9 --- /dev/null +++ b/lib/Doctrine/ORM/Tools/Console/Command/ClearCache/EntityRegionCommand.php @@ -0,0 +1,132 @@ +. + */ + +namespace Doctrine\ORM\Tools\Console\Command\ClearCache; + +use Symfony\Component\Console\Command\Command; +use Symfony\Component\Console\Input\InputOption; +use Symfony\Component\Console\Input\InputArgument; +use Symfony\Component\Console\Input\InputInterface; +use Symfony\Component\Console\Output\OutputInterface; +use Doctrine\ORM\Cache\Region\DefaultRegion; +use Doctrine\ORM\Cache; + +/** + * Command to clear a entity cache region. + * + * @since 2.5 + * @author Fabio B. Silva + */ +class EntityRegionCommand extends Command +{ + /** + * {@inheritdoc} + */ + protected function configure() + { + $this + ->setName('orm:clear-cache:region:entity') + ->setDescription('Clear a second-level cache entity region.') + ->addArgument('entity-class', InputArgument::OPTIONAL, 'The entity name.') + ->addArgument('entity-id', InputArgument::OPTIONAL, 'The entity identifier.') + ->addOption('all', null, InputOption::VALUE_NONE, 'If defined, all entity regions will be deleted/invalidated.') + ->addOption('flush', null, InputOption::VALUE_NONE,'If defined, all cache entries will be flushed.'); + + + $this->setHelp(<<%command.name% command is meant to clear a second-level cache entity region for an associated Entity Manager. +It is possible to delete/invalidate all entity region, a specific entity region or flushes the cache provider. + +The execution type differ on how you execute the command. +If you want to invalidate all entries for an entity region this command would do the work: + +%command.name% 'Entities\MyEntity' + +To invalidate a specific entry you should use : + +%command.name% 'Entities\MyEntity' 1 + +If you want to invalidate all entries for the all entity regions: + +%command.name% --all + +Alternatively, if you want to flush the configured cache provider for an entity region use this command: + +%command.name% 'Entities\MyEntity' --flush + +Finally, be aware that if --flush option is passed, +not all cache providers are able to flush entries, because of a limitation of its execution nature. +EOT + ); + } + + /** + * {@inheritdoc} + */ + protected function execute(InputInterface $input, OutputInterface $output) + { + $em = $this->getHelper('em')->getEntityManager(); + $entityClass = $input->getArgument('entity-class'); + $entityId = $input->getArgument('entity-id'); + $cache = $em->getCache(); + + if ( ! $cache instanceof Cache) { + throw new \InvalidArgumentException('No second-level cache is configured on the given EntityManager.'); + } + + if ( ! $entityClass && ! $input->getOption('all')) { + throw new \InvalidArgumentException('Invalid argument "--entity-class"'); + } + + if ($input->getOption('flush')) { + $entityRegion = $cache->getEntityCacheRegion($entityClass); + + if ( ! $entityRegion instanceof DefaultRegion) { + throw new \InvalidArgumentException(sprintf( + 'The option "--flush" expects a "Doctrine\ORM\Cache\Region\DefaultRegion", but got "%s".', + is_object($entityRegion) ? get_class($entityRegion) : gettype($entityRegion) + )); + } + + $entityRegion->getCache()->flushAll(); + + $output->writeln(sprintf('Flushing cache provider configured for entity named "%s"', $entityClass)); + + return; + } + + if ($input->getOption('all')) { + $output->writeln('Clearing all second-level cache entity regions'); + + $cache->evictEntityRegions(); + + return; + } + + if ($entityId) { + $output->writeln(sprintf('Clearing second-level cache entry for entity "%s" identified by "%s"', $entityClass, $entityId)); + $cache->evictEntity($entityClass, $entityId); + + return; + } + + $output->writeln(sprintf('Clearing second-level cache for entity "%s"', $entityClass)); + $cache->evictEntityRegion($entityClass); + } +} \ No newline at end of file diff --git a/lib/Doctrine/ORM/Tools/Console/Command/ClearCache/QueryRegionCommand.php b/lib/Doctrine/ORM/Tools/Console/Command/ClearCache/QueryRegionCommand.php new file mode 100644 index 000000000..b5d75d3b3 --- /dev/null +++ b/lib/Doctrine/ORM/Tools/Console/Command/ClearCache/QueryRegionCommand.php @@ -0,0 +1,124 @@ +. + */ + +namespace Doctrine\ORM\Tools\Console\Command\ClearCache; + +use Symfony\Component\Console\Command\Command; +use Symfony\Component\Console\Input\InputOption; +use Symfony\Component\Console\Input\InputArgument; +use Symfony\Component\Console\Input\InputInterface; +use Symfony\Component\Console\Output\OutputInterface; +use Doctrine\ORM\Cache\Region\DefaultRegion; +use Doctrine\ORM\Cache; + +/** + * Command to clear a query cache region. + * + * @since 2.5 + * @author Fabio B. Silva + */ +class QueryRegionCommand extends Command +{ + /** + * {@inheritdoc} + */ + protected function configure() + { + $this + ->setName('orm:clear-cache:region:query') + ->setDescription('Clear a second-level cache query region.') + ->addArgument('region-name', InputArgument::OPTIONAL, 'The query region to clear.') + ->addOption('all', null, InputOption::VALUE_NONE, 'If defined, all query regions will be deleted/invalidated.') + ->addOption('flush', null, InputOption::VALUE_NONE,'If defined, all cache entries will be flushed.'); + + + $this->setHelp(<<%command.name% command is meant to clear a second-level cache query region for an associated Entity Manager. +It is possible to delete/invalidate all query region, a specific query region or flushes the cache provider. + +The execution type differ on how you execute the command. +If you want to invalidate all entries for the default query region this command would do the work: + +%command.name% + +To invalidate entries for a specific query region you should use : + +%command.name% my_region_name + +If you want to invalidate all entries for the all query region: + +%command.name% --all + +Alternatively, if you want to flush the configured cache provider use this command: + +%command.name% my_region_name --flush + +Finally, be aware that if --flush option is passed, +not all cache providers are able to flush entries, because of a limitation of its execution nature. +EOT + ); + } + + /** + * {@inheritdoc} + */ + protected function execute(InputInterface $input, OutputInterface $output) + { + $em = $this->getHelper('em')->getEntityManager(); + $name = $input->getArgument('region-name'); + $cache = $em->getCache(); + + if ($name === null) { + $name = Cache::DEFAULT_QUERY_REGION_NAME; + } + + if ( ! $cache instanceof Cache) { + throw new \InvalidArgumentException('No second-level cache is configured on the given EntityManager.'); + } + + if ($input->getOption('flush')) { + $queryCache = $cache->getQueryCache($name); + $queryRegion = $queryCache->getRegion(); + + if ( ! $queryRegion instanceof DefaultRegion) { + throw new \InvalidArgumentException(sprintf( + 'The option "--flush" expects a "Doctrine\ORM\Cache\Region\DefaultRegion", but got "%s".', + is_object($queryRegion) ? get_class($queryRegion) : gettype($queryRegion) + )); + } + + $queryRegion->getCache()->flushAll(); + + $output->writeln(sprintf('Flushing cache provider configured for second-level cache query region named "%s"', $name)); + + return; + } + + if ($input->getOption('all')) { + $output->writeln('Clearing all second-level cache query regions'); + + $cache->evictQueryRegions(); + + return; + } + + $output->writeln(sprintf('Clearing second-level cache query region named "%s"', $name)); + $cache->evictQueryRegion($name); + } +} \ No newline at end of file diff --git a/tests/Doctrine/Tests/Mocks/CacheEntryMock.php b/tests/Doctrine/Tests/Mocks/CacheEntryMock.php index 902f092e0..7053df563 100644 --- a/tests/Doctrine/Tests/Mocks/CacheEntryMock.php +++ b/tests/Doctrine/Tests/Mocks/CacheEntryMock.php @@ -4,6 +4,9 @@ namespace Doctrine\Tests\Mocks; use Doctrine\ORM\Cache\CacheEntry; +/** + * Cache entry mock + */ class CacheEntryMock extends \ArrayObject implements CacheEntry { diff --git a/tests/Doctrine/Tests/Mocks/CacheKeyMock.php b/tests/Doctrine/Tests/Mocks/CacheKeyMock.php index e427c2f41..f87bc38b1 100644 --- a/tests/Doctrine/Tests/Mocks/CacheKeyMock.php +++ b/tests/Doctrine/Tests/Mocks/CacheKeyMock.php @@ -4,8 +4,16 @@ namespace Doctrine\Tests\Mocks; use Doctrine\ORM\Cache\CacheKey; +/** + * Cache key mock + * + * Used to store/retrieve entries from a cache region + */ class CacheKeyMock extends CacheKey { + /** + * @param string $hash The string hash that represend this cache key + */ function __construct($hash) { $this->hash = $hash; diff --git a/tests/Doctrine/Tests/Mocks/CacheRegionMock.php b/tests/Doctrine/Tests/Mocks/CacheRegionMock.php index a4ef52ca3..05366379e 100644 --- a/tests/Doctrine/Tests/Mocks/CacheRegionMock.php +++ b/tests/Doctrine/Tests/Mocks/CacheRegionMock.php @@ -7,18 +7,35 @@ use Doctrine\ORM\Cache\CacheKey; use Doctrine\ORM\Cache\Lock; use Doctrine\ORM\Cache\Region; +/** + * Cache region mock + */ class CacheRegionMock implements Region { public $calls = array(); public $returns = array(); public $name; - + + /** + * Queue a return value for a specific method invocation + * + * @param string $method + * @param mixed $value + */ public function addReturn($method, $value) { $this->returns[$method][] = $value; } - public function getReturn($method, $default) + /** + * Dequeue a value for a specific method invocation + * + * @param string $method + * @param mixed $default + * + * @return mixed + */ + private function getReturn($method, $default) { if (isset($this->returns[$method]) && ! empty($this->returns[$method])) { return array_shift($this->returns[$method]); @@ -27,6 +44,9 @@ class CacheRegionMock implements Region return $default; } + /** + * {@inheritdoc} + */ public function getName() { $this->calls[__FUNCTION__][] = array(); @@ -34,6 +54,9 @@ class CacheRegionMock implements Region return $this->name; } + /** + * {@inheritdoc} + */ public function contains(CacheKey $key) { $this->calls[__FUNCTION__][] = array('key' => $key); @@ -41,6 +64,9 @@ class CacheRegionMock implements Region return $this->getReturn(__FUNCTION__, false); } + /** + * {@inheritdoc} + */ public function evict(CacheKey $key) { $this->calls[__FUNCTION__][] = array('key' => $key); @@ -48,6 +74,9 @@ class CacheRegionMock implements Region return $this->getReturn(__FUNCTION__, true); } + /** + * {@inheritdoc} + */ public function evictAll() { $this->calls[__FUNCTION__][] = array(); @@ -55,6 +84,9 @@ class CacheRegionMock implements Region return $this->getReturn(__FUNCTION__, true); } + /** + * {@inheritdoc} + */ public function get(CacheKey $key) { $this->calls[__FUNCTION__][] = array('key' => $key); @@ -62,6 +94,9 @@ class CacheRegionMock implements Region return $this->getReturn(__FUNCTION__, null); } + /** + * {@inheritdoc} + */ public function put(CacheKey $key, CacheEntry $entry, Lock $lock = null) { $this->calls[__FUNCTION__][] = array('key' => $key, 'entry' => $entry); @@ -69,6 +104,9 @@ class CacheRegionMock implements Region return $this->getReturn(__FUNCTION__, true); } + /** + * {@inheritdoc} + */ public function clear() { $this->calls = array(); diff --git a/tests/Doctrine/Tests/Mocks/ConcurrentRegionMock.php b/tests/Doctrine/Tests/Mocks/ConcurrentRegionMock.php index e299f2a70..fc488b4b2 100644 --- a/tests/Doctrine/Tests/Mocks/ConcurrentRegionMock.php +++ b/tests/Doctrine/Tests/Mocks/ConcurrentRegionMock.php @@ -10,22 +10,38 @@ use Doctrine\ORM\Cache\CacheKey; use Doctrine\ORM\Cache\Region; use Doctrine\ORM\Cache\Lock; +/** + * Concurrent region mock + * + * Used to mock a ConcurrentRegion + */ class ConcurrentRegionMock implements ConcurrentRegion { public $calls = array(); public $exceptions = array(); public $locks = array(); - + /** * @var \Doctrine\ORM\Cache\Region */ private $region; + /** + * @param \Doctrine\ORM\Cache\Region $region + */ public function __construct(Region $region) { $this->region = $region; } + /** + * Dequeue an exception for a specific method invocation + * + * @param string $method + * @param mixed $default + * + * @return mixed + */ private function throwException($method) { if (isset($this->exceptions[$method]) && ! empty($this->exceptions[$method])) { @@ -37,16 +53,31 @@ class ConcurrentRegionMock implements ConcurrentRegion } } + /** + * Queue an exception for the next method invocation + * + * @param string $method + * @param \Exception $e + */ public function addException($method, \Exception $e) { $this->exceptions[$method][] = $e; } + /** + * Locks a specific cache entry + * + * @param \Doctrine\ORM\Cache\CacheKey $key + * @param \Doctrine\ORM\Cache\Lock $lock + */ public function setLock(CacheKey $key, Lock $lock) { $this->locks[$key->hash] = $lock; } + /** + * {@inheritdoc} + */ public function contains(CacheKey $key) { $this->calls[__FUNCTION__][] = array('key' => $key); @@ -60,6 +91,9 @@ class ConcurrentRegionMock implements ConcurrentRegion return $this->region->contains($key); } + /** + * {@inheritdoc} + */ public function evict(CacheKey $key) { $this->calls[__FUNCTION__][] = array('key' => $key); @@ -69,6 +103,9 @@ class ConcurrentRegionMock implements ConcurrentRegion return $this->region->evict($key); } + /** + * {@inheritdoc} + */ public function evictAll() { $this->calls[__FUNCTION__][] = array(); @@ -78,6 +115,9 @@ class ConcurrentRegionMock implements ConcurrentRegion return $this->region->evictAll(); } + /** + * {@inheritdoc} + */ public function get(CacheKey $key) { $this->calls[__FUNCTION__][] = array('key' => $key); @@ -91,6 +131,9 @@ class ConcurrentRegionMock implements ConcurrentRegion return $this->region->get($key); } + /** + * {@inheritdoc} + */ public function getName() { $this->calls[__FUNCTION__][] = array(); @@ -100,6 +143,9 @@ class ConcurrentRegionMock implements ConcurrentRegion return $this->region->getName(); } + /** + * {@inheritdoc} + */ public function put(CacheKey $key, CacheEntry $entry, Lock $lock = null) { $this->calls[__FUNCTION__][] = array('key' => $key, 'entry' => $entry); @@ -118,6 +164,9 @@ class ConcurrentRegionMock implements ConcurrentRegion return $this->region->put($key, $entry); } + /** + * {@inheritdoc} + */ public function lock(CacheKey $key) { $this->calls[__FUNCTION__][] = array('key' => $key); @@ -131,6 +180,9 @@ class ConcurrentRegionMock implements ConcurrentRegion return $this->locks[$key->hash] = Lock::createLockRead(); } + /** + * {@inheritdoc} + */ public function unlock(CacheKey $key, Lock $lock) { $this->calls[__FUNCTION__][] = array('key' => $key, 'lock' => $lock); diff --git a/tests/Doctrine/Tests/Mocks/TimestampRegionMock.php b/tests/Doctrine/Tests/Mocks/TimestampRegionMock.php index ade513060..b55c7c5e3 100644 --- a/tests/Doctrine/Tests/Mocks/TimestampRegionMock.php +++ b/tests/Doctrine/Tests/Mocks/TimestampRegionMock.php @@ -5,6 +5,11 @@ namespace Doctrine\Tests\Mocks; use Doctrine\ORM\Cache\TimestampRegion; use Doctrine\ORM\Cache\CacheKey; +/** + * Timestamp region mock + * + * Used to mock a TimestampRegion + */ class TimestampRegionMock extends CacheRegionMock implements TimestampRegion { public function update(CacheKey $key) diff --git a/tests/Doctrine/Tests/ORM/Tools/Console/Command/ClearCacheCollectionRegionCommandTest.php b/tests/Doctrine/Tests/ORM/Tools/Console/Command/ClearCacheCollectionRegionCommandTest.php new file mode 100644 index 000000000..de1e1772c --- /dev/null +++ b/tests/Doctrine/Tests/ORM/Tools/Console/Command/ClearCacheCollectionRegionCommandTest.php @@ -0,0 +1,94 @@ +enableSecondLevelCache(); + parent::setUp(); + + $this->application = new Application(); + $this->command = new CollectionRegionCommand(); + + $this->application->setHelperSet(new HelperSet(array( + 'em' => new EntityManagerHelper($this->_em) + ))); + + $this->application->add($this->command); + } + + public function testClearAllRegion() + { + $command = $this->application->find('orm:clear-cache:region:collection'); + $tester = new CommandTester($command); + $tester->execute(array( + 'command' => $command->getName(), + '--all' => true, + )); + + $this->assertEquals('Clearing all second-level cache collection regions' . PHP_EOL, $tester->getDisplay()); + } + + public function testClearByOwnerEntityClassName() + { + $command = $this->application->find('orm:clear-cache:region:collection'); + $tester = new CommandTester($command); + $tester->execute(array( + 'command' => $command->getName(), + 'owner-class' => 'Doctrine\Tests\Models\Cache\State', + 'association' => 'cities', + )); + + $this->assertEquals('Clearing second-level cache for collection "Doctrine\Tests\Models\Cache\State#cities"' . PHP_EOL, $tester->getDisplay()); + } + + public function testClearCacheEntryName() + { + $command = $this->application->find('orm:clear-cache:region:collection'); + $tester = new CommandTester($command); + $tester->execute(array( + 'command' => $command->getName(), + 'owner-class' => 'Doctrine\Tests\Models\Cache\State', + 'association' => 'cities', + 'owner-id' => 1, + )); + + $this->assertEquals('Clearing second-level cache entry for collection "Doctrine\Tests\Models\Cache\State#cities" owner entity identified by "1"' . PHP_EOL, $tester->getDisplay()); + } + + public function testFlushRegionName() + { + $command = $this->application->find('orm:clear-cache:region:collection'); + $tester = new CommandTester($command); + $tester->execute(array( + 'command' => $command->getName(), + 'owner-class' => 'Doctrine\Tests\Models\Cache\State', + 'association' => 'cities', + '--flush' => true, + )); + + $this->assertEquals('Flushing cache provider configured for "Doctrine\Tests\Models\Cache\State#cities"' . PHP_EOL, $tester->getDisplay()); + } +} diff --git a/tests/Doctrine/Tests/ORM/Tools/Console/Command/ClearCacheEntityRegionCommandTest.php b/tests/Doctrine/Tests/ORM/Tools/Console/Command/ClearCacheEntityRegionCommandTest.php new file mode 100644 index 000000000..7e9e7c23a --- /dev/null +++ b/tests/Doctrine/Tests/ORM/Tools/Console/Command/ClearCacheEntityRegionCommandTest.php @@ -0,0 +1,91 @@ +enableSecondLevelCache(); + parent::setUp(); + + $this->application = new Application(); + $this->command = new EntityRegionCommand(); + + $this->application->setHelperSet(new HelperSet(array( + 'em' => new EntityManagerHelper($this->_em) + ))); + + $this->application->add($this->command); + } + + public function testClearAllRegion() + { + $command = $this->application->find('orm:clear-cache:region:entity'); + $tester = new CommandTester($command); + $tester->execute(array( + 'command' => $command->getName(), + '--all' => true, + )); + + $this->assertEquals('Clearing all second-level cache entity regions' . PHP_EOL, $tester->getDisplay()); + } + + public function testClearByEntityClassName() + { + $command = $this->application->find('orm:clear-cache:region:entity'); + $tester = new CommandTester($command); + $tester->execute(array( + 'command' => $command->getName(), + 'entity-class' => 'Doctrine\Tests\Models\Cache\Country', + )); + + $this->assertEquals('Clearing second-level cache for entity "Doctrine\Tests\Models\Cache\Country"' . PHP_EOL, $tester->getDisplay()); + } + + public function testClearCacheEntryName() + { + $command = $this->application->find('orm:clear-cache:region:entity'); + $tester = new CommandTester($command); + $tester->execute(array( + 'command' => $command->getName(), + 'entity-class' => 'Doctrine\Tests\Models\Cache\Country', + 'entity-id' => 1, + )); + + $this->assertEquals('Clearing second-level cache entry for entity "Doctrine\Tests\Models\Cache\Country" identified by "1"' . PHP_EOL, $tester->getDisplay()); + } + + public function testFlushRegionName() + { + $command = $this->application->find('orm:clear-cache:region:entity'); + $tester = new CommandTester($command); + $tester->execute(array( + 'command' => $command->getName(), + 'entity-class' => 'Doctrine\Tests\Models\Cache\Country', + '--flush' => true, + )); + + $this->assertEquals('Flushing cache provider configured for entity named "Doctrine\Tests\Models\Cache\Country"' . PHP_EOL, $tester->getDisplay()); + } +} diff --git a/tests/Doctrine/Tests/ORM/Tools/Console/Command/ClearCacheQueryRegionCommandTest.php b/tests/Doctrine/Tests/ORM/Tools/Console/Command/ClearCacheQueryRegionCommandTest.php new file mode 100644 index 000000000..130bec8db --- /dev/null +++ b/tests/Doctrine/Tests/ORM/Tools/Console/Command/ClearCacheQueryRegionCommandTest.php @@ -0,0 +1,90 @@ +enableSecondLevelCache(); + parent::setUp(); + + $this->application = new Application(); + $this->command = new QueryRegionCommand(); + + $this->application->setHelperSet(new HelperSet(array( + 'em' => new EntityManagerHelper($this->_em) + ))); + + $this->application->add($this->command); + } + + public function testClearAllRegion() + { + $command = $this->application->find('orm:clear-cache:region:query'); + $tester = new CommandTester($command); + $tester->execute(array( + 'command' => $command->getName(), + '--all' => true, + )); + + $this->assertEquals('Clearing all second-level cache query regions' . PHP_EOL, $tester->getDisplay()); + } + + public function testClearDefaultRegionName() + { + $command = $this->application->find('orm:clear-cache:region:query'); + $tester = new CommandTester($command); + $tester->execute(array( + 'command' => $command->getName(), + 'region-name' => null, + )); + + $this->assertEquals('Clearing second-level cache query region named "query_cache_region"' . PHP_EOL, $tester->getDisplay()); + } + + public function testClearByRegionName() + { + $command = $this->application->find('orm:clear-cache:region:query'); + $tester = new CommandTester($command); + $tester->execute(array( + 'command' => $command->getName(), + 'region-name' => 'my_region', + )); + + $this->assertEquals('Clearing second-level cache query region named "my_region"' . PHP_EOL, $tester->getDisplay()); + } + + public function testFlushRegionName() + { + $command = $this->application->find('orm:clear-cache:region:query'); + $tester = new CommandTester($command); + $tester->execute(array( + 'command' => $command->getName(), + 'region-name' => 'my_region', + '--flush' => true, + )); + + $this->assertEquals('Flushing cache provider configured for second-level cache query region named "my_region"' . PHP_EOL, $tester->getDisplay()); + } +} diff --git a/tools/sandbox/bootstrap.php b/tools/sandbox/bootstrap.php index 5b97b9412..1e7d8ba00 100644 --- a/tools/sandbox/bootstrap.php +++ b/tools/sandbox/bootstrap.php @@ -38,4 +38,18 @@ $connectionOptions = array( 'path' => 'database.sqlite' ); +// Enable second-level cache +$cacheConfig = new \Doctrine\ORM\Cache\CacheConfiguration(); +$cacheDriver = $debug ? new Cache\ArrayCache : new Cache\ApcCache; +$cacheLogger = new \Doctrine\ORM\Cache\Logging\StatisticsCacheLogger(); +$factory = new \Doctrine\ORM\Cache\DefaultCacheFactory($cacheConfig->getRegionsConfiguration(), $cacheDriver); + +if ($debug) { + $cacheConfig->setCacheLogger($cacheLogger); +} + +$cacheConfig->setCacheFactory($factory); +$config->setSecondLevelCacheEnabled(true); +$config->setSecondLevelCacheConfiguration($cacheConfig); + return EntityManager::create($connectionOptions, $config); \ No newline at end of file diff --git a/tools/sandbox/doctrine.php b/tools/sandbox/doctrine.php index 6cadae0d4..052968690 100644 --- a/tools/sandbox/doctrine.php +++ b/tools/sandbox/doctrine.php @@ -16,6 +16,9 @@ $cli->addCommands(array( new \Doctrine\DBAL\Tools\Console\Command\ImportCommand(), // ORM Commands + new \Doctrine\ORM\Tools\Console\Command\ClearCache\QueryRegionCommand(), + new \Doctrine\ORM\Tools\Console\Command\ClearCache\EntityRegionCommand(), + new \Doctrine\ORM\Tools\Console\Command\ClearCache\CollectionRegionCommand(), new \Doctrine\ORM\Tools\Console\Command\ClearCache\MetadataCommand(), new \Doctrine\ORM\Tools\Console\Command\ClearCache\ResultCommand(), new \Doctrine\ORM\Tools\Console\Command\ClearCache\QueryCommand(),