From 175634555a9ab91da660637e72ecf54fcc2c8aee Mon Sep 17 00:00:00 2001 From: Denis Date: Sat, 14 Mar 2026 14:50:12 +0100 Subject: [PATCH 01/12] Move Translator to Symfony Translator decorator. # Conflicts: # Tests/Unit/Translation/TranslatorTest.php # Translation/Translator.php --- Controller/TranslationController.php | 36 ++- .../Compiler/TranslatorPass.php | 79 ++++-- DependencyInjection/Configuration.php | 8 +- .../LexikTranslationExtension.php | 134 ++-------- EventDispatcher/DatabaseResourcesListener.php | 80 ------ Manager/LocaleManager.php | 7 +- Resources/config/services.yaml | 16 +- Resources/doc/index.md | 24 +- Tests/Unit/Translation/TranslatorTest.php | 97 +++----- Tests/app/test/config.yml | 9 +- Translation/Translator.php | 232 ++++++------------ Translation/TranslatorDecorator.php | 195 --------------- 12 files changed, 255 insertions(+), 662 deletions(-) delete mode 100644 EventDispatcher/DatabaseResourcesListener.php delete mode 100644 Translation/TranslatorDecorator.php diff --git a/Controller/TranslationController.php b/Controller/TranslationController.php index 2df5b8b9..44a81198 100644 --- a/Controller/TranslationController.php +++ b/Controller/TranslationController.php @@ -6,7 +6,6 @@ use Lexik\Bundle\TranslationBundle\Form\Type\TransUnitType; use Lexik\Bundle\TranslationBundle\Manager\LocaleManagerInterface; use Lexik\Bundle\TranslationBundle\Storage\StorageInterface; -use Lexik\Bundle\TranslationBundle\Translation\TranslatorDecorator; use Lexik\Bundle\TranslationBundle\Util\Csrf\CsrfCheckerTrait; use Lexik\Bundle\TranslationBundle\Util\Overview\StatsAggregator; use Lexik\Bundle\TranslationBundle\Util\Profiler\TokenFinder; @@ -23,8 +22,14 @@ class TranslationController extends AbstractController { use CsrfCheckerTrait; - public function __construct(private readonly StorageInterface $translationStorage, private readonly StatsAggregator $statsAggregator, private readonly TransUnitFormHandler $transUnitFormHandler, private readonly TranslatorInterface $lexikTranslator, private readonly TranslatorInterface $translator, private readonly LocaleManagerInterface $localeManager, private readonly ?TokenFinder $tokenFinder) - { + public function __construct( + private readonly StorageInterface $translationStorage, + private readonly StatsAggregator $statsAggregator, + private readonly TransUnitFormHandler $transUnitFormHandler, + private readonly TranslatorInterface $translator, + private readonly LocaleManagerInterface $localeManager, + private readonly ?TokenFinder $tokenFinder + ) { } /** @@ -34,7 +39,13 @@ public function overviewAction(): Response { $stats = $this->statsAggregator->getStats(); - return $this->render('@LexikTranslation/Translation/overview.html.twig', ['layout' => $this->getParameter('lexik_translation.base_layout'), 'locales' => $this->getManagedLocales(), 'domains' => $this->translationStorage->getTransUnitDomains(), 'latestTrans' => $this->translationStorage->getLatestUpdatedAt(), 'stats' => $stats]); + return $this->render('@LexikTranslation/Translation/overview.html.twig', [ + 'layout' => $this->getParameter('lexik_translation.base_layout'), + 'locales' => $this->getManagedLocales(), + 'domains' => $this->translationStorage->getTransUnitDomains(), + 'latestTrans' => $this->translationStorage->getLatestUpdatedAt(), + 'stats' => $stats, + ]); } /** @@ -47,7 +58,14 @@ public function gridAction(): Response $tokens = $this->tokenFinder->find(); } - return $this->render('@LexikTranslation/Translation/grid.html.twig', ['layout' => $this->getParameter('lexik_translation.base_layout'), 'inputType' => $this->getParameter('lexik_translation.grid_input_type'), 'autoCacheClean' => $this->getParameter('lexik_translation.auto_cache_clean'), 'toggleSimilar' => $this->getParameter('lexik_translation.grid_toggle_similar'), 'locales' => $this->getManagedLocales(), 'tokens' => $tokens]); + return $this->render('@LexikTranslation/Translation/grid.html.twig', [ + 'layout' => $this->getParameter('lexik_translation.base_layout'), + 'inputType' => $this->getParameter('lexik_translation.grid_input_type'), + 'autoCacheClean' => $this->getParameter('lexik_translation.auto_cache_clean'), + 'toggleSimilar' => $this->getParameter('lexik_translation.grid_toggle_similar'), + 'locales' => $this->getManagedLocales(), + 'tokens' => $tokens, + ]); } /** @@ -55,8 +73,8 @@ public function gridAction(): Response */ public function invalidateCacheAction(Request $request): Response { - if (method_exists($this->lexikTranslator, 'removeLocalesCacheFiles')) { - $this->lexikTranslator->removeLocalesCacheFiles($this->getManagedLocales()); + if (method_exists($this->translator, 'removeLocalesCacheFiles')) { + $this->translator->removeLocalesCacheFiles($this->getManagedLocales()); } $message = $this->translator->trans('translations.cache_removed', [], 'LexikTranslationBundle'); @@ -94,10 +112,8 @@ public function newAction(Request $request): Response /** * Returns managed locales. - * - * @return array */ - protected function getManagedLocales() + protected function getManagedLocales(): array { return $this->localeManager->getLocales(); } diff --git a/DependencyInjection/Compiler/TranslatorPass.php b/DependencyInjection/Compiler/TranslatorPass.php index eda7d70b..257500ea 100644 --- a/DependencyInjection/Compiler/TranslatorPass.php +++ b/DependencyInjection/Compiler/TranslatorPass.php @@ -21,6 +21,12 @@ class TranslatorPass implements CompilerPassInterface */ public function process(ContainerBuilder $container): void { + // Keep the compatibility with old versions of the bundle (options fallback_locale and managed_locales). + $this->processEnabledLocales($container); + $this->processFallbacksLocales($container); + + $this->processRessources($container); + // loaders $loaders = []; $loadersReferences = []; @@ -37,29 +43,13 @@ public function process(ContainerBuilder $container): void } } - // Find the translator service by alias or class name - $translatorId = null; if ($container->hasDefinition('lexik_translation.translator')) { - $translatorId = 'lexik_translation.translator'; - } elseif ($container->hasAlias('lexik_translation.translator')) { - $translatorId = (string) $container->getAlias('lexik_translation.translator'); - } elseif ($container->hasDefinition('Lexik\Bundle\TranslationBundle\Translation\Translator')) { - $translatorId = 'Lexik\Bundle\TranslationBundle\Translation\Translator'; - } - - if ($translatorId && $container->hasDefinition($translatorId)) { - $translatorDef = $container->findDefinition($translatorId); + $translatorDef = $container->findDefinition('lexik_translation.translator'); $serviceRefs = [...$loadersReferencesById, ...['event_dispatcher' => new Reference('event_dispatcher')]]; - // Use named arguments if available, otherwise use numeric indices - if ($translatorDef->getArguments() && array_key_exists('$container', $translatorDef->getArguments())) { - $translatorDef->replaceArgument('$container', ServiceLocatorTagPass::register($container, $serviceRefs)); - $translatorDef->replaceArgument('$loaderIds', $loaders); - } else { - $translatorDef->replaceArgument(0, ServiceLocatorTagPass::register($container, $serviceRefs)); - $translatorDef->replaceArgument(3, $loaders); - } + $translatorDef->replaceArgument('$container', ServiceLocatorTagPass::register($container, $serviceRefs)); + $translatorDef->replaceArgument('$loaderIds', $loaders); } if ($container->hasDefinition(FileImporter::class)) { @@ -73,4 +63,55 @@ public function process(ContainerBuilder $container): void } } } + + private function processRessources(ContainerBuilder $container): void + { + $translator = $container->getDefinition('translator.default'); + + $defaultOptions = $translator->getArgument(4); + + // If the resources type is set to "database", we don't want to load any resource file, as they will be loaded from the database. + $ressourcesType = $container->getParameter('lexik_translation.resources_type'); + + if ('database' === $ressourcesType) { + $defaultOptions['resource_files'] = []; + $translator->replaceArgument(4, $defaultOptions); + return; + } + + // If the option "managed_locales_only" is set to true, we only want to load the resource files for the enabled locales. + if (true === $container->getParameter('lexik_translation.managed_locales_only')) { + $enabledLocales = $translator->getArgument(5); + + $defaultOptions['resource_files'] = array_filter($defaultOptions['resource_files'], static function ($locale) use ($enabledLocales) { + return in_array($locale, $enabledLocales, true); + }, \ARRAY_FILTER_USE_KEY); + + $translator->replaceArgument(4, $defaultOptions); + } + } + + private function processFallbacksLocales(ContainerBuilder $container): void + { + $fallbackLocale = $container->getParameter('lexik_translation.fallback_locale'); + + if (!empty($fallbackLocale)) { + $translator = $container->findDefinition('translator.default'); + $translator->addMethodCall('setFallbackLocales', [ $fallbackLocale ]); + } + } + + private function processEnabledLocales(ContainerBuilder $container): void + { + $enabledLocales = $container->getParameter('kernel.enabled_locales'); + + if (empty($enabledLocales)) { + $fallbackEnabledLocales = $container->getParameter('lexik_translation.managed_locales'); + if (!empty($fallbackEnabledLocales)) { + $enabledLocales = $fallbackEnabledLocales; + } + $translator = $container->findDefinition('translator.default'); + $translator->replaceArgument(5, $enabledLocales); + } + } } diff --git a/DependencyInjection/Configuration.php b/DependencyInjection/Configuration.php index f71c858f..30253014 100644 --- a/DependencyInjection/Configuration.php +++ b/DependencyInjection/Configuration.php @@ -40,9 +40,9 @@ public function getConfigTreeBuilder(): TreeBuilder ->end() ->arrayNode('fallback_locale') - ->isRequired() - ->requiresAtLeastOneElement() + ->setDeprecated('lexik/translation-bundle', '8.0', 'The "%node%" option is deprecated. Use "framework.translator.fallbacks" instead.') ->prototype('scalar')->end() + ->defaultValue([]) ->beforeNormalization() ->ifString() ->then(fn($value) => [$value]) @@ -50,9 +50,9 @@ public function getConfigTreeBuilder(): TreeBuilder ->end() ->arrayNode('managed_locales') - ->isRequired() - ->requiresAtLeastOneElement() + ->info('Locales managed in the translation grid. If not set, falls back to "framework.enabled_locales".') ->prototype('scalar')->end() + ->defaultValue([]) ->end() ->scalarNode('grid_input_type') diff --git a/DependencyInjection/LexikTranslationExtension.php b/DependencyInjection/LexikTranslationExtension.php index d4d8c680..8d2a9f55 100644 --- a/DependencyInjection/LexikTranslationExtension.php +++ b/DependencyInjection/LexikTranslationExtension.php @@ -2,10 +2,8 @@ namespace Lexik\Bundle\TranslationBundle\DependencyInjection; +use Lexik\Bundle\TranslationBundle\LexikTranslationBundle; use Symfony\Component\DependencyInjection\Loader\YamlFileLoader; -use Symfony\Component\Validator\Validation; -use Symfony\Component\Form\Form; -use Symfony\Component\Security\Core\Exception\AuthenticationException; use Doctrine\ORM\Events; use Doctrine\ORM\Mapping\Driver\SimplifiedXmlDriver; use Doctrine\ORM\Mapping\Driver\AttributeDriver; @@ -13,15 +11,12 @@ use Lexik\Bundle\TranslationBundle\Storage\StorageInterface; use Symfony\Component\Config\FileLocator; use Symfony\Component\Config\Definition\Processor; -use Symfony\Component\Config\Resource\DirectoryResource; use Symfony\Component\DependencyInjection\Extension\Extension; use Symfony\Component\DependencyInjection\Extension\PrependExtensionInterface; use Symfony\Component\DependencyInjection\Reference; use Symfony\Component\DependencyInjection\Parameter; use Symfony\Component\DependencyInjection\Definition; use Symfony\Component\DependencyInjection\ContainerBuilder; -use Symfony\Component\Finder\Finder; -use Symfony\Component\HttpKernel\Kernel; /** * This is the class that loads and manages your bundle configuration @@ -44,12 +39,20 @@ public function load(array $configs, ContainerBuilder $container): void $loader = new YamlFileLoader($container, new FileLocator(__DIR__.'/../Resources/config')); $loader->load('services.yaml'); - // set parameters - sort($config['managed_locales']); - $container->setParameter('lexik_translation.managed_locales', $config['managed_locales']); + // Resolve managed_locales: fallback to framework.enabled_locales if not set + $managedLocales = $config['managed_locales']; + if (empty($managedLocales)) { + $managedLocales = $container->hasParameter('kernel.enabled_locales') + ? $container->getParameter('kernel.enabled_locales') + : []; + } + sort($managedLocales); + + $container->setParameter('lexik_translation.managed_locales', $managedLocales); $container->setParameter('lexik_translation.fallback_locale', $config['fallback_locale']); $container->setParameter('lexik_translation.storage', $config['storage']); $container->setParameter('lexik_translation.resources_type', $config['resources_registration']['type']); + $container->setParameter('lexik_translation.managed_locales_only', $config['resources_registration']['managed_locales_only']); $container->setParameter('lexik_translation.base_layout', $config['base_layout']); $container->setParameter('lexik_translation.grid_input_type', $config['grid_input_type']); $container->setParameter('lexik_translation.grid_toggle_similar', $config['grid_toggle_similar']); @@ -71,14 +74,12 @@ public function load(array $configs, ContainerBuilder $container): void if (true === $config['dev_tools']['enable']) { $this->buildDevServicesDefinition($container); } - - $this->registerTranslatorConfiguration($config, $container); } /** * @param int $cacheInterval */ - public function buildCacheCleanListenerDefinition(ContainerBuilder $container, $cacheInterval) + public function buildCacheCleanListenerDefinition(ContainerBuilder $container, $cacheInterval): void { $listener = new Definition(); $listener->setClass('%lexik_translation.listener.clean_translation_cache.class%'); @@ -116,7 +117,7 @@ public function prepend(ContainerBuilder $container): void * @param string $objectManager * @throws \RuntimeException */ - protected function buildTranslationStorageDefinition(ContainerBuilder $container, $storage, $objectManager) + protected function buildTranslationStorageDefinition(ContainerBuilder $container, $storage, $objectManager): void { $container->setParameter('lexik_translation.storage.type', $storage); @@ -168,7 +169,7 @@ protected function buildTranslationStorageDefinition(ContainerBuilder $container * @param string $driverId * @param string $driverClass */ - protected function createDoctrineMappingDriver(ContainerBuilder $container, $driverId, $driverClass) + protected function createDoctrineMappingDriver(ContainerBuilder $container, $driverId, $driverClass): void { $driverDefinition = new Definition($driverClass, [ [dirname(__DIR__) . '/Resources/config/model' => 'Lexik\Bundle\TranslationBundle\Model'], @@ -185,11 +186,11 @@ protected function createDoctrineMappingDriver(ContainerBuilder $container, $dri * @param ContainerBuilder $container * @param string $driverId */ - protected function createDoctrineAttributeDriver(ContainerBuilder $container, $driverId) + protected function createDoctrineAttributeDriver(ContainerBuilder $container, $driverId): void { // Calculate bundle path using ReflectionClass to get the actual bundle location // This works even when the bundle is installed via Composer or symlinked - $bundleReflection = new \ReflectionClass(\Lexik\Bundle\TranslationBundle\LexikTranslationBundle::class); + $bundleReflection = new \ReflectionClass(LexikTranslationBundle::class); $bundleDir = dirname($bundleReflection->getFileName()); $modelPath = $bundleDir . '/Model'; @@ -213,7 +214,7 @@ protected function createDoctrineAttributeDriver(ContainerBuilder $container, $d /** * Load dev tools. */ - protected function buildDevServicesDefinition(ContainerBuilder $container) + protected function buildDevServicesDefinition(ContainerBuilder $container): void { $container ->getDefinition('lexik_translation.data_grid.request_handler') @@ -225,103 +226,4 @@ protected function buildDevServicesDefinition(ContainerBuilder $container) $container->setDefinition($container->getParameter('lexik_translation.token_finder.class'), $tokenFinderDefinition); } - - /** - * Register the "lexik_translation.translator" service configuration. - */ - protected function registerTranslatorConfiguration(array $config, ContainerBuilder $container) - { - // use the Lexik translator decorator as default translator service - $alias = $container->setAlias('translator', 'lexik_translation.translator'); - $alias->setPublic(true); - - // Get the inner translator (the actual Symfony translator) for adding resources - // The decorator will delegate to it - $innerTranslator = $container->hasDefinition('lexik_translation.translator.inner') - ? $container->findDefinition('lexik_translation.translator.inner') - : $container->findDefinition('translator'); - - $innerTranslator->addMethodCall('setFallbackLocales', [$config['fallback_locale']]); - - // For adding file resources, we'll add them to the inner translator - $translator = $innerTranslator; - - $registration = $config['resources_registration']; - - // Discover translation directories - if ('all' === $registration['type'] || 'files' === $registration['type']) { - $dirs = []; - - if (class_exists(Validation::class)) { - $r = new \ReflectionClass(Validation::class); - - $dirs[] = dirname($r->getFilename()).'/Resources/translations'; - } - - if (class_exists(Form::class)) { - $r = new \ReflectionClass(Form::class); - - $dirs[] = dirname($r->getFilename()).'/Resources/translations'; - } - - if (class_exists(AuthenticationException::class)) { - $r = new \ReflectionClass(AuthenticationException::class); - - if (is_dir($dir = dirname($r->getFilename()).'/../Resources/translations')) { - $dirs[] = $dir; - } - } - - $overridePath = $container->getParameter('kernel.project_dir').'/Resources/%s/translations'; - - foreach ($container->getParameter('kernel.bundles') as $bundle => $class) { - $reflection = new \ReflectionClass($class); - - if (is_dir($dir = dirname($reflection->getFilename()).'/Resources/translations')) { - $dirs[] = $dir; - } - - if (is_dir($dir = dirname($reflection->getFileName(), 2).'/translations')) { - $dirs[] = $dir; - } - - if (is_dir($dir = sprintf($overridePath, $bundle))) { - $dirs[] = $dir; - } - } - - if (is_dir($dir = $container->getParameter('kernel.project_dir').'/Resources/translations')) { - $dirs[] = $dir; - } - - if (Kernel::MAJOR_VERSION >= 4 && is_dir($dir = $container->getParameter('kernel.project_dir').'/translations')) { - $dirs[] = $dir; - } - - // Register translation resources - if (count($dirs) > 0) { - foreach ($dirs as $dir) { - $container->addResource(new DirectoryResource($dir)); - } - - $finder = Finder::create(); - $finder->files(); - - if (true === $registration['managed_locales_only']) { - // only look for managed locales - $finder->name(sprintf('/(.*\.(%s)\.\w+$)/', implode('|', $config['managed_locales']))); - } else { - $finder->filter(fn(\SplFileInfo $file) => 2 === substr_count($file->getBasename(), '.') && preg_match('/\.\w+$/', $file->getBasename())); - } - - $finder->in($dirs); - - foreach ($finder as $file) { - // filename is domain.locale.format - [$domain, $locale, $format] = explode('.', $file->getBasename(), 3); - $translator->addMethodCall('addResource', [$format, (string) $file, $locale, $domain]); - } - } - } - } } diff --git a/EventDispatcher/DatabaseResourcesListener.php b/EventDispatcher/DatabaseResourcesListener.php deleted file mode 100644 index e0b27edb..00000000 --- a/EventDispatcher/DatabaseResourcesListener.php +++ /dev/null @@ -1,80 +0,0 @@ - - */ -class DatabaseResourcesListener implements EventSubscriberInterface -{ - private bool $resourcesAdded = false; - - public function __construct( - #[Autowire(service: 'translator')] - private readonly TranslatorInterface $translator, - #[Autowire(service: 'Lexik\Bundle\TranslationBundle\Translation\Loader')] - private readonly DatabaseLoader $databaseLoader, - #[Autowire([ - 'resources_type' => '%lexik_translation.resources_type%' - ])] - private readonly array $options - ) { - } - - public static function getSubscribedEvents(): array - { - return [ - KernelEvents::REQUEST => ['addDatabaseResources', 10], - ]; - } - - public function addDatabaseResources(RequestEvent $event): void - { - if ($this->resourcesAdded) { - return; - } - - $resourcesType = $this->options['resources_type'] ?? 'all'; - if ('all' !== $resourcesType && 'database' !== $resourcesType) { - return; - } - - // Get database resources via event - $eventDispatcher = $event->getKernel()->getContainer()->get('event_dispatcher'); - $getResourcesEvent = new GetDatabaseResourcesEvent(); - $eventDispatcher->dispatch($getResourcesEvent); - - $resources = $getResourcesEvent->getResources(); - - // Add resources to translator if it's our decorator - if ($this->translator instanceof TranslatorDecorator) { - $this->translator->addDatabaseResources(); - } elseif (method_exists($this->translator, 'addResource')) { - // Fallback for direct translator access - foreach ($resources as $resource) { - $locale = $resource['locale']; - $domain = $resource['domain'] ?? 'messages'; - $this->translator->addResource('database', 'DB', $locale, $domain); - } - } - // Note: If neither works, the DatabaseLoader will still be called - // automatically when translations are requested for a locale/domain - - $this->resourcesAdded = true; - } -} diff --git a/Manager/LocaleManager.php b/Manager/LocaleManager.php index 64eb8194..dcb5cad5 100644 --- a/Manager/LocaleManager.php +++ b/Manager/LocaleManager.php @@ -8,17 +8,14 @@ class LocaleManager implements LocaleManagerInterface { /** - * Constructor + * @param list $managedLocales */ public function __construct( protected array $managedLocales ) { } - /** - * @return array - */ - public function getLocales() + public function getLocales(): array { return $this->managedLocales; } diff --git a/Resources/config/services.yaml b/Resources/config/services.yaml index 3219ba58..98115338 100644 --- a/Resources/config/services.yaml +++ b/Resources/config/services.yaml @@ -51,10 +51,11 @@ services: # Translator lexik_translation.translator: class: Lexik\Bundle\TranslationBundle\Translation\Translator + decorates: 'translator' + decoration_on_invalid: ignore arguments: + $translator: '@.inner' $container: '@service_container' - $formatter: '@translator.formatter.default' - $defaultLocale: '%kernel.default_locale%' $loaderIds: [] $options: cache_dir: '%kernel.cache_dir%/translations' @@ -63,26 +64,17 @@ services: scanned_directories: [] cache_vary: [] resources_type: '%lexik_translation.resources_type%' - calls: - - [setConfigCacheFactory, ['@config_cache_factory']] - tags: - - { name: kernel.locale_aware } public: true Lexik\Bundle\TranslationBundle\Translation\Translator: alias: lexik_translation.translator public: true - # TranslatorDecorator alias for backward compatibility - Lexik\Bundle\TranslationBundle\Translation\TranslatorDecorator: - alias: lexik_translation.translator - public: true - Lexik\Bundle\TranslationBundle\Storage\StorageInterface: alias: lexik_translation.translation_storage # Loader - Lexik\Bundle\TranslationBundle\Translation\Loader: + Lexik\Bundle\TranslationBundle\Translation\Loader\DatabaseLoader: class: '%lexik_translation.loader.database.class%' arguments: - '@lexik_translation.translation_storage' diff --git a/Resources/doc/index.md b/Resources/doc/index.md index bb1e6c5b..187fca74 100644 --- a/Resources/doc/index.md +++ b/Resources/doc/index.md @@ -52,13 +52,29 @@ Configuration #### Minimum configuration -You must at least define the fallback locale(s) as for the `framework.translator` node, and define all locales you will manage. +The bundle decorates the Symfony Translator service instead of extending it. This means the bundle now leverages the standard Symfony translator configuration. As a result, `fallback_locale` and `managed_locales` are no longer required: + +- `fallback_locale` is **deprecated**. Use `framework.translator.fallbacks` instead. +- `managed_locales` is now **optional**. If not set, it falls back to `framework.enabled_locales`. + +**Minimal setup** — the bundle works with no specific configuration if your `framework` config already defines `enabled_locales` and `translator.fallbacks`: + +```yml +# config/packages/framework.yaml +framework: + default_locale: en + enabled_locales: [en, fr, de] + translator: + fallbacks: [en] +``` + +**Legacy setup** — for backward compatibility, you can still use the bundle's own options. They will override the framework values: ```yml -# app/config/config.yml +# config/packages/lexik_translation.yaml lexik_translation: - fallback_locale: [en] # (required) default locale(s) to use - managed_locales: [en, fr, de] # (required) locales that the bundle has to manage + fallback_locale: [en] # (deprecated) use framework.translator.fallbacks instead + managed_locales: [en, fr, de] # (optional) falls back to framework.enabled_locales ``` #### Additional configuration options diff --git a/Tests/Unit/Translation/TranslatorTest.php b/Tests/Unit/Translation/TranslatorTest.php index 71c2a306..45752108 100644 --- a/Tests/Unit/Translation/TranslatorTest.php +++ b/Tests/Unit/Translation/TranslatorTest.php @@ -36,13 +36,13 @@ public function testAddDatabaseResources(): void $expected = [ 'de' => [ ['database', 'DB', 'superTranslations'] - ], + ], 'en' => [ - ['database', 'DB', 'messages'], + ['database', 'DB', 'messages'], ['database', 'DB', 'superTranslations'] - ], + ], 'fr' => [ - ['database', 'DB', 'messages'], + ['database', 'DB', 'messages'], ['database', 'DB', 'superTranslations'], ] ]; @@ -63,24 +63,24 @@ public function testRemoveCacheFile(): void $translator = $this->createTranslator($this->getMockSqliteEntityManager(), $cacheDir); // remove locale 'fr' - $this->assertTrue(file_exists($cacheDir.'/catalogue.fr.php')); - $this->assertTrue(file_exists($cacheDir.'/catalogue.fr.php.meta')); - $this->assertTrue(file_exists($cacheDir.'/catalogue.fr_FR.php')); - $this->assertTrue(file_exists($cacheDir.'/catalogue.fr_FR.php.meta')); + $this->assertFileExists($cacheDir . '/catalogue.fr.php'); + $this->assertFileExists($cacheDir . '/catalogue.fr.php.meta'); + $this->assertFileExists($cacheDir . '/catalogue.fr_FR.php'); + $this->assertFileExists($cacheDir . '/catalogue.fr_FR.php.meta'); $translator->removeCacheFile('fr'); - $this->assertFalse(file_exists($cacheDir.'/catalogue.fr.php')); - $this->assertFalse(file_exists($cacheDir.'/catalogue.fr.php.meta')); - $this->assertFalse(file_exists($cacheDir.'/catalogue.fr_FR.php')); - $this->assertFalse(file_exists($cacheDir.'/catalogue.fr_FR.php.meta')); + $this->assertFileDoesNotExist($cacheDir . '/catalogue.fr.php'); + $this->assertFileDoesNotExist($cacheDir . '/catalogue.fr.php.meta'); + $this->assertFileDoesNotExist($cacheDir . '/catalogue.fr_FR.php'); + $this->assertFileDoesNotExist($cacheDir . '/catalogue.fr_FR.php.meta'); // remove locale 'en' - $this->assertTrue(file_exists($cacheDir.'/catalogue.en.php')); - $this->assertTrue(file_exists($cacheDir.'/catalogue.en.php.meta')); + $this->assertFileExists($cacheDir . '/catalogue.en.php'); + $this->assertFileExists($cacheDir . '/catalogue.en.php.meta'); $translator->removeCacheFile('en'); - $this->assertFalse(file_exists($cacheDir.'/catalogue.en.php')); - $this->assertFalse(file_exists($cacheDir.'/catalogue.en.php.meta')); + $this->assertFileDoesNotExist($cacheDir . '/catalogue.en.php'); + $this->assertFileDoesNotExist($cacheDir . '/catalogue.en.php.meta'); } /** @@ -92,25 +92,25 @@ public function testRemoveLocalesCacheFiles(): void $this->createFakeCacheFiles($cacheDir); $translator = $this->createTranslator($this->getMockSqliteEntityManager(), $cacheDir); - $this->assertTrue(file_exists($cacheDir.'/database.resources.php')); - $this->assertTrue(file_exists($cacheDir.'/database.resources.php.meta')); - $this->assertTrue(file_exists($cacheDir.'/catalogue.fr.php')); - $this->assertTrue(file_exists($cacheDir.'/catalogue.fr.php.meta')); - $this->assertTrue(file_exists($cacheDir.'/catalogue.fr_FR.php')); - $this->assertTrue(file_exists($cacheDir.'/catalogue.fr_FR.php.meta')); - $this->assertTrue(file_exists($cacheDir.'/catalogue.en.php')); - $this->assertTrue(file_exists($cacheDir.'/catalogue.en.php.meta')); + $this->assertFileExists($cacheDir . '/database.resources.php'); + $this->assertFileExists($cacheDir . '/database.resources.php.meta'); + $this->assertFileExists($cacheDir . '/catalogue.fr.php'); + $this->assertFileExists($cacheDir . '/catalogue.fr.php.meta'); + $this->assertFileExists($cacheDir . '/catalogue.fr_FR.php'); + $this->assertFileExists($cacheDir . '/catalogue.fr_FR.php.meta'); + $this->assertFileExists($cacheDir . '/catalogue.en.php'); + $this->assertFileExists($cacheDir . '/catalogue.en.php.meta'); $translator->removeLocalesCacheFiles(['fr', 'en']); - $this->assertFalse(file_exists($cacheDir.'/database.resources.php')); - $this->assertFalse(file_exists($cacheDir.'/database.resources.php.meta')); - $this->assertFalse(file_exists($cacheDir.'/catalogue.fr.php')); - $this->assertFalse(file_exists($cacheDir.'/catalogue.fr.php.meta')); - $this->assertFalse(file_exists($cacheDir.'/catalogue.fr_FR.php')); - $this->assertFalse(file_exists($cacheDir.'/catalogue.fr_FR.php.meta')); - $this->assertFalse(file_exists($cacheDir.'/catalogue.en.php')); - $this->assertFalse(file_exists($cacheDir.'/catalogue.en.php.meta')); + $this->assertFileDoesNotExist($cacheDir . '/database.resources.php'); + $this->assertFileDoesNotExist($cacheDir . '/database.resources.php.meta'); + $this->assertFileDoesNotExist($cacheDir . '/catalogue.fr.php'); + $this->assertFileDoesNotExist($cacheDir . '/catalogue.fr.php.meta'); + $this->assertFileDoesNotExist($cacheDir . '/catalogue.fr_FR.php'); + $this->assertFileDoesNotExist($cacheDir . '/catalogue.fr_FR.php.meta'); + $this->assertFileDoesNotExist($cacheDir . '/catalogue.en.php'); + $this->assertFileDoesNotExist($cacheDir . '/catalogue.en.php.meta'); } protected function createTranslator($em, $cacheDir): TranslatorMock @@ -128,22 +128,18 @@ protected function createTranslator($em, $cacheDir): TranslatorMock $container->set('event_dispatcher', $dispatcher); $container->compile(); - $loaderIds = []; + $innerTranslator = new \Symfony\Component\Translation\Translator('en', new MessageFormatter()); + $options = [ 'cache_dir' => $cacheDir, 'debug' => true, - 'resource_files' => [], - 'cache_vary' => [], - 'scanned_directories' => [], - 'enabled_locales' => ['en', 'fr'], - 'default_locale' => 'en', + 'resources_type' => 'all', ]; return new TranslatorMock( + translator: $innerTranslator, container: $container, - formatter: new MessageFormatter(), - defaultLocale: 'en', - loaderIds: $loaderIds, + loaderIds: [], options: $options ); } @@ -171,30 +167,13 @@ protected function createFakeCacheFiles($cacheDir): void class TranslatorMock extends Translator { public array $dbResources = []; - public array $options = [ - 'cache_dir' => '', - 'debug' => false, - 'resource_files' => [], - 'cache_vary' => [], - 'scanned_directories' => [], - 'enabled_locales' => [], - 'default_locale' => 'en', - 'loader_ids' => [], - 'formatter' => null, - 'container' => null - ]; public function addResource(string $format, mixed $resource, string $locale, ?string $domain = null): void { - if(empty( $domain )) { - var_dump('Domain is empty in TranslatorMock::addResource'); - var_dump($format, $resource, $locale); - exit; - } if ('database' === $format) { $this->dbResources[$locale][] = [$format, $resource, $domain]; } parent::addResource($format, $resource, $locale, $domain); } -} +} \ No newline at end of file diff --git a/Tests/app/test/config.yml b/Tests/app/test/config.yml index 503d2db9..a224fda4 100644 --- a/Tests/app/test/config.yml +++ b/Tests/app/test/config.yml @@ -4,9 +4,12 @@ imports: framework: fragments: ~ secret: afasfsf + default_locale: 'en' + enabled_locales: ['en', 'pl', 'de', 'sv'] translator: enabled: true + fallbacks: ['en'] -lexik_translation: - fallback_locale: en - managed_locales: [en, pl, de, sv] +#lexik_translation: +# fallback_locale: en +# managed_locales: [en, pl, de, sv] diff --git a/Translation/Translator.php b/Translation/Translator.php index b6dad880..7b82dc6c 100644 --- a/Translation/Translator.php +++ b/Translation/Translator.php @@ -3,140 +3,120 @@ namespace Lexik\Bundle\TranslationBundle\Translation; use Lexik\Bundle\TranslationBundle\EventDispatcher\Event\GetDatabaseResourcesEvent; -use Symfony\Component\Translation\Loader\LoaderInterface; + +use Psr\Container\ContainerExceptionInterface; +use Psr\Container\ContainerInterface; +use Psr\Container\NotFoundExceptionInterface; use Symfony\Component\Config\ConfigCache; +use Symfony\Component\Config\ConfigCacheFactoryInterface; use Symfony\Component\Finder\Finder; -use Psr\Container\ContainerInterface; -use Symfony\Component\Translation\Formatter\MessageFormatter; -use Symfony\Bundle\FrameworkBundle\Translation\Translator as SymfonyTranslator; +use Symfony\Component\Translation\Loader\LoaderInterface; +use Symfony\Component\Translation\MessageCatalogueInterface; +use Symfony\Contracts\Translation\TranslatableInterface; use Symfony\Contracts\Translation\TranslatorInterface; -use Symfony\Contracts\Translation\LocaleAwareInterface; -use Symfony\Component\Translation\TranslatorBagInterface; /** - * Translator service class that decorates Symfony's Translator. + * Decorator for Symfony Translator service to add database translation resources. * - * Uses composition instead of inheritance to be compatible with Symfony 8 - * where the Translator class is final. + * This decorator wraps the original translator service and adds functionality + * to load translations from the database. It implements TranslatorInterface + * to maintain compatibility with Symfony 8 where Translator is final. * * @author Cédric Girard */ -class Translator implements TranslatorInterface, LocaleAwareInterface, TranslatorBagInterface +class Translator implements TranslatorInterface { - private SymfonyTranslator $translator; - protected array $resourceLocales = []; - protected array $resources = []; - protected array $resourceFiles = []; - protected array $scannedDirectories = []; - protected string $cacheFile; private bool $isResourcesLoaded = false; - - /** @var array For tracking database resources (mainly for testing) */ - public array $dbResources = []; + private string $cacheFile; public function __construct( - protected ContainerInterface $container, - MessageFormatter $formatter, - string $defaultLocale, - protected array $loaderIds, - protected array $options + private $translator, + private readonly ContainerInterface $container, + private readonly array $loaderIds, + private array $options ) { - $this->resourceLocales = []; - $this->resources = []; - $this->resourceFiles = []; - $this->scannedDirectories = []; - - $this->options['resource_files'] = $this->options['resource_files'] ?? []; - $this->options['scanned_directories'] = $this->options['scanned_directories'] ?? []; - $this->options['cache_vary'] = $this->options['cache_vary'] ?? []; $this->options['cache_dir'] = $this->options['cache_dir'] ?? sys_get_temp_dir(); $this->options['debug'] = $this->options['debug'] ?? false; $this->options['resources_type'] = $this->options['resources_type'] ?? 'all'; - $this->cacheFile = sprintf('%s/database.resources.php', $this->options['cache_dir']); + } - // Filter out custom options that Symfony translator doesn't recognize - // Only pass valid Symfony translator options - $symfonyOptions = [ - 'cache_dir' => $this->options['cache_dir'], - 'debug' => $this->options['debug'], - ]; - - // Add other valid Symfony options if they exist - $validSymfonyOptions = ['cache_dir', 'debug', 'resource_files', 'scanned_directories', 'cache_vary']; - foreach ($validSymfonyOptions as $key) { - if (isset($this->options[$key])) { - $symfonyOptions[$key] = $this->options[$key]; - } - } + public function setConfigCacheFactory(ConfigCacheFactoryInterface $configCacheFactory): void + { + $this->translator->setConfigCacheFactory($configCacheFactory); + } - // Create the inner Symfony translator - $this->translator = new SymfonyTranslator( - container: $this->container, - formatter: $formatter, - defaultLocale: $defaultLocale, - loaderIds: $this->loaderIds, - options: $symfonyOptions, - enabledLocales: [] - ); + public function addLoader(string $format, LoaderInterface $loader): void + { + $this->translator->addLoader($format, $loader); } - /** - * {@inheritdoc} - */ - public function trans(?string $id, array $parameters = [], ?string $domain = null, ?string $locale = null): string + public function addResource(string $format, mixed $resource, string $locale, ?string $domain = null): void { - $this->loadDatabaseResourcesIfNeeded(); - return $this->translator->trans($id, $parameters, $domain, $locale); + $this->translator->addResource($format, $resource, $locale, $domain); + } + + public function setLocale(string $locale): void + { + $this->translator->setLocale($locale); } - /** - * {@inheritdoc} - */ public function getLocale(): string { return $this->translator->getLocale(); } - /** - * {@inheritdoc} - */ - public function setLocale(string $locale): void + public function setFallbackLocales(array $locales): void { - $this->translator->setLocale($locale); + $this->translator->setFallbackLocales($locales); } - /** - * {@inheritdoc} - */ - public function getCatalogue(?string $locale = null): \Symfony\Component\Translation\MessageCatalogueInterface + public function getFallbackLocales(): array { - $this->loadDatabaseResourcesIfNeeded(); - return $this->translator->getCatalogue($locale); + return $this->translator->getFallbackLocales(); } - /** - * {@inheritdoc} - */ - public function getCatalogues(): array + public function addGlobalParameter(string $id, string|int|float|TranslatableInterface $value): void { - return $this->translator->getCatalogues(); + $this->translator->addGlobalParameter($id, $value); } - /** - * Load database resources if needed. - */ - private function loadDatabaseResourcesIfNeeded(): void + public function getGlobalParameters(): array { - $resourcesType = $this->options['resources_type'] ?? 'all'; + return $this->translator->getGlobalParameters(); + } + + public function trans(?string $id, array $parameters = [], ?string $domain = null, ?string $locale = null): string + { + $resourcesType = $this->options['resources_type']; if (!$this->isResourcesLoaded && ('all' === $resourcesType || 'database' === $resourcesType)) { $this->addDatabaseResources(); } + + return $this->translator->trans($id, $parameters, $domain, $locale); + } + + public function getCatalogue(?string $locale = null): MessageCatalogueInterface + { + return $this->translator->getCatalogue($locale); + } + + public function getCatalogues(): array + { + return $this->translator->getCatalogues(); + } + + public function warmUp(string $cacheDir, ?string $buildDir = null): array + { + return $this->translator->warmUp($cacheDir, $buildDir); } /** * Add all resources available in database. + * + * This method is called by DatabaseResourcesListener to register + * database translation resources with the translator. */ public function addDatabaseResources(): void { @@ -159,17 +139,8 @@ public function addDatabaseResources(): void $resources = include $this->cacheFile; } - // Use reflection to access the addResource method on the inner translator - $reflection = new \ReflectionClass($this->translator); - $addResourceMethod = $reflection->getMethod('addResource'); - foreach ($resources as $resource) { - $locale = $resource['locale']; - $domain = $resource['domain'] ?? 'messages'; - $addResourceMethod->invoke($this->translator, 'database', 'DB', $locale, $domain); - - // Track for testing purposes - $this->dbResources[$locale][] = ['database', 'DB', $domain]; + $this->addResource('database', 'DB', $resource['locale'], $resource['domain'] ?? 'messages'); } $this->isResourcesLoaded = true; @@ -177,11 +148,8 @@ public function addDatabaseResources(): void /** * Remove the cache file corresponding to the given locale. - * - * @param string $locale - * @return boolean */ - public function removeCacheFile($locale) + public function removeCacheFile(string $locale): bool { if (!file_exists($this->cacheFile)) { return true; @@ -210,7 +178,7 @@ public function removeCacheFile($locale) /** * Remove the cache file corresponding to each given locale. */ - public function removeLocalesCacheFiles(array $locales) + public function removeLocalesCacheFiles(array $locales): void { foreach ($locales as $locale) { $this->removeCacheFile($locale); @@ -233,17 +201,15 @@ public function removeLocalesCacheFiles(array $locales) } /** - * @param string $path - * * @throws \RuntimeException */ - protected function invalidateSystemCacheForFile($path) + protected function invalidateSystemCacheForFile(string $path): void { if (ini_get('apc.enabled') && function_exists('apc_delete_file')) { if (apc_exists($path) && !apc_delete_file($path)) { throw new \RuntimeException(sprintf('Failed to clear APC Cache for file %s', $path)); } - } elseif ('cli' === php_sapi_name() ? ini_get('opcache.enable_cli') : ini_get('opcache.enable')) { + } elseif ('cli' === PHP_SAPI ? ini_get('opcache.enable_cli') : ini_get('opcache.enable')) { if (function_exists("opcache_invalidate") && !opcache_invalidate($path, true)) { throw new \RuntimeException(sprintf('Failed to clear OPCache for file %s', $path)); } @@ -255,11 +221,11 @@ protected function invalidateSystemCacheForFile($path) * * @return array */ - public function getFormats() + public function getFormats(): array { $allFormats = []; - foreach ($this->loaderIds as $id => $formats) { + foreach ($this->loaderIds as $formats) { foreach ($formats as $format) { if ('database' !== $format) { $allFormats[] = $format; @@ -273,18 +239,17 @@ public function getFormats() /** * Returns a loader according to the given format. * - * @param string $format - * @throws \RuntimeException - * @return LoaderInterface + * @throws ContainerExceptionInterface + * @throws NotFoundExceptionInterface */ - public function getLoader($format) + public function getLoader(string $format): LoaderInterface { $loader = null; $i = 0; $ids = array_keys($this->loaderIds); while ($i < count($ids) && null === $loader) { - if (in_array($format, $this->loaderIds[$ids[$i]])) { + if (\in_array($format, $this->loaderIds[ $ids[ $i ] ], true)) { $loader = $this->container->get($ids[$i]); } $i++; @@ -296,47 +261,4 @@ public function getLoader($format) return $loader; } - - /** - * Set fallback locales. - */ - public function setFallbackLocales(array $locales): void - { - $this->translator->setFallbackLocales($locales); - } - - /** - * Get fallback locales. - */ - public function getFallbackLocales(): array - { - return $this->translator->getFallbackLocales(); - } - - /** - * Warms up the cache. - */ - public function warmUp(string $cacheDir): array - { - return $this->translator->warmUp($cacheDir); - } - - /** - * Set config cache factory. - */ - public function setConfigCacheFactory(\Symfony\Component\Config\ConfigCacheFactoryInterface $configCacheFactory): void - { - $this->translator->setConfigCacheFactory($configCacheFactory); - } - - /** - * Add resource to the inner translator. - */ - public function addResource(string $format, mixed $resource, string $locale, ?string $domain = null): void - { - // Use reflection to access the protected addResource method - $reflection = new \ReflectionClass($this->translator); - $addResourceMethod = $reflection->getMethod('addResource'); - $addResourceMethod->invoke($this->translator, $format, $resource, $locale, $domain); - } } diff --git a/Translation/TranslatorDecorator.php b/Translation/TranslatorDecorator.php deleted file mode 100644 index 99849f1d..00000000 --- a/Translation/TranslatorDecorator.php +++ /dev/null @@ -1,195 +0,0 @@ - - */ -class TranslatorDecorator implements TranslatorInterface -{ - private bool $isResourcesLoaded = false; - private string $cacheFile; - - public function __construct( - private readonly TranslatorInterface $translator, - private readonly \Psr\Container\ContainerInterface $container, - private readonly array $options - ) { - $this->options['cache_dir'] = $this->options['cache_dir'] ?? sys_get_temp_dir(); - $this->options['debug'] = $this->options['debug'] ?? false; - $this->options['resources_type'] = $this->options['resources_type'] ?? 'all'; - $this->cacheFile = sprintf('%s/database.resources.php', $this->options['cache_dir']); - } - - /** - * {@inheritdoc} - */ - public function trans(string $id, array $parameters = [], ?string $domain = null, ?string $locale = null): string - { - // Database resources are loaded via DatabaseResourcesListener event subscriber - // No need to load here as the loader is registered and will be called automatically - return $this->translator->trans($id, $parameters, $domain, $locale); - } - - /** - * {@inheritdoc} - */ - public function getLocale(): string - { - return $this->translator->getLocale(); - } - - /** - * {@inheritdoc} - */ - public function setLocale(string $locale): void - { - $this->translator->setLocale($locale); - } - - /** - * Add all resources available in database. - * - * This method is called by DatabaseResourcesListener to register - * database translation resources with the translator. - */ - public function addDatabaseResources(): void - { - if ($this->isResourcesLoaded) { - return; - } - - $cache = new ConfigCache($this->cacheFile, $this->options['debug'] ?? false); - - if (!$cache->isFresh()) { - $event = new GetDatabaseResourcesEvent(); - $this->container->get('event_dispatcher')->dispatch($event); - - $resources = $event->getResources(); - $metadata = []; - - foreach ($resources as $resource) { - $metadata[] = new DatabaseFreshResource($resource['locale'], $resource['domain'] ?? 'messages'); - } - - $content = sprintf("write($content, $metadata); - } else { - $resources = include $this->cacheFile; - } - - // Add resources using reflection to access protected addResource method - // or use the public API if available in Symfony 8 - $reflection = new \ReflectionClass($this->translator); - if ($reflection->hasMethod('addResource')) { - $addResource = $reflection->getMethod('addResource'); - $addResource->setAccessible(true); - foreach ($resources as $resource) { - $addResource->invoke( - $this->translator, - 'database', - 'DB', - $resource['locale'], - $resource['domain'] ?? 'messages' - ); - } - } - - $this->isResourcesLoaded = true; - } - - /** - * Remove the cache file corresponding to the given locale. - * - * @param string $locale - * @return boolean - */ - public function removeCacheFile(string $locale): bool - { - if (!file_exists($this->cacheFile)) { - return true; - } - - $localeExploded = explode('_', $locale); - $finder = new Finder(); - $finder->files()->in($this->options['cache_dir'])->name(sprintf('/catalogue\.%s.*\.php$/', $localeExploded[0])); - $deleted = true; - foreach ($finder as $file) { - $path = $file->getRealPath(); - $this->invalidateSystemCacheForFile($path); - $deleted = unlink($path); - - $metadata = $path.'.meta'; - if (file_exists($metadata)) { - $this->invalidateSystemCacheForFile($metadata); - unlink($metadata); - } - } - - return $deleted; - } - - /** - * Remove the cache file corresponding to each given locale. - */ - public function removeLocalesCacheFiles(array $locales): void - { - foreach ($locales as $locale) { - $this->removeCacheFile($locale); - } - - // also remove database.resources.php cache file - $file = sprintf('%s/database.resources.php', $this->options['cache_dir']); - if (file_exists($file)) { - $this->invalidateSystemCacheForFile($file); - unlink($file); - } - - $metadata = $file.'.meta'; - if (file_exists($metadata)) { - $this->invalidateSystemCacheForFile($metadata); - unlink($metadata); - } - - $this->isResourcesLoaded = false; - } - - /** - * @param string $path - * - * @throws \RuntimeException - */ - protected function invalidateSystemCacheForFile(string $path): void - { - if (ini_get('apc.enabled') && function_exists('apc_delete_file')) { - if (apc_exists($path) && !apc_delete_file($path)) { - throw new \RuntimeException(sprintf('Failed to clear APC Cache for file %s', $path)); - } - } elseif ('cli' === php_sapi_name() ? ini_get('opcache.enable_cli') : ini_get('opcache.enable')) { - if (function_exists("opcache_invalidate") && !opcache_invalidate($path, true)) { - throw new \RuntimeException(sprintf('Failed to clear OPCache for file %s', $path)); - } - } - } - - /** - * Get the decorated translator instance. - * Useful for accessing methods not in TranslatorInterface. - */ - public function getDecoratedTranslator(): TranslatorInterface - { - return $this->translator; - } -} From 56f3b2794ce7ee5c87e2845b45d2d257b6f77aa0 Mon Sep 17 00:00:00 2001 From: Denis Date: Sun, 15 Mar 2026 16:27:10 +0100 Subject: [PATCH 02/12] Fix all PHPStan errors --- Command/ExportTranslationsCommand.php | 10 +- Command/ImportTranslationsCommand.php | 58 +++------ Controller/RestController.php | 9 +- Controller/TranslationController.php | 9 +- .../LexikTranslationExtension.php | 12 +- Document/File.php | 9 +- Document/TransUnit.php | 9 +- Document/TransUnitRepository.php | 113 ++++++++---------- Document/Translation.php | 17 +-- Entity/File.php | 9 +- Entity/TransUnit.php | 5 +- Entity/TransUnitRepository.php | 27 +---- Entity/Translation.php | 13 +- .../CleanTranslationCacheListener.php | 2 +- .../GetDatabaseResourcesListener.php | 5 +- Form/Type/TransUnitType.php | 8 +- Form/Type/TranslationType.php | 10 +- Manager/FileInterface.php | 15 ++- Manager/FileManager.php | 24 +--- Manager/FileManagerInterface.php | 12 +- Manager/TransUnitInterface.php | 36 +++--- Manager/TransUnitManager.php | 29 ++--- Manager/TransUnitManagerInterface.php | 11 +- Model/File.php | 3 +- Model/TransUnit.php | 20 +--- Model/Translation.php | 38 +++--- Storage/AbstractDoctrineStorage.php | 29 +++-- Storage/DoctrineORMStorage.php | 59 ++------- Storage/Listener/DoctrineORMListener.php | 8 +- Storage/StorageInterface.php | 4 +- .../Command/ImportTranslationsCommandTest.php | 4 +- .../Document/TransUnitRepositoryTest.php | 16 +-- Translation/Exporter/ExporterInterface.php | 11 +- Translation/Exporter/JsonExporter.php | 6 +- Translation/Exporter/PhpExporter.php | 6 +- Translation/Exporter/XliffExporter.php | 30 ++--- Translation/Exporter/YamlExporter.php | 6 +- Translation/Importer/FileImporter.php | 5 +- Util/DataGrid/DataGridFormatter.php | 54 ++++----- Util/DataGrid/DataGridRequestHandler.php | 7 +- 40 files changed, 280 insertions(+), 478 deletions(-) diff --git a/Command/ExportTranslationsCommand.php b/Command/ExportTranslationsCommand.php index c8fe10ea..68edf8dc 100644 --- a/Command/ExportTranslationsCommand.php +++ b/Command/ExportTranslationsCommand.php @@ -5,6 +5,7 @@ use Lexik\Bundle\TranslationBundle\Manager\FileInterface; use Lexik\Bundle\TranslationBundle\Storage\StorageInterface; use Lexik\Bundle\TranslationBundle\Translation\Exporter\ExporterCollector; +use Lexik\Bundle\TranslationBundle\Translation\Translator; use Symfony\Component\Console\Attribute\AsCommand; use Symfony\Component\Console\Command\Command; use Symfony\Component\Console\Input\InputInterface; @@ -164,15 +165,10 @@ protected function exportFile(FileInterface $file) /** * If the output file exists we merge existing translations with those from the database. - * - * @param FileInterface $file - * @param string $outputFile - * @param array $translations - * @return array */ - protected function mergeExistingTranslations($file, $outputFile, $translations) + protected function mergeExistingTranslations(FileInterface $file, string $outputFile, array $translations): array { - if (file_exists($outputFile)) { + if (file_exists($outputFile) && method_exists($this->translator, 'getLoader')) { $extension = pathinfo($outputFile, PATHINFO_EXTENSION); $loader = $this->translator->getLoader($extension); $messageCatalogue = $loader->load($outputFile, $file->getLocale(), $file->getDomain()); diff --git a/Command/ImportTranslationsCommand.php b/Command/ImportTranslationsCommand.php index 04a9e672..676efdca 100644 --- a/Command/ImportTranslationsCommand.php +++ b/Command/ImportTranslationsCommand.php @@ -12,10 +12,11 @@ use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Input\InputOption; use Symfony\Component\Console\Output\OutputInterface; +use Symfony\Component\DependencyInjection\Attribute\Autowire; use Symfony\Component\Finder\Finder; use Symfony\Component\Form\Form; use Symfony\Component\HttpKernel\Bundle\BundleInterface; -use Symfony\Component\HttpKernel\Kernel; +use Symfony\Component\HttpKernel\KernelInterface; use Symfony\Component\Security\Core\Exception\AuthenticationException; use Symfony\Component\Validator\Validation; use Symfony\Contracts\Translation\TranslatorInterface; @@ -53,13 +54,13 @@ )] class ImportTranslationsCommand extends Command { - /** - * @param TranslatorInterface $translator - */ public function __construct( private readonly TranslatorInterface $translator, private readonly LocaleManagerInterface $localeManager, private readonly FileImporter $fileImporter, + private readonly KernelInterface $kernel, + #[Autowire('%kernel.project_dir%')] + private readonly string $projectDir, ) { parent::__construct(); } @@ -106,7 +107,7 @@ protected function execute(InputInterface $input, OutputInterface $output): int $bundleName = $this->input->getArgument('bundle'); if ($bundleName) { - $bundle = $this->getApplication()->getKernel()->getBundle($bundleName); + $bundle = $this->kernel->getBundle($bundleName); $this->importBundleTranslationFiles($bundle, $locales, $domains, (bool)$this->input->getOption('globals')); } else { if (!$this->input->getOption('import-path')) { @@ -141,7 +142,7 @@ protected function execute(InputInterface $input, OutputInterface $output): int $this->importTranslationFilesFromPath($importPath, $locales, $domains); } - if ($this->input->getOption('cache-clear')) { + if ($this->input->getOption('cache-clear') && method_exists($this->translator, 'removeLocalesCacheFiles')) { $this->output->writeln('Removing translations cache files ...'); $this->translator->removeLocalesCacheFiles($locales); } @@ -203,14 +204,10 @@ protected function importComponentTranslationFiles(array $locales, array $domain /** * Imports application translation files. */ - protected function importAppTranslationFiles(array $locales, array $domains) + protected function importAppTranslationFiles(array $locales, array $domains): void { - if (Kernel::MAJOR_VERSION >= 4) { - $translationPath = $this->getApplication()->getKernel()->getProjectDir() . '/translations'; - $finder = $this->findTranslationsFiles($translationPath, $locales, $domains, false); - } else { - $finder = $this->findTranslationsFiles($this->getApplication()->getKernel()->getRootDir(), $locales, $domains); - } + $translationPath = $this->projectDir . '/translations'; + $finder = $this->findTranslationsFiles($translationPath, $locales, $domains, false); $this->importTranslationFiles($finder); } @@ -221,7 +218,7 @@ protected function importAppTranslationFiles(array $locales, array $domains) */ protected function importBundlesTranslationFiles(array $locales, array $domains, $global = false) { - $bundles = $this->getApplication()->getKernel()->getBundles(); + $bundles = $this->kernel->getBundles(); foreach ($bundles as $bundle) { $this->importBundleTranslationFiles($bundle, $locales, $domains, $global); @@ -230,20 +227,11 @@ protected function importBundlesTranslationFiles(array $locales, array $domains, /** * Imports translation files form the specific bundles. - * - * @param array $locales - * @param array $domains - * @param boolean $global */ - protected function importBundleTranslationFiles(BundleInterface $bundle, $locales, $domains, $global = false) + protected function importBundleTranslationFiles(BundleInterface $bundle, array $locales, array $domains, bool $global = false): void { if ($global) { - $kernel = $this->getApplication()->getKernel(); - if (Kernel::MAJOR_VERSION >= 4) { - $path = $kernel->getProjectDir() . '/app'; - } else { - $path = $kernel->getRootDir(); - } + $path = $this->projectDir . '/app'; $path .= '/Resources/' . $bundle->getName() . '/translations'; @@ -270,10 +258,8 @@ protected function importBundleTranslationFiles(BundleInterface $bundle, $locale /** * Imports some translations files. - * - * @param Finder $finder */ - protected function importTranslationFiles($finder) + protected function importTranslationFiles(?Finder $finder): void { if (!$finder instanceof Finder) { $this->output->writeln('No file to import'); @@ -297,20 +283,17 @@ protected function importTranslationFiles($finder) /** * Return a Finder object if $path has a Resources/translations folder. - * - * @param string $path - * @return Finder */ - protected function findTranslationsFiles($path, array $locales, array $domains, $autocompletePath = true) + protected function findTranslationsFiles(string $path, array $locales, array $domains, $autocompletePath = true): ?Finder { $finder = null; - if (preg_match('#^win#i', PHP_OS)) { + if (0 === stripos(PHP_OS_FAMILY, "win")) { $path = preg_replace('#' . preg_quote(DIRECTORY_SEPARATOR, '#') . '#', '/', $path); } if (true === $autocompletePath) { - $dir = (str_starts_with((string) $path, $this->getApplication()->getKernel()->getProjectDir() . '/Resources')) ? $path : $path . '/Resources/translations'; + $dir = (str_starts_with((string) $path, $this->projectDir . '/Resources')) ? $path : $path . '/Resources/translations'; } else { $dir = $path; } @@ -327,12 +310,9 @@ protected function findTranslationsFiles($path, array $locales, array $domains, return (null !== $finder && $finder->count() > 0) ? $finder : null; } - /** - * @return string - */ - protected function getFileNamePattern(array $locales, array $domains) + protected function getFileNamePattern(array $locales, array $domains): string { - $formats = $this->translator->getFormats(); + $formats = method_exists($this->translator, 'getFormats') ? $this->translator->getFormats() : []; if (count($domains)) { $regex = sprintf('/((%s)\.(%s)\.(%s))/', implode('|', $domains), implode('|', $locales), implode('|', $formats)); diff --git a/Controller/RestController.php b/Controller/RestController.php index 08243013..51b871b9 100644 --- a/Controller/RestController.php +++ b/Controller/RestController.php @@ -10,6 +10,7 @@ use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; use Symfony\Component\HttpFoundation\JsonResponse; use Symfony\Component\HttpFoundation\Request; +use Symfony\Component\HttpKernel\Exception\NotFoundHttpException; /** * @author Cédric Girard @@ -18,8 +19,6 @@ class RestController extends AbstractController { use CsrfCheckerTrait; - private $csrfTokenManager; - public function __construct( private readonly DataGridRequestHandler $dataGridRequestHandler, private readonly DataGridFormatter $dataGridFormatter, @@ -43,7 +42,7 @@ public function listByProfileAction(Request $request, string $token): JsonRespon } /** - * @throws \Symfony\Component\HttpKernel\Exception\NotFoundHttpException + * @throws NotFoundHttpException */ public function updateAction(Request $request, int $id): JsonResponse { @@ -55,7 +54,7 @@ public function updateAction(Request $request, int $id): JsonResponse } /** - * @throws \Symfony\Component\HttpKernel\Exception\NotFoundHttpException + * @throws NotFoundHttpException */ public function deleteAction(int $id): JsonResponse { @@ -73,7 +72,7 @@ public function deleteAction(int $id): JsonResponse } /** - * @throws \Symfony\Component\HttpKernel\Exception\NotFoundHttpException + * @throws NotFoundHttpException */ public function deleteTranslationAction(int $id, string $locale): JsonResponse { diff --git a/Controller/TranslationController.php b/Controller/TranslationController.php index 44a81198..bd08f26e 100644 --- a/Controller/TranslationController.php +++ b/Controller/TranslationController.php @@ -10,6 +10,7 @@ use Lexik\Bundle\TranslationBundle\Util\Overview\StatsAggregator; use Lexik\Bundle\TranslationBundle\Util\Profiler\TokenFinder; use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; +use Symfony\Component\Form\SubmitButton; use Symfony\Component\HttpFoundation\JsonResponse; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; @@ -85,7 +86,7 @@ public function invalidateCacheAction(Request $request): Response return new JsonResponse(['message' => $message]); } - $request->getSession()->getFlashBag()->add('success', $message); + $this->addFlash('success', $message); return $this->redirect($this->generateUrl('lexik_translation_grid')); } @@ -100,9 +101,11 @@ public function newAction(Request $request): Response if ($this->transUnitFormHandler->process($form, $request)) { $message = $this->translator->trans('translations.successfully_added', [], 'LexikTranslationBundle'); - $request->getSession()->getFlashBag()->add('success', $message); + $this->addFlash('success', $message); - $redirectUrl = $form->get('save_add')->isClicked() ? 'lexik_translation_new' : 'lexik_translation_grid'; + /** @var SubmitButton $btn */ + $btn = $form->get('save_add'); + $redirectUrl = $btn->isClicked() ? 'lexik_translation_new' : 'lexik_translation_grid'; return $this->redirect($this->generateUrl($redirectUrl)); } diff --git a/DependencyInjection/LexikTranslationExtension.php b/DependencyInjection/LexikTranslationExtension.php index 8d2a9f55..e4f05af8 100644 --- a/DependencyInjection/LexikTranslationExtension.php +++ b/DependencyInjection/LexikTranslationExtension.php @@ -63,7 +63,7 @@ public function load(array $configs, ContainerBuilder $container): void $container->setParameter('lexik_translation.exporter.json.hierarchical_format', $config['exporter']['json_hierarchical_format']); $container->setParameter('lexik_translation.exporter.yml.use_tree', $config['exporter']['use_yml_tree']); - $objectManager = $config['storage']['object_manager'] ?? null; + $objectManager = $config['storage']['object_manager'] ?? 'default'; $this->buildTranslationStorageDefinition($container, $config['storage']['type'], $objectManager); @@ -117,12 +117,12 @@ public function prepend(ContainerBuilder $container): void * @param string $objectManager * @throws \RuntimeException */ - protected function buildTranslationStorageDefinition(ContainerBuilder $container, $storage, $objectManager): void + protected function buildTranslationStorageDefinition(ContainerBuilder $container, $storage, string $objectManager): void { $container->setParameter('lexik_translation.storage.type', $storage); - if (StorageInterface::STORAGE_ORM == $storage) { - $args = [new Reference('doctrine'), $objectManager ?? 'default']; + if (StorageInterface::STORAGE_ORM === $storage) { + $args = [new Reference('doctrine'), $objectManager]; // Create XML driver for backward compatibility if (class_exists(SimplifiedXmlDriver::class)) { @@ -141,8 +141,8 @@ protected function buildTranslationStorageDefinition(ContainerBuilder $container $container->setDefinition('lexik_translation.orm.listener', $metadataListener); - } elseif (StorageInterface::STORAGE_MONGODB == $storage) { - $args = [new Reference('doctrine_mongodb'), $objectManager ?? 'default']; + } elseif (StorageInterface::STORAGE_MONGODB === $storage) { + $args = [new Reference('doctrine_mongodb'), $objectManager]; $this->createDoctrineMappingDriver($container, 'lexik_translation.mongodb.metadata.xml', '%doctrine_mongodb.odm.metadata.xml.class%'); } else { diff --git a/Document/File.php b/Document/File.php index 806971ab..2d5a602b 100644 --- a/Document/File.php +++ b/Document/File.php @@ -3,17 +3,13 @@ namespace Lexik\Bundle\TranslationBundle\Document; use Lexik\Bundle\TranslationBundle\Model\File as FileModel; -use Lexik\Bundle\TranslationBundle\Manager\FileInterface; use DateTime; /** * @author Cédric Girard */ -class File extends FileModel implements FileInterface +class File extends FileModel { - /** - * {@inheritdoc} - */ public function prePersist(): void { $now = new DateTime("now"); @@ -22,9 +18,6 @@ public function prePersist(): void $this->updatedAt = $now->format('U'); } - /** - * {@inheritdoc} - */ public function preUpdate(): void { $now = new DateTime("now"); diff --git a/Document/TransUnit.php b/Document/TransUnit.php index 0fc0b0f9..c48d5026 100644 --- a/Document/TransUnit.php +++ b/Document/TransUnit.php @@ -4,7 +4,6 @@ use Lexik\Bundle\TranslationBundle\Model\TransUnit as TransUnitModel; use Lexik\Bundle\TranslationBundle\Manager\TransUnitInterface; -use MongoTimestamp; /** * @author Cédric Girard @@ -12,16 +11,10 @@ class TransUnit extends TransUnitModel implements TransUnitInterface { /** - * Convert all MongoTimestamp object to time. + * @deprecated No longer needed since the legacy mongo extension is no longer supported. */ public function convertMongoTimestamp(): void { - $this->createdAt = ($this->createdAt instanceof MongoTimestamp) ? $this->createdAt->sec : $this->createdAt; - $this->updatedAt = ($this->updatedAt instanceof MongoTimestamp) ? $this->updatedAt->sec : $this->updatedAt; - - foreach ($this->getTranslations() as $translation) { - $translation->convertMongoTimestamp(); - } } /** diff --git a/Document/TransUnitRepository.php b/Document/TransUnitRepository.php index bb40979a..4fe99747 100644 --- a/Document/TransUnitRepository.php +++ b/Document/TransUnitRepository.php @@ -4,7 +4,7 @@ use Doctrine\ODM\MongoDB\Query\Builder; use Doctrine\ODM\MongoDB\Repository\DocumentRepository; -use Lexik\Bundle\TranslationBundle\Model\File as ModelFile; +use Lexik\Bundle\TranslationBundle\Manager\FileInterface; use MongoDB\BSON\ObjectId; use MongoDB\BSON\Regex; @@ -17,10 +17,8 @@ class TransUnitRepository extends DocumentRepository { /** * Returns all domain available in database. - * - * @return array */ - public function getAllDomains() + public function getAllDomains(): array { $results = $this->createQueryBuilder() ->distinct('domain') @@ -115,7 +113,7 @@ public function getAllDomainsByLocale(): array } } - usort($domainsByLocale, function ($a, $b) { + usort($domainsByLocale, static function ($a, $b) { $result = strcmp((string) $a['locale'], (string) $b['locale']); if (0 === $result) { $result = strcmp((string) $a['domain'], (string) $b['domain']); @@ -133,7 +131,7 @@ public function getAllDomainsByLocale(): array * @param string $domain * @return array */ - public function getAllByLocaleAndDomain($locale, $domain) + public function getAllByLocaleAndDomain(string $locale, string $domain): array { $results = $this->createQueryBuilder() ->hydrate(false) @@ -148,7 +146,7 @@ public function getAllByLocaleAndDomain($locale, $domain) $i = 0; $index = null; while ($i < $item['translations'] && null === $index) { - if ($item['translations'][$i]['locale'] == $locale) { + if ($item['translations'][$i]['locale'] === $locale) { $index = $i; } $i++; @@ -216,11 +214,15 @@ public function getTransUnitList(?array $locales = null, int $rows = 20, int $pa /** * Count the number of trans unit. + * @param array $criteria */ - public function count(?array $locales = null, ?array $filters = null): int + public function count(array $criteria = []): int { $builder = $this->createQueryBuilder(); + $filters = $criteria['filters'] ?? null; + $locales = $criteria['locales'] ?? null; + $this->addTransUnitFilters($builder, $filters); $this->addTranslationFilter($builder, $locales, $filters); @@ -233,11 +235,8 @@ public function count(?array $locales = null, ?array $filters = null): int /** * Returns all translations for the given file. - * - * @param boolean $onlyUpdated - * @return array */ - public function getTranslationsForFile(ModelFile $file, $onlyUpdated) + public function getTranslationsForFile(FileInterface $file, bool $onlyUpdated): array { $builder = $this->createQueryBuilder() ->hydrate(false) @@ -252,7 +251,7 @@ public function getTranslationsForFile(ModelFile $file, $onlyUpdated) $content = null; $i = 0; while ($i < (is_countable($result['translations']) ? count($result['translations']) : 0) && null === $content) { - if ($file->getLocale() == $result['translations'][$i]['locale']) { + if ($file->getLocale() === $result['translations'][$i]['locale']) { if ($onlyUpdated) { // Handle MongoDB Timestamp objects - they have a 'sec' property $createdAt = $result['translations'][$i]['createdAt'] ?? null; @@ -282,7 +281,7 @@ public function getTranslationsForFile(ModelFile $file, $onlyUpdated) /** * Add conditions according to given filters. */ - protected function addTransUnitFilters(Builder $builder, ?array $filters = null) + protected function addTransUnitFilters(Builder $builder, ?array $filters = null): void { if (isset($filters['_search']) && $filters['_search']) { if (!empty($filters['domain'])) { @@ -341,71 +340,53 @@ public function getLatestTranslationUpdatedAt() ->getQuery() ->getSingleResult(); - if (!isset($result['translations'], $result['translations'][0])) { + if (!isset($result['translations'][0])) { return null; } return new \DateTime(date('Y-m-d H:i:s', $result['translations'][0]['updated_at']->sec)); } - /** - * @return array - */ - public function countByDomains() + public function countByDomains(): array { - $reduce = <<createAggregationBuilder(); + $results = $aggregationBuilder + ->group() + ->field('_id')->expression('$domain') + ->field('number')->sum(1) + ->execute(); - $results = $this->createQueryBuilder() - ->group([], - []) // @todo: group and reduce won't work anymore, but this method seems to be untested - ->reduce($reduce) - ->hydrate(false) - ->getQuery() - ->execute(); + $counts = []; + foreach ($results as $row) { + $counts[] = [ + 'domain' => $row['_id'], + 'number' => $row['number'], + ]; + } - return $results[0]['count'] ?? []; + return $counts; } - /** - * @param string $domain - * @return array - */ - public function countTranslationsByLocales($domain) + public function countTranslationsByLocales(string $domain): array { - $reduce = <<createAggregationBuilder(); + $results = $aggregationBuilder + ->match() + ->field('domain')->equals($domain) + ->unwind('$translations') + ->group() + ->field('_id')->expression('$translations.locale') + ->field('number')->sum(1) + ->execute(); - $results = $this->createQueryBuilder() - ->field('domain')->equals($domain) - ->group([], []) // @todo: won't work, untested - ->reduce($reduce) - ->hydrate(false) - ->getQuery() - ->execute(); + $counts = []; + foreach ($results as $row) { + $counts[] = [ + 'locale' => $row['_id'], + 'number' => $row['number'], + ]; + } - return $results[0]['count'] ?? []; + return $counts; } } diff --git a/Document/Translation.php b/Document/Translation.php index b7bd6b4a..63862f9a 100644 --- a/Document/Translation.php +++ b/Document/Translation.php @@ -2,6 +2,7 @@ namespace Lexik\Bundle\TranslationBundle\Document; +use Lexik\Bundle\TranslationBundle\Manager\FileInterface; use Lexik\Bundle\TranslationBundle\Model\Translation as TranslationModel; use Lexik\Bundle\TranslationBundle\Manager\TranslationInterface; @@ -11,25 +12,13 @@ class Translation extends TranslationModel implements TranslationInterface { // Relationship mapping is defined in XML: Resources/config/doctrine/Translation.mongodb-odm.xml - protected $file; - - public function setFile($file): void - { - $this->file = $file; - } - - public function getFile() - { - return $this->file; - } + protected FileInterface $file; /** - * Convert all MongoTimestamp object to time. + * @deprecated No longer needed since the legacy mongo extension is no longer supported. */ public function convertMongoTimestamp(): void { - $this->createdAt = ($this->createdAt instanceof \MongoTimestamp) ? $this->createdAt->sec : $this->createdAt; - $this->updatedAt = ($this->updatedAt instanceof \MongoTimestamp) ? $this->updatedAt->sec : $this->updatedAt; } /** diff --git a/Entity/File.php b/Entity/File.php index 0f65c5ee..9c5fa7a7 100644 --- a/Entity/File.php +++ b/Entity/File.php @@ -6,7 +6,6 @@ use Doctrine\ORM\Mapping\HasLifecycleCallbacks; use Doctrine\ORM\Mapping\PrePersist; use Doctrine\ORM\Mapping\PreUpdate; -use Lexik\Bundle\TranslationBundle\Manager\FileInterface; use Lexik\Bundle\TranslationBundle\Model\File as FileModel; use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity; @@ -15,7 +14,7 @@ */ #[HasLifecycleCallbacks] #[UniqueEntity(fields: ['hash'])] -class File extends FileModel implements FileInterface +class File extends FileModel { protected $id; @@ -23,9 +22,6 @@ class File extends FileModel implements FileInterface // Relationship mapping is defined in XML: Resources/config/doctrine/File.orm.xml protected Collection $translations; - /** - * {@inheritdoc} - */ #[PrePersist] public function prePersist(): void { @@ -33,9 +29,6 @@ public function prePersist(): void $this->updatedAt = new \DateTime("now"); } - /** - * {@inheritdoc} - */ #[PreUpdate] public function preUpdate(): void { diff --git a/Entity/TransUnit.php b/Entity/TransUnit.php index b097fd2e..4cc684b0 100644 --- a/Entity/TransUnit.php +++ b/Entity/TransUnit.php @@ -2,6 +2,7 @@ namespace Lexik\Bundle\TranslationBundle\Entity; +use Doctrine\Common\Collections\Collection; use Doctrine\ORM\Mapping\HasLifecycleCallbacks; use Doctrine\ORM\Mapping\PrePersist; use Doctrine\ORM\Mapping\PreUpdate; @@ -23,12 +24,10 @@ class TransUnit extends TransUnitModel implements TransUnitInterface // translations property is inherited from TransUnitModel // Relationship mapping is defined in XML: Resources/config/doctrine/TransUnit.orm.xml - protected $translations; + protected Collection $translations; /** * Add translations - * - * @param \Lexik\Bundle\TranslationBundle\Entity\Translation $translations */ public function addTranslation(DocumentTranslation|Translation $translation): void { diff --git a/Entity/TransUnitRepository.php b/Entity/TransUnitRepository.php index 277aa5f1..5aa79a15 100644 --- a/Entity/TransUnitRepository.php +++ b/Entity/TransUnitRepository.php @@ -2,11 +2,10 @@ namespace Lexik\Bundle\TranslationBundle\Entity; +use Lexik\Bundle\TranslationBundle\Manager\FileInterface; use Lexik\Bundle\TranslationBundle\Util\Doctrine\SingleColumnArrayHydrator; -use Doctrine\ORM\Query; use Doctrine\ORM\QueryBuilder; use Doctrine\ORM\EntityRepository; -use Lexik\Bundle\TranslationBundle\Model\File as ModelFile; /** * Repository for TransUnit entity. @@ -17,10 +16,8 @@ class TransUnitRepository extends EntityRepository { /** * Returns all domain available in database. - * - * @return array */ - public function getAllDomainsByLocale() + public function getAllDomainsByLocale(): array { return $this->createQueryBuilder('tu') ->select('te.locale, tu.domain') @@ -34,10 +31,8 @@ public function getAllDomainsByLocale() /** * Returns all domains for each locale. - * - * @return array */ - public function getAllByLocaleAndDomain($locale, $domain): mixed + public function getAllByLocaleAndDomain(string $locale, string $domain): array { return $this->createQueryBuilder('tu') ->select('tu, te') @@ -68,12 +63,8 @@ public function getAllDomains(): mixed /** * Returns some trans units with their translations. - * - * @param int $rows - * @param int $page - * @return array */ - public function getTransUnitList(?array $locales = null, $rows = 20, $page = 1, ?array $filters = null): mixed + public function getTransUnitList(?array $locales = null, int $rows = 20, int $page = 1, ?array $filters = null): array { $this->loadCustomHydrator(); @@ -130,10 +121,7 @@ public function count(array $criteria = []): int return (int) $builder->getQuery()->getSingleScalarResult(); } - /** - * @return array - */ - public function countByDomains(): mixed + public function countByDomains(): array { return $this->createQueryBuilder('tu') ->select('COUNT(DISTINCT tu.id) AS number, tu.domain') @@ -144,11 +132,8 @@ public function countByDomains(): mixed /** * Returns all translations for the given file. - * - * @param boolean $onlyUpdated - * @return array */ - public function getTranslationsForFile(ModelFile $file, $onlyUpdated): array + public function getTranslationsForFile(FileInterface $file, bool $onlyUpdated): array { $builder = $this->createQueryBuilder('tu') ->select('tu.key, te.content') diff --git a/Entity/Translation.php b/Entity/Translation.php index 6c609059..0b24567c 100644 --- a/Entity/Translation.php +++ b/Entity/Translation.php @@ -5,6 +5,7 @@ use Doctrine\ORM\Mapping\HasLifecycleCallbacks; use Doctrine\ORM\Mapping\PrePersist; use Doctrine\ORM\Mapping\PreUpdate; +use Lexik\Bundle\TranslationBundle\Manager\FileInterface; use Lexik\Bundle\TranslationBundle\Manager\TranslationInterface; use Lexik\Bundle\TranslationBundle\Model\TransUnit; use Lexik\Bundle\TranslationBundle\Model\Translation as TranslationModel; @@ -23,17 +24,7 @@ class Translation extends TranslationModel implements TranslationInterface // Relationship mappings are defined in XML: Resources/config/doctrine/Translation.orm.xml protected $transUnit; - protected $file; - - public function setFile($file): void - { - $this->file = $file; - } - - public function getFile() - { - return $this->file; - } + protected FileInterface $file; // modifiedManually is inherited from TranslationModel diff --git a/EventDispatcher/CleanTranslationCacheListener.php b/EventDispatcher/CleanTranslationCacheListener.php index 1213559f..1968cb85 100644 --- a/EventDispatcher/CleanTranslationCacheListener.php +++ b/EventDispatcher/CleanTranslationCacheListener.php @@ -35,7 +35,7 @@ public function onKernelRequest(RequestEvent $event) ->in($this->cacheDirectory.'/translations') ->date('< '.$lastUpdateTime->format('Y-m-d H:i:s')); - if ($finder->count() > 0) { + if ($finder->count() > 0 && method_exists($this->translator, 'removeLocalesCacheFiles')) { $this->translator->removeLocalesCacheFiles($this->localeManager->getLocales()); } } diff --git a/EventDispatcher/GetDatabaseResourcesListener.php b/EventDispatcher/GetDatabaseResourcesListener.php index 14cd70f6..6df69e25 100644 --- a/EventDispatcher/GetDatabaseResourcesListener.php +++ b/EventDispatcher/GetDatabaseResourcesListener.php @@ -3,6 +3,7 @@ namespace Lexik\Bundle\TranslationBundle\EventDispatcher; use Lexik\Bundle\TranslationBundle\EventDispatcher\Event\GetDatabaseResourcesEvent; +use Lexik\Bundle\TranslationBundle\Storage\DoctrineORMStorage; use Lexik\Bundle\TranslationBundle\Storage\StorageInterface; /** @@ -19,10 +20,10 @@ public function __construct( /** * Query the database to get translation resources and set it on the event. */ - public function onGetDatabaseResources(GetDatabaseResourcesEvent $event) + public function onGetDatabaseResources(GetDatabaseResourcesEvent $event): void { // prevent errors on command such as cache:clear if doctrine schema has not been updated yet - if (StorageInterface::STORAGE_ORM == $this->storageType && !$this->storage->translationsTablesExist()) { + if (StorageInterface::STORAGE_ORM === $this->storageType && $this->storage instanceof DoctrineORMStorage && !$this->storage->translationsTablesExist()) { $resources = []; } else { $resources = $this->storage->getTransUnitDomainsByLocale(); diff --git a/Form/Type/TransUnitType.php b/Form/Type/TransUnitType.php index 9f6cfc91..1151e035 100644 --- a/Form/Type/TransUnitType.php +++ b/Form/Type/TransUnitType.php @@ -20,7 +20,7 @@ class TransUnitType extends AbstractType /** * {@inheritdoc} */ - public function buildForm(FormBuilderInterface $builder, array $options) + public function buildForm(FormBuilderInterface $builder, array $options): void { $builder->add('key', TextType::class, ['label' => 'translations.key']); $builder->add('domain', ChoiceType::class, ['label' => 'translations.domain', 'choices' => array_merge( @@ -35,7 +35,7 @@ public function buildForm(FormBuilderInterface $builder, array $options) /** * {@inheritdoc} */ - public function configureOptions(OptionsResolver $resolver) + public function configureOptions(OptionsResolver $resolver): void { $resolver->setDefaults(['data_class' => null, 'default_domain' => ['messages'], 'domains' => [], 'translation_class' => null, 'translation_domain' => 'LexikTranslationBundle']); } @@ -43,7 +43,7 @@ public function configureOptions(OptionsResolver $resolver) /** * {@inheritdoc} */ - public function getName() + public function getName(): string { return $this->getBlockPrefix(); } @@ -51,7 +51,7 @@ public function getName() /** * {@inheritdoc} */ - public function getBlockPrefix() + public function getBlockPrefix(): string { return 'lxk_trans_unit'; } diff --git a/Form/Type/TranslationType.php b/Form/Type/TranslationType.php index 2adb5a69..aaf020a6 100644 --- a/Form/Type/TranslationType.php +++ b/Form/Type/TranslationType.php @@ -20,7 +20,7 @@ class TranslationType extends AbstractType /** * {@inheritdoc} */ - public function buildForm(FormBuilderInterface $builder, array $options) + public function buildForm(FormBuilderInterface $builder, array $options): void { $builder->add('locale', HiddenType::class); $builder->add('content', TextareaType::class, ['required' => false]); @@ -29,7 +29,7 @@ public function buildForm(FormBuilderInterface $builder, array $options) /** * {@inheritdoc} */ - public function buildView(FormView $view, FormInterface $form, array $options) + public function buildView(FormView $view, FormInterface $form, array $options): void { $view->vars['label'] = $form['locale']->getData(); } @@ -37,7 +37,7 @@ public function buildView(FormView $view, FormInterface $form, array $options) /** * {@inheritdoc} */ - public function configureOptions(OptionsResolver $resolver) + public function configureOptions(OptionsResolver $resolver): void { $resolver->setDefaults(['data_class' => null, 'translation_domain' => 'LexikTranslationBundle']); } @@ -45,7 +45,7 @@ public function configureOptions(OptionsResolver $resolver) /** * {@inheritdoc} */ - public function getName() + public function getName(): string { return $this->getBlockPrefix(); } @@ -53,7 +53,7 @@ public function getName() /** * {@inheritdoc} */ - public function getBlockPrefix() + public function getBlockPrefix(): string { return 'lxk_translation'; } diff --git a/Manager/FileInterface.php b/Manager/FileInterface.php index 3f889c49..55b42e1f 100644 --- a/Manager/FileInterface.php +++ b/Manager/FileInterface.php @@ -2,8 +2,6 @@ namespace Lexik\Bundle\TranslationBundle\Manager; -use Symfony\Component\HttpFoundation\File\File; - /** * File interface. * @@ -11,4 +9,17 @@ */ interface FileInterface { + public function getId(); + public function setDomain(string $domain): void; + public function getDomain(): string; + public function setLocale(string $locale): void; + public function getLocale(): string; + public function setExtention(string $extention): void; + public function getExtention(): string; + public function setPath(string $path): void; + public function getPath(): string; + public function setName(string $name): void; + public function getName(): string; + public function setHash(string $hash): void; + public function getHash(): string; } diff --git a/Manager/FileManager.php b/Manager/FileManager.php index 743b4782..540411a0 100644 --- a/Manager/FileManager.php +++ b/Manager/FileManager.php @@ -12,21 +12,16 @@ */ class FileManager implements FileManagerInterface { - /** - * Construct. - * - * @param string $rootDir - */ public function __construct( private readonly StorageInterface $storage, - private $rootDir, + private readonly string $rootDir, ) { } /** * {@inheritdoc} */ - public function getFor($name, $path = null) + public function getFor(string $name, ?string $path = null): FileInterface { if (null === $path) { $path = sprintf('%s/Resources/translations', $this->rootDir); @@ -42,7 +37,7 @@ public function getFor($name, $path = null) /** * {@inheritdoc} */ - public function create($name, $path, $flush = false) + public function create(string $name, string $path, bool $flush = false): FileInterface { $path = $this->getFileRelativePath($path); @@ -64,23 +59,16 @@ public function create($name, $path, $flush = false) /** * Returns the has for the given file. - * - * @param string $name - * @param string $relativePath - * @return string */ - protected function generateHash($name, $relativePath) + protected function generateHash(string $name, string $relativePath): string { return md5($relativePath . DIRECTORY_SEPARATOR . $name); } /** * Returns the relative according to the kernel.root_dir value. - * - * @param string $filePath - * @return string */ - protected function getFileRelativePath($filePath) + protected function getFileRelativePath(string $filePath): string { $commonParts = []; @@ -98,7 +86,7 @@ protected function getFileRelativePath($filePath) $i = 0; while ($i < count($rootDirParts)) { - if (isset($rootDirParts[$i], $filePathParts[$i]) && $rootDirParts[$i] == $filePathParts[$i]) { + if (isset($rootDirParts[$i], $filePathParts[$i]) && $rootDirParts[$i] === $filePathParts[$i]) { $commonParts[] = $rootDirParts[$i]; } $i++; diff --git a/Manager/FileManagerInterface.php b/Manager/FileManagerInterface.php index 4c66fc4c..a49fa3d9 100644 --- a/Manager/FileManagerInterface.php +++ b/Manager/FileManagerInterface.php @@ -12,20 +12,12 @@ interface FileManagerInterface { /** * Create a new file. - * - * @param string $name - * @param string $path - * @return File */ - public function create($name, $path, $flush = false); + public function create(string $name, string $path, bool $flush = false): FileInterface; /** * Returns a translation file according to the given name and path. * If path is null, app/Resources/translations will be used as default path. - * - * @param string $name - * @param string $path - * @return File */ - public function getFor($name, $path = null); + public function getFor(string $name, ?string $path = null): FileInterface; } diff --git a/Manager/TransUnitInterface.php b/Manager/TransUnitInterface.php index a23c78aa..1a48b1a5 100644 --- a/Manager/TransUnitInterface.php +++ b/Manager/TransUnitInterface.php @@ -3,6 +3,9 @@ namespace Lexik\Bundle\TranslationBundle\Manager; use Doctrine\Common\Collections\Collection; +use Lexik\Bundle\TranslationBundle\Document\Translation as DocumentTranslation; +use Lexik\Bundle\TranslationBundle\Entity\Translation; + /** * TransUnit manager interface. * @@ -10,32 +13,23 @@ */ interface TransUnitInterface { - /** - * @return TranslationInterface[] - */ - public function getTranslations(): array|Collection; - - /** - * @param string $locale - * - * @return bool - */ + public function getId(); + + public function addTranslation(DocumentTranslation|Translation $translation): void; + + public function removeTranslation(DocumentTranslation|Translation $translation): void; + + public function getTranslations(): Collection; + public function hasTranslation(string $locale): bool; - /** - * @param string $locale - * - * @return TranslationInterface - */ public function getTranslation(string $locale): ?TranslationInterface; - /** - * @param string $key - */ public function setKey(string $key): void; - /** - * @param string $domain - */ + public function getKey(): string; + public function setDomain(string $domain): void; + + public function getDomain(): string; } diff --git a/Manager/TransUnitManager.php b/Manager/TransUnitManager.php index 8676787f..ed1a343f 100644 --- a/Manager/TransUnitManager.php +++ b/Manager/TransUnitManager.php @@ -4,7 +4,6 @@ use Lexik\Bundle\TranslationBundle\Model\Translation; use Lexik\Bundle\TranslationBundle\Storage\StorageInterface; -use Lexik\Bundle\TranslationBundle\Storage\PropelStorage; /** * Class to manage TransUnit entities or documents. @@ -103,15 +102,15 @@ public function updateTranslation(TransUnitInterface $transUnit, $locale, $conte $found = false; while ($i < $end && !$found) { - $found = ($transUnit->getTranslations()->get($i)->getLocale() == $locale); + $found = ($transUnit->getTranslations()->get($i)->getLocale() === $locale); $i++; } if ($found) { - /* @var Translation $translation */ + /* @var TranslationInterface $translation */ $translation = $transUnit->getTranslations()->get($i - 1); if ($merge) { - if ($translation->isModifiedManually() || $translation->getContent() == $content) { + if ($translation->isModifiedManually() || $translation->getContent() === $content) { return null; } @@ -127,10 +126,6 @@ public function updateTranslation(TransUnitInterface $transUnit, $locale, $conte $translation->setContent($content); } - if (null !== $translation && $this->storage instanceof PropelStorage) { - $this->storage->persist($translation); - } - if ($flush) { $this->storage->flush(); } @@ -153,11 +148,8 @@ public function updateTranslationsContent(TransUnitInterface $transUnit, array $ $originalContent = $translation->getContent(); $translation = $this->updateTranslation($transUnit, $locale, $content); - $contentUpdated = ($translation->getContent() != $originalContent); + $contentUpdated = ($translation->getContent() !== $originalContent); - if ($this->storage instanceof PropelStorage) { - $this->storage->persist($transUnit); - } } else { //We need to get a proper file for this translation $file = $this->getTranslationFile($transUnit, $locale); @@ -178,7 +170,7 @@ public function updateTranslationsContent(TransUnitInterface $transUnit, array $ /** * Get the proper File for this TransUnit and locale */ - public function getTranslationFile(TransUnitInterface &$transUnit, string $locale) + public function getTranslationFile(TransUnitInterface $transUnit, string $locale) { $file = null; foreach ($transUnit->getTranslations() as $translation) { @@ -197,10 +189,7 @@ public function getTranslationFile(TransUnitInterface &$transUnit, string $local return $file; } - /** - * @return bool - */ - public function delete(TransUnitInterface $transUnit) + public function delete(TransUnitInterface $transUnit): bool { try { $this->storage->remove($transUnit); @@ -213,11 +202,7 @@ public function delete(TransUnitInterface $transUnit) } } - /** - * @param string $locale - * @return bool - */ - public function deleteTranslation(TransUnitInterface $transUnit, $locale) + public function deleteTranslation(TransUnitInterface $transUnit, string $locale): bool { try { $translation = $transUnit->getTranslation($locale); diff --git a/Manager/TransUnitManagerInterface.php b/Manager/TransUnitManagerInterface.php index ca6f8b95..8e4d88ae 100644 --- a/Manager/TransUnitManagerInterface.php +++ b/Manager/TransUnitManagerInterface.php @@ -48,12 +48,15 @@ public function addTranslation(TransUnitInterface $transUnit, $locale, $content, * @param boolean $merge * @return TranslationInterface */ - public function updateTranslation(TransUnitInterface $transUnit, $locale, $content, $flush = false, bool $merge = false): ?TranslationInterface; + public function updateTranslation(TransUnitInterface $transUnit, string $locale, $content, bool $flush = false, bool $merge = false): ?TranslationInterface; /** - * Update the content of each translations for the given trans unit. - * - * @param boolean $flush + * Update the content of each translation for the given trans unit. */ public function updateTranslationsContent(TransUnitInterface $transUnit, array $translations, bool $flush = false): void; + + public function delete(TransUnitInterface $transUnit): bool; + + public function deleteTranslation(TransUnitInterface $transUnit, string $locale): bool; + } diff --git a/Model/File.php b/Model/File.php index 9dbca1b8..24d2ea4b 100644 --- a/Model/File.php +++ b/Model/File.php @@ -6,6 +6,7 @@ use Doctrine\Common\Collections\Collection; use Doctrine\DBAL\Types\Types; use Doctrine\ORM\Mapping as ORM; +use Lexik\Bundle\TranslationBundle\Manager\FileInterface; use Symfony\Component\Validator\Constraints as Assert; /** @@ -14,7 +15,7 @@ * @author Cédric Girard */ #[ORM\MappedSuperclass] -abstract class File +abstract class File implements FileInterface { protected $id; diff --git a/Model/TransUnit.php b/Model/TransUnit.php index 3d6ba81f..d0704d5c 100644 --- a/Model/TransUnit.php +++ b/Model/TransUnit.php @@ -34,9 +34,9 @@ abstract class TransUnit protected string $domain; /** - * @var \Doctrine\Common\Collections\Collection + * @var Collection */ - protected $translations; + protected Collection $translations; #[ORM\Column(name: 'created_at', type: Types::DATETIME_MUTABLE, nullable: true)] protected DateTime|string $createdAt; @@ -105,8 +105,6 @@ public function getDomain(): string /** * Add translations - * - * @param Translation $translations */ public function addTranslation(DocumentTranslation|Translation $translation): void { @@ -115,8 +113,6 @@ public function addTranslation(DocumentTranslation|Translation $translation): vo /** * Remove translations - * - * @param Translation $translations */ public function removeTranslation(DocumentTranslation|Translation $translation): void { @@ -125,10 +121,8 @@ public function removeTranslation(DocumentTranslation|Translation $translation): /** * Get translations - * - * @return \Doctrine\Common\Collections\Collection */ - public function getTranslations(): array|Collection + public function getTranslations(): Collection { return $this->translations; } @@ -146,13 +140,11 @@ public function hasTranslation(string $locale): bool /** * Return the content of translation for the given locale. - * - * @param string $locale */ public function getTranslation(string $locale): ?TranslationInterface { foreach ($this->getTranslations() as $translation) { - if ($translation->getLocale() == $locale) { + if ($translation->getLocale() === $locale) { return $translation; } } @@ -173,9 +165,9 @@ public function setTranslations(Collection $collection): void } /** - * Return transaltions with not blank content. + * Return translations with not blank content. * - * @return \Doctrine\Common\Collections\Collection + * @return Collection */ public function filterNotBlankTranslations(): Collection { diff --git a/Model/Translation.php b/Model/Translation.php index bd529f32..2b2cbbaa 100644 --- a/Model/Translation.php +++ b/Model/Translation.php @@ -5,6 +5,7 @@ use Doctrine\DBAL\Types\Types; use Doctrine\ORM\Mapping as ORM; use DateTime; +use Lexik\Bundle\TranslationBundle\Manager\FileInterface; use Symfony\Component\Validator\Constraints as Assert; /** @@ -17,7 +18,7 @@ abstract class Translation { #[ORM\Column(name: 'locale', type: Types::STRING, length: 10)] #[Assert\NotBlank] - protected $locale; + protected string $locale; #[ORM\Column(name: 'content', type: Types::TEXT, nullable: true)] #[Assert\NotBlank(groups: ['contentNotBlank'])] @@ -29,18 +30,15 @@ abstract class Translation #[ORM\Column(name: 'updated_at', type: Types::DATETIME_MUTABLE, nullable: true)] protected $updatedAt; - /** - * @var boolean - */ #[ORM\Column(name: 'modified_manually', type: Types::BOOLEAN, nullable: true)] - protected $modifiedManually = false; + protected bool $modifiedManually = false; + + protected FileInterface $file; /** * Set locale - * - * @param string $locale */ - public function setLocale($locale) + public function setLocale(string $locale): void { $this->locale = $locale; $this->content = ''; @@ -48,10 +46,8 @@ public function setLocale($locale) /** * Get locale - * - * @return string */ - public function getLocale() + public function getLocale(): string { return $this->locale; } @@ -97,19 +93,23 @@ public function getUpdatedAt() return $this->updatedAt; } - /** - * @return bool - */ - public function isModifiedManually() + public function isModifiedManually(): bool { return $this->modifiedManually; } - /** - * @param bool $modifiedManually - */ - public function setModifiedManually($modifiedManually) + public function setModifiedManually(bool $modifiedManually): void { $this->modifiedManually = $modifiedManually; } + + public function setFile(FileInterface $file): void + { + $this->file = $file; + } + + public function getFile(): FileInterface + { + return $this->file; + } } diff --git a/Storage/AbstractDoctrineStorage.php b/Storage/AbstractDoctrineStorage.php index 73c32ad4..66a1e457 100644 --- a/Storage/AbstractDoctrineStorage.php +++ b/Storage/AbstractDoctrineStorage.php @@ -8,6 +8,7 @@ use Lexik\Bundle\TranslationBundle\Entity\TransUnitRepository; use Lexik\Bundle\TranslationBundle\Entity\FileRepository; use Lexik\Bundle\TranslationBundle\Document\FileRepository as DocumentFileRepository; +use Lexik\Bundle\TranslationBundle\Document\TransUnitRepository as DocumentTransUnitRepository; /** * Common doctrine storage logic. @@ -30,22 +31,24 @@ protected function getManager(): ObjectManager /** * Returns the TransUnit repository. - * - * @return object */ - protected function getTransUnitRepository(): TransUnitRepository + protected function getTransUnitRepository(): TransUnitRepository|DocumentTransUnitRepository { - return $this->getManager()->getRepository($this->classes['trans_unit']); + /** @var TransUnitRepository|DocumentTransUnitRepository $repository */ + $repository = $this->getManager()->getRepository($this->classes['trans_unit']); + + return $repository; } /** * Returns the File repository. - * - * @return object */ protected function getFileRepository(): FileRepository|DocumentFileRepository { - return $this->getManager()->getRepository($this->classes['file']); + /** @var FileRepository|DocumentFileRepository $repository */ + $repository = $this->getManager()->getRepository($this->classes['file']); + + return $repository; } /** @@ -75,9 +78,9 @@ public function flush($entity = null): void /** * {@inheritdoc} */ - public function clear($entityName = null): void + public function clear(): void { - $this->getManager()->clear($entityName); + $this->getManager()->clear(); } /** @@ -121,15 +124,11 @@ public function getTransUnitDomains(): mixed */ public function getTransUnitById($id): ?TransUnitInterface { - return $this->getTransUnitRepository()->findOneById($id); + return $this->getTransUnitRepository()->find($id); } /** * Returns a TransUnit by its key and domain. - * - * @param string $key - * @param string $domain - * @return TransUnitInterface */ public function getTransUnitByKeyAndDomain(string $key, string $domain): ?TransUnitInterface { @@ -146,7 +145,7 @@ public function getTransUnitByKeyAndDomain(string $key, string $domain): ?TransU /** * {@inheritdoc} */ - public function getTransUnitDomainsByLocale() + public function getTransUnitDomainsByLocale(): array { return $this->getTransUnitRepository()->getAllDomainsByLocale(); } diff --git a/Storage/DoctrineORMStorage.php b/Storage/DoctrineORMStorage.php index 038d467b..d30c2182 100644 --- a/Storage/DoctrineORMStorage.php +++ b/Storage/DoctrineORMStorage.php @@ -2,11 +2,6 @@ namespace Lexik\Bundle\TranslationBundle\Storage; -use Doctrine\DBAL\DriverManager; -use Doctrine\DBAL\Driver\PDO\SQLite\Driver as SQLiteDriver; -use Doctrine\DBAL\Exception\ConnectionException; -use Doctrine\DBAL\Schema\DefaultSchemaManagerFactory; -use Doctrine\ORM\Configuration; use Doctrine\ORM\EntityManager; use DateTime; @@ -19,58 +14,22 @@ class DoctrineORMStorage extends AbstractDoctrineStorage { /** * Returns true if translation tables exist. - * - * @return boolean */ - public function translationsTablesExist() + public function translationsTablesExist(): bool { /** @var EntityManager $em */ $em = $this->getManager(); - $connection = $em->getConnection(); - - // listDatabases() is not available for SQLite - if (!$connection->getDriver() instanceof SQLiteDriver) { - // init a tmp connection without dbname/path/url in case it does not exist yet - $params = $connection->getParams(); - if (isset($params['master'])) { - $params = $params['master']; - } - - unset($params['dbname'], $params['path'], $params['url']); - - try { - $configuration = new Configuration(); - if (class_exists(DefaultSchemaManagerFactory::class)) { - $configuration->setSchemaManagerFactory(new DefaultSchemaManagerFactory()); - } - $tmpConnection = DriverManager::getConnection($params, $configuration); - $schemaManager = method_exists($tmpConnection, 'createSchemaManager') - ? $tmpConnection->createSchemaManager() - : $tmpConnection->getSchemaManager(); + try { + $tables = [ + $em->getClassMetadata($this->getModelClass('trans_unit'))->getTableName(), + $em->getClassMetadata($this->getModelClass('translation'))->getTableName(), + ]; - $dbExists = in_array($connection->getDatabase(), $schemaManager->listDatabases()); - $tmpConnection->close(); - } catch (ConnectionException|\Exception) { - $dbExists = false; - } - - if (!$dbExists) { - return false; - } + return $em->getConnection()->createSchemaManager()->tablesExist($tables); + } catch (\Exception) { + return false; } - - // checks tables exist - $tables = [ - $em->getClassMetadata($this->getModelClass('trans_unit'))->getTableName(), - $em->getClassMetadata($this->getModelClass('translation'))->getTableName(), - ]; - - $schemaManager = method_exists($connection, 'createSchemaManager') - ? $connection->createSchemaManager() - : $connection->getSchemaManager(); - - return $schemaManager->tablesExist($tables); } /** diff --git a/Storage/Listener/DoctrineORMListener.php b/Storage/Listener/DoctrineORMListener.php index a18ab6f3..c95052b0 100644 --- a/Storage/Listener/DoctrineORMListener.php +++ b/Storage/Listener/DoctrineORMListener.php @@ -3,11 +3,11 @@ namespace Lexik\Bundle\TranslationBundle\Storage\Listener; use Doctrine\ORM\Event\LoadClassMetadataEventArgs; -use Doctrine\ORM\Mapping\ClassMetadataInfo; +use Doctrine\ORM\Mapping\ClassMetadata; class DoctrineORMListener { - public function loadClassMetadata(LoadClassMetadataEventArgs $eventArgs) + public function loadClassMetadata(LoadClassMetadataEventArgs $eventArgs): void { $params = $eventArgs->getEntityManager()->getConnection()->getParams(); @@ -15,10 +15,10 @@ public function loadClassMetadata(LoadClassMetadataEventArgs $eventArgs) return; } - /** @var ClassMetadataInfo $metadata */ + /** @var ClassMetadata $metadata */ $metadata = $eventArgs->getClassMetadata(); - if (!str_contains((string) $metadata->getName(), 'TranslationBundle')) { + if (!str_contains($metadata->getName(), 'TranslationBundle')) { return; } diff --git a/Storage/StorageInterface.php b/Storage/StorageInterface.php index dcd5ee53..411658df 100644 --- a/Storage/StorageInterface.php +++ b/Storage/StorageInterface.php @@ -42,10 +42,8 @@ public function flush($entity = null); /** * Clear managed objects. - * - * @param string $entityName */ - public function clear($entityName = null); + public function clear(): void; /** * Returns the class's namespace according to the given name. diff --git a/Tests/Command/ImportTranslationsCommandTest.php b/Tests/Command/ImportTranslationsCommandTest.php index 24e46e4c..6d90b4ee 100644 --- a/Tests/Command/ImportTranslationsCommandTest.php +++ b/Tests/Command/ImportTranslationsCommandTest.php @@ -88,7 +88,9 @@ public function testExecute() command: new ImportTranslationsCommand( translator: $container->get('lexik_translation.translator'), localeManager: $container->get(LocaleManagerInterface::class), - fileImporter: $container->get('lexik_translation.importer.file') + fileImporter: $container->get('lexik_translation.importer.file'), + kernel: static::$kernel, + projectDir: $container->getParameter('kernel.project_dir') ) ); diff --git a/Tests/Unit/Repository/Document/TransUnitRepositoryTest.php b/Tests/Unit/Repository/Document/TransUnitRepositoryTest.php index 0b37f883..5088b83d 100644 --- a/Tests/Unit/Repository/Document/TransUnitRepositoryTest.php +++ b/Tests/Unit/Repository/Document/TransUnitRepositoryTest.php @@ -93,16 +93,16 @@ public function testCount() $dm = $this->loadDatabase(); $repository = $dm->getRepository(self::DOCUMENT_TRANS_UNIT_CLASS); - $this->assertEquals(3, $repository->count(null, [])); - $this->assertEquals(3, $repository->count(['fr', 'de', 'en'], [])); - $this->assertEquals(3, $repository->count(['fr', 'it'], [])); - $this->assertEquals(3, $repository->count(['fr', 'de'], ['_search' => false, 'key' => 'good'])); - $this->assertEquals(1, $repository->count(['fr', 'de'], ['_search' => true, 'key' => 'good'])); - $this->assertEquals(1, $repository->count(['en', 'de'], ['_search' => true, 'domain' => 'super'])); + $this->assertEquals(3, $repository->count(['locales' => null, 'filters' => []])); + $this->assertEquals(3, $repository->count(['locales' => ['fr', 'de', 'en'], 'filters' => []])); + $this->assertEquals(3, $repository->count(['locales' => ['fr', 'it'], 'filters' => []])); + $this->assertEquals(3, $repository->count(['locales' => ['fr', 'de'], 'filters' => ['_search' => false, 'key' => 'good']])); + $this->assertEquals(1, $repository->count(['locales' => ['fr', 'de'], 'filters' => ['_search' => true, 'key' => 'good']])); + $this->assertEquals(1, $repository->count(['locales' => ['en', 'de'], 'filters' => ['_search' => true, 'domain' => 'super']])); $this->assertEquals(1, - $repository->count(['en', 'fr', 'de'], ['_search' => true, 'key' => 'hel', 'domain' => 'uper'])); + $repository->count(['locales' => ['en', 'fr', 'de'], 'filters' => ['_search' => true, 'key' => 'hel', 'domain' => 'uper']])); $this->assertEquals(2, - $repository->count(['en', 'de'], ['_search' => true, 'key' => 'say', 'domain' => 'ssa'])); + $repository->count(['locales' => ['en', 'de'], 'filters' => ['_search' => true, 'key' => 'say', 'domain' => 'ssa']])); } /** diff --git a/Translation/Exporter/ExporterInterface.php b/Translation/Exporter/ExporterInterface.php index bbf5479e..991bdaab 100644 --- a/Translation/Exporter/ExporterInterface.php +++ b/Translation/Exporter/ExporterInterface.php @@ -11,18 +11,11 @@ interface ExporterInterface { /** * Export translations in to the given file. - * - * @param string $file - * @param array $translations - * @return boolean */ - public function export($file, $translations); + public function export(string $file, array $translations): bool; /** * Returns true if this exporter support the given format. - * - * @param string $format - * @return boolean */ - public function support($format); + public function support(string $format): bool; } diff --git a/Translation/Exporter/JsonExporter.php b/Translation/Exporter/JsonExporter.php index 54630aae..03882bfc 100644 --- a/Translation/Exporter/JsonExporter.php +++ b/Translation/Exporter/JsonExporter.php @@ -20,7 +20,7 @@ public function __construct( /** * {@inheritdoc} */ - public function export($file, $translations) + public function export(string $file, array $translations): bool { $bytes = file_put_contents($file, json_encode($this->hierarchicalFormat ? $this->hierarchicalFormat($translations) : $translations, JSON_PRETTY_PRINT)); @@ -30,9 +30,9 @@ public function export($file, $translations) /** * {@inheritdoc} */ - public function support($format) + public function support(string $format): bool { - return ('json' == $format); + return ('json' === $format); } /** diff --git a/Translation/Exporter/PhpExporter.php b/Translation/Exporter/PhpExporter.php index 89140636..f9ba8e8b 100644 --- a/Translation/Exporter/PhpExporter.php +++ b/Translation/Exporter/PhpExporter.php @@ -12,7 +12,7 @@ class PhpExporter implements ExporterInterface /** * {@inheritdoc} */ - public function export($file, $translations) + public function export(string $file, array $translations): bool { $phpContent = sprintf("createXmlDocument(); @@ -39,9 +39,9 @@ public function export($file, $translations) /** * {@inheritdoc} */ - public function support($format) + public function support(string $format): bool { - return ('xlf' == $format || 'xliff' == $format); + return ('xlf' === $format || 'xliff' === $format); } /** @@ -49,7 +49,7 @@ public function support($format) * * @return \DOMDocument */ - protected function createXmlDocument() + protected function createXmlDocument(): \DOMDocument { $dom = new \DOMDocument('1.0', 'utf-8'); $dom->formatOutput = true; @@ -59,11 +59,9 @@ protected function createXmlDocument() /** * Add root nodes to a document. - * - * @param string|null $targetLanguage - * @return \DOMElement + * @throws \DOMException */ - protected function addRootNodes(\DOMDocument $dom, $targetLanguage = null) + protected function addRootNodes(\DOMDocument $dom, ?string $targetLanguage = null): \DOMElement { $xliff = $dom->appendChild($dom->createElement('xliff')); $xliff->appendChild(new \DOMAttr('xmlns', 'urn:oasis:names:tc:xliff:document:1.2')); @@ -78,28 +76,26 @@ protected function addRootNodes(\DOMDocument $dom, $targetLanguage = null) $fileNode->appendChild(new \DOMAttr('target-language', $targetLanguage)); } - $bodyNode = $fileNode->appendChild($dom->createElement('body')); + $body = $dom->createElement('body'); + $fileNode->appendChild($body); - return $bodyNode; + return $body; } /** * Create a new trans-unit node. * - * @param int $id - * @param string $key - * @param string $value - * @return \DOMElement + * @throws \DOMException */ - protected function createTranslationNode(\DOMDocument $dom, $id, $key, $value) + protected function createTranslationNode(\DOMDocument $dom, int $id, string $key, string $value): \DOMElement { $translationNode = $dom->createElement('trans-unit'); - $translationNode->appendChild(new \DOMAttr('id', $id)); + $translationNode->appendChild(new \DOMAttr('id', (string) $id)); /** * @see http://docs.oasis-open.org/xliff/v1.2/os/xliff-core.html#approved */ - if ($value != '') { + if ($value !== '') { $translationNode->appendChild(new \DOMAttr('approved', 'yes')); } diff --git a/Translation/Exporter/YamlExporter.php b/Translation/Exporter/YamlExporter.php index 59beb1b1..c369c908 100644 --- a/Translation/Exporter/YamlExporter.php +++ b/Translation/Exporter/YamlExporter.php @@ -20,7 +20,7 @@ public function __construct( /** * {@inheritdoc} */ - public function export($file, $translations) + public function export(string $file, array $translations): bool { if ($this->createTree) { $result = $this->createMultiArray($translations); @@ -122,8 +122,8 @@ protected function flattenArray($array, $prefix = '') /** * {@inheritdoc} */ - public function support($format) + public function support(string $format): bool { - return ('yml' == $format || 'yaml' == $format); + return ('yml' === $format || 'yaml' === $format); } } diff --git a/Translation/Importer/FileImporter.php b/Translation/Importer/FileImporter.php index 46019e65..775e55af 100644 --- a/Translation/Importer/FileImporter.php +++ b/Translation/Importer/FileImporter.php @@ -123,10 +123,7 @@ public function import(SplFileInfo $file, $forceUpdate = false, $merge = false) $this->storage->flush(); - // clear only Lexik entities - foreach (['file', 'trans_unit', 'translation'] as $name) { - $this->storage->clear($this->storage->getModelClass($name)); - } + $this->storage->clear(); return $imported; } diff --git a/Util/DataGrid/DataGridFormatter.php b/Util/DataGrid/DataGridFormatter.php index 95b6ee6b..0f530125 100644 --- a/Util/DataGrid/DataGridFormatter.php +++ b/Util/DataGrid/DataGridFormatter.php @@ -12,44 +12,32 @@ */ class DataGridFormatter { - /** - * Constructor. - * - * @param string $storage - */ - public function __construct(protected LocaleManagerInterface $localeManager, protected $storage) - { + public function __construct( + protected LocaleManagerInterface $localeManager, + protected string $storage + ) { } /** * Returns a JSON response with formatted data. - * - * @param array $transUnits - * @param integer $total - * @return \Symfony\Component\HttpFoundation\JsonResponse */ - public function createListResponse($transUnits, $total) + public function createListResponse(array $transUnits, int $total): JsonResponse { return new JsonResponse(['translations' => $this->format($transUnits), 'total' => $total]); } /** * Returns a JSON response with formatted data. - * - * @return \Symfony\Component\HttpFoundation\JsonResponse */ - public function createSingleResponse(mixed $transUnit) + public function createSingleResponse(mixed $transUnit): JsonResponse { return new JsonResponse($this->formatOne($transUnit)); } /** - * Format the tanslations list. - * - * @param array $transUnits - * @return array + * Format the translations list. */ - protected function format($transUnits) + protected function format(array $transUnits): array { $formatted = []; @@ -62,19 +50,20 @@ protected function format($transUnits) /** * Format a single TransUnit. - * - * @param array $transUnit - * @return array */ - protected function formatOne($transUnit) + protected function formatOne(TransUnitInterface|array $transUnit): array { if (is_object($transUnit)) { $transUnit = $this->toArray($transUnit); - } elseif (StorageInterface::STORAGE_MONGODB == $this->storage) { + } elseif (StorageInterface::STORAGE_MONGODB === $this->storage) { $transUnit['id'] = $transUnit['_id']->{'$id'}; } - $formatted = ['_id' => $transUnit['id'], '_domain' => $transUnit['domain'], '_key' => $transUnit['key']]; + $formatted = [ + '_id' => $transUnit['id'], + '_domain' => $transUnit['domain'], + '_key' => $transUnit['key'], + ]; // add locales in the same order as in managed_locales param foreach ($this->localeManager->getLocales() as $locale) { @@ -83,7 +72,7 @@ protected function formatOne($transUnit) // then fill locales value foreach ($transUnit['translations'] as $translation) { - if (in_array($translation['locale'], $this->localeManager->getLocales())) { + if (in_array($translation['locale'], $this->localeManager->getLocales(), true)) { $formatted[$translation['locale']] = $translation['content']; } } @@ -93,12 +82,15 @@ protected function formatOne($transUnit) /** * Convert a trans unit into an array. - * - * @return array */ - protected function toArray(TransUnitInterface $transUnit) + protected function toArray(TransUnitInterface $transUnit): array { - $data = ['id' => $transUnit->getId(), 'domain' => $transUnit->getDomain(), 'key' => $transUnit->getKey(), 'translations' => []]; + $data = [ + 'id' => $transUnit->getId(), + 'domain' => $transUnit->getDomain(), + 'key' => $transUnit->getKey(), + 'translations' => [], + ]; foreach ($transUnit->getTranslations() as $translation) { $data['translations'][] = ['locale' => $translation->getLocale(), 'content' => $translation->getContent()]; diff --git a/Util/DataGrid/DataGridRequestHandler.php b/Util/DataGrid/DataGridRequestHandler.php index 05a536fc..315e78b6 100644 --- a/Util/DataGrid/DataGridRequestHandler.php +++ b/Util/DataGrid/DataGridRequestHandler.php @@ -5,6 +5,7 @@ use Lexik\Bundle\TranslationBundle\Manager\FileManagerInterface; use Lexik\Bundle\TranslationBundle\Manager\LocaleManagerInterface; use Lexik\Bundle\TranslationBundle\Document\TransUnit as TransUnitDocument; +use Lexik\Bundle\TranslationBundle\Manager\TransUnitInterface; use Lexik\Bundle\TranslationBundle\Manager\TransUnitManagerInterface; use Lexik\Bundle\TranslationBundle\Model\TransUnit; use Lexik\Bundle\TranslationBundle\Storage\StorageInterface; @@ -152,12 +153,8 @@ public function getByToken($token) /** * Updates a trans unit from the request. - * - * @param integer $id - * @throws NotFoundHttpException - * @return \Lexik\Bundle\TranslationBundle\Model\TransUnit */ - public function updateFromRequest($id, Request $request) + public function updateFromRequest(int $id, Request $request): TransUnitInterface { $transUnit = $this->storage->getTransUnitById($id); From c9d5f6def855ba080d7b8e9a36ffef7e3af5edde Mon Sep 17 00:00:00 2001 From: Denis Date: Sun, 15 Mar 2026 18:06:11 +0100 Subject: [PATCH 03/12] Fix composer dependencies to enable Symfony 8 installation --- .gitignore | 1 + .../Command/ImportTranslationsCommandTest.php | 19 +++---------------- composer.json | 5 ++--- 3 files changed, 6 insertions(+), 19 deletions(-) diff --git a/.gitignore b/.gitignore index 4cdb362b..7756f250 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,6 @@ # Composer dependencies (installed with composer install) vendor +composer.lock # PhpStorm IDE configuration and cache .idea diff --git a/Tests/Command/ImportTranslationsCommandTest.php b/Tests/Command/ImportTranslationsCommandTest.php index 6d90b4ee..62e18dad 100644 --- a/Tests/Command/ImportTranslationsCommandTest.php +++ b/Tests/Command/ImportTranslationsCommandTest.php @@ -6,13 +6,11 @@ use Doctrine\ORM\EntityManager; use Doctrine\ORM\Tools\Console\Command\SchemaTool\CreateCommand; use Doctrine\ORM\Tools\Console\Command\SchemaTool\DropCommand; -use Lexik\Bundle\TranslationBundle\Manager\LocaleManagerInterface; use Symfony\Bundle\FrameworkBundle\Test\WebTestCase; use Symfony\Bundle\FrameworkBundle\Console\Application; use Symfony\Component\Console\Input\ArrayInput; use Symfony\Component\Console\Output\NullOutput; use Symfony\Component\Console\Tester\CommandTester; -use Lexik\Bundle\TranslationBundle\Command\ImportTranslationsCommand; /** * Test the translations import command, with option and arguments @@ -48,8 +46,8 @@ public function setUp(): void */ private static function addDoctrineCommands(DropCommand $dropCommand, CreateCommand $createCommand) { - static::$application->add($dropCommand); - static::$application->add($createCommand); + static::$application->addCommand($dropCommand); + static::$application->addCommand($createCommand); } /** @@ -81,19 +79,8 @@ private static function runCommand($commandName, $options = []) * * @group command */ - public function testExecute() + public function testExecute(): void { - $container = self::$kernel->getContainer(); - static::$application->add( - command: new ImportTranslationsCommand( - translator: $container->get('lexik_translation.translator'), - localeManager: $container->get(LocaleManagerInterface::class), - fileImporter: $container->get('lexik_translation.importer.file'), - kernel: static::$kernel, - projectDir: $container->getParameter('kernel.project_dir') - ) - ); - $command = static::$application->find("lexik:translations:import"); $commandTester = new CommandTester($command); diff --git a/composer.json b/composer.json index 766aee90..b8aa5253 100644 --- a/composer.json +++ b/composer.json @@ -22,7 +22,7 @@ } ], "require": { - "php": "^8.1|^8.2|^8.3|^8.4", + "php": "^8.2|^8.3|^8.4", "doctrine/orm": "^3", "monolog/monolog": "^3.2", "symfony/asset": "^7.0|^8.0", @@ -41,7 +41,7 @@ "doctrine/annotations": "^2", "doctrine/cache": "^1.4|^2.0", "doctrine/data-fixtures": "^1.1|^2.0", - "doctrine/doctrine-bundle": "^2.2", + "doctrine/doctrine-bundle": "^2.2 || ^3.0", "doctrine/mongodb-odm": "^2.7", "doctrine/mongodb-odm-bundle": "^5.0", "friendsofphp/php-cs-fixer": "^3.64", @@ -73,7 +73,6 @@ }, "config": { "platform": { - "php": "8.2.0", "ext-mongodb": "2.1.4" }, "sort-packages": true From ad05f589b2d4f9c6d4ef13a0375a19288df527f2 Mon Sep 17 00:00:00 2001 From: Denis Date: Sun, 15 Mar 2026 18:32:20 +0100 Subject: [PATCH 04/12] CS Fixer --- Command/ExportTranslationsCommand.php | 19 +++++++--- Command/ImportTranslationsCommand.php | 6 +-- Controller/TranslationController.php | 22 +++++------ .../Compiler/RegisterMappingPass.php | 4 +- .../Compiler/TranslatorPass.php | 2 +- DependencyInjection/Configuration.php | 8 ++-- .../LexikTranslationExtension.php | 22 +++++------ Document/File.php | 2 +- Document/TransUnit.php | 2 +- Document/TransUnitRepository.php | 2 +- Document/Translation.php | 2 +- Entity/TransUnit.php | 5 +-- Entity/TransUnitRepository.php | 4 +- Entity/Translation.php | 6 +-- Entity/TranslationRepository.php | 2 +- .../CleanTranslationCacheListener.php | 14 +++---- Form/Handler/TransUnitFormHandler.php | 8 ++-- Form/Type/TransUnitType.php | 10 ++--- Form/Type/TranslationType.php | 4 +- Manager/FileManagerInterface.php | 1 + Manager/TransUnitManager.php | 4 +- Model/TransUnit.php | 8 ++-- Model/Translation.php | 3 +- Storage/AbstractDoctrineStorage.php | 10 ++--- Storage/DoctrineMongoDBStorage.php | 5 ++- Storage/DoctrineORMStorage.php | 2 +- Storage/StorageInterface.php | 6 +-- .../Command/ImportTranslationsCommandTest.php | 12 +++--- Tests/Fixtures/test.fr.php | 3 +- Tests/Unit/BaseUnitTestCase.php | 38 ++++++++++--------- .../CleanTranslationCacheListenerTest.php | 17 ++++----- .../Document/FileRepositoryTest.php | 2 +- .../Document/TransUnitRepositoryTest.php | 36 +++++++++++++----- .../Repository/Entity/FileRepositoryTest.php | 2 +- .../Entity/TransUnitRepositoryTest.php | 10 ++--- .../Translation/Exporter/JsonExporterTest.php | 6 +-- .../Translation/Exporter/PhpExporterTest.php | 8 ++-- .../Translation/Exporter/YamlExporterTest.php | 18 ++++----- .../Translation/Importer/FileImporterTest.php | 8 ++-- .../Translation/Loader/DatabaseLoaderTest.php | 4 +- .../Manager/TransUnitManagerTest.php | 2 +- Tests/Unit/Translation/TranslatorTest.php | 28 +++++++------- .../Util/DataGrid/DataGridFormatterTest.php | 4 +- .../DataGrid/DataGridRequestHandlerTest.php | 5 +-- Tests/app/test/database.php | 2 +- Tests/bootstrap.php | 5 ++- Translation/DatabaseFreshResource.php | 1 - Translation/Exporter/XliffExporter.php | 2 +- Translation/Importer/FileImporter.php | 10 ++--- Translation/Translator.php | 8 ++-- Util/Csrf/CsrfCheckerTrait.php | 2 +- Util/DataGrid/DataGridFormatter.php | 16 ++++---- Util/DataGrid/DataGridRequestHandler.php | 4 +- Util/Overview/StatsAggregator.php | 4 +- 54 files changed, 232 insertions(+), 208 deletions(-) diff --git a/Command/ExportTranslationsCommand.php b/Command/ExportTranslationsCommand.php index 68edf8dc..6fe186d1 100644 --- a/Command/ExportTranslationsCommand.php +++ b/Command/ExportTranslationsCommand.php @@ -5,7 +5,6 @@ use Lexik\Bundle\TranslationBundle\Manager\FileInterface; use Lexik\Bundle\TranslationBundle\Storage\StorageInterface; use Lexik\Bundle\TranslationBundle\Translation\Exporter\ExporterCollector; -use Lexik\Bundle\TranslationBundle\Translation\Translator; use Symfony\Component\Console\Attribute\AsCommand; use Symfony\Component\Console\Command\Command; use Symfony\Component\Console\Input\InputInterface; @@ -58,16 +57,24 @@ protected function configure(): void { $this->addOption( - 'locales', 'l', InputOption::VALUE_OPTIONAL, - 'Only export files for given locales. e.g. "--locales=en,de"', null + 'locales', + 'l', + InputOption::VALUE_OPTIONAL, + 'Only export files for given locales. e.g. "--locales=en,de"', + null ); $this->addOption( - 'domains', 'd', InputOption::VALUE_OPTIONAL, - 'Only export files for given domains. e.g. "--domains=messages,validators"', null + 'domains', + 'd', + InputOption::VALUE_OPTIONAL, + 'Only export files for given domains. e.g. "--domains=messages,validators"', + null ); $this->addOption('format', 'f', InputOption::VALUE_OPTIONAL, 'Force the output format.', null); $this->addOption( - 'override', 'o', InputOption::VALUE_NONE, + 'override', + 'o', + InputOption::VALUE_NONE, 'Only export modified phrases (app/Resources/translations are exported fully anyway)' ); $this->addOption('export-path', 'p', InputOption::VALUE_REQUIRED, 'Export files to given path.'); diff --git a/Command/ImportTranslationsCommand.php b/Command/ImportTranslationsCommand.php index 676efdca..ce216d4b 100644 --- a/Command/ImportTranslationsCommand.php +++ b/Command/ImportTranslationsCommand.php @@ -182,8 +182,8 @@ protected function importTranslationFilesFromPath($path, array $locales, array $ protected function importComponentTranslationFiles(array $locales, array $domains) { $classes = [ - Validation::class => '/Resources/translations', - Form::class => '/Resources/translations', + Validation::class => '/Resources/translations', + Form::class => '/Resources/translations', AuthenticationException::class => '/../Resources/translations', ]; @@ -249,7 +249,7 @@ protected function importBundleTranslationFiles(BundleInterface $bundle, array $ $bundle->getPath() . '/Resources/translations', ]; - foreach($paths as $path) { + foreach ($paths as $path) { $this->output->writeln(sprintf('# %s:', $bundle->getName())); $finder = $this->findTranslationsFiles($path, $locales, $domains, false); $this->importTranslationFiles($finder); diff --git a/Controller/TranslationController.php b/Controller/TranslationController.php index bd08f26e..5993b25c 100644 --- a/Controller/TranslationController.php +++ b/Controller/TranslationController.php @@ -41,11 +41,11 @@ public function overviewAction(): Response $stats = $this->statsAggregator->getStats(); return $this->render('@LexikTranslation/Translation/overview.html.twig', [ - 'layout' => $this->getParameter('lexik_translation.base_layout'), - 'locales' => $this->getManagedLocales(), - 'domains' => $this->translationStorage->getTransUnitDomains(), - 'latestTrans' => $this->translationStorage->getLatestUpdatedAt(), - 'stats' => $stats, + 'layout' => $this->getParameter('lexik_translation.base_layout'), + 'locales' => $this->getManagedLocales(), + 'domains' => $this->translationStorage->getTransUnitDomains(), + 'latestTrans' => $this->translationStorage->getLatestUpdatedAt(), + 'stats' => $stats, ]); } @@ -60,12 +60,12 @@ public function gridAction(): Response } return $this->render('@LexikTranslation/Translation/grid.html.twig', [ - 'layout' => $this->getParameter('lexik_translation.base_layout'), - 'inputType' => $this->getParameter('lexik_translation.grid_input_type'), + 'layout' => $this->getParameter('lexik_translation.base_layout'), + 'inputType' => $this->getParameter('lexik_translation.grid_input_type'), 'autoCacheClean' => $this->getParameter('lexik_translation.auto_cache_clean'), - 'toggleSimilar' => $this->getParameter('lexik_translation.grid_toggle_similar'), - 'locales' => $this->getManagedLocales(), - 'tokens' => $tokens, + 'toggleSimilar' => $this->getParameter('lexik_translation.grid_toggle_similar'), + 'locales' => $this->getManagedLocales(), + 'tokens' => $tokens, ]); } @@ -110,7 +110,7 @@ public function newAction(Request $request): Response return $this->redirect($this->generateUrl($redirectUrl)); } - return $this->render('@LexikTranslation/Translation/new.html.twig', ['layout' => $this->getParameter('lexik_translation.base_layout'), 'form' => $form->createView()]); + return $this->render('@LexikTranslation/Translation/new.html.twig', ['layout' => $this->getParameter('lexik_translation.base_layout'), 'form' => $form->createView()]); } /** diff --git a/DependencyInjection/Compiler/RegisterMappingPass.php b/DependencyInjection/Compiler/RegisterMappingPass.php index 7bdbc892..ac183d75 100644 --- a/DependencyInjection/Compiler/RegisterMappingPass.php +++ b/DependencyInjection/Compiler/RegisterMappingPass.php @@ -5,10 +5,10 @@ use Doctrine\ORM\Mapping\Driver\AttributeDriver; use Doctrine\ORM\Mapping\Driver\SimplifiedXmlDriver; use Lexik\Bundle\TranslationBundle\Storage\StorageInterface; +use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface; use Symfony\Component\DependencyInjection\ContainerBuilder; use Symfony\Component\DependencyInjection\Definition; use Symfony\Component\DependencyInjection\Reference; -use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface; /** * Doctrine metadata pass to add a driver to load model class mapping. @@ -26,7 +26,7 @@ public function process(ContainerBuilder $container): void $name = empty($storage['object_manager']) ? 'default' : $storage['object_manager']; - $ormDriverId = sprintf('doctrine.orm.%s_metadata_driver', $name); + $ormDriverId = sprintf('doctrine.orm.%s_metadata_driver', $name); $mongodbDriverId = sprintf('doctrine_mongodb.odm.%s_metadata_driver', $name); if (StorageInterface::STORAGE_ORM == $storage['type'] && $container->hasDefinition($ormDriverId)) { diff --git a/DependencyInjection/Compiler/TranslatorPass.php b/DependencyInjection/Compiler/TranslatorPass.php index 257500ea..c2e5ab5e 100644 --- a/DependencyInjection/Compiler/TranslatorPass.php +++ b/DependencyInjection/Compiler/TranslatorPass.php @@ -4,9 +4,9 @@ use Lexik\Bundle\TranslationBundle\Translation\Exporter\ExporterCollector; use Lexik\Bundle\TranslationBundle\Translation\Importer\FileImporter; +use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface; use Symfony\Component\DependencyInjection\Compiler\ServiceLocatorTagPass; use Symfony\Component\DependencyInjection\ContainerBuilder; -use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface; use Symfony\Component\DependencyInjection\Reference; /** diff --git a/DependencyInjection/Configuration.php b/DependencyInjection/Configuration.php index 30253014..f21dd3df 100644 --- a/DependencyInjection/Configuration.php +++ b/DependencyInjection/Configuration.php @@ -45,7 +45,7 @@ public function getConfigTreeBuilder(): TreeBuilder ->defaultValue([]) ->beforeNormalization() ->ifString() - ->then(fn($value) => [$value]) + ->then(fn ($value) => [$value]) ->end() ->end() @@ -60,7 +60,7 @@ public function getConfigTreeBuilder(): TreeBuilder ->defaultValue('text') ->validate() ->ifNotInArray($inputTypes) - ->thenInvalid('The input type "%s" is not supported. Please use one of the following types: '.implode(', ', $inputTypes)) + ->thenInvalid('The input type "%s" is not supported. Please use one of the following types: ' . implode(', ', $inputTypes)) ->end() ->end() @@ -84,7 +84,7 @@ public function getConfigTreeBuilder(): TreeBuilder ->defaultValue(StorageInterface::STORAGE_ORM) ->validate() ->ifNotInArray($storages) - ->thenInvalid('The storage "%s" is not supported. Please use one of the following storage: '.implode(', ', $storages)) + ->thenInvalid('The storage "%s" is not supported. Please use one of the following storage: ' . implode(', ', $storages)) ->end() ->end() ->scalarNode('object_manager') @@ -100,7 +100,7 @@ public function getConfigTreeBuilder(): TreeBuilder ->defaultValue('all') ->validate() ->ifNotInArray($registrationTypes) - ->thenInvalid('Invalid registration type "%s". Please use one of the following types: '.implode(', ', $registrationTypes)) + ->thenInvalid('Invalid registration type "%s". Please use one of the following types: ' . implode(', ', $registrationTypes)) ->end() ->end() ->booleanNode('managed_locales_only') diff --git a/DependencyInjection/LexikTranslationExtension.php b/DependencyInjection/LexikTranslationExtension.php index e4f05af8..d20b13ba 100644 --- a/DependencyInjection/LexikTranslationExtension.php +++ b/DependencyInjection/LexikTranslationExtension.php @@ -2,21 +2,21 @@ namespace Lexik\Bundle\TranslationBundle\DependencyInjection; -use Lexik\Bundle\TranslationBundle\LexikTranslationBundle; -use Symfony\Component\DependencyInjection\Loader\YamlFileLoader; use Doctrine\ORM\Events; -use Doctrine\ORM\Mapping\Driver\SimplifiedXmlDriver; use Doctrine\ORM\Mapping\Driver\AttributeDriver; +use Doctrine\ORM\Mapping\Driver\SimplifiedXmlDriver; +use Lexik\Bundle\TranslationBundle\LexikTranslationBundle; use Lexik\Bundle\TranslationBundle\Manager\LocaleManagerInterface; use Lexik\Bundle\TranslationBundle\Storage\StorageInterface; -use Symfony\Component\Config\FileLocator; use Symfony\Component\Config\Definition\Processor; +use Symfony\Component\Config\FileLocator; +use Symfony\Component\DependencyInjection\ContainerBuilder; +use Symfony\Component\DependencyInjection\Definition; use Symfony\Component\DependencyInjection\Extension\Extension; use Symfony\Component\DependencyInjection\Extension\PrependExtensionInterface; -use Symfony\Component\DependencyInjection\Reference; +use Symfony\Component\DependencyInjection\Loader\YamlFileLoader; use Symfony\Component\DependencyInjection\Parameter; -use Symfony\Component\DependencyInjection\Definition; -use Symfony\Component\DependencyInjection\ContainerBuilder; +use Symfony\Component\DependencyInjection\Reference; /** * This is the class that loads and manages your bundle configuration @@ -36,7 +36,7 @@ public function load(array $configs, ContainerBuilder $container): void $configuration = new Configuration(); $config = $processor->processConfiguration($configuration, $configs); - $loader = new YamlFileLoader($container, new FileLocator(__DIR__.'/../Resources/config')); + $loader = new YamlFileLoader($container, new FileLocator(__DIR__ . '/../Resources/config')); $loader->load('services.yaml'); // Resolve managed_locales: fallback to framework.enabled_locales if not set @@ -90,7 +90,7 @@ public function buildCacheCleanListenerDefinition(ContainerBuilder $container, $ $listener->addArgument(new Reference(LocaleManagerInterface::class)); $listener->addArgument($cacheInterval); - $listener->addTag('kernel.event_listener', ['event' => 'kernel.request', 'method' => 'onKernelRequest']); + $listener->addTag('kernel.event_listener', ['event' => 'kernel.request', 'method' => 'onKernelRequest']); $container->setDefinition('lexik_translation.listener.clean_translation_cache', $listener); } @@ -150,9 +150,9 @@ protected function buildTranslationStorageDefinition(ContainerBuilder $container } $args[] = [ - 'trans_unit' => new Parameter(sprintf('lexik_translation.%s.trans_unit.class', $storage)), + 'trans_unit' => new Parameter(sprintf('lexik_translation.%s.trans_unit.class', $storage)), 'translation' => new Parameter(sprintf('lexik_translation.%s.translation.class', $storage)), - 'file' => new Parameter(sprintf('lexik_translation.%s.file.class', $storage)) + 'file' => new Parameter(sprintf('lexik_translation.%s.file.class', $storage)) ]; $storageDefinition = new Definition(); diff --git a/Document/File.php b/Document/File.php index 2d5a602b..d57ca4a5 100644 --- a/Document/File.php +++ b/Document/File.php @@ -2,8 +2,8 @@ namespace Lexik\Bundle\TranslationBundle\Document; -use Lexik\Bundle\TranslationBundle\Model\File as FileModel; use DateTime; +use Lexik\Bundle\TranslationBundle\Model\File as FileModel; /** * @author Cédric Girard diff --git a/Document/TransUnit.php b/Document/TransUnit.php index c48d5026..bec506cc 100644 --- a/Document/TransUnit.php +++ b/Document/TransUnit.php @@ -2,8 +2,8 @@ namespace Lexik\Bundle\TranslationBundle\Document; -use Lexik\Bundle\TranslationBundle\Model\TransUnit as TransUnitModel; use Lexik\Bundle\TranslationBundle\Manager\TransUnitInterface; +use Lexik\Bundle\TranslationBundle\Model\TransUnit as TransUnitModel; /** * @author Cédric Girard diff --git a/Document/TransUnitRepository.php b/Document/TransUnitRepository.php index 4fe99747..ac7639ea 100644 --- a/Document/TransUnitRepository.php +++ b/Document/TransUnitRepository.php @@ -256,7 +256,7 @@ public function getTranslationsForFile(FileInterface $file, bool $onlyUpdated): // Handle MongoDB Timestamp objects - they have a 'sec' property $createdAt = $result['translations'][$i]['createdAt'] ?? null; $updatedAt = $result['translations'][$i]['updatedAt'] ?? null; - + if ($createdAt && $updatedAt) { $createdAtSec = \is_object($createdAt) && \property_exists($createdAt, 'sec') ? $createdAt->sec : $createdAt; $updatedAtSec = \is_object($updatedAt) && \property_exists($updatedAt, 'sec') ? $updatedAt->sec : $updatedAt; diff --git a/Document/Translation.php b/Document/Translation.php index 63862f9a..1eccc13e 100644 --- a/Document/Translation.php +++ b/Document/Translation.php @@ -3,8 +3,8 @@ namespace Lexik\Bundle\TranslationBundle\Document; use Lexik\Bundle\TranslationBundle\Manager\FileInterface; -use Lexik\Bundle\TranslationBundle\Model\Translation as TranslationModel; use Lexik\Bundle\TranslationBundle\Manager\TranslationInterface; +use Lexik\Bundle\TranslationBundle\Model\Translation as TranslationModel; /** * @author Cédric Girard diff --git a/Entity/TransUnit.php b/Entity/TransUnit.php index 4cc684b0..5b72be6b 100644 --- a/Entity/TransUnit.php +++ b/Entity/TransUnit.php @@ -2,16 +2,15 @@ namespace Lexik\Bundle\TranslationBundle\Entity; +use DateTime; use Doctrine\Common\Collections\Collection; use Doctrine\ORM\Mapping\HasLifecycleCallbacks; use Doctrine\ORM\Mapping\PrePersist; use Doctrine\ORM\Mapping\PreUpdate; -use Lexik\Bundle\TranslationBundle\Entity\Translation; +use Lexik\Bundle\TranslationBundle\Document\Translation as DocumentTranslation; use Lexik\Bundle\TranslationBundle\Manager\TransUnitInterface; use Lexik\Bundle\TranslationBundle\Model\TransUnit as TransUnitModel; -use Lexik\Bundle\TranslationBundle\Document\Translation as DocumentTranslation; use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity; -use DateTime; /** * @author Cédric Girard diff --git a/Entity/TransUnitRepository.php b/Entity/TransUnitRepository.php index 5aa79a15..d272a19d 100644 --- a/Entity/TransUnitRepository.php +++ b/Entity/TransUnitRepository.php @@ -2,10 +2,10 @@ namespace Lexik\Bundle\TranslationBundle\Entity; +use Doctrine\ORM\EntityRepository; +use Doctrine\ORM\QueryBuilder; use Lexik\Bundle\TranslationBundle\Manager\FileInterface; use Lexik\Bundle\TranslationBundle\Util\Doctrine\SingleColumnArrayHydrator; -use Doctrine\ORM\QueryBuilder; -use Doctrine\ORM\EntityRepository; /** * Repository for TransUnit entity. diff --git a/Entity/Translation.php b/Entity/Translation.php index 0b24567c..f6b9f790 100644 --- a/Entity/Translation.php +++ b/Entity/Translation.php @@ -2,15 +2,15 @@ namespace Lexik\Bundle\TranslationBundle\Entity; +use DateTime; use Doctrine\ORM\Mapping\HasLifecycleCallbacks; use Doctrine\ORM\Mapping\PrePersist; use Doctrine\ORM\Mapping\PreUpdate; use Lexik\Bundle\TranslationBundle\Manager\FileInterface; use Lexik\Bundle\TranslationBundle\Manager\TranslationInterface; -use Lexik\Bundle\TranslationBundle\Model\TransUnit; use Lexik\Bundle\TranslationBundle\Model\Translation as TranslationModel; +use Lexik\Bundle\TranslationBundle\Model\TransUnit; use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity; -use DateTime; /** * @author Cédric Girard @@ -64,7 +64,7 @@ public function getTransUnit(): TransUnit #[PrePersist] public function prePersist(): void { - $now = new DateTime("now"); + $now = new DateTime("now"); $this->createdAt = $now; $this->updatedAt = $now; } diff --git a/Entity/TranslationRepository.php b/Entity/TranslationRepository.php index 08e763d2..20567553 100644 --- a/Entity/TranslationRepository.php +++ b/Entity/TranslationRepository.php @@ -2,8 +2,8 @@ namespace Lexik\Bundle\TranslationBundle\Entity; -use Doctrine\ORM\EntityRepository; use Datetime; +use Doctrine\ORM\EntityRepository; /** * Repository for Translation entity. diff --git a/EventDispatcher/CleanTranslationCacheListener.php b/EventDispatcher/CleanTranslationCacheListener.php index 1968cb85..b6b0af4c 100644 --- a/EventDispatcher/CleanTranslationCacheListener.php +++ b/EventDispatcher/CleanTranslationCacheListener.php @@ -4,8 +4,8 @@ use Lexik\Bundle\TranslationBundle\Manager\LocaleManagerInterface; use Lexik\Bundle\TranslationBundle\Storage\StorageInterface; -use Symfony\Component\HttpKernel\Event\RequestEvent; use Symfony\Component\Finder\Finder; +use Symfony\Component\HttpKernel\Event\RequestEvent; use Symfony\Contracts\Translation\TranslatorInterface; /** @@ -32,8 +32,8 @@ public function onKernelRequest(RequestEvent $event) $finder = new Finder(); $finder->files() - ->in($this->cacheDirectory.'/translations') - ->date('< '.$lastUpdateTime->format('Y-m-d H:i:s')); + ->in($this->cacheDirectory . '/translations') + ->date('< ' . $lastUpdateTime->format('Y-m-d H:i:s')); if ($finder->count() > 0 && method_exists($this->translator, 'removeLocalesCacheFiles')) { $this->translator->removeLocalesCacheFiles($this->localeManager->getLocales()); @@ -53,15 +53,15 @@ private function isCacheExpired() return true; } - $cache_file = $this->cacheDirectory.'/translations/cache_timestamp'; - $cache_dir =$this->cacheDirectory.'/translations'; + $cache_file = $this->cacheDirectory . '/translations/cache_timestamp'; + $cache_dir = $this->cacheDirectory . '/translations'; if ('\\' === DIRECTORY_SEPARATOR) { $cache_file = strtr($cache_file, '/', '\\'); $cache_dir = strtr($cache_dir, '/', '\\'); } if (!\is_dir($cache_dir) && !\mkdir($cache_dir, 0777, true) && !\is_dir($cache_dir)) { throw new \RuntimeException(sprintf('Directory "%s" was not created', $cache_dir)); - } + } if (!\file_exists($cache_file)) { \touch($cache_file); return true; @@ -77,7 +77,7 @@ private function isCacheExpired() private function checkCacheFolder() { - if (!is_dir($dirName = $this->cacheDirectory.'/translations') && !mkdir($dirName) && !is_dir($dirName)) { + if (!is_dir($dirName = $this->cacheDirectory . '/translations') && !mkdir($dirName) && !is_dir($dirName)) { throw new \RuntimeException(sprintf('Directory "%s" was not created', $dirName)); } } diff --git a/Form/Handler/TransUnitFormHandler.php b/Form/Handler/TransUnitFormHandler.php index 68bbc4f7..8e5272db 100644 --- a/Form/Handler/TransUnitFormHandler.php +++ b/Form/Handler/TransUnitFormHandler.php @@ -2,10 +2,10 @@ namespace Lexik\Bundle\TranslationBundle\Form\Handler; -use Lexik\Bundle\TranslationBundle\Manager\LocaleManagerInterface; -use Lexik\Bundle\TranslationBundle\Manager\TransUnitManagerInterface; use Lexik\Bundle\TranslationBundle\Manager\FileInterface; use Lexik\Bundle\TranslationBundle\Manager\FileManagerInterface; +use Lexik\Bundle\TranslationBundle\Manager\LocaleManagerInterface; +use Lexik\Bundle\TranslationBundle\Manager\TransUnitManagerInterface; use Lexik\Bundle\TranslationBundle\Storage\StorageInterface; use Symfony\Component\Form\FormInterface; use Symfony\Component\HttpFoundation\Request; @@ -41,8 +41,8 @@ public function createFormData() public function getFormOptions() { return [ - 'domains' => $this->storage->getTransUnitDomains(), - 'data_class' => $this->storage->getModelClass('trans_unit'), + 'domains' => $this->storage->getTransUnitDomains(), + 'data_class' => $this->storage->getModelClass('trans_unit'), 'translation_class' => $this->storage->getModelClass('translation'), ]; } diff --git a/Form/Type/TransUnitType.php b/Form/Type/TransUnitType.php index 1151e035..15cda4da 100644 --- a/Form/Type/TransUnitType.php +++ b/Form/Type/TransUnitType.php @@ -2,11 +2,11 @@ namespace Lexik\Bundle\TranslationBundle\Form\Type; -use Symfony\Component\Form\Extension\Core\Type\TextType; +use Symfony\Component\Form\AbstractType; use Symfony\Component\Form\Extension\Core\Type\ChoiceType; use Symfony\Component\Form\Extension\Core\Type\CollectionType; use Symfony\Component\Form\Extension\Core\Type\SubmitType; -use Symfony\Component\Form\AbstractType; +use Symfony\Component\Form\Extension\Core\Type\TextType; use Symfony\Component\Form\FormBuilderInterface; use Symfony\Component\OptionsResolver\OptionsResolver; @@ -23,11 +23,11 @@ class TransUnitType extends AbstractType public function buildForm(FormBuilderInterface $builder, array $options): void { $builder->add('key', TextType::class, ['label' => 'translations.key']); - $builder->add('domain', ChoiceType::class, ['label' => 'translations.domain', 'choices' => array_merge( + $builder->add('domain', ChoiceType::class, ['label' => 'translations.domain', 'choices' => array_merge( array_combine($options['default_domain'], $options['default_domain']), array_combine($options['domains'], $options['domains']) )]); - $builder->add('translations', CollectionType::class, ['entry_type' => TranslationType::class, 'label' => 'translations.page_title', 'required' => false, 'entry_options' => ['data_class' => $options['translation_class']]]); + $builder->add('translations', CollectionType::class, ['entry_type' => TranslationType::class, 'label' => 'translations.page_title', 'required' => false, 'entry_options' => ['data_class' => $options['translation_class']]]); $builder->add('save', SubmitType::class, ['label' => 'translations.save']); $builder->add('save_add', SubmitType::class, ['label' => 'translations.save_add']); } @@ -37,7 +37,7 @@ public function buildForm(FormBuilderInterface $builder, array $options): void */ public function configureOptions(OptionsResolver $resolver): void { - $resolver->setDefaults(['data_class' => null, 'default_domain' => ['messages'], 'domains' => [], 'translation_class' => null, 'translation_domain' => 'LexikTranslationBundle']); + $resolver->setDefaults(['data_class' => null, 'default_domain' => ['messages'], 'domains' => [], 'translation_class' => null, 'translation_domain' => 'LexikTranslationBundle']); } /** diff --git a/Form/Type/TranslationType.php b/Form/Type/TranslationType.php index aaf020a6..3c9c1ef6 100644 --- a/Form/Type/TranslationType.php +++ b/Form/Type/TranslationType.php @@ -6,8 +6,8 @@ use Symfony\Component\Form\Extension\Core\Type\HiddenType; use Symfony\Component\Form\Extension\Core\Type\TextareaType; use Symfony\Component\Form\FormBuilderInterface; -use Symfony\Component\Form\FormView; use Symfony\Component\Form\FormInterface; +use Symfony\Component\Form\FormView; use Symfony\Component\OptionsResolver\OptionsResolver; /** @@ -39,7 +39,7 @@ public function buildView(FormView $view, FormInterface $form, array $options): */ public function configureOptions(OptionsResolver $resolver): void { - $resolver->setDefaults(['data_class' => null, 'translation_domain' => 'LexikTranslationBundle']); + $resolver->setDefaults(['data_class' => null, 'translation_domain' => 'LexikTranslationBundle']); } /** diff --git a/Manager/FileManagerInterface.php b/Manager/FileManagerInterface.php index a49fa3d9..b734f121 100644 --- a/Manager/FileManagerInterface.php +++ b/Manager/FileManagerInterface.php @@ -3,6 +3,7 @@ namespace Lexik\Bundle\TranslationBundle\Manager; use Lexik\Bundle\TranslationBundle\Entity\File; + /** * File manager interface. * diff --git a/Manager/TransUnitManager.php b/Manager/TransUnitManager.php index ed1a343f..4fa82e83 100644 --- a/Manager/TransUnitManager.php +++ b/Manager/TransUnitManager.php @@ -66,7 +66,7 @@ public function addTranslation( $content, ?FileInterface $file = null, bool $flush = false - ): ?TranslationInterface{ + ): ?TranslationInterface { $translation = null; if (!$transUnit->hasTranslation(locale: $locale)) { $class = $this->storage->getModelClass(name: 'translation'); @@ -136,7 +136,7 @@ public function updateTranslation(TransUnitInterface $transUnit, $locale, $conte /** * {@inheritdoc} */ - public function updateTranslationsContent(TransUnitInterface $transUnit, array $translations, $flush = false): void + public function updateTranslationsContent(TransUnitInterface $transUnit, array $translations, $flush = false): void { foreach ($translations as $locale => $content) { if (!empty($content)) { diff --git a/Model/TransUnit.php b/Model/TransUnit.php index d0704d5c..d4e995c7 100644 --- a/Model/TransUnit.php +++ b/Model/TransUnit.php @@ -2,15 +2,15 @@ namespace Lexik\Bundle\TranslationBundle\Model; -use Doctrine\Common\Collections\Collection; +use DateTime; use Doctrine\Common\Collections\ArrayCollection; +use Doctrine\Common\Collections\Collection; use Doctrine\DBAL\Types\Types; use Doctrine\ORM\Mapping as ORM; +use Lexik\Bundle\TranslationBundle\Document\Translation as DocumentTranslation; +use Lexik\Bundle\TranslationBundle\Entity\Translation; use Lexik\Bundle\TranslationBundle\Manager\TranslationInterface; use Symfony\Component\Validator\Constraints as Assert; -use Lexik\Bundle\TranslationBundle\Entity\Translation; -use Lexik\Bundle\TranslationBundle\Document\Translation as DocumentTranslation; -use DateTime; /** * This class represent a trans unit which contain translations for a given domain and key. diff --git a/Model/Translation.php b/Model/Translation.php index 2b2cbbaa..e735983c 100644 --- a/Model/Translation.php +++ b/Model/Translation.php @@ -2,9 +2,9 @@ namespace Lexik\Bundle\TranslationBundle\Model; +use DateTime; use Doctrine\DBAL\Types\Types; use Doctrine\ORM\Mapping as ORM; -use DateTime; use Lexik\Bundle\TranslationBundle\Manager\FileInterface; use Symfony\Component\Validator\Constraints as Assert; @@ -72,7 +72,6 @@ public function getContent() return $this->content; } - /** * Get createdAt * diff --git a/Storage/AbstractDoctrineStorage.php b/Storage/AbstractDoctrineStorage.php index 66a1e457..d04ad6c3 100644 --- a/Storage/AbstractDoctrineStorage.php +++ b/Storage/AbstractDoctrineStorage.php @@ -3,12 +3,12 @@ namespace Lexik\Bundle\TranslationBundle\Storage; use Doctrine\Persistence\ObjectManager; -use Symfony\Bridge\Doctrine\ManagerRegistry; -use Lexik\Bundle\TranslationBundle\Manager\TransUnitInterface; -use Lexik\Bundle\TranslationBundle\Entity\TransUnitRepository; -use Lexik\Bundle\TranslationBundle\Entity\FileRepository; use Lexik\Bundle\TranslationBundle\Document\FileRepository as DocumentFileRepository; use Lexik\Bundle\TranslationBundle\Document\TransUnitRepository as DocumentTransUnitRepository; +use Lexik\Bundle\TranslationBundle\Entity\FileRepository; +use Lexik\Bundle\TranslationBundle\Entity\TransUnitRepository; +use Lexik\Bundle\TranslationBundle\Manager\TransUnitInterface; +use Symfony\Bridge\Doctrine\ManagerRegistry; /** * Common doctrine storage logic. @@ -135,7 +135,7 @@ public function getTransUnitByKeyAndDomain(string $key, string $domain): ?TransU $key = mb_substr($key, 0, 255, 'UTF-8'); $fields = [ - 'key' => $key, + 'key' => $key, 'domain' => $domain, ]; diff --git a/Storage/DoctrineMongoDBStorage.php b/Storage/DoctrineMongoDBStorage.php index 33de8881..cac72ba7 100644 --- a/Storage/DoctrineMongoDBStorage.php +++ b/Storage/DoctrineMongoDBStorage.php @@ -1,6 +1,7 @@ getTransUnitRepository()->countByDomains(); } @@ -29,7 +30,7 @@ public function getCountTransUnitByDomains(): array /** * {@inheritdoc} */ - public function getCountTranslationByLocales(string $domain):array + public function getCountTranslationByLocales(string $domain): array { return $this->getTransUnitRepository()->countTranslationsByLocales($domain); } diff --git a/Storage/DoctrineORMStorage.php b/Storage/DoctrineORMStorage.php index d30c2182..ab16d135 100644 --- a/Storage/DoctrineORMStorage.php +++ b/Storage/DoctrineORMStorage.php @@ -2,8 +2,8 @@ namespace Lexik\Bundle\TranslationBundle\Storage; -use Doctrine\ORM\EntityManager; use DateTime; +use Doctrine\ORM\EntityManager; /** * Doctrine ORM storage class. diff --git a/Storage/StorageInterface.php b/Storage/StorageInterface.php index 411658df..9514289b 100644 --- a/Storage/StorageInterface.php +++ b/Storage/StorageInterface.php @@ -2,9 +2,9 @@ namespace Lexik\Bundle\TranslationBundle\Storage; -use Lexik\Bundle\TranslationBundle\Manager\TransUnitInterface; use DateTime; use Lexik\Bundle\TranslationBundle\Manager\FileInterface; +use Lexik\Bundle\TranslationBundle\Manager\TransUnitInterface; /** * Translation storage interface. @@ -16,7 +16,7 @@ interface StorageInterface /** * All the available config storage types. */ - public const STORAGE_ORM = 'orm'; + public const STORAGE_ORM = 'orm'; public const STORAGE_MONGODB = 'mongodb'; /** @@ -120,7 +120,7 @@ public function getTransUnitList(?array $locales = null, ?int $rows = 20, ?int $ * * @return int */ - public function countTransUnits(?array $locales = null, ?array $filters = null): int; + public function countTransUnits(?array $locales = null, ?array $filters = null): int; /** * Returns all translations for the given file. diff --git a/Tests/Command/ImportTranslationsCommandTest.php b/Tests/Command/ImportTranslationsCommandTest.php index 62e18dad..be0107ef 100644 --- a/Tests/Command/ImportTranslationsCommandTest.php +++ b/Tests/Command/ImportTranslationsCommandTest.php @@ -2,12 +2,12 @@ namespace Lexik\Bundle\TranslationBundle\Tests\Command; -use Doctrine\ORM\Tools\Console\EntityManagerProvider\SingleManagerProvider; use Doctrine\ORM\EntityManager; use Doctrine\ORM\Tools\Console\Command\SchemaTool\CreateCommand; use Doctrine\ORM\Tools\Console\Command\SchemaTool\DropCommand; -use Symfony\Bundle\FrameworkBundle\Test\WebTestCase; +use Doctrine\ORM\Tools\Console\EntityManagerProvider\SingleManagerProvider; use Symfony\Bundle\FrameworkBundle\Console\Application; +use Symfony\Bundle\FrameworkBundle\Test\WebTestCase; use Symfony\Component\Console\Input\ArrayInput; use Symfony\Component\Console\Output\NullOutput; use Symfony\Component\Console\Tester\CommandTester; @@ -86,11 +86,11 @@ public function testExecute(): void $commandTester = new CommandTester($command); $commandTester->execute( [ - 'command' => $command->getName(), - 'bundle' => 'LexikTranslationBundle', + 'command' => $command->getName(), + 'bundle' => 'LexikTranslationBundle', '--cache-clear' => true, - '--force' => true, - '--locales' => ['en', 'fr'], + '--force' => true, + '--locales' => ['en', 'fr'], ] ); diff --git a/Tests/Fixtures/test.fr.php b/Tests/Fixtures/test.fr.php index a4293d56..238b9d4d 100644 --- a/Tests/Fixtures/test.fr.php +++ b/Tests/Fixtures/test.fr.php @@ -1,5 +1,6 @@ 'Hey mec :D', + 'key.dude' => 'Hey mec :D', 'key.stuff' => 'Truc cool', ]; diff --git a/Tests/Unit/BaseUnitTestCase.php b/Tests/Unit/BaseUnitTestCase.php index 88a9eb55..b2b2cc4c 100644 --- a/Tests/Unit/BaseUnitTestCase.php +++ b/Tests/Unit/BaseUnitTestCase.php @@ -2,23 +2,23 @@ namespace Lexik\Bundle\TranslationBundle\Tests\Unit; -use Doctrine\DBAL\DriverManager; -use Doctrine\ODM\MongoDB\Mapping\Driver\SimplifiedXmlDriver as XmlDriver; use Doctrine\Common\DataFixtures\Executor\MongoDBExecutor; use Doctrine\Common\DataFixtures\Executor\ORMExecutor; use Doctrine\Common\DataFixtures\Purger\MongoDBPurger; use Doctrine\Common\DataFixtures\Purger\ORMPurger; +use Doctrine\DBAL\DriverManager; use Doctrine\ODM\MongoDB\Configuration; use Doctrine\ODM\MongoDB\DocumentManager; use Doctrine\ODM\MongoDB\Mapping\ClassMetadataFactory; +use Doctrine\ODM\MongoDB\Mapping\Driver\SimplifiedXmlDriver as XmlDriver; use Doctrine\ODM\MongoDB\MongoDBException; use Doctrine\ODM\MongoDB\SchemaManager; use Doctrine\ORM\EntityManager; use Doctrine\ORM\EntityRepository; use Doctrine\ORM\Mapping\ClassMetadataFactory as DoctrineClassMetadataFactory; use Doctrine\ORM\Mapping\Driver\SimplifiedXmlDriver; -use Doctrine\ORM\Tools\SchemaTool; use Doctrine\ORM\ORMSetup as Setup; +use Doctrine\ORM\Tools\SchemaTool; use Doctrine\Persistence\ObjectManager; use Lexik\Bundle\TranslationBundle\Storage\DoctrineMongoDBStorage; use Lexik\Bundle\TranslationBundle\Storage\DoctrineORMStorage; @@ -37,13 +37,13 @@ */ abstract class BaseUnitTestCase extends TestCase { - final const ENTITY_TRANS_UNIT_CLASS = 'Lexik\Bundle\TranslationBundle\Entity\TransUnit'; - final const ENTITY_TRANSLATION_CLASS = 'Lexik\Bundle\TranslationBundle\Entity\Translation'; - final const ENTITY_FILE_CLASS = 'Lexik\Bundle\TranslationBundle\Entity\File'; + final public const ENTITY_TRANS_UNIT_CLASS = 'Lexik\Bundle\TranslationBundle\Entity\TransUnit'; + final public const ENTITY_TRANSLATION_CLASS = 'Lexik\Bundle\TranslationBundle\Entity\Translation'; + final public const ENTITY_FILE_CLASS = 'Lexik\Bundle\TranslationBundle\Entity\File'; - final const DOCUMENT_TRANS_UNIT_CLASS = 'Lexik\Bundle\TranslationBundle\Document\TransUnit'; - final const DOCUMENT_TRANSLATION_CLASS = 'Lexik\Bundle\TranslationBundle\Document\Translation'; - final const DOCUMENT_FILE_CLASS = 'Lexik\Bundle\TranslationBundle\Document\File'; + final public const DOCUMENT_TRANS_UNIT_CLASS = 'Lexik\Bundle\TranslationBundle\Document\TransUnit'; + final public const DOCUMENT_TRANSLATION_CLASS = 'Lexik\Bundle\TranslationBundle\Document\Translation'; + final public const DOCUMENT_FILE_CLASS = 'Lexik\Bundle\TranslationBundle\Document\File'; /** * Create a storage class form doctrine ORM. @@ -55,9 +55,9 @@ protected function getORMStorage(EntityManager $em) $registryMock = $this->getDoctrineRegistryMock($em); $storage = new DoctrineORMStorage($registryMock, 'default', [ - 'trans_unit' => self::ENTITY_TRANS_UNIT_CLASS, + 'trans_unit' => self::ENTITY_TRANS_UNIT_CLASS, 'translation' => self::ENTITY_TRANSLATION_CLASS, - 'file' => self::ENTITY_FILE_CLASS, + 'file' => self::ENTITY_FILE_CLASS, ]); return $storage; @@ -71,9 +71,9 @@ protected function getMongoDBStorage(DocumentManager $dm): DoctrineMongoDBStorag $registryMock = $this->getDoctrineRegistryMock($dm); $storage = new DoctrineMongoDBStorage($registryMock, 'default', [ - 'trans_unit' => self::DOCUMENT_TRANS_UNIT_CLASS, + 'trans_unit' => self::DOCUMENT_TRANS_UNIT_CLASS, 'translation' => self::DOCUMENT_TRANSLATION_CLASS, - 'file' => self::DOCUMENT_FILE_CLASS, + 'file' => self::DOCUMENT_FILE_CLASS, ]); return $storage; @@ -152,7 +152,7 @@ protected function getMockSqliteEntityManager($mockCustomHydrator = false) // xml driver $xmlDriver = new SimplifiedXmlDriver( [ - __DIR__ . '/../../Resources/config/model' => 'Lexik\Bundle\TranslationBundle\Model', + __DIR__ . '/../../Resources/config/model' => 'Lexik\Bundle\TranslationBundle\Model', __DIR__ . '/../../Resources/config/doctrine' => 'Lexik\Bundle\TranslationBundle\Entity', ] ); @@ -161,7 +161,10 @@ protected function getMockSqliteEntityManager($mockCustomHydrator = false) [ __DIR__ . '/../../Model', __DIR__ . '/../../Entity', - ], false, null, null + ], + false, + null, + null ); $config->setMetadataDriverImpl($xmlDriver); @@ -201,7 +204,7 @@ protected function getMockSqliteEntityManager($mockCustomHydrator = false) protected function getMockMongoDbDocumentManager(): DocumentManager { $prefixes = [ - __DIR__ . '/../../Resources/config/model' => 'Lexik\Bundle\TranslationBundle\Model', + __DIR__ . '/../../Resources/config/model' => 'Lexik\Bundle\TranslationBundle\Model', __DIR__ . '/../../Resources/config/doctrine' => 'Lexik\Bundle\TranslationBundle\Document', ]; $xmlDriver = new XmlDriver($prefixes); @@ -224,7 +227,7 @@ protected function getMockMongoDbDocumentManager(): DocumentManager $server = MONGO_SERVER; $driverOptions = [ 'typeMap' => [ - 'root' => 'array', + 'root' => 'array', 'document' => 'array', ], ]; @@ -232,7 +235,6 @@ protected function getMockMongoDbDocumentManager(): DocumentManager $dm = DocumentManager::create($conn, $config); - return $dm; } } diff --git a/Tests/Unit/EventDispatcher/CleanTranslationCacheListenerTest.php b/Tests/Unit/EventDispatcher/CleanTranslationCacheListenerTest.php index 6d380437..1ca31eed 100644 --- a/Tests/Unit/EventDispatcher/CleanTranslationCacheListenerTest.php +++ b/Tests/Unit/EventDispatcher/CleanTranslationCacheListenerTest.php @@ -2,16 +2,16 @@ namespace Lexik\Bundle\TranslationBundle\Tests\Unit\EventDispatcher; +use Lexik\Bundle\TranslationBundle\EventDispatcher\CleanTranslationCacheListener; use Lexik\Bundle\TranslationBundle\Storage\StorageInterface; -use Symfony\Component\DependencyInjection\ContainerInterface; use Lexik\Bundle\TranslationBundle\Translation\Translator; -use Lexik\Bundle\TranslationBundle\EventDispatcher\CleanTranslationCacheListener; -use Symfony\Component\HttpKernel\HttpKernelInterface; -use Symfony\Component\HttpKernel\Event\GetResponseEvent; +use PHPUnit\Framework\TestCase; +use Symfony\Component\DependencyInjection\ContainerInterface; +use Symfony\Component\Finder\Finder; use Symfony\Component\HttpFoundation\Request; +use Symfony\Component\HttpKernel\Event\GetResponseEvent; +use Symfony\Component\HttpKernel\HttpKernelInterface; use Symfony\Component\Translation\MessageSelector; -use Symfony\Component\Finder\Finder; -use PHPUnit\Framework\TestCase; /** * Unit test for CleanTranslationCacheListener class @@ -20,7 +20,6 @@ */ class CleanTranslationCacheListenerTest extends TestCase { - private $tempDir; public function setUp(): void @@ -32,7 +31,7 @@ public function testDefaultLocale() { $request = Request::create('/'); - $date = new \DateTime; + $date = new \DateTime(); if (!\file_exists($this->tempDir)) { \mkdir($this->tempDir); @@ -49,7 +48,7 @@ public function testDefaultLocale() $container = $this->getMock(ContainerInterface::class); - $translator = $this->getMock(Translator::class, [], [$container, new MessageSelector]); + $translator = $this->getMock(Translator::class, [], [$container, new MessageSelector()]); $translator->expects($this->any())->method('removeLocalesCacheFiles')->will($this->returnValue(true)); diff --git a/Tests/Unit/Repository/Document/FileRepositoryTest.php b/Tests/Unit/Repository/Document/FileRepositoryTest.php index 3d6bffc0..9f431376 100644 --- a/Tests/Unit/Repository/Document/FileRepositoryTest.php +++ b/Tests/Unit/Repository/Document/FileRepositoryTest.php @@ -52,7 +52,7 @@ public function assertFilesPath($expected, $result) { $i = 0; foreach ($result as $file) { - $this->assertEquals($expected[$i], $file->getPath().'/'.$file->getName()); + $this->assertEquals($expected[$i], $file->getPath() . '/' . $file->getName()); $i++; } } diff --git a/Tests/Unit/Repository/Document/TransUnitRepositoryTest.php b/Tests/Unit/Repository/Document/TransUnitRepositoryTest.php index 5088b83d..9d10ec88 100644 --- a/Tests/Unit/Repository/Document/TransUnitRepositoryTest.php +++ b/Tests/Unit/Repository/Document/TransUnitRepositoryTest.php @@ -99,10 +99,14 @@ public function testCount() $this->assertEquals(3, $repository->count(['locales' => ['fr', 'de'], 'filters' => ['_search' => false, 'key' => 'good']])); $this->assertEquals(1, $repository->count(['locales' => ['fr', 'de'], 'filters' => ['_search' => true, 'key' => 'good']])); $this->assertEquals(1, $repository->count(['locales' => ['en', 'de'], 'filters' => ['_search' => true, 'domain' => 'super']])); - $this->assertEquals(1, - $repository->count(['locales' => ['en', 'fr', 'de'], 'filters' => ['_search' => true, 'key' => 'hel', 'domain' => 'uper']])); - $this->assertEquals(2, - $repository->count(['locales' => ['en', 'de'], 'filters' => ['_search' => true, 'key' => 'say', 'domain' => 'ssa']])); + $this->assertEquals( + 1, + $repository->count(['locales' => ['en', 'fr', 'de'], 'filters' => ['_search' => true, 'key' => 'hel', 'domain' => 'uper']]) + ); + $this->assertEquals( + 2, + $repository->count(['locales' => ['en', 'de'], 'filters' => ['_search' => true, 'key' => 'say', 'domain' => 'ssa']]) + ); } /** @@ -140,8 +144,12 @@ public function testGetTransUnitList() ]; $this->assertSameTransUnit($expected, $result); - $result = $repository->getTransUnitList(['fr', 'de'], 10, 1, - ['sidx' => 'key', 'sord' => 'DESC', '_search' => true, 'domain' => 'mess']); + $result = $repository->getTransUnitList( + ['fr', 'de'], + 10, + 1, + ['sidx' => 'key', 'sord' => 'DESC', '_search' => true, 'domain' => 'mess'] + ); $expected = [ [ 'key' => 'key.say_wtf', @@ -160,8 +168,12 @@ public function testGetTransUnitList() ]; $this->assertSameTransUnit($expected, $result); - $result = $repository->getTransUnitList(['fr', 'de'], 10, 1, - ['sidx' => 'key', 'sord' => 'DESC', '_search' => true, 'domain' => 'mess', 'key' => 'oo']); + $result = $repository->getTransUnitList( + ['fr', 'de'], + 10, + 1, + ['sidx' => 'key', 'sord' => 'DESC', '_search' => true, 'domain' => 'mess', 'key' => 'oo'] + ); $expected = [ [ 'key' => 'key.say_goodbye', @@ -173,8 +185,12 @@ public function testGetTransUnitList() ]; $this->assertSameTransUnit($expected, $result); - $result = $repository->getTransUnitList(['fr', 'en'], 10, 1, - ['sidx' => 'key', 'sord' => 'DESC', '_search' => true, 'fr' => 'alu']); + $result = $repository->getTransUnitList( + ['fr', 'en'], + 10, + 1, + ['sidx' => 'key', 'sord' => 'DESC', '_search' => true, 'fr' => 'alu'] + ); $expected = [ [ 'key' => 'key.say_hello', diff --git a/Tests/Unit/Repository/Entity/FileRepositoryTest.php b/Tests/Unit/Repository/Entity/FileRepositoryTest.php index 859fef35..178f22f6 100644 --- a/Tests/Unit/Repository/Entity/FileRepositoryTest.php +++ b/Tests/Unit/Repository/Entity/FileRepositoryTest.php @@ -52,7 +52,7 @@ public function assertFilesPath($expected, $result) { $i = 0; foreach ($result as $file) { - $this->assertEquals($expected[$i], $file->getPath().'/'.$file->getName()); + $this->assertEquals($expected[$i], $file->getPath() . '/' . $file->getName()); $i++; } } diff --git a/Tests/Unit/Repository/Entity/TransUnitRepositoryTest.php b/Tests/Unit/Repository/Entity/TransUnitRepositoryTest.php index d6f6ffd9..7dec2058 100644 --- a/Tests/Unit/Repository/Entity/TransUnitRepositoryTest.php +++ b/Tests/Unit/Repository/Entity/TransUnitRepositoryTest.php @@ -22,9 +22,9 @@ public function testGetAllDomainsByLocale() $results = $repository->getAllDomainsByLocale(); $expected = [ ['locale' => 'de', 'domain' => 'superTranslations'], - ['locale' => 'en', 'domain' => 'messages'], - ['locale' => 'en', 'domain' => 'superTranslations'], - ['locale' => 'fr', 'domain' => 'messages'], + ['locale' => 'en', 'domain' => 'messages'], + ['locale' => 'en', 'domain' => 'superTranslations'], + ['locale' => 'fr', 'domain' => 'messages'], ['locale' => 'fr', 'domain' => 'superTranslations'] ]; @@ -124,11 +124,11 @@ public function testGetTranslationsForFile() $em = $this->loadDatabase(); $repository = $em->getRepository(self::ENTITY_TRANS_UNIT_CLASS); - $file = $em->getRepository(self::ENTITY_FILE_CLASS)->findOneBy(['domain' => 'messages', 'locale' => 'fr', 'extention' => 'yml']); + $file = $em->getRepository(self::ENTITY_FILE_CLASS)->findOneBy(['domain' => 'messages', 'locale' => 'fr', 'extention' => 'yml']); $this->assertInstanceOf(self::ENTITY_FILE_CLASS, $file); $result = $repository->getTranslationsForFile($file, false); - $expected = ['key.say_goodbye' => 'au revoir', 'key.say_wtf' => 'c\'est quoi ce bordel !?!']; + $expected = ['key.say_goodbye' => 'au revoir', 'key.say_wtf' => 'c\'est quoi ce bordel !?!']; $this->assertEquals($expected, $result); // update a translation and then get translations with onlyUpdated = true diff --git a/Tests/Unit/Translation/Exporter/JsonExporterTest.php b/Tests/Unit/Translation/Exporter/JsonExporterTest.php index 159bb80d..6960f1e5 100644 --- a/Tests/Unit/Translation/Exporter/JsonExporterTest.php +++ b/Tests/Unit/Translation/Exporter/JsonExporterTest.php @@ -16,8 +16,8 @@ class JsonExporterTest extends TestCase public function tearDown(): void { - if (file_exists(__DIR__.$this->outFileName)) { - unlink(__DIR__.$this->outFileName); + if (file_exists(__DIR__ . $this->outFileName)) { + unlink(__DIR__ . $this->outFileName); } } @@ -26,7 +26,7 @@ public function tearDown(): void */ public function testExport() { - $outFile = __DIR__.$this->outFileName; + $outFile = __DIR__ . $this->outFileName; $exporter = new JsonExporter(); diff --git a/Tests/Unit/Translation/Exporter/PhpExporterTest.php b/Tests/Unit/Translation/Exporter/PhpExporterTest.php index b3a108de..c1439149 100644 --- a/Tests/Unit/Translation/Exporter/PhpExporterTest.php +++ b/Tests/Unit/Translation/Exporter/PhpExporterTest.php @@ -16,10 +16,10 @@ class PhpExporterTest extends TestCase public function tearDown(): void { - $outFile = __DIR__.$this->outFileName; + $outFile = __DIR__ . $this->outFileName; - if (file_exists(__DIR__.$this->outFileName)) { - unlink(__DIR__.$this->outFileName); + if (file_exists(__DIR__ . $this->outFileName)) { + unlink(__DIR__ . $this->outFileName); } } @@ -28,7 +28,7 @@ public function tearDown(): void */ public function testExport() { - $outFile = __DIR__.$this->outFileName; + $outFile = __DIR__ . $this->outFileName; $exporter = new PhpExporter(); diff --git a/Tests/Unit/Translation/Exporter/YamlExporterTest.php b/Tests/Unit/Translation/Exporter/YamlExporterTest.php index b076f49c..0edabe51 100644 --- a/Tests/Unit/Translation/Exporter/YamlExporterTest.php +++ b/Tests/Unit/Translation/Exporter/YamlExporterTest.php @@ -16,10 +16,10 @@ class YamlExporterTest extends TestCase public function tearDown(): void { - $outFile = __DIR__.$this->outFileName; + $outFile = __DIR__ . $this->outFileName; - if (file_exists(__DIR__.$this->outFileName)) { - unlink(__DIR__.$this->outFileName); + if (file_exists(__DIR__ . $this->outFileName)) { + unlink(__DIR__ . $this->outFileName); } } @@ -28,7 +28,7 @@ public function tearDown(): void */ public function testExport() { - $outFile = __DIR__.$this->outFileName; + $outFile = __DIR__ . $this->outFileName; $exporter = new YamlExporter(); @@ -59,7 +59,7 @@ public function testCreateMultiArray() $this->assertEquals($expected, $result); $result = $exporter->createMultiArray(['foo.bar.baz' => 'foobar', 'foo.foobaz' => 'bazbar']); - $expected = ['foo' => ['foobaz' => 'bazbar', 'bar' => ['baz' => 'foobar']]]; + $expected = ['foo' => ['foobaz' => 'bazbar', 'bar' => ['baz' => 'foobar']]]; $this->assertEquals($expected, $result); } @@ -75,15 +75,15 @@ public function testflattenArray() $this->assertEquals($expected, $result); $result = $exporter->flattenArray( - ['bundle' => ['foo' => ['foobaz' => 'bazbar', 'bar' => ['baz0' => 'foobar', 'baz1' => 'foobaz']]]] + ['bundle' => ['foo' => ['foobaz' => 'bazbar', 'bar' => ['baz0' => 'foobar', 'baz1' => 'foobaz']]]] ); - $expected = ['bundle.foo' => ['foobaz' => 'bazbar', 'bar' => ['baz0' => 'foobar', 'baz1' => 'foobaz']]]; + $expected = ['bundle.foo' => ['foobaz' => 'bazbar', 'bar' => ['baz0' => 'foobar', 'baz1' => 'foobaz']]]; $this->assertEquals($expected, $result); $result = $exporter->flattenArray( - ['bundle' => ['foo' => ['foobaz' => 'bazbar', 'bar' => ['baz' => 'foobar']]]] + ['bundle' => ['foo' => ['foobaz' => 'bazbar', 'bar' => ['baz' => 'foobar']]]] ); - $expected = ['bundle.foo' => ['foobaz' => 'bazbar', 'bar' => ['baz' => 'foobar']]]; + $expected = ['bundle.foo' => ['foobaz' => 'bazbar', 'bar' => ['baz' => 'foobar']]]; $this->assertEquals($expected, $result); } } diff --git a/Tests/Unit/Translation/Importer/FileImporterTest.php b/Tests/Unit/Translation/Importer/FileImporterTest.php index 49a54cbb..e7f2e17e 100644 --- a/Tests/Unit/Translation/Importer/FileImporterTest.php +++ b/Tests/Unit/Translation/Importer/FileImporterTest.php @@ -2,13 +2,13 @@ namespace Lexik\Bundle\TranslationBundle\Tests\Unit\Translation\Importer; -use Lexik\Bundle\TranslationBundle\Translation\Importer\FileImporter; use Lexik\Bundle\TranslationBundle\Manager\FileManager; use Lexik\Bundle\TranslationBundle\Manager\TransUnitManager; use Lexik\Bundle\TranslationBundle\Tests\Unit\BaseUnitTestCase; -use Symfony\Component\Translation\Loader\YamlFileLoader; -use Symfony\Component\Translation\Loader\PhpFileLoader; +use Lexik\Bundle\TranslationBundle\Translation\Importer\FileImporter; use Symfony\Component\Finder\SplFileInfo; +use Symfony\Component\Translation\Loader\PhpFileLoader; +use Symfony\Component\Translation\Loader\YamlFileLoader; /** * FileImporter tests. @@ -37,7 +37,7 @@ public function testImport() $this->assertDatabaseEntries($em, 0); // import files - $files = [new SplFileInfo(__DIR__.'/../../../Fixtures/test.en.yml', '', ''), new SplFileInfo(__DIR__.'/../../../Fixtures/test.fr.php', '', '')]; + $files = [new SplFileInfo(__DIR__ . '/../../../Fixtures/test.en.yml', '', ''), new SplFileInfo(__DIR__ . '/../../../Fixtures/test.fr.php', '', '')]; foreach ($files as $file) { $importer->import($file); diff --git a/Tests/Unit/Translation/Loader/DatabaseLoaderTest.php b/Tests/Unit/Translation/Loader/DatabaseLoaderTest.php index ccdb0eb8..305c6828 100644 --- a/Tests/Unit/Translation/Loader/DatabaseLoaderTest.php +++ b/Tests/Unit/Translation/Loader/DatabaseLoaderTest.php @@ -3,8 +3,8 @@ namespace Lexik\Bundle\TranslationBundle\Tests\Unit\Translation\Loader; use Lexik\Bundle\TranslationBundle\Entity\TransUnit; -use Lexik\Bundle\TranslationBundle\Translation\Loader\DatabaseLoader; use Lexik\Bundle\TranslationBundle\Tests\Unit\BaseUnitTestCase; +use Lexik\Bundle\TranslationBundle\Translation\Loader\DatabaseLoader; use Symfony\Component\Translation\MessageCatalogue; /** @@ -31,7 +31,7 @@ public function testLoad() $this->assertEquals('it', $catalogue->getLocale()); $catalogue = $loader->load(null, 'fr'); - $expectedTranslations = ['messages' => ['key.say_goodbye' => 'au revoir', 'key.say_wtf' => 'c\'est quoi ce bordel !?!']]; + $expectedTranslations = ['messages' => ['key.say_goodbye' => 'au revoir', 'key.say_wtf' => 'c\'est quoi ce bordel !?!']]; $this->assertInstanceOf(MessageCatalogue::class, $catalogue); $this->assertEquals($expectedTranslations, $catalogue->all()); $this->assertEquals('fr', $catalogue->getLocale()); diff --git a/Tests/Unit/Translation/Manager/TransUnitManagerTest.php b/Tests/Unit/Translation/Manager/TransUnitManagerTest.php index e0cbc0d4..f89c46c8 100644 --- a/Tests/Unit/Translation/Manager/TransUnitManagerTest.php +++ b/Tests/Unit/Translation/Manager/TransUnitManagerTest.php @@ -7,8 +7,8 @@ use Doctrine\ORM\EntityManager; use Doctrine\ORM\UnitOfWork as ORMUnitOfWork; use Lexik\Bundle\TranslationBundle\Entity\TransUnit; -use Lexik\Bundle\TranslationBundle\Manager\TransUnitManager; use Lexik\Bundle\TranslationBundle\Manager\FileManager; +use Lexik\Bundle\TranslationBundle\Manager\TransUnitManager; use Lexik\Bundle\TranslationBundle\Storage\DoctrineMongoDBStorage; use Lexik\Bundle\TranslationBundle\Storage\DoctrineORMStorage; use Lexik\Bundle\TranslationBundle\Tests\Unit\BaseUnitTestCase; diff --git a/Tests/Unit/Translation/TranslatorTest.php b/Tests/Unit/Translation/TranslatorTest.php index 45752108..88c8e958 100644 --- a/Tests/Unit/Translation/TranslatorTest.php +++ b/Tests/Unit/Translation/TranslatorTest.php @@ -4,11 +4,11 @@ use Lexik\Bundle\TranslationBundle\EventDispatcher\Event\GetDatabaseResourcesEvent; use Lexik\Bundle\TranslationBundle\EventDispatcher\GetDatabaseResourcesListener; -use Lexik\Bundle\TranslationBundle\Translation\Translator; use Lexik\Bundle\TranslationBundle\Tests\Unit\BaseUnitTestCase; +use Lexik\Bundle\TranslationBundle\Translation\Translator; +use Symfony\Component\DependencyInjection\Container; use Symfony\Component\EventDispatcher\EventDispatcher; use Symfony\Component\Translation\Formatter\MessageFormatter; -use Symfony\Component\DependencyInjection\Container; /** * Translator tests. @@ -26,8 +26,8 @@ public function testAddDatabaseResources(): void $this->createSchema($em); $this->loadFixtures($em); - if (file_exists(sys_get_temp_dir().'/database.resources.php')) { - unlink(sys_get_temp_dir().'/database.resources.php'); + if (file_exists(sys_get_temp_dir() . '/database.resources.php')) { + unlink(sys_get_temp_dir() . '/database.resources.php'); } $translator = $this->createTranslator($em, sys_get_temp_dir()); @@ -58,7 +58,7 @@ public function testAddDatabaseResources(): void */ public function testRemoveCacheFile(): void { - $cacheDir = __DIR__.'/../../../vendor/test_cache_dir'; + $cacheDir = __DIR__ . '/../../../vendor/test_cache_dir'; $this->createFakeCacheFiles($cacheDir); $translator = $this->createTranslator($this->getMockSqliteEntityManager(), $cacheDir); @@ -88,7 +88,7 @@ public function testRemoveCacheFile(): void */ public function testRemoveLocalesCacheFiles(): void { - $cacheDir = __DIR__.'/../../../vendor/test_cache_dir'; + $cacheDir = __DIR__ . '/../../../vendor/test_cache_dir'; $this->createFakeCacheFiles($cacheDir); $translator = $this->createTranslator($this->getMockSqliteEntityManager(), $cacheDir); @@ -150,17 +150,17 @@ protected function createFakeCacheFiles($cacheDir): void mkdir($cacheDir); } - touch($cacheDir.'/catalogue.fr.php'); - touch($cacheDir.'/catalogue.fr.php.meta'); + touch($cacheDir . '/catalogue.fr.php'); + touch($cacheDir . '/catalogue.fr.php.meta'); - touch($cacheDir.'/catalogue.fr_FR.php'); - touch($cacheDir.'/catalogue.fr_FR.php.meta'); + touch($cacheDir . '/catalogue.fr_FR.php'); + touch($cacheDir . '/catalogue.fr_FR.php.meta'); - touch($cacheDir.'/catalogue.en.php'); - touch($cacheDir.'/catalogue.en.php.meta'); + touch($cacheDir . '/catalogue.en.php'); + touch($cacheDir . '/catalogue.en.php.meta'); - touch($cacheDir.'/database.resources.php'); - touch($cacheDir.'/database.resources.php.meta'); + touch($cacheDir . '/database.resources.php'); + touch($cacheDir . '/database.resources.php.meta'); } } diff --git a/Tests/Unit/Util/DataGrid/DataGridFormatterTest.php b/Tests/Unit/Util/DataGrid/DataGridFormatterTest.php index 8f881f9a..40857a0e 100644 --- a/Tests/Unit/Util/DataGrid/DataGridFormatterTest.php +++ b/Tests/Unit/Util/DataGrid/DataGridFormatterTest.php @@ -4,8 +4,8 @@ use Lexik\Bundle\TranslationBundle\Manager\LocaleManager; use Lexik\Bundle\TranslationBundle\Storage\StorageInterface; -use Lexik\Bundle\TranslationBundle\Util\DataGrid\DataGridFormatter; use Lexik\Bundle\TranslationBundle\Tests\Unit\BaseUnitTestCase; +use Lexik\Bundle\TranslationBundle\Util\DataGrid\DataGridFormatter; /** * @author Cédric Girard @@ -20,7 +20,7 @@ public function testCreateListResponse() $datas = [['id' => 2, 'key' => 'key.say_goodbye', 'domain' => 'messages', 'translations' => [['locale' => 'fr', 'content' => 'au revoir'], ['locale' => 'en', 'content' => 'good bye']]], ['id' => 1, 'key' => 'key.say_hello', 'domain' => 'superTranslations', 'translations' => [['locale' => 'fr', 'content' => 'salut'], ['locale' => 'de', 'content' => 'heil']]], ['id' => 3, 'key' => 'key.say_wtf', 'domain' => 'messages', 'translations' => [['locale' => 'fr', 'content' => 'c\'est quoi ce bordel !?!'], ['locale' => 'xx', 'content' => 'xxx xxx xxx']]]]; $total = 3; - $expected = ['translations' => [['_id' => 2, '_domain' => 'messages', '_key' => 'key.say_goodbye', 'de' => '', 'en' => 'good bye', 'fr' => 'au revoir'], ['_id' => 1, '_domain' => 'superTranslations', '_key' => 'key.say_hello', 'de' => 'heil', 'en' => '', 'fr' => 'salut'], ['_id' => 3, '_domain' => 'messages', '_key' => 'key.say_wtf', 'de' => '', 'en' => '', 'fr' => 'c\'est quoi ce bordel !?!']], 'total' => 3]; + $expected = ['translations' => [['_id' => 2, '_domain' => 'messages', '_key' => 'key.say_goodbye', 'de' => '', 'en' => 'good bye', 'fr' => 'au revoir'], ['_id' => 1, '_domain' => 'superTranslations', '_key' => 'key.say_hello', 'de' => 'heil', 'en' => '', 'fr' => 'salut'], ['_id' => 3, '_domain' => 'messages', '_key' => 'key.say_wtf', 'de' => '', 'en' => '', 'fr' => 'c\'est quoi ce bordel !?!']], 'total' => 3]; $formatter = new DataGridFormatter(new LocaleManager(['de', 'en', 'fr']), StorageInterface::STORAGE_ORM); $this->assertEquals(json_encode($expected, JSON_HEX_APOS), $formatter->createListResponse($datas, $total)->getContent()); diff --git a/Tests/Unit/Util/DataGrid/DataGridRequestHandlerTest.php b/Tests/Unit/Util/DataGrid/DataGridRequestHandlerTest.php index 7f62f49c..49672ba5 100644 --- a/Tests/Unit/Util/DataGrid/DataGridRequestHandlerTest.php +++ b/Tests/Unit/Util/DataGrid/DataGridRequestHandlerTest.php @@ -2,13 +2,12 @@ namespace Lexik\Bundle\TranslationBundle\Tests\Unit\Util\DataGrid; -use Lexik\Bundle\TranslationBundle\Manager\TransUnitManager; use Lexik\Bundle\TranslationBundle\Manager\FileManagerInterface; -use Lexik\Bundle\TranslationBundle\Storage\StorageInterface; use Lexik\Bundle\TranslationBundle\Manager\LocaleManager; +use Lexik\Bundle\TranslationBundle\Manager\TransUnitManager; +use Lexik\Bundle\TranslationBundle\Storage\StorageInterface; use Lexik\Bundle\TranslationBundle\Tests\Unit\BaseUnitTestCase; use Lexik\Bundle\TranslationBundle\Util\DataGrid\DataGridRequestHandler; -use Symfony\Component\HttpFoundation\Request; /** * @author Cédric Girard diff --git a/Tests/app/test/database.php b/Tests/app/test/database.php index fcb43a7b..19a0dafb 100644 --- a/Tests/app/test/database.php +++ b/Tests/app/test/database.php @@ -3,7 +3,7 @@ if (ORM_TYPE == "doctrine") { $container->loadFromExtension( 'doctrine', - ['orm' => ['mappings' => ['Mapping' => ['type' => 'xml', 'prefix' => 'Lexik\Bundle\TranslationBundle\Entity', 'is_bundle' => false, 'dir' => '%kernel.project_dir%/Resources/config/doctrine']]], 'dbal' => ['charset' => 'UTF8', 'driver' => DB_ENGINE, 'host' => DB_HOST, 'port' => DB_PORT, 'dbname' => DB_NAME, 'user' => DB_USER, 'password' => DB_PASSWD]] + ['orm' => ['mappings' => ['Mapping' => ['type' => 'xml', 'prefix' => 'Lexik\Bundle\TranslationBundle\Entity', 'is_bundle' => false, 'dir' => '%kernel.project_dir%/Resources/config/doctrine']]], 'dbal' => ['charset' => 'UTF8', 'driver' => DB_ENGINE, 'host' => DB_HOST, 'port' => DB_PORT, 'dbname' => DB_NAME, 'user' => DB_USER, 'password' => DB_PASSWD]] ); } else { throw new Exception("Currently only doctrine is supported"); diff --git a/Tests/bootstrap.php b/Tests/bootstrap.php index 7dd2f835..83bf11e9 100644 --- a/Tests/bootstrap.php +++ b/Tests/bootstrap.php @@ -1,4 +1,5 @@ createElement('trans-unit'); $translationNode->appendChild(new \DOMAttr('id', (string) $id)); - + /** * @see http://docs.oasis-open.org/xliff/v1.2/os/xliff-core.html#approved */ diff --git a/Translation/Importer/FileImporter.php b/Translation/Importer/FileImporter.php index 775e55af..d8c100c2 100644 --- a/Translation/Importer/FileImporter.php +++ b/Translation/Importer/FileImporter.php @@ -2,14 +2,14 @@ namespace Lexik\Bundle\TranslationBundle\Translation\Importer; -use Symfony\Component\Finder\SplFileInfo; -use Lexik\Bundle\TranslationBundle\Entity\Translation; -use Lexik\Bundle\TranslationBundle\Storage\StorageInterface; use Lexik\Bundle\TranslationBundle\Document\TransUnit as TransUnitDocument; +use Lexik\Bundle\TranslationBundle\Entity\Translation; use Lexik\Bundle\TranslationBundle\Manager\FileManagerInterface; -use Lexik\Bundle\TranslationBundle\Manager\TransUnitManagerInterface; -use Lexik\Bundle\TranslationBundle\Manager\TransUnitInterface; use Lexik\Bundle\TranslationBundle\Manager\TranslationInterface; +use Lexik\Bundle\TranslationBundle\Manager\TransUnitInterface; +use Lexik\Bundle\TranslationBundle\Manager\TransUnitManagerInterface; +use Lexik\Bundle\TranslationBundle\Storage\StorageInterface; +use Symfony\Component\Finder\SplFileInfo; /** * Import a translation file into the database. diff --git a/Translation/Translator.php b/Translation/Translator.php index 7b82dc6c..e99d09b2 100644 --- a/Translation/Translator.php +++ b/Translation/Translator.php @@ -114,7 +114,7 @@ public function warmUp(string $cacheDir, ?string $buildDir = null): array /** * Add all resources available in database. - * + * * This method is called by DatabaseResourcesListener to register * database translation resources with the translator. */ @@ -157,7 +157,7 @@ public function removeCacheFile(string $locale): bool $localeExploded = explode('_', $locale); $finder = new Finder(); - $finder->files()->in($this->options['cache_dir'])->name(sprintf( '/catalogue\.%s.*\.php$/', $localeExploded[0])); + $finder->files()->in($this->options['cache_dir'])->name(sprintf('/catalogue\.%s.*\.php$/', $localeExploded[0])); $deleted = true; foreach ($finder as $file) { @@ -165,7 +165,7 @@ public function removeCacheFile(string $locale): bool $this->invalidateSystemCacheForFile($path); $deleted = unlink($path); - $metadata = $path.'.meta'; + $metadata = $path . '.meta'; if (file_exists($metadata)) { $this->invalidateSystemCacheForFile($metadata); unlink($metadata); @@ -191,7 +191,7 @@ public function removeLocalesCacheFiles(array $locales): void unlink($file); } - $metadata = $file.'.meta'; + $metadata = $file . '.meta'; if (file_exists($metadata)) { $this->invalidateSystemCacheForFile($metadata); unlink($metadata); diff --git a/Util/Csrf/CsrfCheckerTrait.php b/Util/Csrf/CsrfCheckerTrait.php index 5a4de918..128b2855 100644 --- a/Util/Csrf/CsrfCheckerTrait.php +++ b/Util/Csrf/CsrfCheckerTrait.php @@ -2,8 +2,8 @@ namespace Lexik\Bundle\TranslationBundle\Util\Csrf; -use Symfony\Component\Security\Csrf\CsrfTokenManager; use Symfony\Component\HttpFoundation\RequestStack; +use Symfony\Component\Security\Csrf\CsrfTokenManager; use Symfony\Contracts\Service\Attribute\Required; /** diff --git a/Util/DataGrid/DataGridFormatter.php b/Util/DataGrid/DataGridFormatter.php index 0f530125..20487632 100644 --- a/Util/DataGrid/DataGridFormatter.php +++ b/Util/DataGrid/DataGridFormatter.php @@ -3,9 +3,9 @@ namespace Lexik\Bundle\TranslationBundle\Util\DataGrid; use Lexik\Bundle\TranslationBundle\Manager\LocaleManagerInterface; +use Lexik\Bundle\TranslationBundle\Manager\TransUnitInterface; use Lexik\Bundle\TranslationBundle\Storage\StorageInterface; use Symfony\Component\HttpFoundation\JsonResponse; -use Lexik\Bundle\TranslationBundle\Manager\TransUnitInterface; /** * @author Cédric Girard @@ -23,7 +23,7 @@ public function __construct( */ public function createListResponse(array $transUnits, int $total): JsonResponse { - return new JsonResponse(['translations' => $this->format($transUnits), 'total' => $total]); + return new JsonResponse(['translations' => $this->format($transUnits), 'total' => $total]); } /** @@ -60,9 +60,9 @@ protected function formatOne(TransUnitInterface|array $transUnit): array } $formatted = [ - '_id' => $transUnit['id'], + '_id' => $transUnit['id'], '_domain' => $transUnit['domain'], - '_key' => $transUnit['key'], + '_key' => $transUnit['key'], ]; // add locales in the same order as in managed_locales param @@ -86,14 +86,14 @@ protected function formatOne(TransUnitInterface|array $transUnit): array protected function toArray(TransUnitInterface $transUnit): array { $data = [ - 'id' => $transUnit->getId(), - 'domain' => $transUnit->getDomain(), - 'key' => $transUnit->getKey(), + 'id' => $transUnit->getId(), + 'domain' => $transUnit->getDomain(), + 'key' => $transUnit->getKey(), 'translations' => [], ]; foreach ($transUnit->getTranslations() as $translation) { - $data['translations'][] = ['locale' => $translation->getLocale(), 'content' => $translation->getContent()]; + $data['translations'][] = ['locale' => $translation->getLocale(), 'content' => $translation->getContent()]; } return $data; diff --git a/Util/DataGrid/DataGridRequestHandler.php b/Util/DataGrid/DataGridRequestHandler.php index 315e78b6..db847bc5 100644 --- a/Util/DataGrid/DataGridRequestHandler.php +++ b/Util/DataGrid/DataGridRequestHandler.php @@ -2,9 +2,9 @@ namespace Lexik\Bundle\TranslationBundle\Util\DataGrid; +use Lexik\Bundle\TranslationBundle\Document\TransUnit as TransUnitDocument; use Lexik\Bundle\TranslationBundle\Manager\FileManagerInterface; use Lexik\Bundle\TranslationBundle\Manager\LocaleManagerInterface; -use Lexik\Bundle\TranslationBundle\Document\TransUnit as TransUnitDocument; use Lexik\Bundle\TranslationBundle\Manager\TransUnitInterface; use Lexik\Bundle\TranslationBundle\Manager\TransUnitManagerInterface; use Lexik\Bundle\TranslationBundle\Model\TransUnit; @@ -200,7 +200,7 @@ protected function filterTokenTranslations($transUnits, $count, $parameters) if (count($filters) > 0) { $end = count($transUnits); - for ($i=0; $i<$end; $i++) { + for ($i = 0; $i < $end; $i++) { $match = true; foreach ($filters as $column => $str) { diff --git a/Util/Overview/StatsAggregator.php b/Util/Overview/StatsAggregator.php index 38add9b9..c3b012f6 100644 --- a/Util/Overview/StatsAggregator.php +++ b/Util/Overview/StatsAggregator.php @@ -32,9 +32,9 @@ public function getStats() foreach ($this->localeManager->getLocales() as $locale) { $localeCount = $byLocale[$locale] ?? 0; - $stats[$domain][$locale] = ['keys' => $total, + $stats[$domain][$locale] = ['keys' => $total, 'translated' => $localeCount, - 'completed' => ($total > 0) ? floor(($localeCount / $total) * 100) : 0, + 'completed' => ($total > 0) ? floor(($localeCount / $total) * 100) : 0, ]; } } From 9eaa7e590560325efaf4fcfb331a4f4c47d6fd2f Mon Sep 17 00:00:00 2001 From: Denis Date: Sun, 15 Mar 2026 18:44:50 +0100 Subject: [PATCH 05/12] Mapping update: modifiedManually is false by default --- Model/Translation.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Model/Translation.php b/Model/Translation.php index e735983c..cfc00c28 100644 --- a/Model/Translation.php +++ b/Model/Translation.php @@ -30,7 +30,7 @@ abstract class Translation #[ORM\Column(name: 'updated_at', type: Types::DATETIME_MUTABLE, nullable: true)] protected $updatedAt; - #[ORM\Column(name: 'modified_manually', type: Types::BOOLEAN, nullable: true)] + #[ORM\Column(name: 'modified_manually', type: Types::BOOLEAN, options: ['default' => false])] protected bool $modifiedManually = false; protected FileInterface $file; From bca5cb413b27a4733537f5be53d3b17d733d5e8c Mon Sep 17 00:00:00 2001 From: Denis Date: Sun, 15 Mar 2026 21:38:27 +0100 Subject: [PATCH 06/12] Remove unused parameters. Cache dir is now configured with the one defined in the Symfony Translator --- DependencyInjection/Compiler/TranslatorPass.php | 14 ++++++++++++++ Resources/config/services.yaml | 3 --- 2 files changed, 14 insertions(+), 3 deletions(-) diff --git a/DependencyInjection/Compiler/TranslatorPass.php b/DependencyInjection/Compiler/TranslatorPass.php index c2e5ab5e..1a1b8427 100644 --- a/DependencyInjection/Compiler/TranslatorPass.php +++ b/DependencyInjection/Compiler/TranslatorPass.php @@ -25,6 +25,7 @@ public function process(ContainerBuilder $container): void $this->processEnabledLocales($container); $this->processFallbacksLocales($container); + $this->processCacheDir($container); $this->processRessources($container); // loaders @@ -114,4 +115,17 @@ private function processEnabledLocales(ContainerBuilder $container): void $translator->replaceArgument(5, $enabledLocales); } } + + private function processCacheDir(ContainerBuilder $container): void + { + $translator = $container->findDefinition('translator.default'); + $options = $translator->getArgument(4); + $cacheDir = $options['cache_dir'] ?? null; + if (null !== $cacheDir) { + $translatorDef = $container->findDefinition('lexik_translation.translator'); + $defaultOptions = $translatorDef->getArgument('$options'); + $defaultOptions['cache_dir'] = $cacheDir; + $translatorDef->replaceArgument('$options', $defaultOptions); + } + } } diff --git a/Resources/config/services.yaml b/Resources/config/services.yaml index 98115338..28f83d47 100644 --- a/Resources/config/services.yaml +++ b/Resources/config/services.yaml @@ -60,9 +60,6 @@ services: $options: cache_dir: '%kernel.cache_dir%/translations' debug: '%kernel.debug%' - resource_files: [] - scanned_directories: [] - cache_vary: [] resources_type: '%lexik_translation.resources_type%' public: true From 41b951bf6c038ccecb740110414b7b64a11768ce Mon Sep 17 00:00:00 2001 From: Denis Date: Sun, 15 Mar 2026 21:47:04 +0100 Subject: [PATCH 07/12] Rollback to PHP 8.4 in Dockerfile --- Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Dockerfile b/Dockerfile index 986dde95..b2c56328 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,4 +1,4 @@ -FROM php:8.3-cli-bullseye +FROM php:8.4-cli-bullseye ENV COMPOSER_ALLOW_SUPERUSER=1 From e7867aca05a6f0ac6b95f3c4814eb51848de6270 Mon Sep 17 00:00:00 2001 From: Denis Date: Sun, 15 Mar 2026 22:11:32 +0100 Subject: [PATCH 08/12] Fix Dockerfile. Upgrade Docker MongoDB from 4.0 to 4.4. --- Dockerfile | 4 ---- docker-compose.yml | 2 +- 2 files changed, 1 insertion(+), 5 deletions(-) diff --git a/Dockerfile b/Dockerfile index b2c56328..7db9c737 100644 --- a/Dockerfile +++ b/Dockerfile @@ -21,8 +21,4 @@ COPY --from=composer:latest /usr/bin/composer /usr/bin/composer WORKDIR /app -COPY . . - -RUN composer install --prefer-dist --no-progress - CMD ["composer", "test"] diff --git a/docker-compose.yml b/docker-compose.yml index 0cd30454..3ea03ee9 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -31,7 +31,7 @@ services: retries: 3 mongo: - image: mongo:4.0 + image: mongo:4.4 environment: MONGO_INITDB_ROOT_USERNAME: admin MONGO_INITDB_ROOT_PASSWORD: secret From 07f06ba8cb4df4fd330fa9379e4cb2645fdd8679 Mon Sep 17 00:00:00 2001 From: Bart McLeod Date: Tue, 7 Jul 2026 23:23:39 +0200 Subject: [PATCH 09/12] Fix file should be allowed to be null --- Document/Translation.php | 2 +- Entity/Translation.php | 2 +- Model/Translation.php | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Document/Translation.php b/Document/Translation.php index 1eccc13e..1bc124da 100644 --- a/Document/Translation.php +++ b/Document/Translation.php @@ -12,7 +12,7 @@ class Translation extends TranslationModel implements TranslationInterface { // Relationship mapping is defined in XML: Resources/config/doctrine/Translation.mongodb-odm.xml - protected FileInterface $file; + protected ?FileInterface $file = null; /** * @deprecated No longer needed since the legacy mongo extension is no longer supported. diff --git a/Entity/Translation.php b/Entity/Translation.php index f6b9f790..8d05ec8b 100644 --- a/Entity/Translation.php +++ b/Entity/Translation.php @@ -24,7 +24,7 @@ class Translation extends TranslationModel implements TranslationInterface // Relationship mappings are defined in XML: Resources/config/doctrine/Translation.orm.xml protected $transUnit; - protected FileInterface $file; + protected ?FileInterface $file = null; // modifiedManually is inherited from TranslationModel diff --git a/Model/Translation.php b/Model/Translation.php index cfc00c28..b0b842d7 100644 --- a/Model/Translation.php +++ b/Model/Translation.php @@ -33,7 +33,7 @@ abstract class Translation #[ORM\Column(name: 'modified_manually', type: Types::BOOLEAN, options: ['default' => false])] protected bool $modifiedManually = false; - protected FileInterface $file; + protected ?FileInterface $file = null; /** * Set locale @@ -107,7 +107,7 @@ public function setFile(FileInterface $file): void $this->file = $file; } - public function getFile(): FileInterface + public function getFile(): ?FileInterface { return $this->file; } From 9f9840897d32c320c83ebb1fd1732947cbf81a2f Mon Sep 17 00:00:00 2001 From: Bart McLeod Date: Tue, 7 Jul 2026 23:24:26 +0200 Subject: [PATCH 10/12] Compose update --- composer.lock | 1789 +++++++++++++++++++++++-------------------------- 1 file changed, 835 insertions(+), 954 deletions(-) diff --git a/composer.lock b/composer.lock index fffd5241..8bf274fb 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "2f22c916da236e6c350a1e7cab9f61bf", + "content-hash": "b8d2269beaad4139f7b57df745e01ca2", "packages": [ { "name": "doctrine/collections", @@ -94,16 +94,16 @@ }, { "name": "doctrine/dbal", - "version": "4.4.2", + "version": "4.4.3", "source": { "type": "git", "url": "https://github.com/doctrine/dbal.git", - "reference": "476f7f0fa6ea4aa5364926db7fabdf6049075722" + "reference": "61e730f1658814821a85f2402c945f3883407dec" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/doctrine/dbal/zipball/476f7f0fa6ea4aa5364926db7fabdf6049075722", - "reference": "476f7f0fa6ea4aa5364926db7fabdf6049075722", + "url": "https://api.github.com/repos/doctrine/dbal/zipball/61e730f1658814821a85f2402c945f3883407dec", + "reference": "61e730f1658814821a85f2402c945f3883407dec", "shasum": "" }, "require": { @@ -180,7 +180,7 @@ ], "support": { "issues": "https://github.com/doctrine/dbal/issues", - "source": "https://github.com/doctrine/dbal/tree/4.4.2" + "source": "https://github.com/doctrine/dbal/tree/4.4.3" }, "funding": [ { @@ -196,7 +196,7 @@ "type": "tidelift" } ], - "time": "2026-02-26T12:12:19+00:00" + "time": "2026-03-20T08:52:12+00:00" }, { "name": "doctrine/deprecations", @@ -248,63 +248,58 @@ }, { "name": "doctrine/doctrine-bundle", - "version": "2.18.2", + "version": "3.2.4", "source": { "type": "git", "url": "https://github.com/doctrine/DoctrineBundle.git", - "reference": "0ff098b29b8b3c68307c8987dcaed7fd829c6546" + "reference": "75f1bf75d0ba099f23e7d43ebd804df5bec58c29" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/doctrine/DoctrineBundle/zipball/0ff098b29b8b3c68307c8987dcaed7fd829c6546", - "reference": "0ff098b29b8b3c68307c8987dcaed7fd829c6546", + "url": "https://api.github.com/repos/doctrine/DoctrineBundle/zipball/75f1bf75d0ba099f23e7d43ebd804df5bec58c29", + "reference": "75f1bf75d0ba099f23e7d43ebd804df5bec58c29", "shasum": "" }, "require": { - "doctrine/dbal": "^3.7.0 || ^4.0", + "doctrine/dbal": "^4.0", "doctrine/deprecations": "^1.0", - "doctrine/persistence": "^3.1 || ^4", + "doctrine/persistence": "^4", "doctrine/sql-formatter": "^1.0.1", - "php": "^8.1", - "symfony/cache": "^6.4 || ^7.0", - "symfony/config": "^6.4 || ^7.0", - "symfony/console": "^6.4 || ^7.0", - "symfony/dependency-injection": "^6.4 || ^7.0", - "symfony/doctrine-bridge": "^6.4.3 || ^7.0.3", - "symfony/framework-bundle": "^6.4 || ^7.0", - "symfony/service-contracts": "^2.5 || ^3" + "php": "^8.4", + "symfony/cache": "^6.4 || ^7.0 || ^8.0", + "symfony/config": "^6.4 || ^7.0 || ^8.0", + "symfony/console": "^6.4 || ^7.0 || ^8.0", + "symfony/dependency-injection": "^6.4 || ^7.0 || ^8.0", + "symfony/doctrine-bridge": "^6.4.3 || ^7.0.3 || ^8.0", + "symfony/framework-bundle": "^6.4 || ^7.0 || ^8.0", + "symfony/service-contracts": "^3" }, "conflict": { - "doctrine/annotations": ">=3.0", - "doctrine/cache": "< 1.11", - "doctrine/orm": "<2.17 || >=4.0", - "symfony/var-exporter": "< 6.4.1 || 7.0.0", - "twig/twig": "<2.13 || >=3.0 <3.0.4" + "doctrine/orm": "<3.0 || >=4.0", + "twig/twig": "<3.0.4" }, "require-dev": { - "doctrine/annotations": "^1 || ^2", - "doctrine/cache": "^1.11 || ^2.0", "doctrine/coding-standard": "^14", - "doctrine/orm": "^2.17 || ^3.1", - "friendsofphp/proxy-manager-lts": "^1.0", - "phpstan/phpstan": "2.1.1", + "doctrine/orm": "^3.4.4", + "phpstan/phpstan": "^2.1.13", "phpstan/phpstan-phpunit": "2.0.3", "phpstan/phpstan-strict-rules": "^2", - "phpunit/phpunit": "^10.5.53 || ^12.3.10", - "psr/log": "^1.1.4 || ^2.0 || ^3.0", - "symfony/doctrine-messenger": "^6.4 || ^7.0", - "symfony/expression-language": "^6.4 || ^7.0", - "symfony/messenger": "^6.4 || ^7.0", - "symfony/property-info": "^6.4 || ^7.0", - "symfony/security-bundle": "^6.4 || ^7.0", - "symfony/stopwatch": "^6.4 || ^7.0", - "symfony/string": "^6.4 || ^7.0", - "symfony/twig-bridge": "^6.4 || ^7.0", - "symfony/validator": "^6.4 || ^7.0", - "symfony/var-exporter": "^6.4.1 || ^7.0.1", - "symfony/web-profiler-bundle": "^6.4 || ^7.0", - "symfony/yaml": "^6.4 || ^7.0", - "twig/twig": "^2.14.7 || ^3.0.4" + "phpstan/phpstan-symfony": "^2.0.9", + "phpunit/phpunit": "^12.3.10", + "psr/log": "^3.0", + "symfony/doctrine-messenger": "^6.4 || ^7.0 || ^8.0", + "symfony/expression-language": "^6.4 || ^7.0 || ^8.0", + "symfony/http-kernel": "^6.4 || ^7.0 || ^8.0", + "symfony/messenger": "^6.4 || ^7.0 || ^8.0", + "symfony/property-info": "^6.4 || ^7.0 || ^8.0", + "symfony/security-bundle": "^6.4 || ^7.0 || ^8.0", + "symfony/stopwatch": "^6.4 || ^7.0 || ^8.0", + "symfony/string": "^6.4 || ^7.0 || ^8.0", + "symfony/twig-bridge": "^6.4 || ^7.0 || ^8.0", + "symfony/validator": "^6.4 || ^7.0 || ^8.0", + "symfony/web-profiler-bundle": "^6.4 || ^7.0 || ^8.0", + "symfony/yaml": "^6.4 || ^7.0 || ^8.0", + "twig/twig": "^3.21.1" }, "suggest": { "doctrine/orm": "The Doctrine ORM integration is optional in the bundle.", @@ -349,7 +344,7 @@ ], "support": { "issues": "https://github.com/doctrine/DoctrineBundle/issues", - "source": "https://github.com/doctrine/DoctrineBundle/tree/2.18.2" + "source": "https://github.com/doctrine/DoctrineBundle/tree/3.2.4" }, "funding": [ { @@ -365,41 +360,48 @@ "type": "tidelift" } ], - "time": "2025-12-20T21:35:32+00:00" + "time": "2026-06-09T19:11:55+00:00" }, { "name": "doctrine/doctrine-migrations-bundle", - "version": "3.7.0", + "version": "4.0.0", "source": { "type": "git", "url": "https://github.com/doctrine/DoctrineMigrationsBundle.git", - "reference": "1e380c6dd8ac8488217f39cff6b77e367f1a644b" + "reference": "20505da78735744fb4a42a3bb9a416b345ad6f7c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/doctrine/DoctrineMigrationsBundle/zipball/1e380c6dd8ac8488217f39cff6b77e367f1a644b", - "reference": "1e380c6dd8ac8488217f39cff6b77e367f1a644b", + "url": "https://api.github.com/repos/doctrine/DoctrineMigrationsBundle/zipball/20505da78735744fb4a42a3bb9a416b345ad6f7c", + "reference": "20505da78735744fb4a42a3bb9a416b345ad6f7c", "shasum": "" }, "require": { - "doctrine/doctrine-bundle": "^2.4 || ^3.0", + "doctrine/dbal": "^4", + "doctrine/doctrine-bundle": "^3", "doctrine/migrations": "^3.2", - "php": "^7.2 || ^8.0", - "symfony/deprecation-contracts": "^2.1 || ^3", - "symfony/framework-bundle": "^5.4 || ^6.0 || ^7.0 || ^8.0" + "php": "^8.4", + "psr/log": "^3", + "symfony/config": "^6.4 || ^7.0 || ^8.0", + "symfony/console": "^6.4 || ^7.0 || ^8.0", + "symfony/dependency-injection": "^6.4 || ^7.0 || ^8.0", + "symfony/deprecation-contracts": "^3", + "symfony/framework-bundle": "^6.4 || ^7.0 || ^8.0", + "symfony/http-foundation": "^6.4 || ^7.0 || ^8.0", + "symfony/http-kernel": "^6.4 || ^7.0 || ^8.0", + "symfony/service-contracts": "^3.0" }, "require-dev": { "composer/semver": "^3.0", - "doctrine/coding-standard": "^12 || ^14", - "doctrine/orm": "^2.6 || ^3", - "phpstan/phpstan": "^1.4 || ^2", - "phpstan/phpstan-deprecation-rules": "^1 || ^2", - "phpstan/phpstan-phpunit": "^1 || ^2", - "phpstan/phpstan-strict-rules": "^1.1 || ^2", - "phpstan/phpstan-symfony": "^1.3 || ^2", - "phpunit/phpunit": "^8.5 || ^9.5", - "symfony/phpunit-bridge": "^6.3 || ^7 || ^8", - "symfony/var-exporter": "^5.4 || ^6 || ^7 || ^8" + "doctrine/coding-standard": "^14", + "doctrine/orm": "^3", + "phpstan/phpstan": "^2", + "phpstan/phpstan-deprecation-rules": "^2", + "phpstan/phpstan-phpunit": "^2", + "phpstan/phpstan-strict-rules": "^2", + "phpstan/phpstan-symfony": "^2", + "phpunit/phpunit": "^12.5", + "symfony/var-exporter": "^6.4 || ^7 || ^8" }, "type": "symfony-bundle", "autoload": { @@ -434,7 +436,7 @@ ], "support": { "issues": "https://github.com/doctrine/DoctrineMigrationsBundle/issues", - "source": "https://github.com/doctrine/DoctrineMigrationsBundle/tree/3.7.0" + "source": "https://github.com/doctrine/DoctrineMigrationsBundle/tree/4.0.0" }, "funding": [ { @@ -450,7 +452,7 @@ "type": "tidelift" } ], - "time": "2025-11-15T19:02:59+00:00" + "time": "2025-12-05T08:14:38+00:00" }, { "name": "doctrine/event-manager", @@ -635,30 +637,29 @@ }, { "name": "doctrine/instantiator", - "version": "2.0.0", + "version": "2.1.0", "source": { "type": "git", "url": "https://github.com/doctrine/instantiator.git", - "reference": "c6222283fa3f4ac679f8b9ced9a4e23f163e80d0" + "reference": "23da848e1a2308728fe5fdddabf4be17ff9720c7" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/doctrine/instantiator/zipball/c6222283fa3f4ac679f8b9ced9a4e23f163e80d0", - "reference": "c6222283fa3f4ac679f8b9ced9a4e23f163e80d0", + "url": "https://api.github.com/repos/doctrine/instantiator/zipball/23da848e1a2308728fe5fdddabf4be17ff9720c7", + "reference": "23da848e1a2308728fe5fdddabf4be17ff9720c7", "shasum": "" }, "require": { - "php": "^8.1" + "php": "^8.4" }, "require-dev": { - "doctrine/coding-standard": "^11", + "doctrine/coding-standard": "^14", "ext-pdo": "*", "ext-phar": "*", "phpbench/phpbench": "^1.2", - "phpstan/phpstan": "^1.9.4", - "phpstan/phpstan-phpunit": "^1.3", - "phpunit/phpunit": "^9.5.27", - "vimeo/psalm": "^5.4" + "phpstan/phpstan": "^2.1", + "phpstan/phpstan-phpunit": "^2.0", + "phpunit/phpunit": "^10.5.58" }, "type": "library", "autoload": { @@ -685,7 +686,7 @@ ], "support": { "issues": "https://github.com/doctrine/instantiator/issues", - "source": "https://github.com/doctrine/instantiator/tree/2.0.0" + "source": "https://github.com/doctrine/instantiator/tree/2.1.0" }, "funding": [ { @@ -701,7 +702,7 @@ "type": "tidelift" } ], - "time": "2022-12-30T00:23:10+00:00" + "time": "2026-01-05T06:47:08+00:00" }, { "name": "doctrine/lexer", @@ -782,16 +783,16 @@ }, { "name": "doctrine/migrations", - "version": "3.9.6", + "version": "3.9.7", "source": { "type": "git", "url": "https://github.com/doctrine/migrations.git", - "reference": "ffd8355cdd8505fc650d9604f058bf62aedd80a1" + "reference": "96cb2a89b56c9efb0bac38e606dc0b0f13e650ec" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/doctrine/migrations/zipball/ffd8355cdd8505fc650d9604f058bf62aedd80a1", - "reference": "ffd8355cdd8505fc650d9604f058bf62aedd80a1", + "url": "https://api.github.com/repos/doctrine/migrations/zipball/96cb2a89b56c9efb0bac38e606dc0b0f13e650ec", + "reference": "96cb2a89b56c9efb0bac38e606dc0b0f13e650ec", "shasum": "" }, "require": { @@ -865,7 +866,7 @@ ], "support": { "issues": "https://github.com/doctrine/migrations/issues", - "source": "https://github.com/doctrine/migrations/tree/3.9.6" + "source": "https://github.com/doctrine/migrations/tree/3.9.7" }, "funding": [ { @@ -881,20 +882,20 @@ "type": "tidelift" } ], - "time": "2026-02-11T06:46:11+00:00" + "time": "2026-04-23T19:33:20+00:00" }, { "name": "doctrine/orm", - "version": "3.6.2", + "version": "3.6.7", "source": { "type": "git", "url": "https://github.com/doctrine/orm.git", - "reference": "4262eb495b4d2a53b45de1ac58881e0091f2970f" + "reference": "bc217c0e19c3a9eadfa67697143b87c9ba01272c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/doctrine/orm/zipball/4262eb495b4d2a53b45de1ac58881e0091f2970f", - "reference": "4262eb495b4d2a53b45de1ac58881e0091f2970f", + "url": "https://api.github.com/repos/doctrine/orm/zipball/bc217c0e19c3a9eadfa67697143b87c9ba01272c", + "reference": "bc217c0e19c3a9eadfa67697143b87c9ba01272c", "shasum": "" }, "require": { @@ -967,25 +968,26 @@ ], "support": { "issues": "https://github.com/doctrine/orm/issues", - "source": "https://github.com/doctrine/orm/tree/3.6.2" + "source": "https://github.com/doctrine/orm/tree/3.6.7" }, - "time": "2026-01-30T21:41:41+00:00" + "time": "2026-05-25T16:45:47+00:00" }, { "name": "doctrine/persistence", - "version": "4.1.1", + "version": "4.2.0", "source": { "type": "git", "url": "https://github.com/doctrine/persistence.git", - "reference": "b9c49ad3558bb77ef973f4e173f2e9c2eca9be09" + "reference": "49ab73e0d3e2ac8d1f5ecda3dd8acd5503781e8b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/doctrine/persistence/zipball/b9c49ad3558bb77ef973f4e173f2e9c2eca9be09", - "reference": "b9c49ad3558bb77ef973f4e173f2e9c2eca9be09", + "url": "https://api.github.com/repos/doctrine/persistence/zipball/49ab73e0d3e2ac8d1f5ecda3dd8acd5503781e8b", + "reference": "49ab73e0d3e2ac8d1f5ecda3dd8acd5503781e8b", "shasum": "" }, "require": { + "doctrine/deprecations": "^1", "doctrine/event-manager": "^1 || ^2", "php": "^8.1", "psr/cache": "^1.0 || ^2.0 || ^3.0" @@ -996,13 +998,13 @@ "phpstan/phpstan-phpunit": "^2", "phpstan/phpstan-strict-rules": "^2", "phpunit/phpunit": "^10.5.58 || ^12", - "symfony/cache": "^4.4 || ^5.4 || ^6.0 || ^7.0", - "symfony/finder": "^4.4 || ^5.4 || ^6.0 || ^7.0" + "symfony/cache": "^4.4 || ^5.4 || ^6.0 || ^7.0 || ^8.0", + "symfony/finder": "^4.4 || ^5.4 || ^6.0 || ^7.0 || ^8.0" }, "type": "library", "autoload": { "psr-4": { - "Doctrine\\Persistence\\": "src/Persistence" + "Doctrine\\Persistence\\": "src" } }, "notification-url": "https://packagist.org/downloads/", @@ -1046,7 +1048,7 @@ ], "support": { "issues": "https://github.com/doctrine/persistence/issues", - "source": "https://github.com/doctrine/persistence/tree/4.1.1" + "source": "https://github.com/doctrine/persistence/tree/4.2.0" }, "funding": [ { @@ -1062,7 +1064,7 @@ "type": "tidelift" } ], - "time": "2025-10-16T20:13:18+00:00" + "time": "2026-04-26T12:12:52+00:00" }, { "name": "doctrine/sql-formatter", @@ -1426,28 +1428,25 @@ }, { "name": "symfony/asset", - "version": "v7.4.6", + "version": "v8.1.0", "source": { "type": "git", "url": "https://github.com/symfony/asset.git", - "reference": "d944ae87e4697af05aadeacfc5e603c3c18ef4fb" + "reference": "4bd4d143b7e53f40d45877df52eb2b18282bdac4" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/asset/zipball/d944ae87e4697af05aadeacfc5e603c3c18ef4fb", - "reference": "d944ae87e4697af05aadeacfc5e603c3c18ef4fb", + "url": "https://api.github.com/repos/symfony/asset/zipball/4bd4d143b7e53f40d45877df52eb2b18282bdac4", + "reference": "4bd4d143b7e53f40d45877df52eb2b18282bdac4", "shasum": "" }, "require": { - "php": ">=8.2" - }, - "conflict": { - "symfony/http-foundation": "<6.4" + "php": ">=8.4.1" }, "require-dev": { - "symfony/http-client": "^6.4|^7.0|^8.0", - "symfony/http-foundation": "^6.4|^7.0|^8.0", - "symfony/http-kernel": "^6.4|^7.0|^8.0" + "symfony/http-client": "^7.4|^8.0", + "symfony/http-foundation": "^7.4|^8.0", + "symfony/http-kernel": "^7.4|^8.0" }, "type": "library", "autoload": { @@ -1475,7 +1474,7 @@ "description": "Manages URL generation and versioning of web assets such as CSS stylesheets, JavaScript files and image files", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/asset/tree/v7.4.6" + "source": "https://github.com/symfony/asset/tree/v8.1.0" }, "funding": [ { @@ -1495,38 +1494,33 @@ "type": "tidelift" } ], - "time": "2026-02-09T09:33:46+00:00" + "time": "2026-05-29T05:06:50+00:00" }, { "name": "symfony/cache", - "version": "v7.4.13", + "version": "v8.0.14", "source": { "type": "git", "url": "https://github.com/symfony/cache.git", - "reference": "4c09e18a92cce126cc0d1155825279fca8cd0673" + "reference": "76ec84217eb39e4787d03928bba86a25cc859f76" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/cache/zipball/4c09e18a92cce126cc0d1155825279fca8cd0673", - "reference": "4c09e18a92cce126cc0d1155825279fca8cd0673", + "url": "https://api.github.com/repos/symfony/cache/zipball/76ec84217eb39e4787d03928bba86a25cc859f76", + "reference": "76ec84217eb39e4787d03928bba86a25cc859f76", "shasum": "" }, "require": { - "php": ">=8.2", + "php": ">=8.4", "psr/cache": "^2.0|^3.0", "psr/log": "^1.1|^2|^3", "symfony/cache-contracts": "^3.6", - "symfony/deprecation-contracts": "^2.5|^3", "symfony/service-contracts": "^2.5|^3", - "symfony/var-exporter": "^6.4|^7.0|^8.0" + "symfony/var-exporter": "^7.4|^8.0" }, "conflict": { - "doctrine/dbal": "<3.6", "ext-redis": "<6.1", - "ext-relay": "<0.12.1", - "symfony/dependency-injection": "<6.4", - "symfony/http-kernel": "<6.4", - "symfony/var-dumper": "<6.4" + "ext-relay": "<0.12.1" }, "provide": { "psr/cache-implementation": "2.0|3.0", @@ -1535,16 +1529,16 @@ }, "require-dev": { "cache/integration-tests": "dev-master", - "doctrine/dbal": "^3.6|^4", + "doctrine/dbal": "^4.3", "predis/predis": "^1.1|^2.0", "psr/simple-cache": "^1.0|^2.0|^3.0", - "symfony/clock": "^6.4|^7.0|^8.0", - "symfony/config": "^6.4|^7.0|^8.0", - "symfony/dependency-injection": "^6.4|^7.0|^8.0", - "symfony/filesystem": "^6.4|^7.0|^8.0", - "symfony/http-kernel": "^6.4|^7.0|^8.0", - "symfony/messenger": "^6.4|^7.0|^8.0", - "symfony/var-dumper": "^6.4|^7.0|^8.0" + "symfony/clock": "^7.4|^8.0", + "symfony/config": "^7.4|^8.0", + "symfony/dependency-injection": "^7.4|^8.0", + "symfony/filesystem": "^7.4|^8.0", + "symfony/http-kernel": "^7.4|^8.0", + "symfony/messenger": "^7.4|^8.0", + "symfony/var-dumper": "^7.4|^8.0" }, "type": "library", "autoload": { @@ -1579,7 +1573,7 @@ "psr6" ], "support": { - "source": "https://github.com/symfony/cache/tree/v7.4.13" + "source": "https://github.com/symfony/cache/tree/v8.0.14" }, "funding": [ { @@ -1599,20 +1593,20 @@ "type": "tidelift" } ], - "time": "2026-05-24T08:43:14+00:00" + "time": "2026-06-17T15:00:27+00:00" }, { "name": "symfony/cache-contracts", - "version": "v3.7.0", + "version": "v3.7.1", "source": { "type": "git", "url": "https://github.com/symfony/cache-contracts.git", - "reference": "225e8a254166bd3442e370c6f50145465db63831" + "reference": "9789738bc19af1106dc54d6afba9a0b467516cf2" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/cache-contracts/zipball/225e8a254166bd3442e370c6f50145465db63831", - "reference": "225e8a254166bd3442e370c6f50145465db63831", + "url": "https://api.github.com/repos/symfony/cache-contracts/zipball/9789738bc19af1106dc54d6afba9a0b467516cf2", + "reference": "9789738bc19af1106dc54d6afba9a0b467516cf2", "shasum": "" }, "require": { @@ -1659,7 +1653,7 @@ "standards" ], "support": { - "source": "https://github.com/symfony/cache-contracts/tree/v3.7.0" + "source": "https://github.com/symfony/cache-contracts/tree/v3.7.1" }, "funding": [ { @@ -1679,38 +1673,37 @@ "type": "tidelift" } ], - "time": "2026-05-05T15:33:14+00:00" + "time": "2026-06-05T06:23:12+00:00" }, { "name": "symfony/config", - "version": "v7.4.7", + "version": "v8.1.1", "source": { "type": "git", "url": "https://github.com/symfony/config.git", - "reference": "6c17162555bfb58957a55bb0e43e00035b6ae3d5" + "reference": "c18ae45733f9a5006ba81a13047d08a93e0dea1c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/config/zipball/6c17162555bfb58957a55bb0e43e00035b6ae3d5", - "reference": "6c17162555bfb58957a55bb0e43e00035b6ae3d5", + "url": "https://api.github.com/repos/symfony/config/zipball/c18ae45733f9a5006ba81a13047d08a93e0dea1c", + "reference": "c18ae45733f9a5006ba81a13047d08a93e0dea1c", "shasum": "" }, "require": { - "php": ">=8.2", + "php": ">=8.4.1", "symfony/deprecation-contracts": "^2.5|^3", - "symfony/filesystem": "^7.1|^8.0", - "symfony/polyfill-ctype": "~1.8" + "symfony/filesystem": "^7.4|^8.0", + "symfony/polyfill-ctype": "^1.8" }, "conflict": { - "symfony/finder": "<6.4", "symfony/service-contracts": "<2.5" }, "require-dev": { - "symfony/event-dispatcher": "^6.4|^7.0|^8.0", - "symfony/finder": "^6.4|^7.0|^8.0", - "symfony/messenger": "^6.4|^7.0|^8.0", + "symfony/event-dispatcher": "^7.4|^8.0", + "symfony/finder": "^7.4|^8.0", + "symfony/messenger": "^7.4|^8.0", "symfony/service-contracts": "^2.5|^3", - "symfony/yaml": "^6.4|^7.0|^8.0" + "symfony/yaml": "^7.4|^8.0" }, "type": "library", "autoload": { @@ -1738,7 +1731,7 @@ "description": "Helps you find, load, combine, autofill and validate configuration values of any kind", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/config/tree/v7.4.7" + "source": "https://github.com/symfony/config/tree/v8.1.1" }, "funding": [ { @@ -1758,51 +1751,43 @@ "type": "tidelift" } ], - "time": "2026-03-06T10:41:14+00:00" + "time": "2026-06-09T10:54:51+00:00" }, { "name": "symfony/console", - "version": "v7.4.7", + "version": "v8.0.14", "source": { "type": "git", "url": "https://github.com/symfony/console.git", - "reference": "e1e6770440fb9c9b0cf725f81d1361ad1835329d" + "reference": "e2a77289192c413abfe54f1d507159f911a20728" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/console/zipball/e1e6770440fb9c9b0cf725f81d1361ad1835329d", - "reference": "e1e6770440fb9c9b0cf725f81d1361ad1835329d", + "url": "https://api.github.com/repos/symfony/console/zipball/e2a77289192c413abfe54f1d507159f911a20728", + "reference": "e2a77289192c413abfe54f1d507159f911a20728", "shasum": "" }, "require": { - "php": ">=8.2", - "symfony/deprecation-contracts": "^2.5|^3", - "symfony/polyfill-mbstring": "~1.0", + "php": ">=8.4", + "symfony/polyfill-mbstring": "^1.0", "symfony/service-contracts": "^2.5|^3", - "symfony/string": "^7.2|^8.0" - }, - "conflict": { - "symfony/dependency-injection": "<6.4", - "symfony/dotenv": "<6.4", - "symfony/event-dispatcher": "<6.4", - "symfony/lock": "<6.4", - "symfony/process": "<6.4" + "symfony/string": "^7.4|^8.0" }, "provide": { "psr/log-implementation": "1.0|2.0|3.0" }, "require-dev": { "psr/log": "^1|^2|^3", - "symfony/config": "^6.4|^7.0|^8.0", - "symfony/dependency-injection": "^6.4|^7.0|^8.0", - "symfony/event-dispatcher": "^6.4|^7.0|^8.0", - "symfony/http-foundation": "^6.4|^7.0|^8.0", - "symfony/http-kernel": "^6.4|^7.0|^8.0", - "symfony/lock": "^6.4|^7.0|^8.0", - "symfony/messenger": "^6.4|^7.0|^8.0", - "symfony/process": "^6.4|^7.0|^8.0", - "symfony/stopwatch": "^6.4|^7.0|^8.0", - "symfony/var-dumper": "^6.4|^7.0|^8.0" + "symfony/config": "^7.4|^8.0", + "symfony/dependency-injection": "^7.4|^8.0", + "symfony/event-dispatcher": "^7.4|^8.0", + "symfony/http-foundation": "^7.4|^8.0", + "symfony/http-kernel": "^7.4|^8.0", + "symfony/lock": "^7.4|^8.0", + "symfony/messenger": "^7.4|^8.0", + "symfony/process": "^7.4|^8.0", + "symfony/stopwatch": "^7.4|^8.0", + "symfony/var-dumper": "^7.4|^8.0" }, "type": "library", "autoload": { @@ -1836,7 +1821,7 @@ "terminal" ], "support": { - "source": "https://github.com/symfony/console/tree/v7.4.7" + "source": "https://github.com/symfony/console/tree/v8.0.14" }, "funding": [ { @@ -1856,43 +1841,40 @@ "type": "tidelift" } ], - "time": "2026-03-06T14:06:20+00:00" + "time": "2026-06-16T12:45:11+00:00" }, { "name": "symfony/dependency-injection", - "version": "v7.4.7", + "version": "v8.0.14", "source": { "type": "git", "url": "https://github.com/symfony/dependency-injection.git", - "reference": "0f651e58f4917fb0e2cd261ccbfe3d71e6e0f5db" + "reference": "55d83c634f0bd7d6b5f64be8950dc389dca17a17" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/dependency-injection/zipball/0f651e58f4917fb0e2cd261ccbfe3d71e6e0f5db", - "reference": "0f651e58f4917fb0e2cd261ccbfe3d71e6e0f5db", + "url": "https://api.github.com/repos/symfony/dependency-injection/zipball/55d83c634f0bd7d6b5f64be8950dc389dca17a17", + "reference": "55d83c634f0bd7d6b5f64be8950dc389dca17a17", "shasum": "" }, "require": { - "php": ">=8.2", + "php": ">=8.4", "psr/container": "^1.1|^2.0", "symfony/deprecation-contracts": "^2.5|^3", "symfony/service-contracts": "^3.6", - "symfony/var-exporter": "^6.4.20|^7.2.5|^8.0" + "symfony/var-exporter": "^7.4|^8.0" }, "conflict": { - "ext-psr": "<1.1|>=2", - "symfony/config": "<6.4", - "symfony/finder": "<6.4", - "symfony/yaml": "<6.4" + "ext-psr": "<1.1|>=2" }, "provide": { "psr/container-implementation": "1.1|2.0", "symfony/service-implementation": "1.1|2.0|3.0" }, "require-dev": { - "symfony/config": "^6.4|^7.0|^8.0", - "symfony/expression-language": "^6.4|^7.0|^8.0", - "symfony/yaml": "^6.4|^7.0|^8.0" + "symfony/config": "^7.4|^8.0", + "symfony/expression-language": "^7.4|^8.0", + "symfony/yaml": "^7.4|^8.0" }, "type": "library", "autoload": { @@ -1920,7 +1902,7 @@ "description": "Allows you to standardize and centralize the way objects are constructed in your application", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/dependency-injection/tree/v7.4.7" + "source": "https://github.com/symfony/dependency-injection/tree/v8.0.14" }, "funding": [ { @@ -1940,20 +1922,20 @@ "type": "tidelift" } ], - "time": "2026-03-03T07:48:48+00:00" + "time": "2026-06-27T06:17:20+00:00" }, { "name": "symfony/deprecation-contracts", - "version": "v3.7.0", + "version": "v3.7.1", "source": { "type": "git", "url": "https://github.com/symfony/deprecation-contracts.git", - "reference": "50f59d1f3ca46d41ac911f97a78626b6756af35b" + "reference": "f3202fa1b5097b0af062dc978b32ecf63404e31d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/50f59d1f3ca46d41ac911f97a78626b6756af35b", - "reference": "50f59d1f3ca46d41ac911f97a78626b6756af35b", + "url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/f3202fa1b5097b0af062dc978b32ecf63404e31d", + "reference": "f3202fa1b5097b0af062dc978b32ecf63404e31d", "shasum": "" }, "require": { @@ -1991,7 +1973,7 @@ "description": "A generic function and convention to trigger deprecation notices", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/deprecation-contracts/tree/v3.7.0" + "source": "https://github.com/symfony/deprecation-contracts/tree/v3.7.1" }, "funding": [ { @@ -2011,72 +1993,63 @@ "type": "tidelift" } ], - "time": "2026-04-13T15:52:40+00:00" + "time": "2026-06-05T06:23:12+00:00" }, { "name": "symfony/doctrine-bridge", - "version": "v7.4.7", + "version": "v8.1.1", "source": { "type": "git", "url": "https://github.com/symfony/doctrine-bridge.git", - "reference": "4fc5e2dd41be3c0b6321e0373072782edeff45ed" + "reference": "883547207ff3b77c5cec9f4f16dd330ccd7b2849" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/doctrine-bridge/zipball/4fc5e2dd41be3c0b6321e0373072782edeff45ed", - "reference": "4fc5e2dd41be3c0b6321e0373072782edeff45ed", + "url": "https://api.github.com/repos/symfony/doctrine-bridge/zipball/883547207ff3b77c5cec9f4f16dd330ccd7b2849", + "reference": "883547207ff3b77c5cec9f4f16dd330ccd7b2849", "shasum": "" }, "require": { "doctrine/event-manager": "^2", "doctrine/persistence": "^3.1|^4", - "php": ">=8.2", + "php": ">=8.4.1", "symfony/deprecation-contracts": "^2.5|^3", - "symfony/polyfill-ctype": "~1.8", - "symfony/polyfill-mbstring": "~1.0", + "symfony/polyfill-ctype": "^1.8", + "symfony/polyfill-mbstring": "^1.0", "symfony/service-contracts": "^2.5|^3" }, "conflict": { "doctrine/collections": "<1.8", - "doctrine/dbal": "<3.6", + "doctrine/dbal": "<4.3", "doctrine/lexer": "<1.1", - "doctrine/orm": "<2.15", - "symfony/cache": "<6.4", - "symfony/dependency-injection": "<6.4", - "symfony/form": "<6.4.6|>=7,<7.0.6", - "symfony/http-foundation": "<6.4", - "symfony/http-kernel": "<6.4", - "symfony/lock": "<6.4", - "symfony/messenger": "<6.4", - "symfony/property-info": "<6.4", - "symfony/security-bundle": "<6.4", - "symfony/security-core": "<6.4", - "symfony/validator": "<7.4" + "doctrine/orm": "<3.4", + "symfony/property-info": "<8.0" }, "require-dev": { "doctrine/collections": "^1.8|^2.0", "doctrine/data-fixtures": "^1.1|^2", - "doctrine/dbal": "^3.6|^4", - "doctrine/orm": "^2.15|^3", + "doctrine/dbal": "^4.3", + "doctrine/orm": "^3.4", "psr/log": "^1|^2|^3", - "symfony/cache": "^6.4|^7.0|^8.0", - "symfony/config": "^6.4|^7.0|^8.0", - "symfony/dependency-injection": "^6.4|^7.0|^8.0", - "symfony/doctrine-messenger": "^6.4|^7.0|^8.0", - "symfony/expression-language": "^6.4|^7.0|^8.0", - "symfony/form": "^7.2|^8.0", - "symfony/http-kernel": "^6.4|^7.0|^8.0", - "symfony/lock": "^6.4|^7.0|^8.0", - "symfony/messenger": "^6.4|^7.0|^8.0", - "symfony/property-access": "^6.4|^7.0|^8.0", - "symfony/property-info": "^6.4|^7.0|^8.0", - "symfony/security-core": "^6.4|^7.0|^8.0", - "symfony/stopwatch": "^6.4|^7.0|^8.0", - "symfony/translation": "^6.4|^7.0|^8.0", - "symfony/type-info": "^7.1.8|^8.0", - "symfony/uid": "^6.4|^7.0|^8.0", + "symfony/cache": "^7.4|^8.0", + "symfony/config": "^7.4|^8.0", + "symfony/console": "^8.1", + "symfony/dependency-injection": "^7.4|^8.0", + "symfony/doctrine-messenger": "^7.4|^8.0", + "symfony/expression-language": "^7.4|^8.0", + "symfony/form": "^7.4|^8.0", + "symfony/http-kernel": "^7.4|^8.0", + "symfony/lock": "^7.4|^8.0", + "symfony/messenger": "^7.4|^8.0", + "symfony/property-access": "^7.4|^8.0", + "symfony/property-info": "^8.0", + "symfony/security-core": "^7.4|^8.0", + "symfony/stopwatch": "^7.4|^8.0", + "symfony/translation": "^7.4|^8.0", + "symfony/type-info": "^7.4|^8.0", + "symfony/uid": "^7.4|^8.0", "symfony/validator": "^7.4|^8.0", - "symfony/var-dumper": "^6.4|^7.0|^8.0" + "symfony/var-dumper": "^7.4|^8.0" }, "type": "symfony-bridge", "autoload": { @@ -2104,7 +2077,7 @@ "description": "Provides integration for Doctrine with various Symfony components", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/doctrine-bridge/tree/v7.4.7" + "source": "https://github.com/symfony/doctrine-bridge/tree/v8.1.1" }, "funding": [ { @@ -2124,37 +2097,36 @@ "type": "tidelift" } ], - "time": "2026-03-05T08:16:50+00:00" + "time": "2026-06-12T08:43:41+00:00" }, { "name": "symfony/error-handler", - "version": "v7.4.8", + "version": "v8.1.0", "source": { "type": "git", "url": "https://github.com/symfony/error-handler.git", - "reference": "8dd79d8af777ee6cba2fd4d98da6ffb839f3c0fa" + "reference": "d8aeb1abd3fef84795567850d3a567bdb5945ee5" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/error-handler/zipball/8dd79d8af777ee6cba2fd4d98da6ffb839f3c0fa", - "reference": "8dd79d8af777ee6cba2fd4d98da6ffb839f3c0fa", + "url": "https://api.github.com/repos/symfony/error-handler/zipball/d8aeb1abd3fef84795567850d3a567bdb5945ee5", + "reference": "d8aeb1abd3fef84795567850d3a567bdb5945ee5", "shasum": "" }, "require": { - "php": ">=8.2", + "php": ">=8.4.1", "psr/log": "^1|^2|^3", "symfony/polyfill-php85": "^1.32", - "symfony/var-dumper": "^6.4|^7.0|^8.0" + "symfony/var-dumper": "^7.4|^8.0" }, "conflict": { - "symfony/deprecation-contracts": "<2.5", - "symfony/http-kernel": "<6.4" + "symfony/deprecation-contracts": "<2.5" }, "require-dev": { - "symfony/console": "^6.4|^7.0|^8.0", + "symfony/console": "^7.4|^8.0", "symfony/deprecation-contracts": "^2.5|^3", - "symfony/http-kernel": "^6.4|^7.0|^8.0", - "symfony/serializer": "^6.4|^7.0|^8.0", + "symfony/http-kernel": "^7.4|^8.0", + "symfony/serializer": "^7.4|^8.0", "symfony/webpack-encore-bundle": "^1.0|^2.0" }, "bin": [ @@ -2186,7 +2158,7 @@ "description": "Provides tools to manage errors and ease debugging PHP code", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/error-handler/tree/v7.4.8" + "source": "https://github.com/symfony/error-handler/tree/v8.1.0" }, "funding": [ { @@ -2206,28 +2178,29 @@ "type": "tidelift" } ], - "time": "2026-03-24T13:12:05+00:00" + "time": "2026-05-29T05:06:50+00:00" }, { "name": "symfony/event-dispatcher", - "version": "v7.4.9", + "version": "v8.1.1", "source": { "type": "git", "url": "https://github.com/symfony/event-dispatcher.git", - "reference": "e4a2e29753c7801f7a8340e066cfa788f3bc8101" + "reference": "abd6c11dc468725d1627302ad10f6cd486e9e3d0" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/e4a2e29753c7801f7a8340e066cfa788f3bc8101", - "reference": "e4a2e29753c7801f7a8340e066cfa788f3bc8101", + "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/abd6c11dc468725d1627302ad10f6cd486e9e3d0", + "reference": "abd6c11dc468725d1627302ad10f6cd486e9e3d0", "shasum": "" }, "require": { - "php": ">=8.2", + "php": ">=8.4.1", + "symfony/deprecation-contracts": "^2.5|^3", "symfony/event-dispatcher-contracts": "^2.5|^3" }, "conflict": { - "symfony/dependency-injection": "<6.4", + "symfony/security-http": "<7.4", "symfony/service-contracts": "<2.5" }, "provide": { @@ -2236,14 +2209,14 @@ }, "require-dev": { "psr/log": "^1|^2|^3", - "symfony/config": "^6.4|^7.0|^8.0", - "symfony/dependency-injection": "^6.4|^7.0|^8.0", - "symfony/error-handler": "^6.4|^7.0|^8.0", - "symfony/expression-language": "^6.4|^7.0|^8.0", - "symfony/framework-bundle": "^6.4|^7.0|^8.0", - "symfony/http-foundation": "^6.4|^7.0|^8.0", + "symfony/config": "^7.4|^8.0", + "symfony/dependency-injection": "^7.4|^8.0", + "symfony/error-handler": "^7.4|^8.0", + "symfony/expression-language": "^7.4|^8.0", + "symfony/framework-bundle": "^7.4|^8.0", + "symfony/http-foundation": "^7.4|^8.0", "symfony/service-contracts": "^2.5|^3", - "symfony/stopwatch": "^6.4|^7.0|^8.0" + "symfony/stopwatch": "^7.4|^8.0" }, "type": "library", "autoload": { @@ -2271,7 +2244,7 @@ "description": "Provides tools that allow your application components to communicate with each other by dispatching events and listening to them", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/event-dispatcher/tree/v7.4.9" + "source": "https://github.com/symfony/event-dispatcher/tree/v8.1.1" }, "funding": [ { @@ -2291,20 +2264,20 @@ "type": "tidelift" } ], - "time": "2026-04-18T13:18:21+00:00" + "time": "2026-06-09T12:28:30+00:00" }, { "name": "symfony/event-dispatcher-contracts", - "version": "v3.7.0", + "version": "v3.7.1", "source": { "type": "git", "url": "https://github.com/symfony/event-dispatcher-contracts.git", - "reference": "ccba7060602b7fed0b03c85bf025257f76d9ef32" + "reference": "c7de7a00ffb67842132da02ea92988a39ccd9f4e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/event-dispatcher-contracts/zipball/ccba7060602b7fed0b03c85bf025257f76d9ef32", - "reference": "ccba7060602b7fed0b03c85bf025257f76d9ef32", + "url": "https://api.github.com/repos/symfony/event-dispatcher-contracts/zipball/c7de7a00ffb67842132da02ea92988a39ccd9f4e", + "reference": "c7de7a00ffb67842132da02ea92988a39ccd9f4e", "shasum": "" }, "require": { @@ -2351,7 +2324,7 @@ "standards" ], "support": { - "source": "https://github.com/symfony/event-dispatcher-contracts/tree/v3.7.0" + "source": "https://github.com/symfony/event-dispatcher-contracts/tree/v3.7.1" }, "funding": [ { @@ -2371,29 +2344,30 @@ "type": "tidelift" } ], - "time": "2026-01-05T13:30:16+00:00" + "time": "2026-06-05T06:23:12+00:00" }, { "name": "symfony/filesystem", - "version": "v7.4.6", + "version": "v8.1.0", "source": { "type": "git", "url": "https://github.com/symfony/filesystem.git", - "reference": "3ebc794fa5315e59fd122561623c2e2e4280538e" + "reference": "99aec13b82b4967ec5088222c4a3ecca955949c2" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/filesystem/zipball/3ebc794fa5315e59fd122561623c2e2e4280538e", - "reference": "3ebc794fa5315e59fd122561623c2e2e4280538e", + "url": "https://api.github.com/repos/symfony/filesystem/zipball/99aec13b82b4967ec5088222c4a3ecca955949c2", + "reference": "99aec13b82b4967ec5088222c4a3ecca955949c2", "shasum": "" }, "require": { - "php": ">=8.2", + "php": ">=8.4.1", + "symfony/deprecation-contracts": "^2.5|^3", "symfony/polyfill-ctype": "~1.8", "symfony/polyfill-mbstring": "~1.8" }, "require-dev": { - "symfony/process": "^6.4|^7.0|^8.0" + "symfony/process": "^7.4|^8.0" }, "type": "library", "autoload": { @@ -2421,7 +2395,7 @@ "description": "Provides basic utilities for the filesystem", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/filesystem/tree/v7.4.6" + "source": "https://github.com/symfony/filesystem/tree/v8.1.0" }, "funding": [ { @@ -2441,27 +2415,27 @@ "type": "tidelift" } ], - "time": "2026-02-25T16:50:00+00:00" + "time": "2026-05-29T05:06:50+00:00" }, { "name": "symfony/finder", - "version": "v7.4.6", + "version": "v8.1.1", "source": { "type": "git", "url": "https://github.com/symfony/finder.git", - "reference": "8655bf1076b7a3a346cb11413ffdabff50c7ffcf" + "reference": "e2989e762c70f9490fa3a00a0ac0fae5aa97a531" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/finder/zipball/8655bf1076b7a3a346cb11413ffdabff50c7ffcf", - "reference": "8655bf1076b7a3a346cb11413ffdabff50c7ffcf", + "url": "https://api.github.com/repos/symfony/finder/zipball/e2989e762c70f9490fa3a00a0ac0fae5aa97a531", + "reference": "e2989e762c70f9490fa3a00a0ac0fae5aa97a531", "shasum": "" }, "require": { - "php": ">=8.2" + "php": ">=8.4.1" }, "require-dev": { - "symfony/filesystem": "^6.4|^7.0|^8.0" + "symfony/filesystem": "^7.4|^8.0" }, "type": "library", "autoload": { @@ -2489,7 +2463,7 @@ "description": "Finds files and directories via an intuitive fluent interface", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/finder/tree/v7.4.6" + "source": "https://github.com/symfony/finder/tree/v8.1.1" }, "funding": [ { @@ -2509,62 +2483,54 @@ "type": "tidelift" } ], - "time": "2026-01-29T09:40:50+00:00" + "time": "2026-06-27T09:05:56+00:00" }, { "name": "symfony/form", - "version": "v7.4.7", + "version": "v8.0.14", "source": { "type": "git", "url": "https://github.com/symfony/form.git", - "reference": "5f24175103fd0a62b98442207c240688210fd88b" + "reference": "36b007caa7fa08be969fee0bf341f6b99dd15000" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/form/zipball/5f24175103fd0a62b98442207c240688210fd88b", - "reference": "5f24175103fd0a62b98442207c240688210fd88b", + "url": "https://api.github.com/repos/symfony/form/zipball/36b007caa7fa08be969fee0bf341f6b99dd15000", + "reference": "36b007caa7fa08be969fee0bf341f6b99dd15000", "shasum": "" }, "require": { - "php": ">=8.2", - "symfony/deprecation-contracts": "^2.5|^3", - "symfony/event-dispatcher": "^6.4|^7.0|^8.0", - "symfony/options-resolver": "^7.3|^8.0", - "symfony/polyfill-ctype": "~1.8", + "php": ">=8.4", + "symfony/event-dispatcher": "^7.4|^8.0", + "symfony/options-resolver": "^7.4|^8.0", + "symfony/polyfill-ctype": "^1.8", "symfony/polyfill-intl-icu": "^1.21", - "symfony/polyfill-mbstring": "~1.0", - "symfony/property-access": "^6.4|^7.0|^8.0", + "symfony/polyfill-mbstring": "^1.0", + "symfony/property-access": "^7.4|^8.0", "symfony/service-contracts": "^2.5|^3" }, "conflict": { - "symfony/console": "<6.4", - "symfony/dependency-injection": "<6.4", - "symfony/doctrine-bridge": "<6.4", - "symfony/error-handler": "<6.4", - "symfony/framework-bundle": "<6.4", - "symfony/http-kernel": "<6.4", "symfony/intl": "<7.4", - "symfony/translation": "<6.4.3|>=7.0,<7.0.3", "symfony/translation-contracts": "<2.5", - "symfony/twig-bridge": "<6.4" + "symfony/validator": "<7.4" }, "require-dev": { "doctrine/collections": "^1.0|^2.0", - "symfony/clock": "^6.4|^7.0|^8.0", - "symfony/config": "^6.4|^7.0|^8.0", - "symfony/console": "^6.4|^7.0|^8.0", - "symfony/dependency-injection": "^6.4|^7.0|^8.0", - "symfony/expression-language": "^6.4|^7.0|^8.0", - "symfony/html-sanitizer": "^6.4|^7.0|^8.0", - "symfony/http-foundation": "^6.4|^7.0|^8.0", - "symfony/http-kernel": "^6.4|^7.0|^8.0", + "symfony/clock": "^7.4|^8.0", + "symfony/config": "^7.4|^8.0", + "symfony/console": "^7.4|^8.0", + "symfony/dependency-injection": "^7.4|^8.0", + "symfony/expression-language": "^7.4|^8.0", + "symfony/html-sanitizer": "^7.4|^8.0", + "symfony/http-foundation": "^7.4|^8.0", + "symfony/http-kernel": "^7.4|^8.0", "symfony/intl": "^7.4|^8.0", - "symfony/security-core": "^6.4|^7.0|^8.0", - "symfony/security-csrf": "^6.4|^7.0|^8.0", - "symfony/translation": "^6.4.3|^7.0.3|^8.0", - "symfony/uid": "^6.4|^7.0|^8.0", - "symfony/validator": "^6.4.12|^7.1.5|^8.0", - "symfony/var-dumper": "^6.4|^7.0|^8.0" + "symfony/security-core": "^7.4|^8.0", + "symfony/security-csrf": "^7.4|^8.0", + "symfony/translation": "^7.4|^8.0", + "symfony/uid": "^7.4|^8.0", + "symfony/validator": "^7.4|^8.0", + "symfony/var-dumper": "^7.4|^8.0" }, "type": "library", "autoload": { @@ -2592,7 +2558,7 @@ "description": "Allows to easily create, process and reuse HTML forms", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/form/tree/v7.4.7" + "source": "https://github.com/symfony/form/tree/v8.0.14" }, "funding": [ { @@ -2612,37 +2578,37 @@ "type": "tidelift" } ], - "time": "2026-03-05T12:30:09+00:00" + "time": "2026-06-16T16:02:37+00:00" }, { "name": "symfony/framework-bundle", - "version": "v7.4.7", + "version": "v8.0.14", "source": { "type": "git", "url": "https://github.com/symfony/framework-bundle.git", - "reference": "c94bc78c85d76af67918404a95d44940f66a7c2f" + "reference": "74134f73e391698bf78b3dd05bb25a0bdfccbabb" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/framework-bundle/zipball/c94bc78c85d76af67918404a95d44940f66a7c2f", - "reference": "c94bc78c85d76af67918404a95d44940f66a7c2f", + "url": "https://api.github.com/repos/symfony/framework-bundle/zipball/74134f73e391698bf78b3dd05bb25a0bdfccbabb", + "reference": "74134f73e391698bf78b3dd05bb25a0bdfccbabb", "shasum": "" }, "require": { "composer-runtime-api": ">=2.1", "ext-xml": "*", - "php": ">=8.2", - "symfony/cache": "^6.4.12|^7.0|^8.0", + "php": ">=8.4", + "symfony/cache": "^7.4|^8.0", "symfony/config": "^7.4.4|^8.0.4", "symfony/dependency-injection": "^7.4.4|^8.0.4", "symfony/deprecation-contracts": "^2.5|^3", - "symfony/error-handler": "^7.3|^8.0", - "symfony/event-dispatcher": "^6.4|^7.0|^8.0", - "symfony/filesystem": "^7.1|^8.0", - "symfony/finder": "^6.4|^7.0|^8.0", + "symfony/error-handler": "^7.4|^8.0", + "symfony/event-dispatcher": "^7.4|^8.0", + "symfony/filesystem": "^7.4|^8.0", + "symfony/finder": "^7.4|^8.0", "symfony/http-foundation": "^7.4|^8.0", "symfony/http-kernel": "^7.4|^8.0", - "symfony/polyfill-mbstring": "~1.0", + "symfony/polyfill-mbstring": "^1.0", "symfony/polyfill-php85": "^1.32", "symfony/routing": "^7.4|^8.0" }, @@ -2650,79 +2616,62 @@ "doctrine/persistence": "<1.3", "phpdocumentor/reflection-docblock": "<5.2|>=7", "phpdocumentor/type-resolver": "<1.5.1", - "symfony/asset": "<6.4", - "symfony/asset-mapper": "<6.4", - "symfony/clock": "<6.4", - "symfony/console": "<6.4", - "symfony/dom-crawler": "<6.4", - "symfony/dotenv": "<6.4", + "symfony/console": "<7.4", "symfony/form": "<7.4", - "symfony/http-client": "<6.4", - "symfony/lock": "<6.4", - "symfony/mailer": "<6.4", + "symfony/json-streamer": "<7.4", "symfony/messenger": "<7.4", - "symfony/mime": "<6.4", - "symfony/property-access": "<6.4", - "symfony/property-info": "<6.4", - "symfony/runtime": "<6.4.13|>=7.0,<7.1.6", - "symfony/scheduler": "<6.4.4|>=7.0.0,<7.0.4", - "symfony/security-core": "<6.4", - "symfony/security-csrf": "<7.2", - "symfony/serializer": "<7.2.5", - "symfony/stopwatch": "<6.4", - "symfony/translation": "<7.3", - "symfony/twig-bridge": "<6.4", - "symfony/twig-bundle": "<6.4", - "symfony/validator": "<6.4", - "symfony/web-profiler-bundle": "<6.4", - "symfony/webhook": "<7.2", + "symfony/mime": "<7.4.9|>=8.0,<8.0.9", + "symfony/security-csrf": "<7.4", + "symfony/serializer": "<7.4", + "symfony/translation": "<7.4", + "symfony/webhook": "<7.4", "symfony/workflow": "<7.4" }, "require-dev": { "doctrine/persistence": "^1.3|^2|^3", "dragonmantank/cron-expression": "^3.1", "phpdocumentor/reflection-docblock": "^5.2|^6.0", + "phpstan/phpdoc-parser": "^1.0|^2.0", "seld/jsonlint": "^1.10", - "symfony/asset": "^6.4|^7.0|^8.0", - "symfony/asset-mapper": "^6.4|^7.0|^8.0", - "symfony/browser-kit": "^6.4|^7.0|^8.0", - "symfony/clock": "^6.4|^7.0|^8.0", - "symfony/console": "^6.4|^7.0|^8.0", - "symfony/css-selector": "^6.4|^7.0|^8.0", - "symfony/dom-crawler": "^6.4|^7.0|^8.0", - "symfony/dotenv": "^6.4|^7.0|^8.0", - "symfony/expression-language": "^6.4|^7.0|^8.0", + "symfony/asset": "^7.4|^8.0", + "symfony/asset-mapper": "^7.4|^8.0", + "symfony/browser-kit": "^7.4|^8.0", + "symfony/clock": "^7.4|^8.0", + "symfony/console": "^7.4|^8.0", + "symfony/css-selector": "^7.4|^8.0", + "symfony/dom-crawler": "^7.4|^8.0", + "symfony/dotenv": "^7.4|^8.0", + "symfony/expression-language": "^7.4|^8.0", "symfony/form": "^7.4|^8.0", - "symfony/html-sanitizer": "^6.4|^7.0|^8.0", - "symfony/http-client": "^6.4|^7.0|^8.0", - "symfony/json-streamer": "^7.3|^8.0", - "symfony/lock": "^6.4|^7.0|^8.0", - "symfony/mailer": "^6.4|^7.0|^8.0", + "symfony/html-sanitizer": "^7.4|^8.0", + "symfony/http-client": "^7.4|^8.0", + "symfony/json-streamer": "^7.4|^8.0", + "symfony/lock": "^7.4|^8.0", + "symfony/mailer": "^7.4|^8.0", "symfony/messenger": "^7.4|^8.0", - "symfony/mime": "^6.4|^7.0|^8.0", - "symfony/notifier": "^6.4|^7.0|^8.0", - "symfony/object-mapper": "^7.3|^8.0", - "symfony/polyfill-intl-icu": "~1.0", - "symfony/process": "^6.4|^7.0|^8.0", - "symfony/property-info": "^6.4|^7.0|^8.0", - "symfony/rate-limiter": "^6.4|^7.0|^8.0", - "symfony/runtime": "^6.4.13|^7.1.6|^8.0", - "symfony/scheduler": "^6.4.4|^7.0.4|^8.0", - "symfony/security-bundle": "^6.4|^7.0|^8.0", - "symfony/semaphore": "^6.4|^7.0|^8.0", - "symfony/serializer": "^7.2.5|^8.0", - "symfony/stopwatch": "^6.4|^7.0|^8.0", - "symfony/string": "^6.4|^7.0|^8.0", - "symfony/translation": "^7.3|^8.0", - "symfony/twig-bundle": "^6.4|^7.0|^8.0", - "symfony/type-info": "^7.1.8|^8.0", - "symfony/uid": "^6.4|^7.0|^8.0", + "symfony/mime": "^7.4.9|^8.0.9", + "symfony/notifier": "^7.4|^8.0", + "symfony/object-mapper": "^7.4.9|^8.0.9", + "symfony/polyfill-intl-icu": "^1.0", + "symfony/process": "^7.4|^8.0", + "symfony/property-info": "^7.4|^8.0", + "symfony/rate-limiter": "^7.4|^8.0", + "symfony/runtime": "^7.4|^8.0", + "symfony/scheduler": "^7.4|^8.0", + "symfony/security-bundle": "^7.4|^8.0", + "symfony/semaphore": "^7.4|^8.0", + "symfony/serializer": "^7.4|^8.0", + "symfony/stopwatch": "^7.4|^8.0", + "symfony/string": "^7.4|^8.0", + "symfony/translation": "^7.4|^8.0", + "symfony/twig-bundle": "^7.4|^8.0", + "symfony/type-info": "^7.4.1|^8.0.1", + "symfony/uid": "^7.4|^8.0", "symfony/validator": "^7.4|^8.0", - "symfony/web-link": "^6.4|^7.0|^8.0", - "symfony/webhook": "^7.2|^8.0", + "symfony/web-link": "^7.4|^8.0", + "symfony/webhook": "^7.4|^8.0", "symfony/workflow": "^7.4|^8.0", - "symfony/yaml": "^7.3|^8.0", - "twig/twig": "^3.12" + "symfony/yaml": "^7.4|^8.0" }, "type": "symfony-bundle", "autoload": { @@ -2750,7 +2699,7 @@ "description": "Provides a tight integration between Symfony components and the Symfony full-stack framework", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/framework-bundle/tree/v7.4.7" + "source": "https://github.com/symfony/framework-bundle/tree/v8.0.14" }, "funding": [ { @@ -2770,41 +2719,40 @@ "type": "tidelift" } ], - "time": "2026-03-06T15:39:55+00:00" + "time": "2026-06-27T08:56:37+00:00" }, { "name": "symfony/http-foundation", - "version": "v7.4.13", + "version": "v8.1.1", "source": { "type": "git", "url": "https://github.com/symfony/http-foundation.git", - "reference": "bc354f47c62301e990b7874fa662326368508e2c" + "reference": "6a168c8fcee806b57ac020244da14293d1f9a883" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/http-foundation/zipball/bc354f47c62301e990b7874fa662326368508e2c", - "reference": "bc354f47c62301e990b7874fa662326368508e2c", + "url": "https://api.github.com/repos/symfony/http-foundation/zipball/6a168c8fcee806b57ac020244da14293d1f9a883", + "reference": "6a168c8fcee806b57ac020244da14293d1f9a883", "shasum": "" }, "require": { - "php": ">=8.2", + "php": ">=8.4.1", "symfony/deprecation-contracts": "^2.5|^3", "symfony/polyfill-mbstring": "^1.1" }, "conflict": { - "doctrine/dbal": "<3.6", - "symfony/cache": "<6.4.12|>=7.0,<7.1.5" + "doctrine/dbal": "<4.3" }, "require-dev": { - "doctrine/dbal": "^3.6|^4", + "doctrine/dbal": "^4.3", "predis/predis": "^1.1|^2.0", - "symfony/cache": "^6.4.12|^7.1.5|^8.0", - "symfony/clock": "^6.4|^7.0|^8.0", - "symfony/dependency-injection": "^6.4|^7.0|^8.0", - "symfony/expression-language": "^6.4|^7.0|^8.0", - "symfony/http-kernel": "^6.4|^7.0|^8.0", - "symfony/mime": "^6.4|^7.0|^8.0", - "symfony/rate-limiter": "^6.4|^7.0|^8.0" + "symfony/cache": "^7.4|^8.0", + "symfony/clock": "^7.4|^8.0", + "symfony/dependency-injection": "^7.4|^8.0", + "symfony/expression-language": "^7.4|^8.0", + "symfony/http-kernel": "^7.4|^8.0", + "symfony/mime": "^7.4|^8.0", + "symfony/rate-limiter": "^7.4|^8.0" }, "type": "library", "autoload": { @@ -2832,7 +2780,7 @@ "description": "Defines an object-oriented layer for the HTTP specification", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/http-foundation/tree/v7.4.13" + "source": "https://github.com/symfony/http-foundation/tree/v8.1.1" }, "funding": [ { @@ -2852,78 +2800,63 @@ "type": "tidelift" } ], - "time": "2026-05-24T11:20:33+00:00" + "time": "2026-06-12T08:43:41+00:00" }, { "name": "symfony/http-kernel", - "version": "v7.4.13", + "version": "v8.0.14", "source": { "type": "git", "url": "https://github.com/symfony/http-kernel.git", - "reference": "9df847980c436451f4f51d1284491bb4356dd989" + "reference": "6685b981881100e5f92a98fb6c5d6739af6a8569" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/http-kernel/zipball/9df847980c436451f4f51d1284491bb4356dd989", - "reference": "9df847980c436451f4f51d1284491bb4356dd989", + "url": "https://api.github.com/repos/symfony/http-kernel/zipball/6685b981881100e5f92a98fb6c5d6739af6a8569", + "reference": "6685b981881100e5f92a98fb6c5d6739af6a8569", "shasum": "" }, "require": { - "php": ">=8.2", + "php": ">=8.4", "psr/log": "^1|^2|^3", - "symfony/deprecation-contracts": "^2.5|^3", - "symfony/error-handler": "^6.4|^7.0|^8.0", - "symfony/event-dispatcher": "^7.3|^8.0", + "symfony/error-handler": "^7.4|^8.0", + "symfony/event-dispatcher": "^7.4|^8.0", "symfony/http-foundation": "^7.4|^8.0", "symfony/polyfill-ctype": "^1.8" }, "conflict": { - "symfony/browser-kit": "<6.4", - "symfony/cache": "<6.4", - "symfony/config": "<6.4", - "symfony/console": "<6.4", - "symfony/dependency-injection": "<6.4", - "symfony/doctrine-bridge": "<6.4", "symfony/flex": "<2.10", - "symfony/form": "<6.4", - "symfony/http-client": "<6.4", "symfony/http-client-contracts": "<2.5", - "symfony/mailer": "<6.4", - "symfony/messenger": "<6.4", - "symfony/translation": "<6.4", "symfony/translation-contracts": "<2.5", - "symfony/twig-bridge": "<6.4", - "symfony/validator": "<6.4", - "symfony/var-dumper": "<6.4", - "twig/twig": "<3.12" + "twig/twig": "<3.21" }, "provide": { "psr/log-implementation": "1.0|2.0|3.0" }, "require-dev": { "psr/cache": "^1.0|^2.0|^3.0", - "symfony/browser-kit": "^6.4|^7.0|^8.0", - "symfony/clock": "^6.4|^7.0|^8.0", - "symfony/config": "^6.4|^7.0|^8.0", - "symfony/console": "^6.4|^7.0|^8.0", - "symfony/css-selector": "^6.4|^7.0|^8.0", - "symfony/dependency-injection": "^6.4.1|^7.0.1|^8.0", - "symfony/dom-crawler": "^6.4|^7.0|^8.0", - "symfony/expression-language": "^6.4|^7.0|^8.0", - "symfony/finder": "^6.4|^7.0|^8.0", + "symfony/browser-kit": "^7.4|^8.0", + "symfony/clock": "^7.4|^8.0", + "symfony/config": "^7.4|^8.0", + "symfony/console": "^7.4|^8.0", + "symfony/css-selector": "^7.4|^8.0", + "symfony/dependency-injection": "^7.4|^8.0", + "symfony/dom-crawler": "^7.4|^8.0", + "symfony/expression-language": "^7.4|^8.0", + "symfony/finder": "^7.4|^8.0", "symfony/http-client-contracts": "^2.5|^3", - "symfony/process": "^6.4|^7.0|^8.0", - "symfony/property-access": "^7.1|^8.0", - "symfony/routing": "^6.4|^7.0|^8.0", - "symfony/serializer": "^7.1|^8.0", - "symfony/stopwatch": "^6.4|^7.0|^8.0", - "symfony/translation": "^6.4|^7.0|^8.0", + "symfony/process": "^7.4|^8.0", + "symfony/property-access": "^7.4|^8.0", + "symfony/routing": "^7.4|^8.0", + "symfony/serializer": "^7.4|^8.0", + "symfony/stopwatch": "^7.4|^8.0", + "symfony/translation": "^7.4|^8.0", "symfony/translation-contracts": "^2.5|^3", - "symfony/uid": "^6.4|^7.0|^8.0", - "symfony/validator": "^6.4|^7.0|^8.0", - "symfony/var-dumper": "^6.4|^7.0|^8.0", - "symfony/var-exporter": "^6.4|^7.0|^8.0", - "twig/twig": "^3.12" + "symfony/uid": "^7.4|^8.0", + "symfony/validator": "^7.4|^8.0", + "symfony/var-dumper": "^7.4|^8.0", + "symfony/var-exporter": "^7.4|^8.0", + "twig/twig": "^3.21" }, "type": "library", "autoload": { @@ -2951,7 +2884,7 @@ "description": "Provides a structured process for converting a Request into a Response", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/http-kernel/tree/v7.4.13" + "source": "https://github.com/symfony/http-kernel/tree/v8.0.14" }, "funding": [ { @@ -2971,24 +2904,24 @@ "type": "tidelift" } ], - "time": "2026-05-27T08:31:43+00:00" + "time": "2026-06-27T09:16:44+00:00" }, { "name": "symfony/options-resolver", - "version": "v7.4.0", + "version": "v8.1.0", "source": { "type": "git", "url": "https://github.com/symfony/options-resolver.git", - "reference": "b38026df55197f9e39a44f3215788edf83187b80" + "reference": "88f9c561f678a02d54b897014049fa839e33ff82" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/options-resolver/zipball/b38026df55197f9e39a44f3215788edf83187b80", - "reference": "b38026df55197f9e39a44f3215788edf83187b80", + "url": "https://api.github.com/repos/symfony/options-resolver/zipball/88f9c561f678a02d54b897014049fa839e33ff82", + "reference": "88f9c561f678a02d54b897014049fa839e33ff82", "shasum": "" }, "require": { - "php": ">=8.2", + "php": ">=8.4.1", "symfony/deprecation-contracts": "^2.5|^3" }, "type": "library", @@ -3022,7 +2955,7 @@ "options" ], "support": { - "source": "https://github.com/symfony/options-resolver/tree/v7.4.0" + "source": "https://github.com/symfony/options-resolver/tree/v8.1.0" }, "funding": [ { @@ -3042,7 +2975,7 @@ "type": "tidelift" } ], - "time": "2025-11-12T15:39:26+00:00" + "time": "2026-05-29T05:06:50+00:00" }, { "name": "symfony/orm-pack", @@ -3098,27 +3031,24 @@ }, { "name": "symfony/password-hasher", - "version": "v7.4.6", + "version": "v8.1.0", "source": { "type": "git", "url": "https://github.com/symfony/password-hasher.git", - "reference": "376755eb9c9857d78aedb68341ad2f46d1908b29" + "reference": "6934d16beaa4677f2c4584229fff1b51099dd7af" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/password-hasher/zipball/376755eb9c9857d78aedb68341ad2f46d1908b29", - "reference": "376755eb9c9857d78aedb68341ad2f46d1908b29", + "url": "https://api.github.com/repos/symfony/password-hasher/zipball/6934d16beaa4677f2c4584229fff1b51099dd7af", + "reference": "6934d16beaa4677f2c4584229fff1b51099dd7af", "shasum": "" }, "require": { - "php": ">=8.2" - }, - "conflict": { - "symfony/security-core": "<6.4" + "php": ">=8.4.1" }, "require-dev": { - "symfony/console": "^6.4|^7.0|^8.0", - "symfony/security-core": "^6.4|^7.0|^8.0" + "symfony/console": "^7.4|^8.0", + "symfony/security-core": "^7.4|^8.0" }, "type": "library", "autoload": { @@ -3150,7 +3080,7 @@ "password" ], "support": { - "source": "https://github.com/symfony/password-hasher/tree/v7.4.6" + "source": "https://github.com/symfony/password-hasher/tree/v8.1.0" }, "funding": [ { @@ -3170,7 +3100,7 @@ "type": "tidelift" } ], - "time": "2026-02-11T16:03:16+00:00" + "time": "2026-05-29T05:06:50+00:00" }, { "name": "symfony/polyfill-ctype", @@ -3257,16 +3187,16 @@ }, { "name": "symfony/polyfill-intl-grapheme", - "version": "v1.33.0", + "version": "v1.38.1", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-intl-grapheme.git", - "reference": "380872130d3a5dd3ace2f4010d95125fde5d5c70" + "reference": "e9247d281d694a5120554d9afaf54e070e88a603" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-intl-grapheme/zipball/380872130d3a5dd3ace2f4010d95125fde5d5c70", - "reference": "380872130d3a5dd3ace2f4010d95125fde5d5c70", + "url": "https://api.github.com/repos/symfony/polyfill-intl-grapheme/zipball/e9247d281d694a5120554d9afaf54e070e88a603", + "reference": "e9247d281d694a5120554d9afaf54e070e88a603", "shasum": "" }, "require": { @@ -3315,7 +3245,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-intl-grapheme/tree/v1.33.0" + "source": "https://github.com/symfony/polyfill-intl-grapheme/tree/v1.38.1" }, "funding": [ { @@ -3335,20 +3265,20 @@ "type": "tidelift" } ], - "time": "2025-06-27T09:58:17+00:00" + "time": "2026-05-26T05:58:03+00:00" }, { "name": "symfony/polyfill-intl-icu", - "version": "v1.33.0", + "version": "v1.38.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-intl-icu.git", - "reference": "bfc8fa13dbaf21d69114b0efcd72ab700fb04d0c" + "reference": "445c90e341fccda10311019cf82ff73bb7343945" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-intl-icu/zipball/bfc8fa13dbaf21d69114b0efcd72ab700fb04d0c", - "reference": "bfc8fa13dbaf21d69114b0efcd72ab700fb04d0c", + "url": "https://api.github.com/repos/symfony/polyfill-intl-icu/zipball/445c90e341fccda10311019cf82ff73bb7343945", + "reference": "445c90e341fccda10311019cf82ff73bb7343945", "shasum": "" }, "require": { @@ -3403,7 +3333,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-intl-icu/tree/v1.33.0" + "source": "https://github.com/symfony/polyfill-intl-icu/tree/v1.38.0" }, "funding": [ { @@ -3423,20 +3353,20 @@ "type": "tidelift" } ], - "time": "2025-06-20T22:24:30+00:00" + "time": "2026-05-25T11:52:53+00:00" }, { "name": "symfony/polyfill-intl-normalizer", - "version": "v1.33.0", + "version": "v1.38.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-intl-normalizer.git", - "reference": "3833d7255cc303546435cb650316bff708a1c75c" + "reference": "2d446c214bdbe5b71bde5011b060a05fece3ae6b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-intl-normalizer/zipball/3833d7255cc303546435cb650316bff708a1c75c", - "reference": "3833d7255cc303546435cb650316bff708a1c75c", + "url": "https://api.github.com/repos/symfony/polyfill-intl-normalizer/zipball/2d446c214bdbe5b71bde5011b060a05fece3ae6b", + "reference": "2d446c214bdbe5b71bde5011b060a05fece3ae6b", "shasum": "" }, "require": { @@ -3488,7 +3418,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-intl-normalizer/tree/v1.33.0" + "source": "https://github.com/symfony/polyfill-intl-normalizer/tree/v1.38.0" }, "funding": [ { @@ -3508,20 +3438,20 @@ "type": "tidelift" } ], - "time": "2024-09-09T11:45:10+00:00" + "time": "2026-05-25T13:48:31+00:00" }, { "name": "symfony/polyfill-mbstring", - "version": "v1.38.1", + "version": "v1.38.2", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-mbstring.git", - "reference": "14c5439eec4ccff081ac14eca2dc57feb2a66d92" + "reference": "d3d318bad5e7a1bfbd026009c8bfb8d8f99ae6b6" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/14c5439eec4ccff081ac14eca2dc57feb2a66d92", - "reference": "14c5439eec4ccff081ac14eca2dc57feb2a66d92", + "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/d3d318bad5e7a1bfbd026009c8bfb8d8f99ae6b6", + "reference": "d3d318bad5e7a1bfbd026009c8bfb8d8f99ae6b6", "shasum": "" }, "require": { @@ -3573,7 +3503,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-mbstring/tree/v1.38.1" + "source": "https://github.com/symfony/polyfill-mbstring/tree/v1.38.2" }, "funding": [ { @@ -3593,100 +3523,20 @@ "type": "tidelift" } ], - "time": "2026-05-26T12:51:13+00:00" - }, - { - "name": "symfony/polyfill-php83", - "version": "v1.38.1", - "source": { - "type": "git", - "url": "https://github.com/symfony/polyfill-php83.git", - "reference": "8339098cae28673c15cce00d80734af0453054e2" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-php83/zipball/8339098cae28673c15cce00d80734af0453054e2", - "reference": "8339098cae28673c15cce00d80734af0453054e2", - "shasum": "" - }, - "require": { - "php": ">=7.2" - }, - "type": "library", - "extra": { - "thanks": { - "url": "https://github.com/symfony/polyfill", - "name": "symfony/polyfill" - } - }, - "autoload": { - "files": [ - "bootstrap.php" - ], - "psr-4": { - "Symfony\\Polyfill\\Php83\\": "" - }, - "classmap": [ - "Resources/stubs" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Nicolas Grekas", - "email": "p@tchwork.com" - }, - { - "name": "Symfony Community", - "homepage": "https://symfony.com/contributors" - } - ], - "description": "Symfony polyfill backporting some PHP 8.3+ features to lower PHP versions", - "homepage": "https://symfony.com", - "keywords": [ - "compatibility", - "polyfill", - "portable", - "shim" - ], - "support": { - "source": "https://github.com/symfony/polyfill-php83/tree/v1.38.1" - }, - "funding": [ - { - "url": "https://symfony.com/sponsor", - "type": "custom" - }, - { - "url": "https://github.com/fabpot", - "type": "github" - }, - { - "url": "https://github.com/nicolas-grekas", - "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", - "type": "tidelift" - } - ], - "time": "2026-05-26T12:51:13+00:00" + "time": "2026-05-27T06:59:30+00:00" }, { "name": "symfony/polyfill-php84", - "version": "v1.33.0", + "version": "v1.38.1", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-php84.git", - "reference": "d8ced4d875142b6a7426000426b8abc631d6b191" + "reference": "f4e1dfaee5b74aba5964fe1fd4dfc7ba5e3085fa" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-php84/zipball/d8ced4d875142b6a7426000426b8abc631d6b191", - "reference": "d8ced4d875142b6a7426000426b8abc631d6b191", + "url": "https://api.github.com/repos/symfony/polyfill-php84/zipball/f4e1dfaee5b74aba5964fe1fd4dfc7ba5e3085fa", + "reference": "f4e1dfaee5b74aba5964fe1fd4dfc7ba5e3085fa", "shasum": "" }, "require": { @@ -3733,7 +3583,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-php84/tree/v1.33.0" + "source": "https://github.com/symfony/polyfill-php84/tree/v1.38.1" }, "funding": [ { @@ -3753,7 +3603,7 @@ "type": "tidelift" } ], - "time": "2025-06-24T13:30:11+00:00" + "time": "2026-05-26T12:51:13+00:00" }, { "name": "symfony/polyfill-php85", @@ -3837,25 +3687,25 @@ }, { "name": "symfony/property-access", - "version": "v7.4.4", + "version": "v8.1.0", "source": { "type": "git", "url": "https://github.com/symfony/property-access.git", - "reference": "fa49bf1ca8fce1ba0e2dba4e4658554cfb9364b1" + "reference": "9261ef060f26cc7b728f67f141ba19b98a6209a9" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/property-access/zipball/fa49bf1ca8fce1ba0e2dba4e4658554cfb9364b1", - "reference": "fa49bf1ca8fce1ba0e2dba4e4658554cfb9364b1", + "url": "https://api.github.com/repos/symfony/property-access/zipball/9261ef060f26cc7b728f67f141ba19b98a6209a9", + "reference": "9261ef060f26cc7b728f67f141ba19b98a6209a9", "shasum": "" }, "require": { - "php": ">=8.2", - "symfony/property-info": "^6.4.32|~7.3.10|^7.4.4|^8.0.4" + "php": ">=8.4.1", + "symfony/property-info": "^7.4.4|^8.0.4" }, "require-dev": { - "symfony/cache": "^6.4|^7.0|^8.0", - "symfony/var-exporter": "^6.4.1|^7.0.1|^8.0" + "symfony/cache": "^7.4|^8.0", + "symfony/var-exporter": "^7.4|^8.0" }, "type": "library", "autoload": { @@ -3894,7 +3744,7 @@ "reflection" ], "support": { - "source": "https://github.com/symfony/property-access/tree/v7.4.4" + "source": "https://github.com/symfony/property-access/tree/v8.1.0" }, "funding": [ { @@ -3914,41 +3764,37 @@ "type": "tidelift" } ], - "time": "2026-01-05T08:47:25+00:00" + "time": "2026-05-29T05:06:50+00:00" }, { "name": "symfony/property-info", - "version": "v7.4.7", + "version": "v8.1.0", "source": { "type": "git", "url": "https://github.com/symfony/property-info.git", - "reference": "02501d75fd834345da3ecdd8e3200ced39e370f8" + "reference": "4721e8c56d0cd2378e0ef9a9899f810008b859f7" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/property-info/zipball/02501d75fd834345da3ecdd8e3200ced39e370f8", - "reference": "02501d75fd834345da3ecdd8e3200ced39e370f8", + "url": "https://api.github.com/repos/symfony/property-info/zipball/4721e8c56d0cd2378e0ef9a9899f810008b859f7", + "reference": "4721e8c56d0cd2378e0ef9a9899f810008b859f7", "shasum": "" }, "require": { - "php": ">=8.2", - "symfony/deprecation-contracts": "^2.5|^3", - "symfony/string": "^6.4|^7.0|^8.0", + "php": ">=8.4.1", + "symfony/string": "^7.4|^8.0", "symfony/type-info": "^7.4.7|^8.0.7" }, "conflict": { "phpdocumentor/reflection-docblock": "<5.2|>=7", - "phpdocumentor/type-resolver": "<1.5.1", - "symfony/cache": "<6.4", - "symfony/dependency-injection": "<6.4", - "symfony/serializer": "<6.4" + "phpdocumentor/type-resolver": "<1.5.1" }, "require-dev": { "phpdocumentor/reflection-docblock": "^5.2|^6.0", "phpstan/phpdoc-parser": "^1.0|^2.0", - "symfony/cache": "^6.4|^7.0|^8.0", - "symfony/dependency-injection": "^6.4|^7.0|^8.0", - "symfony/serializer": "^6.4|^7.0|^8.0" + "symfony/cache": "^7.4|^8.0", + "symfony/dependency-injection": "^7.4|^8.0", + "symfony/serializer": "^7.4|^8.0" }, "type": "library", "autoload": { @@ -3984,7 +3830,7 @@ "validator" ], "support": { - "source": "https://github.com/symfony/property-info/tree/v7.4.7" + "source": "https://github.com/symfony/property-info/tree/v8.1.0" }, "funding": [ { @@ -4004,38 +3850,33 @@ "type": "tidelift" } ], - "time": "2026-03-04T15:53:26+00:00" + "time": "2026-05-29T05:06:50+00:00" }, { "name": "symfony/routing", - "version": "v7.4.13", + "version": "v8.1.0", "source": { "type": "git", "url": "https://github.com/symfony/routing.git", - "reference": "3a162171bb008e5e0f15dce6581373a4c0e8390d" + "reference": "fe0bfec72c8a806109fb9c3a5f2b898fe0c76eb3" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/routing/zipball/3a162171bb008e5e0f15dce6581373a4c0e8390d", - "reference": "3a162171bb008e5e0f15dce6581373a4c0e8390d", + "url": "https://api.github.com/repos/symfony/routing/zipball/fe0bfec72c8a806109fb9c3a5f2b898fe0c76eb3", + "reference": "fe0bfec72c8a806109fb9c3a5f2b898fe0c76eb3", "shasum": "" }, "require": { - "php": ">=8.2", + "php": ">=8.4.1", "symfony/deprecation-contracts": "^2.5|^3" }, - "conflict": { - "symfony/config": "<6.4", - "symfony/dependency-injection": "<6.4", - "symfony/yaml": "<6.4" - }, "require-dev": { "psr/log": "^1|^2|^3", - "symfony/config": "^6.4|^7.0|^8.0", - "symfony/dependency-injection": "^6.4|^7.0|^8.0", - "symfony/expression-language": "^6.4|^7.0|^8.0", - "symfony/http-foundation": "^6.4|^7.0|^8.0", - "symfony/yaml": "^6.4|^7.0|^8.0" + "symfony/config": "^7.4|^8.0", + "symfony/dependency-injection": "^7.4|^8.0", + "symfony/expression-language": "^7.4|^8.0", + "symfony/http-foundation": "^7.4|^8.0", + "symfony/yaml": "^7.4|^8.0" }, "type": "library", "autoload": { @@ -4069,7 +3910,7 @@ "url" ], "support": { - "source": "https://github.com/symfony/routing/tree/v7.4.13" + "source": "https://github.com/symfony/routing/tree/v8.1.0" }, "funding": [ { @@ -4089,50 +3930,42 @@ "type": "tidelift" } ], - "time": "2026-05-24T11:20:33+00:00" + "time": "2026-05-29T05:06:50+00:00" }, { "name": "symfony/security-core", - "version": "v7.4.4", + "version": "v8.1.1", "source": { "type": "git", "url": "https://github.com/symfony/security-core.git", - "reference": "958a70725a8d669bec6721f4cd318d209712e944" + "reference": "2350e2f04858a7d50e758852512f9f5c3091a37b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/security-core/zipball/958a70725a8d669bec6721f4cd318d209712e944", - "reference": "958a70725a8d669bec6721f4cd318d209712e944", + "url": "https://api.github.com/repos/symfony/security-core/zipball/2350e2f04858a7d50e758852512f9f5c3091a37b", + "reference": "2350e2f04858a7d50e758852512f9f5c3091a37b", "shasum": "" }, "require": { - "php": ">=8.2", - "symfony/deprecation-contracts": "^2.5|^3", + "php": ">=8.4.1", "symfony/event-dispatcher-contracts": "^2.5|^3", - "symfony/password-hasher": "^6.4|^7.0|^8.0", + "symfony/password-hasher": "^7.4|^8.0", "symfony/service-contracts": "^2.5|^3" }, - "conflict": { - "symfony/dependency-injection": "<6.4", - "symfony/event-dispatcher": "<6.4", - "symfony/http-foundation": "<6.4", - "symfony/ldap": "<6.4", - "symfony/translation": "<6.4.3|>=7.0,<7.0.3", - "symfony/validator": "<6.4" - }, "require-dev": { "psr/cache": "^1.0|^2.0|^3.0", "psr/container": "^1.1|^2.0", "psr/log": "^1|^2|^3", - "symfony/cache": "^6.4|^7.0|^8.0", - "symfony/dependency-injection": "^6.4|^7.0|^8.0", - "symfony/event-dispatcher": "^6.4|^7.0|^8.0", - "symfony/expression-language": "^6.4|^7.0|^8.0", - "symfony/http-foundation": "^6.4|^7.0|^8.0", - "symfony/ldap": "^6.4|^7.0|^8.0", - "symfony/string": "^6.4|^7.0|^8.0", - "symfony/translation": "^6.4.3|^7.0.3|^8.0", - "symfony/validator": "^6.4|^7.0|^8.0" + "symfony/cache": "^7.4|^8.0", + "symfony/dependency-injection": "^7.4|^8.0", + "symfony/event-dispatcher": "^7.4|^8.0", + "symfony/expression-language": "^7.4|^8.0", + "symfony/http-foundation": "^7.4|^8.0", + "symfony/ldap": "^7.4|^8.0", + "symfony/property-access": "^7.4|^8.0", + "symfony/string": "^7.4|^8.0", + "symfony/translation": "^7.4|^8.0", + "symfony/validator": "^7.4|^8.0" }, "type": "library", "autoload": { @@ -4160,7 +3993,7 @@ "description": "Symfony Security Component - Core Library", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/security-core/tree/v7.4.4" + "source": "https://github.com/symfony/security-core/tree/v8.1.1" }, "funding": [ { @@ -4180,33 +4013,31 @@ "type": "tidelift" } ], - "time": "2026-01-14T09:36:49+00:00" + "time": "2026-06-09T10:54:51+00:00" }, { "name": "symfony/security-csrf", - "version": "v7.4.6", + "version": "v8.1.0", "source": { "type": "git", "url": "https://github.com/symfony/security-csrf.git", - "reference": "d01adcd3141bec95e4cfd338f6b4482f1dd6a42b" + "reference": "c865a8ee0d30b14545d7e5349b8e443f4fa9dc3f" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/security-csrf/zipball/d01adcd3141bec95e4cfd338f6b4482f1dd6a42b", - "reference": "d01adcd3141bec95e4cfd338f6b4482f1dd6a42b", + "url": "https://api.github.com/repos/symfony/security-csrf/zipball/c865a8ee0d30b14545d7e5349b8e443f4fa9dc3f", + "reference": "c865a8ee0d30b14545d7e5349b8e443f4fa9dc3f", "shasum": "" }, "require": { - "php": ">=8.2", - "symfony/security-core": "^6.4|^7.0|^8.0" - }, - "conflict": { - "symfony/http-foundation": "<6.4" + "php": ">=8.4.1", + "symfony/deprecation-contracts": "^2.5|^3", + "symfony/security-core": "^7.4|^8.0" }, "require-dev": { "psr/log": "^1|^2|^3", - "symfony/http-foundation": "^6.4|^7.0|^8.0", - "symfony/http-kernel": "^6.4|^7.0|^8.0" + "symfony/http-foundation": "^7.4|^8.0", + "symfony/http-kernel": "^7.4|^8.0" }, "type": "library", "autoload": { @@ -4234,7 +4065,7 @@ "description": "Symfony Security Component - CSRF Library", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/security-csrf/tree/v7.4.6" + "source": "https://github.com/symfony/security-csrf/tree/v8.1.0" }, "funding": [ { @@ -4254,20 +4085,20 @@ "type": "tidelift" } ], - "time": "2026-02-11T16:03:16+00:00" + "time": "2026-05-29T05:06:50+00:00" }, { "name": "symfony/service-contracts", - "version": "v3.7.0", + "version": "v3.7.1", "source": { "type": "git", "url": "https://github.com/symfony/service-contracts.git", - "reference": "d25d82433a80eba6aa0e6c24b61d7370d99e444a" + "reference": "c0a284bab1ed8aa0417e3d69250ab437739563a0" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/service-contracts/zipball/d25d82433a80eba6aa0e6c24b61d7370d99e444a", - "reference": "d25d82433a80eba6aa0e6c24b61d7370d99e444a", + "url": "https://api.github.com/repos/symfony/service-contracts/zipball/c0a284bab1ed8aa0417e3d69250ab437739563a0", + "reference": "c0a284bab1ed8aa0417e3d69250ab437739563a0", "shasum": "" }, "require": { @@ -4321,7 +4152,7 @@ "standards" ], "support": { - "source": "https://github.com/symfony/service-contracts/tree/v3.7.0" + "source": "https://github.com/symfony/service-contracts/tree/v3.7.1" }, "funding": [ { @@ -4341,24 +4172,24 @@ "type": "tidelift" } ], - "time": "2026-03-28T09:44:51+00:00" + "time": "2026-06-16T09:55:08+00:00" }, { "name": "symfony/stopwatch", - "version": "v7.4.0", + "version": "v8.1.0", "source": { "type": "git", "url": "https://github.com/symfony/stopwatch.git", - "reference": "8a24af0a2e8a872fb745047180649b8418303084" + "reference": "21c07b026905d596e8379caeb115d87aa479499d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/stopwatch/zipball/8a24af0a2e8a872fb745047180649b8418303084", - "reference": "8a24af0a2e8a872fb745047180649b8418303084", + "url": "https://api.github.com/repos/symfony/stopwatch/zipball/21c07b026905d596e8379caeb115d87aa479499d", + "reference": "21c07b026905d596e8379caeb115d87aa479499d", "shasum": "" }, "require": { - "php": ">=8.2", + "php": ">=8.4.1", "symfony/service-contracts": "^2.5|^3" }, "type": "library", @@ -4387,7 +4218,7 @@ "description": "Provides a way to profile code", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/stopwatch/tree/v7.4.0" + "source": "https://github.com/symfony/stopwatch/tree/v8.1.0" }, "funding": [ { @@ -4407,39 +4238,38 @@ "type": "tidelift" } ], - "time": "2025-08-04T07:05:15+00:00" + "time": "2026-05-29T05:06:50+00:00" }, { "name": "symfony/string", - "version": "v7.4.6", + "version": "v8.1.0", "source": { "type": "git", "url": "https://github.com/symfony/string.git", - "reference": "9f209231affa85aa930a5e46e6eb03381424b30b" + "reference": "afd5944f4005862d961efb85c8bbd5c523c4e3c9" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/string/zipball/9f209231affa85aa930a5e46e6eb03381424b30b", - "reference": "9f209231affa85aa930a5e46e6eb03381424b30b", + "url": "https://api.github.com/repos/symfony/string/zipball/afd5944f4005862d961efb85c8bbd5c523c4e3c9", + "reference": "afd5944f4005862d961efb85c8bbd5c523c4e3c9", "shasum": "" }, "require": { - "php": ">=8.2", - "symfony/deprecation-contracts": "^2.5|^3.0", - "symfony/polyfill-ctype": "~1.8", - "symfony/polyfill-intl-grapheme": "~1.33", - "symfony/polyfill-intl-normalizer": "~1.0", - "symfony/polyfill-mbstring": "~1.0" + "php": ">=8.4.1", + "symfony/polyfill-ctype": "^1.8", + "symfony/polyfill-intl-grapheme": "^1.33", + "symfony/polyfill-intl-normalizer": "^1.0", + "symfony/polyfill-mbstring": "^1.0" }, "conflict": { "symfony/translation-contracts": "<2.5" }, "require-dev": { - "symfony/emoji": "^7.1|^8.0", - "symfony/http-client": "^6.4|^7.0|^8.0", - "symfony/intl": "^6.4|^7.0|^8.0", + "symfony/emoji": "^7.4|^8.0", + "symfony/http-client": "^7.4|^8.0", + "symfony/intl": "^7.4|^8.0", "symfony/translation-contracts": "^2.5|^3.0", - "symfony/var-exporter": "^6.4|^7.0|^8.0" + "symfony/var-exporter": "^7.4|^8.0" }, "type": "library", "autoload": { @@ -4478,7 +4308,7 @@ "utf8" ], "support": { - "source": "https://github.com/symfony/string/tree/v7.4.6" + "source": "https://github.com/symfony/string/tree/v8.1.0" }, "funding": [ { @@ -4498,38 +4328,31 @@ "type": "tidelift" } ], - "time": "2026-02-09T09:33:46+00:00" + "time": "2026-05-29T05:06:50+00:00" }, { "name": "symfony/translation", - "version": "v7.4.6", + "version": "v8.1.1", "source": { "type": "git", "url": "https://github.com/symfony/translation.git", - "reference": "1888cf064399868af3784b9e043240f1d89d25ce" + "reference": "342b4218630dc2cf284cedcb2080c80b13404014" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/translation/zipball/1888cf064399868af3784b9e043240f1d89d25ce", - "reference": "1888cf064399868af3784b9e043240f1d89d25ce", + "url": "https://api.github.com/repos/symfony/translation/zipball/342b4218630dc2cf284cedcb2080c80b13404014", + "reference": "342b4218630dc2cf284cedcb2080c80b13404014", "shasum": "" }, "require": { - "php": ">=8.2", - "symfony/deprecation-contracts": "^2.5|^3", - "symfony/polyfill-mbstring": "~1.0", - "symfony/translation-contracts": "^2.5.3|^3.3" + "php": ">=8.4.1", + "symfony/polyfill-mbstring": "^1.0", + "symfony/translation-contracts": "^3.6.1" }, "conflict": { "nikic/php-parser": "<5.0", - "symfony/config": "<6.4", - "symfony/console": "<6.4", - "symfony/dependency-injection": "<6.4", "symfony/http-client-contracts": "<2.5", - "symfony/http-kernel": "<6.4", - "symfony/service-contracts": "<2.5", - "symfony/twig-bundle": "<6.4", - "symfony/yaml": "<6.4" + "symfony/service-contracts": "<2.5" }, "provide": { "symfony/translation-implementation": "2.3|3.0" @@ -4537,17 +4360,17 @@ "require-dev": { "nikic/php-parser": "^5.0", "psr/log": "^1|^2|^3", - "symfony/config": "^6.4|^7.0|^8.0", - "symfony/console": "^6.4|^7.0|^8.0", - "symfony/dependency-injection": "^6.4|^7.0|^8.0", - "symfony/finder": "^6.4|^7.0|^8.0", + "symfony/config": "^7.4|^8.0", + "symfony/console": "^7.4|^8.0", + "symfony/dependency-injection": "^7.4|^8.0", + "symfony/finder": "^7.4|^8.0", "symfony/http-client-contracts": "^2.5|^3.0", - "symfony/http-kernel": "^6.4|^7.0|^8.0", - "symfony/intl": "^6.4|^7.0|^8.0", + "symfony/http-kernel": "^7.4|^8.0", + "symfony/intl": "^7.4|^8.0", "symfony/polyfill-intl-icu": "^1.21", - "symfony/routing": "^6.4|^7.0|^8.0", + "symfony/routing": "^7.4|^8.0", "symfony/service-contracts": "^2.5|^3", - "symfony/yaml": "^6.4|^7.0|^8.0" + "symfony/yaml": "^7.4|^8.0" }, "type": "library", "autoload": { @@ -4578,7 +4401,7 @@ "description": "Provides tools to internationalize your application", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/translation/tree/v7.4.6" + "source": "https://github.com/symfony/translation/tree/v8.1.1" }, "funding": [ { @@ -4598,20 +4421,20 @@ "type": "tidelift" } ], - "time": "2026-02-17T07:53:42+00:00" + "time": "2026-06-06T11:11:44+00:00" }, { "name": "symfony/translation-contracts", - "version": "v3.6.1", + "version": "v3.7.1", "source": { "type": "git", "url": "https://github.com/symfony/translation-contracts.git", - "reference": "65a8bc82080447fae78373aa10f8d13b38338977" + "reference": "ccb206b98faccc511ebae8e5fad50f2dc0b30621" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/translation-contracts/zipball/65a8bc82080447fae78373aa10f8d13b38338977", - "reference": "65a8bc82080447fae78373aa10f8d13b38338977", + "url": "https://api.github.com/repos/symfony/translation-contracts/zipball/ccb206b98faccc511ebae8e5fad50f2dc0b30621", + "reference": "ccb206b98faccc511ebae8e5fad50f2dc0b30621", "shasum": "" }, "require": { @@ -4624,7 +4447,7 @@ "name": "symfony/contracts" }, "branch-alias": { - "dev-main": "3.6-dev" + "dev-main": "3.7-dev" } }, "autoload": { @@ -4660,7 +4483,7 @@ "standards" ], "support": { - "source": "https://github.com/symfony/translation-contracts/tree/v3.6.1" + "source": "https://github.com/symfony/translation-contracts/tree/v3.7.1" }, "funding": [ { @@ -4680,71 +4503,64 @@ "type": "tidelift" } ], - "time": "2025-07-15T13:41:35+00:00" + "time": "2026-06-05T06:23:12+00:00" }, { "name": "symfony/twig-bridge", - "version": "v7.4.7", + "version": "v8.1.1", "source": { "type": "git", "url": "https://github.com/symfony/twig-bridge.git", - "reference": "c67219ca6b79a57b64e36bbb2cd8ba741286587e" + "reference": "471e3b9537f514664ab8595668cd34c65cfa5d93" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/twig-bridge/zipball/c67219ca6b79a57b64e36bbb2cd8ba741286587e", - "reference": "c67219ca6b79a57b64e36bbb2cd8ba741286587e", + "url": "https://api.github.com/repos/symfony/twig-bridge/zipball/471e3b9537f514664ab8595668cd34c65cfa5d93", + "reference": "471e3b9537f514664ab8595668cd34c65cfa5d93", "shasum": "" }, "require": { - "php": ">=8.2", - "symfony/deprecation-contracts": "^2.5|^3", + "php": ">=8.4.1", "symfony/translation-contracts": "^2.5|^3", - "twig/twig": "^3.21" + "twig/twig": "^3.25" }, "conflict": { "phpdocumentor/reflection-docblock": "<5.2|>=7", "phpdocumentor/type-resolver": "<1.5.1", - "symfony/console": "<6.4", - "symfony/form": "<6.4.32|>7,<7.3.10|>7.4,<7.4.4|>8.0,<8.0.4", - "symfony/http-foundation": "<6.4", - "symfony/http-kernel": "<6.4", - "symfony/mime": "<6.4", - "symfony/serializer": "<6.4", - "symfony/translation": "<6.4", - "symfony/workflow": "<6.4" + "symfony/form": "<7.4.4|>8.0,<8.0.4", + "symfony/mime": "<7.4.9|>8.0,<8.0.9" }, "require-dev": { "egulias/email-validator": "^2.1.10|^3|^4", "league/html-to-markdown": "^5.0", "phpdocumentor/reflection-docblock": "^5.2|^6.0", - "symfony/asset": "^6.4|^7.0|^8.0", - "symfony/asset-mapper": "^6.4|^7.0|^8.0", - "symfony/console": "^6.4|^7.0|^8.0", - "symfony/dependency-injection": "^6.4|^7.0|^8.0", - "symfony/emoji": "^7.1|^8.0", - "symfony/expression-language": "^6.4|^7.0|^8.0", - "symfony/finder": "^6.4|^7.0|^8.0", - "symfony/form": "^6.4.32|~7.3.10|^7.4.4|^8.0.4", - "symfony/html-sanitizer": "^6.4|^7.0|^8.0", - "symfony/http-foundation": "^7.3|^8.0", - "symfony/http-kernel": "^6.4|^7.0|^8.0", - "symfony/intl": "^6.4|^7.0|^8.0", - "symfony/mime": "^6.4|^7.0|^8.0", - "symfony/polyfill-intl-icu": "~1.0", - "symfony/property-info": "^6.4|^7.0|^8.0", - "symfony/routing": "^6.4|^7.0|^8.0", + "symfony/asset": "^7.4|^8.0", + "symfony/asset-mapper": "^7.4|^8.0", + "symfony/console": "^7.4|^8.0", + "symfony/dependency-injection": "^7.4|^8.0", + "symfony/emoji": "^7.4|^8.0", + "symfony/expression-language": "^7.4|^8.0", + "symfony/finder": "^7.4|^8.0", + "symfony/form": "^7.4.4|^8.0.4", + "symfony/html-sanitizer": "^7.4|^8.0", + "symfony/http-foundation": "^7.4|^8.0", + "symfony/http-kernel": "^7.4|^8.0", + "symfony/intl": "^7.4|^8.0", + "symfony/mime": "^7.4.9|^8.0.9", + "symfony/polyfill-intl-icu": "^1.0", + "symfony/property-info": "^7.4|^8.0", + "symfony/routing": "^7.4|^8.0", "symfony/security-acl": "^2.8|^3.0", - "symfony/security-core": "^6.4|^7.0|^8.0", - "symfony/security-csrf": "^6.4|^7.0|^8.0", - "symfony/security-http": "^6.4|^7.0|^8.0", - "symfony/serializer": "^6.4.3|^7.0.3|^8.0", - "symfony/stopwatch": "^6.4|^7.0|^8.0", - "symfony/translation": "^6.4|^7.0|^8.0", - "symfony/validator": "^6.4|^7.0|^8.0", - "symfony/web-link": "^6.4|^7.0|^8.0", - "symfony/workflow": "^6.4|^7.0|^8.0", - "symfony/yaml": "^6.4|^7.0|^8.0", + "symfony/security-core": "^7.4|^8.0", + "symfony/security-csrf": "^7.4|^8.0", + "symfony/security-http": "^7.4|^8.0", + "symfony/serializer": "^7.4|^8.0", + "symfony/stopwatch": "^7.4|^8.0", + "symfony/translation": "^7.4|^8.0", + "symfony/validator": "^7.4|^8.0", + "symfony/web-link": "^7.4|^8.0", + "symfony/workflow": "^7.4|^8.0", + "symfony/yaml": "^7.4|^8.0", "twig/cssinliner-extra": "^3", "twig/inky-extra": "^3", "twig/markdown-extra": "^3" @@ -4775,7 +4591,7 @@ "description": "Provides integration for Twig with various Symfony components", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/twig-bridge/tree/v7.4.7" + "source": "https://github.com/symfony/twig-bridge/tree/v8.1.1" }, "funding": [ { @@ -4795,49 +4611,43 @@ "type": "tidelift" } ], - "time": "2026-03-04T15:37:05+00:00" + "time": "2026-06-17T15:04:37+00:00" }, { "name": "symfony/twig-bundle", - "version": "v7.4.4", + "version": "v8.1.0", "source": { "type": "git", "url": "https://github.com/symfony/twig-bundle.git", - "reference": "e8829e02ff96a391ed0703bac9e7ff0537480b6b" + "reference": "b7f4a471a07b8b52174d153e4db12f46954192ed" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/twig-bundle/zipball/e8829e02ff96a391ed0703bac9e7ff0537480b6b", - "reference": "e8829e02ff96a391ed0703bac9e7ff0537480b6b", + "url": "https://api.github.com/repos/symfony/twig-bundle/zipball/b7f4a471a07b8b52174d153e4db12f46954192ed", + "reference": "b7f4a471a07b8b52174d153e4db12f46954192ed", "shasum": "" }, "require": { "composer-runtime-api": ">=2.1", - "php": ">=8.2", + "php": ">=8.4.1", "symfony/config": "^7.4|^8.0", - "symfony/dependency-injection": "^6.4|^7.0|^8.0", - "symfony/deprecation-contracts": "^2.5|^3", - "symfony/http-foundation": "^6.4|^7.0|^8.0", - "symfony/http-kernel": "^6.4.13|^7.1.6|^8.0", - "symfony/twig-bridge": "^7.3|^8.0", - "twig/twig": "^3.12" - }, - "conflict": { - "symfony/framework-bundle": "<6.4", - "symfony/translation": "<6.4" + "symfony/dependency-injection": "^7.4|^8.0", + "symfony/http-foundation": "^7.4|^8.0", + "symfony/http-kernel": "^7.4|^8.0", + "symfony/twig-bridge": "^7.4|^8.0" }, "require-dev": { - "symfony/asset": "^6.4|^7.0|^8.0", - "symfony/expression-language": "^6.4|^7.0|^8.0", - "symfony/finder": "^6.4|^7.0|^8.0", - "symfony/form": "^6.4|^7.0|^8.0", - "symfony/framework-bundle": "^6.4.13|^7.1.6|^8.0", - "symfony/routing": "^6.4|^7.0|^8.0", - "symfony/runtime": "^6.4.13|^7.1.6", - "symfony/stopwatch": "^6.4|^7.0|^8.0", - "symfony/translation": "^6.4|^7.0|^8.0", - "symfony/web-link": "^6.4|^7.0|^8.0", - "symfony/yaml": "^6.4|^7.0|^8.0" + "symfony/asset": "^7.4|^8.0", + "symfony/expression-language": "^7.4|^8.0", + "symfony/finder": "^7.4|^8.0", + "symfony/form": "^7.4|^8.0", + "symfony/framework-bundle": "^7.4|^8.0", + "symfony/routing": "^7.4|^8.0", + "symfony/runtime": "^7.4|^8.0", + "symfony/stopwatch": "^7.4|^8.0", + "symfony/translation": "^7.4|^8.0", + "symfony/web-link": "^7.4|^8.0", + "symfony/yaml": "^7.4|^8.0" }, "type": "symfony-bundle", "autoload": { @@ -4865,7 +4675,7 @@ "description": "Provides a tight integration of Twig into the Symfony full-stack framework", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/twig-bundle/tree/v7.4.4" + "source": "https://github.com/symfony/twig-bundle/tree/v8.1.0" }, "funding": [ { @@ -4885,26 +4695,25 @@ "type": "tidelift" } ], - "time": "2026-01-06T12:34:24+00:00" + "time": "2026-05-29T05:06:50+00:00" }, { "name": "symfony/type-info", - "version": "v7.4.7", + "version": "v8.1.0", "source": { "type": "git", "url": "https://github.com/symfony/type-info.git", - "reference": "31f1e40cbf7851c7354281c90eb1b352c4cb8269" + "reference": "9f24df8a79781b9b9f030fea7dfd2f3bd1e7e7e7" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/type-info/zipball/31f1e40cbf7851c7354281c90eb1b352c4cb8269", - "reference": "31f1e40cbf7851c7354281c90eb1b352c4cb8269", + "url": "https://api.github.com/repos/symfony/type-info/zipball/9f24df8a79781b9b9f030fea7dfd2f3bd1e7e7e7", + "reference": "9f24df8a79781b9b9f030fea7dfd2f3bd1e7e7e7", "shasum": "" }, "require": { - "php": ">=8.2", - "psr/container": "^1.1|^2.0", - "symfony/deprecation-contracts": "^2.5|^3" + "php": ">=8.4.1", + "psr/container": "^1.1|^2.0" }, "conflict": { "phpstan/phpdoc-parser": "<1.30" @@ -4948,7 +4757,7 @@ "type" ], "support": { - "source": "https://github.com/symfony/type-info/tree/v7.4.7" + "source": "https://github.com/symfony/type-info/tree/v8.1.0" }, "funding": [ { @@ -4968,62 +4777,55 @@ "type": "tidelift" } ], - "time": "2026-03-04T12:49:16+00:00" + "time": "2026-05-29T05:06:50+00:00" }, { "name": "symfony/validator", - "version": "v7.4.7", + "version": "v8.1.1", "source": { "type": "git", "url": "https://github.com/symfony/validator.git", - "reference": "3a1a460a9f8c5e5611e15c52c4baa5a62fa3c203" + "reference": "d162b73fa884ce2185033c143172dc12b023051a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/validator/zipball/3a1a460a9f8c5e5611e15c52c4baa5a62fa3c203", - "reference": "3a1a460a9f8c5e5611e15c52c4baa5a62fa3c203", + "url": "https://api.github.com/repos/symfony/validator/zipball/d162b73fa884ce2185033c143172dc12b023051a", + "reference": "d162b73fa884ce2185033c143172dc12b023051a", "shasum": "" }, "require": { - "php": ">=8.2", + "php": ">=8.4.1", "symfony/deprecation-contracts": "^2.5|^3", - "symfony/polyfill-ctype": "~1.8", - "symfony/polyfill-mbstring": "~1.0", - "symfony/polyfill-php83": "^1.27", + "symfony/polyfill-ctype": "^1.8", + "symfony/polyfill-mbstring": "^1.0", "symfony/translation-contracts": "^2.5|^3" }, "conflict": { "doctrine/lexer": "<1.1", - "symfony/dependency-injection": "<6.4", - "symfony/doctrine-bridge": "<7.0", - "symfony/expression-language": "<6.4", - "symfony/http-kernel": "<6.4", - "symfony/intl": "<6.4", - "symfony/property-info": "<6.4", - "symfony/translation": "<6.4.3|>=7.0,<7.0.3", - "symfony/var-exporter": "<6.4.25|>=7.0,<7.3.3", - "symfony/yaml": "<6.4" + "symfony/doctrine-bridge": "<7.4", + "symfony/expression-language": "<7.4" }, "require-dev": { "egulias/email-validator": "^2.1.10|^3|^4", - "symfony/cache": "^6.4|^7.0|^8.0", - "symfony/config": "^6.4|^7.0|^8.0", - "symfony/console": "^6.4|^7.0|^8.0", - "symfony/dependency-injection": "^6.4|^7.0|^8.0", - "symfony/expression-language": "^6.4|^7.0|^8.0", - "symfony/finder": "^6.4|^7.0|^8.0", - "symfony/http-client": "^6.4|^7.0|^8.0", - "symfony/http-foundation": "^6.4|^7.0|^8.0", - "symfony/http-kernel": "^6.4|^7.0|^8.0", - "symfony/intl": "^6.4|^7.0|^8.0", - "symfony/mime": "^6.4|^7.0|^8.0", - "symfony/process": "^6.4|^7.0|^8.0", - "symfony/property-access": "^6.4|^7.0|^8.0", - "symfony/property-info": "^6.4|^7.0|^8.0", - "symfony/string": "^6.4|^7.0|^8.0", - "symfony/translation": "^6.4.3|^7.0.3|^8.0", - "symfony/type-info": "^7.1.8", - "symfony/yaml": "^6.4|^7.0|^8.0" + "symfony/cache": "^7.4|^8.0", + "symfony/clock": "^7.4|^8.0", + "symfony/config": "^7.4|^8.0", + "symfony/console": "^7.4|^8.0", + "symfony/dependency-injection": "^7.4|^8.0", + "symfony/expression-language": "^7.4|^8.0", + "symfony/finder": "^7.4|^8.0", + "symfony/http-client": "^7.4|^8.0", + "symfony/http-foundation": "^7.4|^8.0", + "symfony/http-kernel": "^7.4|^8.0", + "symfony/intl": "^7.4|^8.0", + "symfony/mime": "^7.4|^8.0", + "symfony/process": "^7.4|^8.0", + "symfony/property-access": "^7.4|^8.0", + "symfony/property-info": "^7.4|^8.0", + "symfony/string": "^7.4|^8.0", + "symfony/translation": "^7.4|^8.0", + "symfony/type-info": "^7.4|^8.0", + "symfony/yaml": "^7.4|^8.0" }, "type": "library", "autoload": { @@ -5052,7 +4854,7 @@ "description": "Provides tools to validate values", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/validator/tree/v7.4.7" + "source": "https://github.com/symfony/validator/tree/v8.1.1" }, "funding": [ { @@ -5072,35 +4874,35 @@ "type": "tidelift" } ], - "time": "2026-03-06T11:10:17+00:00" + "time": "2026-06-27T06:18:14+00:00" }, { "name": "symfony/var-dumper", - "version": "v7.4.8", + "version": "v8.1.1", "source": { "type": "git", "url": "https://github.com/symfony/var-dumper.git", - "reference": "9510c3966f749a1d1ff0059e1eabef6cc621e7fd" + "reference": "40096a2515a979f3125c5c928603995b8664c62a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/var-dumper/zipball/9510c3966f749a1d1ff0059e1eabef6cc621e7fd", - "reference": "9510c3966f749a1d1ff0059e1eabef6cc621e7fd", + "url": "https://api.github.com/repos/symfony/var-dumper/zipball/40096a2515a979f3125c5c928603995b8664c62a", + "reference": "40096a2515a979f3125c5c928603995b8664c62a", "shasum": "" }, "require": { - "php": ">=8.2", - "symfony/deprecation-contracts": "^2.5|^3", - "symfony/polyfill-mbstring": "~1.0" + "php": ">=8.4.1", + "symfony/polyfill-mbstring": "^1.0" }, "conflict": { - "symfony/console": "<6.4" + "symfony/console": "<7.4", + "symfony/error-handler": "<7.4" }, "require-dev": { - "symfony/console": "^6.4|^7.0|^8.0", - "symfony/http-kernel": "^6.4|^7.0|^8.0", - "symfony/process": "^6.4|^7.0|^8.0", - "symfony/uid": "^6.4|^7.0|^8.0", + "symfony/console": "^7.4|^8.0", + "symfony/http-kernel": "^7.4|^8.0", + "symfony/process": "^7.4|^8.0", + "symfony/uid": "^7.4|^8.0", "twig/twig": "^3.12" }, "bin": [ @@ -5139,7 +4941,7 @@ "dump" ], "support": { - "source": "https://github.com/symfony/var-dumper/tree/v7.4.8" + "source": "https://github.com/symfony/var-dumper/tree/v8.1.1" }, "funding": [ { @@ -5159,20 +4961,20 @@ "type": "tidelift" } ], - "time": "2026-03-30T13:44:50+00:00" + "time": "2026-06-09T10:54:51+00:00" }, { "name": "symfony/var-exporter", - "version": "v7.4.9", + "version": "v7.4.14", "source": { "type": "git", "url": "https://github.com/symfony/var-exporter.git", - "reference": "22e03a49c95ef054a43601cd159b222bfab1c701" + "reference": "0118811b1d59f323bf131250b3fb919febfece28" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/var-exporter/zipball/22e03a49c95ef054a43601cd159b222bfab1c701", - "reference": "22e03a49c95ef054a43601cd159b222bfab1c701", + "url": "https://api.github.com/repos/symfony/var-exporter/zipball/0118811b1d59f323bf131250b3fb919febfece28", + "reference": "0118811b1d59f323bf131250b3fb919febfece28", "shasum": "" }, "require": { @@ -5220,7 +5022,7 @@ "serialize" ], "support": { - "source": "https://github.com/symfony/var-exporter/tree/v7.4.9" + "source": "https://github.com/symfony/var-exporter/tree/v7.4.14" }, "funding": [ { @@ -5240,32 +5042,32 @@ "type": "tidelift" } ], - "time": "2026-04-18T13:18:21+00:00" + "time": "2026-06-27T08:41:53+00:00" }, { "name": "symfony/yaml", - "version": "v7.4.12", + "version": "v8.1.1", "source": { "type": "git", "url": "https://github.com/symfony/yaml.git", - "reference": "8b6952b56ca6417f25f7a65758cadd0ce02edc51" + "reference": "8e4cdd4311683516be06944f4b85244063cdb886" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/yaml/zipball/8b6952b56ca6417f25f7a65758cadd0ce02edc51", - "reference": "8b6952b56ca6417f25f7a65758cadd0ce02edc51", + "url": "https://api.github.com/repos/symfony/yaml/zipball/8e4cdd4311683516be06944f4b85244063cdb886", + "reference": "8e4cdd4311683516be06944f4b85244063cdb886", "shasum": "" }, "require": { - "php": ">=8.2", - "symfony/deprecation-contracts": "^2.5|^3", + "php": ">=8.4.1", "symfony/polyfill-ctype": "^1.8" }, "conflict": { - "symfony/console": "<6.4" + "symfony/console": "<7.4" }, "require-dev": { - "symfony/console": "^6.4|^7.0|^8.0" + "symfony/console": "^7.4|^8.0", + "yaml/yaml-test-suite": "*" }, "bin": [ "Resources/bin/yaml-lint" @@ -5296,7 +5098,7 @@ "description": "Loads and dumps YAML files", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/yaml/tree/v7.4.12" + "source": "https://github.com/symfony/yaml/tree/v8.1.1" }, "funding": [ { @@ -5316,7 +5118,7 @@ "type": "tidelift" } ], - "time": "2026-05-20T07:20:23+00:00" + "time": "2026-06-09T11:06:24+00:00" }, { "name": "twig/twig", @@ -5466,28 +5268,29 @@ }, { "name": "composer/pcre", - "version": "3.3.2", + "version": "3.4.0", "source": { "type": "git", "url": "https://github.com/composer/pcre.git", - "reference": "b2bed4734f0cc156ee1fe9c0da2550420d99a21e" + "reference": "d5a341b3fb61f3001970940afb1d332968a183ed" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/composer/pcre/zipball/b2bed4734f0cc156ee1fe9c0da2550420d99a21e", - "reference": "b2bed4734f0cc156ee1fe9c0da2550420d99a21e", + "url": "https://api.github.com/repos/composer/pcre/zipball/d5a341b3fb61f3001970940afb1d332968a183ed", + "reference": "d5a341b3fb61f3001970940afb1d332968a183ed", "shasum": "" }, "require": { "php": "^7.4 || ^8.0" }, "conflict": { - "phpstan/phpstan": "<1.11.10" + "phpstan/phpstan": "<2.2.2" }, "require-dev": { - "phpstan/phpstan": "^1.12 || ^2", - "phpstan/phpstan-strict-rules": "^1 || ^2", - "phpunit/phpunit": "^8 || ^9" + "phpstan/phpstan": "^2", + "phpstan/phpstan-deprecation-rules": "^2", + "phpstan/phpstan-strict-rules": "^2", + "phpunit/phpunit": "^9" }, "type": "library", "extra": { @@ -5525,7 +5328,7 @@ ], "support": { "issues": "https://github.com/composer/pcre/issues", - "source": "https://github.com/composer/pcre/tree/3.3.2" + "source": "https://github.com/composer/pcre/tree/3.4.0" }, "funding": [ { @@ -5535,13 +5338,9 @@ { "url": "https://github.com/composer", "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/composer/composer", - "type": "tidelift" } ], - "time": "2024-11-12T16:29:46+00:00" + "time": "2026-06-07T11:47:49+00:00" }, { "name": "composer/semver", @@ -5859,16 +5658,16 @@ }, { "name": "doctrine/data-fixtures", - "version": "2.2.0", + "version": "2.2.1", "source": { "type": "git", "url": "https://github.com/doctrine/data-fixtures.git", - "reference": "7a615ba135e45d67674bb623d90f34f6c7b6bd97" + "reference": "bf7ac3a050b54b261cedfb3d0a44733819062275" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/doctrine/data-fixtures/zipball/7a615ba135e45d67674bb623d90f34f6c7b6bd97", - "reference": "7a615ba135e45d67674bb623d90f34f6c7b6bd97", + "url": "https://api.github.com/repos/doctrine/data-fixtures/zipball/bf7ac3a050b54b261cedfb3d0a44733819062275", + "reference": "bf7ac3a050b54b261cedfb3d0a44733819062275", "shasum": "" }, "require": { @@ -5886,12 +5685,14 @@ "doctrine/dbal": "^3.5 || ^4", "doctrine/mongodb-odm": "^1.3.0 || ^2.0.0", "doctrine/orm": "^2.14 || ^3", + "doctrine/phpcr-odm": "^1.8 || ^2.0", "ext-sqlite3": "*", "fig/log-test": "^1", - "phpstan/phpstan": "2.1.31", - "phpunit/phpunit": "10.5.45 || 12.4.0", - "symfony/cache": "^6.4 || ^7", - "symfony/var-exporter": "^6.4 || ^7" + "jackalope/jackalope-fs": "*", + "phpstan/phpstan": "2.1.46", + "phpunit/phpunit": "10.5.63 || 12.5.12", + "symfony/cache": "^6.4 || ^7 || ^8", + "symfony/var-exporter": "^6.4 || ^7 || ^8" }, "suggest": { "alcaeus/mongo-php-adapter": "For using MongoDB ODM 1.3 with PHP 7 (deprecated)", @@ -5922,7 +5723,7 @@ ], "support": { "issues": "https://github.com/doctrine/data-fixtures/issues", - "source": "https://github.com/doctrine/data-fixtures/tree/2.2.0" + "source": "https://github.com/doctrine/data-fixtures/tree/2.2.1" }, "funding": [ { @@ -5938,20 +5739,20 @@ "type": "tidelift" } ], - "time": "2025-10-17T20:06:20+00:00" + "time": "2026-04-01T13:56:01+00:00" }, { "name": "doctrine/mongodb-odm", - "version": "2.16.1", + "version": "2.16.2", "source": { "type": "git", "url": "https://github.com/doctrine/mongodb-odm.git", - "reference": "b34f2dce3ca5b2de8903419a31ad48837d852b74" + "reference": "da149ec2596c8e3732c5332b19f1351f3d5b6f70" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/doctrine/mongodb-odm/zipball/b34f2dce3ca5b2de8903419a31ad48837d852b74", - "reference": "b34f2dce3ca5b2de8903419a31ad48837d852b74", + "url": "https://api.github.com/repos/doctrine/mongodb-odm/zipball/da149ec2596c8e3732c5332b19f1351f3d5b6f70", + "reference": "da149ec2596c8e3732c5332b19f1351f3d5b6f70", "shasum": "" }, "require": { @@ -6041,7 +5842,7 @@ ], "support": { "issues": "https://github.com/doctrine/mongodb-odm/issues", - "source": "https://github.com/doctrine/mongodb-odm/tree/2.16.1" + "source": "https://github.com/doctrine/mongodb-odm/tree/2.16.2" }, "funding": [ { @@ -6057,7 +5858,7 @@ "type": "tidelift" } ], - "time": "2026-01-29T11:33:08+00:00" + "time": "2026-06-19T09:23:48+00:00" }, { "name": "doctrine/mongodb-odm-bundle", @@ -6147,6 +5948,75 @@ }, "time": "2026-01-26T10:21:57+00:00" }, + { + "name": "ergebnis/agent-detector", + "version": "1.2.0", + "source": { + "type": "git", + "url": "https://github.com/ergebnis/agent-detector.git", + "reference": "e211f17928c8b95a51e06040792d57f5462fb271" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/ergebnis/agent-detector/zipball/e211f17928c8b95a51e06040792d57f5462fb271", + "reference": "e211f17928c8b95a51e06040792d57f5462fb271", + "shasum": "" + }, + "require": { + "php": "~7.4.0 || ~8.0.0 || ~8.1.0 || ~8.2.0 || ~8.3.0 || ~8.4.0 || ~8.5.0 || ~8.6.0" + }, + "require-dev": { + "ergebnis/composer-normalize": "^2.51.0", + "ergebnis/license": "^2.7.0", + "ergebnis/php-cs-fixer-config": "^6.60.2", + "ergebnis/phpstan-rules": "^2.13.1", + "ergebnis/phpunit-slow-test-detector": "^2.24.0", + "ergebnis/rector-rules": "^1.18.1", + "fakerphp/faker": "^1.24.1", + "infection/infection": "^0.26.6", + "phpstan/extension-installer": "^1.4.3", + "phpstan/phpstan": "^2.1.54", + "phpstan/phpstan-deprecation-rules": "^2.0.4", + "phpstan/phpstan-phpunit": "^2.0.16", + "phpstan/phpstan-strict-rules": "^2.0.10", + "phpunit/phpunit": "^9.6.34", + "rector/rector": "^2.4.2" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "1.2-dev" + }, + "composer-normalize": { + "indent-size": 2, + "indent-style": "space" + } + }, + "autoload": { + "psr-4": { + "Ergebnis\\AgentDetector\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Andreas Möller", + "email": "am@localheinz.com", + "homepage": "https://localheinz.com" + } + ], + "description": "Provides a detector for detecting the presence of an agent.", + "homepage": "https://github.com/ergebnis/agent-detector", + "support": { + "issues": "https://github.com/ergebnis/agent-detector/issues", + "security": "https://github.com/ergebnis/agent-detector/blob/main/.github/SECURITY.md", + "source": "https://github.com/ergebnis/agent-detector" + }, + "time": "2026-05-07T08:19:07+00:00" + }, { "name": "evenement/evenement", "version": "v3.0.2", @@ -6257,22 +6127,23 @@ }, { "name": "friendsofphp/php-cs-fixer", - "version": "v3.94.2", + "version": "v3.95.11", "source": { "type": "git", "url": "https://github.com/PHP-CS-Fixer/PHP-CS-Fixer.git", - "reference": "7787ceff91365ba7d623ec410b8f429cdebb4f63" + "reference": "35f98e1293283397824d7f349ce5afb8747c3cd5" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/PHP-CS-Fixer/PHP-CS-Fixer/zipball/7787ceff91365ba7d623ec410b8f429cdebb4f63", - "reference": "7787ceff91365ba7d623ec410b8f429cdebb4f63", + "url": "https://api.github.com/repos/PHP-CS-Fixer/PHP-CS-Fixer/zipball/35f98e1293283397824d7f349ce5afb8747c3cd5", + "reference": "35f98e1293283397824d7f349ce5afb8747c3cd5", "shasum": "" }, "require": { "clue/ndjson-react": "^1.3", "composer/semver": "^3.4", "composer/xdebug-handler": "^3.0.5", + "ergebnis/agent-detector": "^1.2", "ext-filter": "*", "ext-hash": "*", "ext-json": "*", @@ -6283,32 +6154,32 @@ "react/event-loop": "^1.5", "react/socket": "^1.16", "react/stream": "^1.4", - "sebastian/diff": "^4.0.6 || ^5.1.1 || ^6.0.2 || ^7.0 || ^8.0", + "sebastian/diff": "^4.0.6 || ^5.1.1 || ^6.0.2 || ^7.0 || ^8.0 || ^9.0", "symfony/console": "^5.4.47 || ^6.4.24 || ^7.0 || ^8.0", "symfony/event-dispatcher": "^5.4.45 || ^6.4.24 || ^7.0 || ^8.0", "symfony/filesystem": "^5.4.45 || ^6.4.24 || ^7.0 || ^8.0", "symfony/finder": "^5.4.45 || ^6.4.24 || ^7.0 || ^8.0", "symfony/options-resolver": "^5.4.45 || ^6.4.24 || ^7.0 || ^8.0", - "symfony/polyfill-mbstring": "^1.33", - "symfony/polyfill-php80": "^1.33", - "symfony/polyfill-php81": "^1.33", - "symfony/polyfill-php84": "^1.33", + "symfony/polyfill-mbstring": "^1.37", + "symfony/polyfill-php80": "^1.37", + "symfony/polyfill-php81": "^1.37", + "symfony/polyfill-php84": "^1.37", "symfony/process": "^5.4.47 || ^6.4.24 || ^7.2 || ^8.0", "symfony/stopwatch": "^5.4.45 || ^6.4.24 || ^7.0 || ^8.0" }, "require-dev": { - "facile-it/paraunit": "^1.3.1 || ^2.7.1", - "infection/infection": "^0.32.3", - "justinrainbow/json-schema": "^6.6.4", + "facile-it/paraunit": "^1.3.1 || ^2.11.0", + "infection/infection": "^0.32.7", + "justinrainbow/json-schema": "^6.10.0", "keradus/cli-executor": "^2.3", "mikey179/vfsstream": "^1.6.12", "php-coveralls/php-coveralls": "^2.9.1", - "php-cs-fixer/phpunit-constraint-isidenticalstring": "^1.7", - "php-cs-fixer/phpunit-constraint-xmlmatchesxsd": "^1.7", - "phpunit/phpunit": "^9.6.34 || ^10.5.63 || ^11.5.51", - "symfony/polyfill-php85": "^1.33", - "symfony/var-dumper": "^5.4.48 || ^6.4.32 || ^7.4.4 || ^8.0.4", - "symfony/yaml": "^5.4.45 || ^6.4.30 || ^7.4.1 || ^8.0.1" + "php-cs-fixer/phpunit-constraint-isidenticalstring": "^1.8", + "php-cs-fixer/phpunit-constraint-xmlmatchesxsd": "^1.8", + "phpunit/phpunit": "^9.6.34 || ^10.5.63 || ^11.5.55", + "symfony/polyfill-php85": "^1.38", + "symfony/var-dumper": "^5.4.48 || ^6.4.36 || ^7.4.8 || ^8.1.0", + "symfony/yaml": "^5.4.53 || ^6.4.41 || ^7.4.13 || ^8.1.0" }, "suggest": { "ext-dom": "For handling output formats in XML", @@ -6349,7 +6220,7 @@ ], "support": { "issues": "https://github.com/PHP-CS-Fixer/PHP-CS-Fixer/issues", - "source": "https://github.com/PHP-CS-Fixer/PHP-CS-Fixer/tree/v3.94.2" + "source": "https://github.com/PHP-CS-Fixer/PHP-CS-Fixer/tree/v3.95.11" }, "funding": [ { @@ -6357,7 +6228,7 @@ "type": "github" } ], - "time": "2026-02-20T16:13:53+00:00" + "time": "2026-06-25T14:17:04+00:00" }, { "name": "friendsofphp/proxy-manager-lts", @@ -6931,11 +6802,11 @@ }, { "name": "phpstan/phpstan", - "version": "2.1.40", + "version": "2.2.4", "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpstan/phpstan/zipball/9b2c7aeb83a75d8680ea5e7c9b7fca88052b766b", - "reference": "9b2c7aeb83a75d8680ea5e7c9b7fca88052b766b", + "url": "https://api.github.com/repos/phpstan/phpstan/zipball/f0fe3fb03bb53ce68cc2416785b260e62226ec27", + "reference": "f0fe3fb03bb53ce68cc2416785b260e62226ec27", "shasum": "" }, "require": { @@ -6958,6 +6829,17 @@ "license": [ "MIT" ], + "authors": [ + { + "name": "Ondřej Mirtes" + }, + { + "name": "Markus Staab" + }, + { + "name": "Vincent Langlet" + } + ], "description": "PHPStan - PHP Static Analysis Tool", "keywords": [ "dev", @@ -6980,7 +6862,7 @@ "type": "github" } ], - "time": "2026-02-23T15:04:35+00:00" + "time": "2026-07-03T07:00:23+00:00" }, { "name": "phpunit/php-code-coverage", @@ -7940,21 +7822,21 @@ }, { "name": "rector/rector", - "version": "2.3.8", + "version": "2.5.2", "source": { "type": "git", "url": "https://github.com/rectorphp/rector.git", - "reference": "bbd37aedd8df749916cffa2a947cfc4714d1ba2c" + "reference": "49ff6339174bdbdf50b0b35ecbcff14a05ac9e24" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/rectorphp/rector/zipball/bbd37aedd8df749916cffa2a947cfc4714d1ba2c", - "reference": "bbd37aedd8df749916cffa2a947cfc4714d1ba2c", + "url": "https://api.github.com/repos/rectorphp/rector/zipball/49ff6339174bdbdf50b0b35ecbcff14a05ac9e24", + "reference": "49ff6339174bdbdf50b0b35ecbcff14a05ac9e24", "shasum": "" }, "require": { "php": "^7.4|^8.0", - "phpstan/phpstan": "^2.1.38" + "phpstan/phpstan": "^2.2.2" }, "conflict": { "rector/rector-doctrine": "*", @@ -7988,7 +7870,7 @@ ], "support": { "issues": "https://github.com/rectorphp/rector/issues", - "source": "https://github.com/rectorphp/rector/tree/2.3.8" + "source": "https://github.com/rectorphp/rector/tree/2.5.2" }, "funding": [ { @@ -7996,7 +7878,7 @@ "type": "github" } ], - "time": "2026-02-22T09:45:50+00:00" + "time": "2026-06-22T11:39:33+00:00" }, { "name": "sebastian/cli-parser", @@ -9117,20 +8999,20 @@ }, { "name": "symfony/process", - "version": "v7.4.5", + "version": "v8.1.0", "source": { "type": "git", "url": "https://github.com/symfony/process.git", - "reference": "608476f4604102976d687c483ac63a79ba18cc97" + "reference": "c4a9e58f235a6bf7f97ffbfedae2687353ac79e5" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/process/zipball/608476f4604102976d687c483ac63a79ba18cc97", - "reference": "608476f4604102976d687c483ac63a79ba18cc97", + "url": "https://api.github.com/repos/symfony/process/zipball/c4a9e58f235a6bf7f97ffbfedae2687353ac79e5", + "reference": "c4a9e58f235a6bf7f97ffbfedae2687353ac79e5", "shasum": "" }, "require": { - "php": ">=8.2" + "php": ">=8.4.1" }, "type": "library", "autoload": { @@ -9158,7 +9040,7 @@ "description": "Executes commands in sub-processes", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/process/tree/v7.4.5" + "source": "https://github.com/symfony/process/tree/v8.1.0" }, "funding": [ { @@ -9178,7 +9060,7 @@ "type": "tidelift" } ], - "time": "2026-01-26T15:07:59+00:00" + "time": "2026-05-29T05:06:50+00:00" }, { "name": "theseer/tokenizer", @@ -9237,14 +9119,13 @@ "prefer-stable": true, "prefer-lowest": false, "platform": { - "php": "^8.1|^8.2|^8.3|^8.4" + "php": "^8.2|^8.3|^8.4" }, "platform-dev": { "ext-mongodb": "^1.21.0 || ^2.0.0", "ext-pdo": "*" }, "platform-overrides": { - "php": "8.2.0", "ext-mongodb": "2.1.4" }, "plugin-api-version": "2.9.0" From b0b9ad697dedbb54386631f099e2de21d9a3602a Mon Sep 17 00:00:00 2001 From: Bart McLeod Date: Wed, 8 Jul 2026 00:09:52 +0200 Subject: [PATCH 11/12] Fix YamlexporterTest to match new array export format --- Tests/Unit/Translation/Exporter/YamlExporterTest.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Tests/Unit/Translation/Exporter/YamlExporterTest.php b/Tests/Unit/Translation/Exporter/YamlExporterTest.php index 0edabe51..ffb29c21 100644 --- a/Tests/Unit/Translation/Exporter/YamlExporterTest.php +++ b/Tests/Unit/Translation/Exporter/YamlExporterTest.php @@ -34,7 +34,8 @@ public function testExport() // export empty array $exporter->export($outFile, []); - $expectedContent = '{ }'; + // Expectation changed from '{ }' to '{}', because apparently after an update, an empty array is exported differently. + $expectedContent = '{}'; $this->assertEquals($expectedContent, trim(file_get_contents($outFile))); // export array with values From 551470404d3f3382f892d331a493d2ea3d7955ea Mon Sep 17 00:00:00 2001 From: Bart McLeod Date: Wed, 8 Jul 2026 00:18:32 +0200 Subject: [PATCH 12/12] Bumping the php versions for the builds on GitHub, because Symfony httpkernel now requires PHP 8.4 and this runs locally on PHP 8.5, so for now, these will be supported and tested. --- .github/workflows/php.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/php.yml b/.github/workflows/php.yml index f21d7184..6524f215 100644 --- a/.github/workflows/php.yml +++ b/.github/workflows/php.yml @@ -37,7 +37,7 @@ jobs: strategy: matrix: - php-version: ['8.2', '8.3', '8.4'] + php-version: ['8.4', '8.5'] steps: - name: Setup PHP