From a5246589cfce82b66782b8da44abb82aa240fe0e Mon Sep 17 00:00:00 2001 From: Remon van de Kamp Date: Sat, 20 Oct 2018 17:47:06 +0200 Subject: [PATCH] Improve Translator caching --- .../FrameworkExtension.php | 26 ++++++++++++++----- .../FrameworkExtensionTest.php | 22 ++++++++++++++++ .../Tests/Translation/TranslatorTest.php | 25 ++++++++++++++++++ .../Translation/Translator.php | 19 ++++++++++++++ .../Component/Translation/Translator.php | 5 +++- 5 files changed, 89 insertions(+), 8 deletions(-) diff --git a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php index 670033be01..d3998bc758 100644 --- a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php +++ b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php @@ -1075,6 +1075,7 @@ class FrameworkExtension extends Extension // Discover translation directories $dirs = []; $transPaths = []; + $nonExistingDirs = []; if (class_exists('Symfony\Component\Validator\Validation')) { $r = new \ReflectionClass('Symfony\Component\Validator\Validation'); @@ -1093,18 +1094,21 @@ class FrameworkExtension extends Extension $defaultDir = $container->getParameterBag()->resolveValue($config['default_path']); $rootDir = $container->getParameter('kernel.root_dir'); foreach ($container->getParameter('kernel.bundles_metadata') as $name => $bundle) { - if ($container->fileExists($dir = $bundle['path'].'/Resources/translations')) { + if (\is_dir($dir = $bundle['path'].'/Resources/translations')) { $dirs[] = $dir; + } else { + $nonExistingDirs[] = $dir; } - if ($container->fileExists($dir = $rootDir.sprintf('/Resources/%s/translations', $name))) { + if (\is_dir($dir = $rootDir.sprintf('/Resources/%s/translations', $name))) { @trigger_error(sprintf('Translations directory "%s" is deprecated since Symfony 4.2, use "%s" instead.', $dir, $defaultDir), E_USER_DEPRECATED); - $dirs[] = $dir; + } else { + $nonExistingDirs[] = $dir; } } foreach ($config['paths'] as $dir) { - if ($container->fileExists($dir)) { + if (\is_dir($dir)) { $dirs[] = $transPaths[] = $dir; } else { throw new \UnexpectedValueException(sprintf('%s defined in translator.paths does not exist or is not a directory', $dir)); @@ -1119,15 +1123,20 @@ class FrameworkExtension extends Extension $container->getDefinition('console.command.translation_update')->replaceArgument(6, $transPaths); } - if ($container->fileExists($defaultDir)) { + if (\is_dir($defaultDir)) { $dirs[] = $defaultDir; + } else { + $nonExistingDirs[] = $defaultDir; } - if ($container->fileExists($dir = $rootDir.'/Resources/translations')) { + + if (\is_dir($dir = $rootDir.'/Resources/translations')) { if ($dir !== $defaultDir) { @trigger_error(sprintf('Translations directory "%s" is deprecated since Symfony 4.2, use "%s" instead.', $dir, $defaultDir), E_USER_DEPRECATED); } $dirs[] = $dir; + } else { + $nonExistingDirs[] = $dir; } // Register translation resources @@ -1154,7 +1163,10 @@ class FrameworkExtension extends Extension $options = array_merge( $translator->getArgument(4), - ['resource_files' => $files] + [ + 'resource_files' => $files, + 'scanned_directories' => \array_merge($dirs, $nonExistingDirs), + ] ); $translator->replaceArgument(4, $options); diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/FrameworkExtensionTest.php b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/FrameworkExtensionTest.php index ddd9d64286..de674c1082 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/FrameworkExtensionTest.php +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/FrameworkExtensionTest.php @@ -25,6 +25,8 @@ use Symfony\Component\Cache\Adapter\DoctrineAdapter; use Symfony\Component\Cache\Adapter\FilesystemAdapter; use Symfony\Component\Cache\Adapter\ProxyAdapter; use Symfony\Component\Cache\Adapter\RedisAdapter; +use Symfony\Component\Config\Resource\DirectoryResource; +use Symfony\Component\Config\Resource\FileExistenceResource; use Symfony\Component\DependencyInjection\ChildDefinition; use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface; use Symfony\Component\DependencyInjection\Compiler\ResolveInstanceofConditionalsPass; @@ -800,6 +802,26 @@ abstract class FrameworkExtensionTest extends TestCase $calls = $container->getDefinition('translator.default')->getMethodCalls(); $this->assertEquals(['fr'], $calls[1][1][0]); + + $nonExistingDirectories = array_filter( + $options['scanned_directories'], + function ($directory) { + return !file_exists($directory); + } + ); + + $this->assertNotEmpty($nonExistingDirectories, 'FrameworkBundle should pass non existing directories to Translator'); + + $resources = $container->getResources(); + foreach ($resources as $resource) { + if ($resource instanceof DirectoryResource) { + $this->assertNotContains('translations', $resource->getResource()); + } + + if ($resource instanceof FileExistenceResource) { + $this->assertNotContains('translations', $resource->getResource()); + } + } } /** diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/Translation/TranslatorTest.php b/src/Symfony/Bundle/FrameworkBundle/Tests/Translation/TranslatorTest.php index 6b276ca0b9..9e15e4ba41 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/Translation/TranslatorTest.php +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/Translation/TranslatorTest.php @@ -14,6 +14,8 @@ namespace Symfony\Bundle\FrameworkBundle\Tests\Translation; use PHPUnit\Framework\TestCase; use Psr\Container\ContainerInterface; use Symfony\Bundle\FrameworkBundle\Translation\Translator; +use Symfony\Component\Config\Resource\DirectoryResource; +use Symfony\Component\Config\Resource\FileExistenceResource; use Symfony\Component\Filesystem\Filesystem; use Symfony\Component\Translation\Formatter\MessageFormatter; use Symfony\Component\Translation\MessageCatalogue; @@ -223,6 +225,29 @@ class TranslatorTest extends TestCase ]; } + public function testCatalogResourcesAreAddedForScannedDirectories() + { + $loader = new \Symfony\Component\Translation\Loader\YamlFileLoader(); + $resourceFiles = [ + 'fr' => [ + __DIR__.'/../Fixtures/Resources/translations/messages.fr.yml', + ], + ]; + + /** @var Translator $translator */ + $translator = $this->getTranslator($loader, [ + 'resource_files' => $resourceFiles, + 'scanned_directories' => [__DIR__, '/tmp/I/sure/hope/this/does/not/exist'], + ], 'yml'); + + $catalogue = $translator->getCatalogue('fr'); + + $resources = $catalogue->getResources(); + + $this->assertEquals(new DirectoryResource(__DIR__), $resources[1]); + $this->assertEquals(new FileExistenceResource('/tmp/I/sure/hope/this/does/not/exist'), $resources[2]); + } + protected function getCatalogue($locale, $messages, $resources = []) { $catalogue = new MessageCatalogue($locale); diff --git a/src/Symfony/Bundle/FrameworkBundle/Translation/Translator.php b/src/Symfony/Bundle/FrameworkBundle/Translation/Translator.php index e0d0243281..a32e32f898 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Translation/Translator.php +++ b/src/Symfony/Bundle/FrameworkBundle/Translation/Translator.php @@ -12,6 +12,8 @@ namespace Symfony\Bundle\FrameworkBundle\Translation; use Psr\Container\ContainerInterface; +use Symfony\Component\Config\Resource\DirectoryResource; +use Symfony\Component\Config\Resource\FileExistenceResource; use Symfony\Component\HttpKernel\CacheWarmer\WarmableInterface; use Symfony\Component\Translation\Exception\InvalidArgumentException; use Symfony\Component\Translation\Formatter\MessageFormatterInterface; @@ -31,6 +33,7 @@ class Translator extends BaseTranslator implements WarmableInterface 'cache_dir' => null, 'debug' => false, 'resource_files' => [], + 'scanned_directories' => [], ]; /** @@ -48,6 +51,11 @@ class Translator extends BaseTranslator implements WarmableInterface private $resourceFiles; + /** + * @var string[] + */ + private $scannedDirectories; + /** * Constructor. * @@ -78,6 +86,7 @@ class Translator extends BaseTranslator implements WarmableInterface $this->options = array_merge($this->options, $options); $this->resourceLocales = array_keys($this->options['resource_files']); $this->resourceFiles = $this->options['resource_files']; + $this->scannedDirectories = $this->options['scanned_directories']; parent::__construct($defaultLocale, $formatter, $this->options['cache_dir'], $this->options['debug']); } @@ -120,6 +129,16 @@ class Translator extends BaseTranslator implements WarmableInterface parent::initializeCatalogue($locale); } + protected function doLoadCatalogue($locale): void + { + parent::doLoadCatalogue($locale); + + foreach ($this->scannedDirectories as $directory) { + $resourceClass = file_exists($directory) ? DirectoryResource::class : FileExistenceResource::class; + $this->catalogues[$locale]->addResource(new $resourceClass($directory)); + } + } + protected function initialize() { if ($this->resourceFiles) { diff --git a/src/Symfony/Component/Translation/Translator.php b/src/Symfony/Component/Translation/Translator.php index 8a2b2dd9d0..f5ce39ef0d 100644 --- a/src/Symfony/Component/Translation/Translator.php +++ b/src/Symfony/Component/Translation/Translator.php @@ -395,7 +395,10 @@ EOF return $this->cacheDir.'/catalogue.'.$locale.'.'.strtr(substr(base64_encode(hash('sha256', serialize($this->fallbackLocales), true)), 0, 7), '/', '_').'.php'; } - private function doLoadCatalogue($locale): void + /** + * @internal + */ + protected function doLoadCatalogue($locale): void { $this->catalogues[$locale] = new MessageCatalogue($locale);