diff --git a/src/Symfony/Bundle/FrameworkBundle/CHANGELOG.md b/src/Symfony/Bundle/FrameworkBundle/CHANGELOG.md index d6c5ece5e02c7..e8924119b9927 100644 --- a/src/Symfony/Bundle/FrameworkBundle/CHANGELOG.md +++ b/src/Symfony/Bundle/FrameworkBundle/CHANGELOG.md @@ -14,6 +14,8 @@ CHANGELOG * Added `assertResponseFormatSame()` in `BrowserKitAssertionsTrait` * Add support for configuring UUID factory services * Add tag `assets.package` to register asset packages + * Add support to use a PSR-6 compatible cache for Doctrine annotations + * Deprecate all other values than "none", "php_array" and "file" for `framework.annotation.cache` 5.2.0 ----- diff --git a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Configuration.php b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Configuration.php index 565b9d3960d6e..0fdb34cbb644f 100644 --- a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Configuration.php +++ b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Configuration.php @@ -12,6 +12,7 @@ namespace Symfony\Bundle\FrameworkBundle\DependencyInjection; use Doctrine\Common\Annotations\Annotation; +use Doctrine\Common\Annotations\PsrCachedReader; use Doctrine\Common\Cache\Cache; use Doctrine\DBAL\Connection; use Symfony\Bundle\FullStack; @@ -921,13 +922,16 @@ private function addValidationSection(ArrayNodeDefinition $rootNode, callable $e private function addAnnotationsSection(ArrayNodeDefinition $rootNode, callable $willBeAvailable) { + $doctrineCache = $willBeAvailable('doctrine/cache', Cache::class, 'doctrine/annotation'); + $psr6Cache = $willBeAvailable('symfony/cache', PsrCachedReader::class, 'doctrine/annotation'); + $rootNode ->children() ->arrayNode('annotations') ->info('annotation configuration') ->{$willBeAvailable('doctrine/annotations', Annotation::class) ? 'canBeDisabled' : 'canBeEnabled'}() ->children() - ->scalarNode('cache')->defaultValue($willBeAvailable('doctrine/cache', Cache::class, 'doctrine/annotation') ? 'php_array' : 'none')->end() + ->scalarNode('cache')->defaultValue(($doctrineCache || $psr6Cache) ? 'php_array' : 'none')->end() ->scalarNode('file_cache_dir')->defaultValue('%kernel.cache_dir%/annotations')->end() ->booleanNode('debug')->defaultValue($this->debug)->end() ->end() diff --git a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php index 07c033736771f..3ef5e51939e9c 100644 --- a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php +++ b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php @@ -1481,13 +1481,50 @@ private function registerAnnotationsConfiguration(array $config, ContainerBuilde ->setMethodCalls([['registerLoader', ['class_exists']]]); } - if ('none' !== $config['cache']) { + if ('none' === $config['cache']) { + $container->removeDefinition('annotations.cached_reader'); + $container->removeDefinition('annotations.psr_cached_reader'); + + return; + } + + $cacheService = $config['cache']; + if (\in_array($config['cache'], ['php_array', 'file'])) { + $isPsr6Service = $container->hasDefinition('annotations.psr_cached_reader'); + } else { + $isPsr6Service = false; + trigger_deprecation('symfony/framework-bundle', '5.3', 'Using a custom service for "framework.annotation.cache" is deprecated, only values "none", "php_array" and "file" are valid in version 6.0.'); + } + + if ($isPsr6Service) { + $container->removeDefinition('annotations.cached_reader'); + $container->setDefinition('annotations.cached_reader', $container->getDefinition('annotations.psr_cached_reader')); + + if ('php_array' === $config['cache']) { + $cacheService = 'annotations.psr_cache'; + + // Enable warmer only if PHP array is used for cache + $definition = $container->findDefinition('annotations.cache_warmer'); + $definition->addTag('kernel.cache_warmer'); + } elseif ('file' === $config['cache']) { + $cacheService = 'annotations.filesystem_cache_adapter'; + $cacheDir = $container->getParameterBag()->resolveValue($config['file_cache_dir']); + + if (!is_dir($cacheDir) && false === @mkdir($cacheDir, 0777, true) && !is_dir($cacheDir)) { + throw new \RuntimeException(sprintf('Could not create cache directory "%s".', $cacheDir)); + } + + $container + ->getDefinition('annotations.filesystem_cache_adapter') + ->replaceArgument(2, $cacheDir) + ; + } + } else { + // Legacy code for doctrine/annotations:<1.13 if (!class_exists(\Doctrine\Common\Cache\CacheProvider::class)) { throw new LogicException('Annotations cannot be cached as the Doctrine Cache library is not installed. Try running "composer require doctrine/cache".'); } - $cacheService = $config['cache']; - if ('php_array' === $config['cache']) { $cacheService = 'annotations.cache'; @@ -1508,20 +1545,19 @@ private function registerAnnotationsConfiguration(array $config, ContainerBuilde $cacheService = 'annotations.filesystem_cache'; } + } - $container - ->getDefinition('annotations.cached_reader') - ->replaceArgument(2, $config['debug']) - // temporary property to lazy-reference the cache provider without using it until AddAnnotationsCachedReaderPass runs - ->setProperty('cacheProviderBackup', new ServiceClosureArgument(new Reference($cacheService))) - ->addTag('annotations.cached_reader') - ; + $container + ->getDefinition('annotations.cached_reader') + ->replaceArgument(2, $config['debug']) + // temporary property to lazy-reference the cache provider without using it until AddAnnotationsCachedReaderPass runs + ->setProperty('cacheProviderBackup', new ServiceClosureArgument(new Reference($cacheService))) + ->addTag('annotations.cached_reader') + ; - $container->setAlias('annotation_reader', 'annotations.cached_reader'); - $container->setAlias(Reader::class, new Alias('annotations.cached_reader', false)); - } else { - $container->removeDefinition('annotations.cached_reader'); - } + $container->setAlias('annotation_reader', 'annotations.cached_reader'); + $container->setAlias(Reader::class, new Alias('annotations.cached_reader', false)); + $container->removeDefinition('annotations.psr_cached_reader'); } private function registerPropertyAccessConfiguration(array $config, ContainerBuilder $container, PhpFileLoader $loader) diff --git a/src/Symfony/Bundle/FrameworkBundle/Resources/config/annotations.php b/src/Symfony/Bundle/FrameworkBundle/Resources/config/annotations.php index 187d9da6642d0..a880b75a8b9c1 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Resources/config/annotations.php +++ b/src/Symfony/Bundle/FrameworkBundle/Resources/config/annotations.php @@ -14,6 +14,7 @@ use Doctrine\Common\Annotations\AnnotationReader; use Doctrine\Common\Annotations\AnnotationRegistry; use Doctrine\Common\Annotations\CachedReader; +use Doctrine\Common\Annotations\PsrCachedReader; use Doctrine\Common\Annotations\Reader; use Symfony\Bundle\FrameworkBundle\CacheWarmer\AnnotationsCacheWarmer; use Symfony\Component\Cache\Adapter\ArrayAdapter; @@ -36,7 +37,7 @@ ->args([ service('annotations.reader'), inline_service(DoctrineProvider::class)->args([ - inline_service(ArrayAdapter::class) + inline_service(ArrayAdapter::class), ]), abstract_arg('Debug-Flag'), ]) @@ -74,4 +75,22 @@ ->alias('annotation_reader', 'annotations.reader') ->alias(Reader::class, 'annotation_reader'); + + if (class_exists(PsrCachedReader::class)) { + $container->services() + ->set('annotations.psr_cached_reader', PsrCachedReader::class) + ->args([ + service('annotations.reader'), + inline_service(ArrayAdapter::class), + abstract_arg('Debug-Flag'), + ]) + ->set('annotations.psr_cache', PhpArrayAdapter::class) + ->factory([PhpArrayAdapter::class, 'create']) + ->args([ + param('kernel.cache_dir').'/annotations.php', + service('cache.annotations'), + ]) + ->tag('container.hot_path') + ; + } }; diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/FrameworkExtensionTest.php b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/FrameworkExtensionTest.php index e80bece911a08..83087e5844550 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/FrameworkExtensionTest.php +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/FrameworkExtensionTest.php @@ -12,6 +12,7 @@ namespace Symfony\Bundle\FrameworkBundle\Tests\DependencyInjection; use Doctrine\Common\Annotations\Annotation; +use Doctrine\Common\Annotations\PsrCachedReader; use Psr\Cache\CacheItemPoolInterface; use Psr\Log\LoggerAwareInterface; use Symfony\Bridge\PhpUnit\ExpectDeprecationTrait; @@ -578,7 +579,7 @@ public function testNullSessionHandler() $expected = ['session', 'initialized_session', 'logger', 'session_collector']; $this->assertEquals($expected, array_keys($container->getDefinition('session_listener')->getArgument(0)->getValues())); - $this->assertSame(false, $container->getDefinition('session.storage.factory.native')->getArgument(3)); + $this->assertFalse($container->getDefinition('session.storage.factory.native')->getArgument(3)); } /** @@ -597,7 +598,7 @@ public function testNullSessionHandlerLegacy() $expected = ['session', 'initialized_session', 'logger', 'session_collector']; $this->assertEquals($expected, array_keys($container->getDefinition('session_listener')->getArgument(0)->getValues())); - $this->assertSame(false, $container->getDefinition('session.storage.factory.native')->getArgument(3)); + $this->assertFalse($container->getDefinition('session.storage.factory.native')->getArgument(3)); } public function testRequest() @@ -980,7 +981,7 @@ public function testAnnotations() $container->compile(); $this->assertEquals($container->getParameter('kernel.cache_dir').'/annotations', $container->getDefinition('annotations.filesystem_cache_adapter')->getArgument(2)); - $this->assertSame('annotations.filesystem_cache', (string) $container->getDefinition('annotation_reader')->getArgument(1)); + $this->assertSame(class_exists(PsrCachedReader::class) ? 'annotations.filesystem_cache_adapter' : 'annotations.filesystem_cache', (string) $container->getDefinition('annotation_reader')->getArgument(1)); } public function testFileLinkFormat() diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/AutowiringTypesTest.php b/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/AutowiringTypesTest.php index 1d34e54d17a09..b747b75a9af93 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/AutowiringTypesTest.php +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/AutowiringTypesTest.php @@ -13,6 +13,7 @@ use Doctrine\Common\Annotations\AnnotationReader; use Doctrine\Common\Annotations\CachedReader; +use Doctrine\Common\Annotations\PsrCachedReader; use Symfony\Component\Cache\Adapter\FilesystemAdapter; use Symfony\Component\EventDispatcher\EventDispatcher; use Symfony\Component\HttpKernel\Debug\TraceableEventDispatcher; @@ -33,7 +34,7 @@ public function testCachedAnnotationReaderAutowiring() static::bootKernel(); $annotationReader = static::$container->get('test.autowiring_types.autowired_services')->getAnnotationReader(); - $this->assertInstanceOf(CachedReader::class, $annotationReader); + $this->assertInstanceOf(class_exists(PsrCachedReader::class) ? PsrCachedReader::class : CachedReader::class, $annotationReader); } public function testEventDispatcherAutowiring()