From 7528e4c3c6aa9e74a7b1fc12fefaf8c4f9aa6d13 Mon Sep 17 00:00:00 2001 From: fabios Date: Fri, 4 Oct 2013 16:55:49 -0400 Subject: [PATCH] Allow cache drivers that are not an EM's child --- .../AbstractDoctrineExtension.php | 46 +++-- .../DoctrineExtensionTest.php | 162 ++++++++++++++++++ 2 files changed, 196 insertions(+), 12 deletions(-) create mode 100644 src/Symfony/Bridge/Doctrine/Tests/DependencyInjection/DoctrineExtensionTest.php diff --git a/src/Symfony/Bridge/Doctrine/DependencyInjection/AbstractDoctrineExtension.php b/src/Symfony/Bridge/Doctrine/DependencyInjection/AbstractDoctrineExtension.php index 5fd3090a79..50cb74bb86 100644 --- a/src/Symfony/Bridge/Doctrine/DependencyInjection/AbstractDoctrineExtension.php +++ b/src/Symfony/Bridge/Doctrine/DependencyInjection/AbstractDoctrineExtension.php @@ -306,14 +306,30 @@ abstract class AbstractDoctrineExtension extends Extension */ protected function loadObjectManagerCacheDriver(array $objectManager, ContainerBuilder $container, $cacheName) { - $cacheDriver = $objectManager[$cacheName.'_driver']; - $cacheDriverService = $this->getObjectManagerElementName($objectManager['name'].'_'.$cacheName); + $this->loadCacheDriver($cacheName, $objectManager['name'], $objectManager[$cacheName.'_driver'], $container); + } + + /** + * Loads a cache driver. + * + * @param string $cacheDriverServiceId The cache driver name. + * @param string $objectManagerName The object manager name. + * @param array $cacheDriver The cache driver mapping. + * @param \Symfony\Component\DependencyInjection\ContainerBuilder $container The ContainerBuilder instance. + * + * @return string + * + * @throws \InvalidArgumentException + */ + protected function loadCacheDriver($cacheName, $objectManagerName, array $cacheDriver, ContainerBuilder $container) + { + $cacheDriverServiceId = $this->getObjectManagerElementName($objectManagerName . '_' . $cacheName); switch ($cacheDriver['type']) { case 'service': - $container->setAlias($cacheDriverService, new Alias($cacheDriver['id'], false)); + $container->setAlias($cacheDriverServiceId, new Alias($cacheDriver['id'], false)); - return; + return $cacheDriverServiceId; case 'memcache': $memcacheClass = !empty($cacheDriver['class']) ? $cacheDriver['class'] : '%'.$this->getObjectManagerElementName('cache.memcache.class').'%'; $memcacheInstanceClass = !empty($cacheDriver['instance_class']) ? $cacheDriver['instance_class'] : '%'.$this->getObjectManagerElementName('cache.memcache_instance.class').'%'; @@ -324,8 +340,8 @@ abstract class AbstractDoctrineExtension extends Extension $memcacheInstance->addMethodCall('connect', array( $memcacheHost, $memcachePort )); - $container->setDefinition($this->getObjectManagerElementName(sprintf('%s_memcache_instance', $objectManager['name'])), $memcacheInstance); - $cacheDef->addMethodCall('setMemcache', array(new Reference($this->getObjectManagerElementName(sprintf('%s_memcache_instance', $objectManager['name']))))); + $container->setDefinition($this->getObjectManagerElementName(sprintf('%s_memcache_instance', $objectManagerName)), $memcacheInstance); + $cacheDef->addMethodCall('setMemcache', array(new Reference($this->getObjectManagerElementName(sprintf('%s_memcache_instance', $objectManagerName))))); break; case 'memcached': $memcachedClass = !empty($cacheDriver['class']) ? $cacheDriver['class'] : '%'.$this->getObjectManagerElementName('cache.memcached.class').'%'; @@ -337,8 +353,8 @@ abstract class AbstractDoctrineExtension extends Extension $memcachedInstance->addMethodCall('addServer', array( $memcachedHost, $memcachedPort )); - $container->setDefinition($this->getObjectManagerElementName(sprintf('%s_memcached_instance', $objectManager['name'])), $memcachedInstance); - $cacheDef->addMethodCall('setMemcached', array(new Reference($this->getObjectManagerElementName(sprintf('%s_memcached_instance', $objectManager['name']))))); + $container->setDefinition($this->getObjectManagerElementName(sprintf('%s_memcached_instance', $objectManagerName)), $memcachedInstance); + $cacheDef->addMethodCall('setMemcached', array(new Reference($this->getObjectManagerElementName(sprintf('%s_memcached_instance', $objectManagerName))))); break; case 'redis': $redisClass = !empty($cacheDriver['class']) ? $cacheDriver['class'] : '%'.$this->getObjectManagerElementName('cache.redis.class').'%'; @@ -350,8 +366,8 @@ abstract class AbstractDoctrineExtension extends Extension $redisInstance->addMethodCall('connect', array( $redisHost, $redisPort )); - $container->setDefinition($this->getObjectManagerElementName(sprintf('%s_redis_instance', $objectManager['name'])), $redisInstance); - $cacheDef->addMethodCall('setRedis', array(new Reference($this->getObjectManagerElementName(sprintf('%s_redis_instance', $objectManager['name']))))); + $container->setDefinition($this->getObjectManagerElementName(sprintf('%s_redis_instance', $objectManagerName)), $redisInstance); + $cacheDef->addMethodCall('setRedis', array(new Reference($this->getObjectManagerElementName(sprintf('%s_redis_instance', $objectManagerName))))); break; case 'apc': case 'array': @@ -368,12 +384,18 @@ abstract class AbstractDoctrineExtension extends Extension if (!isset($cacheDriver['namespace'])) { // generate a unique namespace for the given application - $cacheDriver['namespace'] = 'sf2'.$this->getMappingResourceExtension().'_'.$objectManager['name'].'_'.hash('sha256',($container->getParameter('kernel.root_dir').$container->getParameter('kernel.environment'))); + $env = $container->getParameter('kernel.root_dir').$container->getParameter('kernel.environment'); + $hash = hash('sha256', $env); + $namespace = 'sf2'.$this->getMappingResourceExtension().'_'.$objectManagerName.'_'.$hash; + + $cacheDriver['namespace'] = $namespace; } $cacheDef->addMethodCall('setNamespace', array($cacheDriver['namespace'])); - $container->setDefinition($cacheDriverService, $cacheDef); + $container->setDefinition($cacheDriverServiceId, $cacheDef); + + return $cacheDriverServiceId; } /** diff --git a/src/Symfony/Bridge/Doctrine/Tests/DependencyInjection/DoctrineExtensionTest.php b/src/Symfony/Bridge/Doctrine/Tests/DependencyInjection/DoctrineExtensionTest.php new file mode 100644 index 0000000000..50b53f135d --- /dev/null +++ b/src/Symfony/Bridge/Doctrine/Tests/DependencyInjection/DoctrineExtensionTest.php @@ -0,0 +1,162 @@ + +* +* For the full copyright and license information, please view the LICENSE +* file that was distributed with this source code. +*/ + +namespace Symfony\Bridge\Doctrine\Tests\DependencyInjection\Compiler; + +use Symfony\Component\DependencyInjection\Definition; +use Symfony\Component\DependencyInjection\ContainerBuilder; +use Symfony\Component\DependencyInjection\ParameterBag\ParameterBag; + +/** + * @author Fabio B. Silva + */ +class DoctrineExtensionTest extends \PHPUnit_Framework_TestCase +{ + /** + * @var \Symfony\Bridge\Doctrine\DependencyInjection\AbstractDoctrineExtension + */ + private $extension; + + protected function setUp() + { + parent::setUp(); + + $this->extension = $this + ->getMockBuilder('Symfony\Bridge\Doctrine\DependencyInjection\AbstractDoctrineExtension') + ->setMethods(array( + 'getMappingResourceConfigDirectory', + 'getObjectManagerElementName', + 'getMappingObjectDefaultName', + 'getMappingResourceExtension', + 'load', + )) + ->getMock() + ; + + $this->extension->expects($this->any()) + ->method('getObjectManagerElementName') + ->will($this->returnCallback(function ($name) { + return 'doctrine.orm.'.$name; + })); + } + + public function providerBasicDrivers() + { + return array( + array('doctrine.orm.cache.apc.class', array('type' => 'apc')), + array('doctrine.orm.cache.array.class', array('type' => 'array')), + array('doctrine.orm.cache.xcache.class', array('type' => 'xcache')), + array('doctrine.orm.cache.wincache.class', array('type' => 'wincache')), + array('doctrine.orm.cache.zenddata.class', array('type' => 'zenddata')), + array('doctrine.orm.cache.redis.class', array('type' => 'redis'), array('setRedis')), + array('doctrine.orm.cache.memcache.class', array('type' => 'memcache'), array('setMemcache')), + array('doctrine.orm.cache.memcached.class', array('type' => 'memcached'), array('setMemcached')), + ); + } + + /** + * @param string $class + * @param array $config + * + * @dataProvider providerBasicDrivers + */ + public function testLoadBasicCacheDriver($class, array $config, array $expectedCalls = array()) + { + $container = $this->createContainer(); + $cacheName = 'metadata_cache'; + $objectManager = array( + 'name' => 'default', + 'metadata_cache_driver' => $config + ); + + $this->invokeLoadCacheDriver($objectManager, $container, $cacheName); + + $this->assertTrue($container->hasDefinition('doctrine.orm.default_metadata_cache')); + + $definition = $container->getDefinition('doctrine.orm.default_metadata_cache'); + $defCalls = $definition->getMethodCalls(); + $expectedCalls[] = 'setNamespace'; + $actualCalls = array_map(function ($call) { + return $call[0]; + }, $defCalls); + + $this->assertFalse($definition->isPublic()); + $this->assertEquals("%$class%", $definition->getClass()); + + foreach (array_unique($expectedCalls) as $call) { + $this->assertContains($call, $actualCalls); + } + } + + public function testServiceCacheDriver() + { + $cacheName = 'metadata_cache'; + $container = $this->createContainer(); + $definition = new Definition('%doctrine.orm.cache.apc.class%'); + $objectManager = array( + 'name' => 'default', + 'metadata_cache_driver' => array( + 'type' => 'service', + 'id' => 'service_driver' + ) + ); + + $container->setDefinition('service_driver', $definition); + + $this->invokeLoadCacheDriver($objectManager, $container, $cacheName); + + $this->assertTrue($container->hasAlias('doctrine.orm.default_metadata_cache')); + } + + /** + * @expectedException InvalidArgumentException + * @expectedExceptionMessage "unrecognized_type" is an unrecognized Doctrine cache driver. + */ + public function testUnrecognizedCacheDriverException() + { + $cacheName = 'metadata_cache'; + $container = $this->createContainer(); + $objectManager = array( + 'name' => 'default', + 'metadata_cache_driver' => array( + 'type' => 'unrecognized_type' + ) + ); + + $this->invokeLoadCacheDriver($objectManager, $container, $cacheName); + } + + protected function invokeLoadCacheDriver(array $objectManager, ContainerBuilder $container, $cacheName) + { + $method = new \ReflectionMethod($this->extension, 'loadObjectManagerCacheDriver'); + + $method->setAccessible(true); + + $method->invokeArgs($this->extension, array($objectManager, $container, $cacheName)); + } + + /** + * @param array $data + * + * @return \Symfony\Component\DependencyInjection\ContainerBuilder + */ + protected function createContainer(array $data = array()) + { + return new ContainerBuilder(new ParameterBag(array_merge(array( + 'kernel.bundles' => array('FrameworkBundle' => 'Symfony\\Bundle\\FrameworkBundle\\FrameworkBundle'), + 'kernel.cache_dir' => __DIR__, + 'kernel.debug' => false, + 'kernel.environment' => 'test', + 'kernel.name' => 'kernel', + 'kernel.root_dir' => __DIR__, + ), $data))); + } +}