Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit a68b4c7

Browse files
committed
feature #28937 Improve Translator caching (rpkamp)
This PR was squashed before being merged into the 4.3-dev branch (closes #28937). Discussion ---------- Improve Translator caching | Q | A | ------------- | --- | Branch? | master | Bug fix? | no | New feature? | yes | BC breaks? | no | Deprecations? | no | Tests pass? | yes | Fixed tickets | #27600 | License | MIT | Doc PR | N/A Add DirectoryResources to MessageCatalogues when loaded. So that when a file is added to one of the directories the cache for all MessageCatalogues will be invalidated. All directories must be added to all MessageCatalogues because we can't predict for which locale files will be added to each individual directory. Also, now that the translator keeps track of its own directories for caching the container no longer needs to it. This means that when a translation changes or is added the container no longer needs to be fully rebuilt, saving a considerable amount of time (compilation time went down from ~4 seconds to ~1 second on each translation change/add in our project). Commits ------- a524658 Improve Translator caching
2 parents f587944 + a524658 commit a68b4c7

File tree

5 files changed

+89
-8
lines changed

5 files changed

+89
-8
lines changed

src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php

Lines changed: 19 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1087,6 +1087,7 @@ private function registerTranslatorConfiguration(array $config, ContainerBuilder
10871087
// Discover translation directories
10881088
$dirs = [];
10891089
$transPaths = [];
1090+
$nonExistingDirs = [];
10901091
if (class_exists('Symfony\Component\Validator\Validation')) {
10911092
$r = new \ReflectionClass('Symfony\Component\Validator\Validation');
10921093

@@ -1105,18 +1106,21 @@ private function registerTranslatorConfiguration(array $config, ContainerBuilder
11051106
$defaultDir = $container->getParameterBag()->resolveValue($config['default_path']);
11061107
$rootDir = $container->getParameter('kernel.root_dir');
11071108
foreach ($container->getParameter('kernel.bundles_metadata') as $name => $bundle) {
1108-
if ($container->fileExists($dir = $bundle['path'].'/Resources/translations')) {
1109+
if (\is_dir($dir = $bundle['path'].'/Resources/translations')) {
11091110
$dirs[] = $dir;
1111+
} else {
1112+
$nonExistingDirs[] = $dir;
11101113
}
1111-
if ($container->fileExists($dir = $rootDir.sprintf('/Resources/%s/translations', $name))) {
1114+
if (\is_dir($dir = $rootDir.sprintf('/Resources/%s/translations', $name))) {
11121115
@trigger_error(sprintf('Translations directory "%s" is deprecated since Symfony 4.2, use "%s" instead.', $dir, $defaultDir), E_USER_DEPRECATED);
1113-
11141116
$dirs[] = $dir;
1117+
} else {
1118+
$nonExistingDirs[] = $dir;
11151119
}
11161120
}
11171121

11181122
foreach ($config['paths'] as $dir) {
1119-
if ($container->fileExists($dir)) {
1123+
if (\is_dir($dir)) {
11201124
$dirs[] = $transPaths[] = $dir;
11211125
} else {
11221126
throw new \UnexpectedValueException(sprintf('%s defined in translator.paths does not exist or is not a directory', $dir));
@@ -1131,15 +1135,20 @@ private function registerTranslatorConfiguration(array $config, ContainerBuilder
11311135
$container->getDefinition('console.command.translation_update')->replaceArgument(6, $transPaths);
11321136
}
11331137

1134-
if ($container->fileExists($defaultDir)) {
1138+
if (\is_dir($defaultDir)) {
11351139
$dirs[] = $defaultDir;
1140+
} else {
1141+
$nonExistingDirs[] = $defaultDir;
11361142
}
1137-
if ($container->fileExists($dir = $rootDir.'/Resources/translations')) {
1143+
1144+
if (\is_dir($dir = $rootDir.'/Resources/translations')) {
11381145
if ($dir !== $defaultDir) {
11391146
@trigger_error(sprintf('Translations directory "%s" is deprecated since Symfony 4.2, use "%s" instead.', $dir, $defaultDir), E_USER_DEPRECATED);
11401147
}
11411148

11421149
$dirs[] = $dir;
1150+
} else {
1151+
$nonExistingDirs[] = $dir;
11431152
}
11441153

11451154
// Register translation resources
@@ -1166,7 +1175,10 @@ private function registerTranslatorConfiguration(array $config, ContainerBuilder
11661175

11671176
$options = array_merge(
11681177
$translator->getArgument(4),
1169-
['resource_files' => $files]
1178+
[
1179+
'resource_files' => $files,
1180+
'scanned_directories' => \array_merge($dirs, $nonExistingDirs),
1181+
]
11701182
);
11711183

11721184
$translator->replaceArgument(4, $options);

src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/FrameworkExtensionTest.php

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,8 @@
2525
use Symfony\Component\Cache\Adapter\FilesystemAdapter;
2626
use Symfony\Component\Cache\Adapter\ProxyAdapter;
2727
use Symfony\Component\Cache\Adapter\RedisAdapter;
28+
use Symfony\Component\Config\Resource\DirectoryResource;
29+
use Symfony\Component\Config\Resource\FileExistenceResource;
2830
use Symfony\Component\DependencyInjection\ChildDefinition;
2931
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
3032
use Symfony\Component\DependencyInjection\Compiler\ResolveInstanceofConditionalsPass;
@@ -797,6 +799,26 @@ public function testTranslator()
797799

798800
$calls = $container->getDefinition('translator.default')->getMethodCalls();
799801
$this->assertEquals(['fr'], $calls[1][1][0]);
802+
803+
$nonExistingDirectories = array_filter(
804+
$options['scanned_directories'],
805+
function ($directory) {
806+
return !file_exists($directory);
807+
}
808+
);
809+
810+
$this->assertNotEmpty($nonExistingDirectories, 'FrameworkBundle should pass non existing directories to Translator');
811+
812+
$resources = $container->getResources();
813+
foreach ($resources as $resource) {
814+
if ($resource instanceof DirectoryResource) {
815+
$this->assertNotContains('translations', $resource->getResource());
816+
}
817+
818+
if ($resource instanceof FileExistenceResource) {
819+
$this->assertNotContains('translations', $resource->getResource());
820+
}
821+
}
800822
}
801823

802824
/**

src/Symfony/Bundle/FrameworkBundle/Tests/Translation/TranslatorTest.php

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@
1414
use PHPUnit\Framework\TestCase;
1515
use Psr\Container\ContainerInterface;
1616
use Symfony\Bundle\FrameworkBundle\Translation\Translator;
17+
use Symfony\Component\Config\Resource\DirectoryResource;
18+
use Symfony\Component\Config\Resource\FileExistenceResource;
1719
use Symfony\Component\Filesystem\Filesystem;
1820
use Symfony\Component\Translation\Formatter\MessageFormatter;
1921
use Symfony\Component\Translation\MessageCatalogue;
@@ -223,6 +225,29 @@ public function getDebugModeAndCacheDirCombinations()
223225
];
224226
}
225227

228+
public function testCatalogResourcesAreAddedForScannedDirectories()
229+
{
230+
$loader = new \Symfony\Component\Translation\Loader\YamlFileLoader();
231+
$resourceFiles = [
232+
'fr' => [
233+
__DIR__.'/../Fixtures/Resources/translations/messages.fr.yml',
234+
],
235+
];
236+
237+
/** @var Translator $translator */
238+
$translator = $this->getTranslator($loader, [
239+
'resource_files' => $resourceFiles,
240+
'scanned_directories' => [__DIR__, '/tmp/I/sure/hope/this/does/not/exist'],
241+
], 'yml');
242+
243+
$catalogue = $translator->getCatalogue('fr');
244+
245+
$resources = $catalogue->getResources();
246+
247+
$this->assertEquals(new DirectoryResource(__DIR__), $resources[1]);
248+
$this->assertEquals(new FileExistenceResource('/tmp/I/sure/hope/this/does/not/exist'), $resources[2]);
249+
}
250+
226251
protected function getCatalogue($locale, $messages, $resources = [])
227252
{
228253
$catalogue = new MessageCatalogue($locale);

src/Symfony/Bundle/FrameworkBundle/Translation/Translator.php

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@
1212
namespace Symfony\Bundle\FrameworkBundle\Translation;
1313

1414
use Psr\Container\ContainerInterface;
15+
use Symfony\Component\Config\Resource\DirectoryResource;
16+
use Symfony\Component\Config\Resource\FileExistenceResource;
1517
use Symfony\Component\HttpKernel\CacheWarmer\WarmableInterface;
1618
use Symfony\Component\Translation\Exception\InvalidArgumentException;
1719
use Symfony\Component\Translation\Formatter\MessageFormatterInterface;
@@ -31,6 +33,7 @@ class Translator extends BaseTranslator implements WarmableInterface
3133
'cache_dir' => null,
3234
'debug' => false,
3335
'resource_files' => [],
36+
'scanned_directories' => [],
3437
];
3538

3639
/**
@@ -48,6 +51,11 @@ class Translator extends BaseTranslator implements WarmableInterface
4851

4952
private $resourceFiles;
5053

54+
/**
55+
* @var string[]
56+
*/
57+
private $scannedDirectories;
58+
5159
/**
5260
* Constructor.
5361
*
@@ -78,6 +86,7 @@ public function __construct(ContainerInterface $container, MessageFormatterInter
7886
$this->options = array_merge($this->options, $options);
7987
$this->resourceLocales = array_keys($this->options['resource_files']);
8088
$this->resourceFiles = $this->options['resource_files'];
89+
$this->scannedDirectories = $this->options['scanned_directories'];
8190

8291
parent::__construct($defaultLocale, $formatter, $this->options['cache_dir'], $this->options['debug']);
8392
}
@@ -120,6 +129,16 @@ protected function initializeCatalogue($locale)
120129
parent::initializeCatalogue($locale);
121130
}
122131

132+
protected function doLoadCatalogue($locale): void
133+
{
134+
parent::doLoadCatalogue($locale);
135+
136+
foreach ($this->scannedDirectories as $directory) {
137+
$resourceClass = file_exists($directory) ? DirectoryResource::class : FileExistenceResource::class;
138+
$this->catalogues[$locale]->addResource(new $resourceClass($directory));
139+
}
140+
}
141+
123142
protected function initialize()
124143
{
125144
if ($this->resourceFiles) {

src/Symfony/Component/Translation/Translator.php

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -395,7 +395,10 @@ private function getCatalogueCachePath($locale)
395395
return $this->cacheDir.'/catalogue.'.$locale.'.'.strtr(substr(base64_encode(hash('sha256', serialize($this->fallbackLocales), true)), 0, 7), '/', '_').'.php';
396396
}
397397

398-
private function doLoadCatalogue($locale): void
398+
/**
399+
* @internal
400+
*/
401+
protected function doLoadCatalogue($locale): void
399402
{
400403
$this->catalogues[$locale] = new MessageCatalogue($locale);
401404

0 commit comments

Comments
 (0)