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/Command/ExportTranslationsCommand.php b/Command/ExportTranslationsCommand.php index c8fe10ea..6fe186d1 100644 --- a/Command/ExportTranslationsCommand.php +++ b/Command/ExportTranslationsCommand.php @@ -57,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.'); @@ -164,15 +172,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..ce216d4b 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); } @@ -181,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', ]; @@ -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'; @@ -261,7 +249,7 @@ protected function importBundleTranslationFiles(BundleInterface $bundle, $locale $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); @@ -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 2df5b8b9..5993b25c 100644 --- a/Controller/TranslationController.php +++ b/Controller/TranslationController.php @@ -6,11 +6,11 @@ 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; 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; @@ -23,8 +23,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 +40,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 +59,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 +74,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'); @@ -67,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')); } @@ -82,22 +101,22 @@ 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)); } - 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()]); } /** * Returns managed locales. - * - * @return array */ - protected function getManagedLocales() + protected function getManagedLocales(): array { return $this->localeManager->getLocales(); } 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 eda7d70b..1a1b8427 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; /** @@ -21,6 +21,13 @@ 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->processCacheDir($container); + $this->processRessources($container); + // loaders $loaders = []; $loadersReferences = []; @@ -37,29 +44,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 +64,68 @@ 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); + } + } + + 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/DependencyInjection/Configuration.php b/DependencyInjection/Configuration.php index f71c858f..f21dd3df 100644 --- a/DependencyInjection/Configuration.php +++ b/DependencyInjection/Configuration.php @@ -40,19 +40,19 @@ 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]) + ->then(fn ($value) => [$value]) ->end() ->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') @@ -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 d4d8c680..d20b13ba 100644 --- a/DependencyInjection/LexikTranslationExtension.php +++ b/DependencyInjection/LexikTranslationExtension.php @@ -2,26 +2,21 @@ namespace Lexik\Bundle\TranslationBundle\DependencyInjection; -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; +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\Resource\DirectoryResource; +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\Finder\Finder; -use Symfony\Component\HttpKernel\Kernel; +use Symfony\Component\DependencyInjection\Reference; /** * This is the class that loads and manages your bundle configuration @@ -41,15 +36,23 @@ 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'); - // 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']); @@ -60,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); @@ -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%'); @@ -89,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); } @@ -116,12 +117,12 @@ public function prepend(ContainerBuilder $container): void * @param string $objectManager * @throws \RuntimeException */ - protected function buildTranslationStorageDefinition(ContainerBuilder $container, $storage, $objectManager) + 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)) { @@ -140,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 { @@ -149,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(); @@ -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/Dockerfile b/Dockerfile index 986dde95..7db9c737 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 @@ -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/Document/File.php b/Document/File.php index 806971ab..d57ca4a5 100644 --- a/Document/File.php +++ b/Document/File.php @@ -2,18 +2,14 @@ namespace Lexik\Bundle\TranslationBundle\Document; -use Lexik\Bundle\TranslationBundle\Model\File as FileModel; -use Lexik\Bundle\TranslationBundle\Manager\FileInterface; use DateTime; +use Lexik\Bundle\TranslationBundle\Model\File as FileModel; /** * @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..bec506cc 100644 --- a/Document/TransUnit.php +++ b/Document/TransUnit.php @@ -2,9 +2,8 @@ namespace Lexik\Bundle\TranslationBundle\Document; -use Lexik\Bundle\TranslationBundle\Model\TransUnit as TransUnitModel; use Lexik\Bundle\TranslationBundle\Manager\TransUnitInterface; -use MongoTimestamp; +use Lexik\Bundle\TranslationBundle\Model\TransUnit as TransUnitModel; /** * @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..ac7639ea 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,12 +251,12 @@ 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; $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; @@ -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..1eccc13e 100644 --- a/Document/Translation.php +++ b/Document/Translation.php @@ -2,8 +2,9 @@ namespace Lexik\Bundle\TranslationBundle\Document; -use Lexik\Bundle\TranslationBundle\Model\Translation as TranslationModel; +use Lexik\Bundle\TranslationBundle\Manager\FileInterface; use Lexik\Bundle\TranslationBundle\Manager\TranslationInterface; +use Lexik\Bundle\TranslationBundle\Model\Translation as TranslationModel; /** * @author Cédric Girard @@ -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..5b72be6b 100644 --- a/Entity/TransUnit.php +++ b/Entity/TransUnit.php @@ -2,15 +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 @@ -23,12 +23,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..d272a19d 100644 --- a/Entity/TransUnitRepository.php +++ b/Entity/TransUnitRepository.php @@ -2,11 +2,10 @@ namespace Lexik\Bundle\TranslationBundle\Entity; -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; +use Doctrine\ORM\QueryBuilder; +use Lexik\Bundle\TranslationBundle\Manager\FileInterface; +use Lexik\Bundle\TranslationBundle\Util\Doctrine\SingleColumnArrayHydrator; /** * 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..f6b9f790 100644 --- a/Entity/Translation.php +++ b/Entity/Translation.php @@ -2,14 +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 @@ -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 @@ -73,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 1213559f..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,10 +32,10 @@ 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) { + 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/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/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/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 9f6cfc91..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; @@ -20,14 +20,14 @@ 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( + $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']); } @@ -35,15 +35,15 @@ 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']); + $resolver->setDefaults(['data_class' => null, 'default_domain' => ['messages'], 'domains' => [], 'translation_class' => null, 'translation_domain' => 'LexikTranslationBundle']); } /** * {@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..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; /** @@ -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,15 +37,15 @@ 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']); + $resolver->setDefaults(['data_class' => null, 'translation_domain' => 'LexikTranslationBundle']); } /** * {@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..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. * @@ -12,20 +13,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/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/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..4fa82e83 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. @@ -67,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'); @@ -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(); } @@ -141,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)) { @@ -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..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. @@ -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..cfc00c28 100644 --- a/Model/Translation.php +++ b/Model/Translation.php @@ -2,9 +2,10 @@ 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; /** @@ -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; + #[ORM\Column(name: 'modified_manually', type: Types::BOOLEAN, options: ['default' => 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; } @@ -76,7 +72,6 @@ public function getContent() return $this->content; } - /** * Get createdAt * @@ -97,19 +92,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/Resources/config/services.yaml b/Resources/config/services.yaml index 3219ba58..28f83d47 100644 --- a/Resources/config/services.yaml +++ b/Resources/config/services.yaml @@ -51,38 +51,27 @@ 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' debug: '%kernel.debug%' - resource_files: [] - 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/Storage/AbstractDoctrineStorage.php b/Storage/AbstractDoctrineStorage.php index 73c32ad4..d04ad6c3 100644 --- a/Storage/AbstractDoctrineStorage.php +++ b/Storage/AbstractDoctrineStorage.php @@ -3,11 +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. @@ -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,22 +124,18 @@ 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 { $key = mb_substr($key, 0, 255, 'UTF-8'); $fields = [ - 'key' => $key, + 'key' => $key, 'domain' => $domain, ]; @@ -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/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 038d467b..ab16d135 100644 --- a/Storage/DoctrineORMStorage.php +++ b/Storage/DoctrineORMStorage.php @@ -2,13 +2,8 @@ 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; +use Doctrine\ORM\EntityManager; /** * Doctrine ORM storage class. @@ -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()); - } + try { + $tables = [ + $em->getClassMetadata($this->getModelClass('trans_unit'))->getTableName(), + $em->getClassMetadata($this->getModelClass('translation'))->getTableName(), + ]; - $tmpConnection = DriverManager::getConnection($params, $configuration); - $schemaManager = method_exists($tmpConnection, 'createSchemaManager') - ? $tmpConnection->createSchemaManager() - : $tmpConnection->getSchemaManager(); - - $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 c28adb38..54940eaf 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..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'; /** @@ -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. @@ -122,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 24e46e4c..be0107ef 100644 --- a/Tests/Command/ImportTranslationsCommandTest.php +++ b/Tests/Command/ImportTranslationsCommandTest.php @@ -2,17 +2,15 @@ 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 Lexik\Bundle\TranslationBundle\Manager\LocaleManagerInterface; -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; -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,27 +79,18 @@ 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') - ) - ); - $command = static::$application->find("lexik:translations:import"); $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 0b37f883..9d10ec88 100644 --- a/Tests/Unit/Repository/Document/TransUnitRepositoryTest.php +++ b/Tests/Unit/Repository/Document/TransUnitRepositoryTest.php @@ -93,16 +93,20 @@ 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(1, - $repository->count(['en', 'fr', 'de'], ['_search' => true, 'key' => 'hel', 'domain' => 'uper'])); - $this->assertEquals(2, - $repository->count(['en', 'de'], ['_search' => true, 'key' => 'say', 'domain' => 'ssa'])); + $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(['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 71c2a306..dcd74531 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,29 +58,29 @@ 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); // 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'); } /** @@ -88,29 +88,29 @@ 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); - $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 ); } @@ -154,43 +150,26 @@ 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'); } } 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]; } 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/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/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 @@ 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..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. @@ -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/Translation/Translator.php b/Translation/Translator.php index b6dad880..e99d09b2 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; @@ -189,7 +157,7 @@ public function removeCacheFile($locale) $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) { @@ -197,7 +165,7 @@ public function removeCacheFile($locale) $this->invalidateSystemCacheForFile($path); $deleted = unlink($path); - $metadata = $path.'.meta'; + $metadata = $path . '.meta'; if (file_exists($metadata)) { $this->invalidateSystemCacheForFile($metadata); unlink($metadata); @@ -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); @@ -223,7 +191,7 @@ public function removeLocalesCacheFiles(array $locales) unlink($file); } - $metadata = $file.'.meta'; + $metadata = $file . '.meta'; if (file_exists($metadata)) { $this->invalidateSystemCacheForFile($metadata); unlink($metadata); @@ -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; - } -} 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 95b6ee6b..20487632 100644 --- a/Util/DataGrid/DataGridFormatter.php +++ b/Util/DataGrid/DataGridFormatter.php @@ -3,53 +3,41 @@ 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 */ 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]); + 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,15 +82,18 @@ 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()]; + $data['translations'][] = ['locale' => $translation->getLocale(), 'content' => $translation->getContent()]; } return $data; diff --git a/Util/DataGrid/DataGridRequestHandler.php b/Util/DataGrid/DataGridRequestHandler.php index 05a536fc..db847bc5 100644 --- a/Util/DataGrid/DataGridRequestHandler.php +++ b/Util/DataGrid/DataGridRequestHandler.php @@ -2,9 +2,10 @@ 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; 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); @@ -203,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, ]; } } 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 diff --git a/composer.lock b/composer.lock deleted file mode 100644 index dd91c00d..00000000 --- a/composer.lock +++ /dev/null @@ -1,9238 +0,0 @@ -{ - "_readme": [ - "This file locks the dependencies of your project to a known state", - "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", - "This file is @generated automatically" - ], - "content-hash": "2f22c916da236e6c350a1e7cab9f61bf", - "packages": [ - { - "name": "doctrine/collections", - "version": "2.6.0", - "source": { - "type": "git", - "url": "https://github.com/doctrine/collections.git", - "reference": "7713da39d8e237f28411d6a616a3dce5e20d5de2" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/doctrine/collections/zipball/7713da39d8e237f28411d6a616a3dce5e20d5de2", - "reference": "7713da39d8e237f28411d6a616a3dce5e20d5de2", - "shasum": "" - }, - "require": { - "doctrine/deprecations": "^1", - "php": "^8.1", - "symfony/polyfill-php84": "^1.30" - }, - "require-dev": { - "doctrine/coding-standard": "^14", - "ext-json": "*", - "phpstan/phpstan": "^2.1.30", - "phpstan/phpstan-phpunit": "^2.0.7", - "phpunit/phpunit": "^10.5.58 || ^11.5.42 || ^12.4" - }, - "type": "library", - "autoload": { - "psr-4": { - "Doctrine\\Common\\Collections\\": "src" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Guilherme Blanco", - "email": "guilhermeblanco@gmail.com" - }, - { - "name": "Roman Borschel", - "email": "roman@code-factory.org" - }, - { - "name": "Benjamin Eberlei", - "email": "kontakt@beberlei.de" - }, - { - "name": "Jonathan Wage", - "email": "jonwage@gmail.com" - }, - { - "name": "Johannes Schmitt", - "email": "schmittjoh@gmail.com" - } - ], - "description": "PHP Doctrine Collections library that adds additional functionality on top of PHP arrays.", - "homepage": "https://www.doctrine-project.org/projects/collections.html", - "keywords": [ - "array", - "collections", - "iterators", - "php" - ], - "support": { - "issues": "https://github.com/doctrine/collections/issues", - "source": "https://github.com/doctrine/collections/tree/2.6.0" - }, - "funding": [ - { - "url": "https://www.doctrine-project.org/sponsorship.html", - "type": "custom" - }, - { - "url": "https://www.patreon.com/phpdoctrine", - "type": "patreon" - }, - { - "url": "https://tidelift.com/funding/github/packagist/doctrine%2Fcollections", - "type": "tidelift" - } - ], - "time": "2026-01-15T10:01:58+00:00" - }, - { - "name": "doctrine/dbal", - "version": "4.4.2", - "source": { - "type": "git", - "url": "https://github.com/doctrine/dbal.git", - "reference": "476f7f0fa6ea4aa5364926db7fabdf6049075722" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/doctrine/dbal/zipball/476f7f0fa6ea4aa5364926db7fabdf6049075722", - "reference": "476f7f0fa6ea4aa5364926db7fabdf6049075722", - "shasum": "" - }, - "require": { - "doctrine/deprecations": "^1.1.5", - "php": "^8.2", - "psr/cache": "^1|^2|^3", - "psr/log": "^1|^2|^3" - }, - "require-dev": { - "doctrine/coding-standard": "14.0.0", - "fig/log-test": "^1", - "jetbrains/phpstorm-stubs": "2023.2", - "phpstan/phpstan": "2.1.30", - "phpstan/phpstan-phpunit": "2.0.7", - "phpstan/phpstan-strict-rules": "^2", - "phpunit/phpunit": "11.5.50", - "slevomat/coding-standard": "8.27.1", - "squizlabs/php_codesniffer": "4.0.1", - "symfony/cache": "^6.3.8|^7.0|^8.0", - "symfony/console": "^5.4|^6.3|^7.0|^8.0" - }, - "suggest": { - "symfony/console": "For helpful console commands such as SQL execution and import of files." - }, - "type": "library", - "autoload": { - "psr-4": { - "Doctrine\\DBAL\\": "src" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Guilherme Blanco", - "email": "guilhermeblanco@gmail.com" - }, - { - "name": "Roman Borschel", - "email": "roman@code-factory.org" - }, - { - "name": "Benjamin Eberlei", - "email": "kontakt@beberlei.de" - }, - { - "name": "Jonathan Wage", - "email": "jonwage@gmail.com" - } - ], - "description": "Powerful PHP database abstraction layer (DBAL) with many features for database schema introspection and management.", - "homepage": "https://www.doctrine-project.org/projects/dbal.html", - "keywords": [ - "abstraction", - "database", - "db2", - "dbal", - "mariadb", - "mssql", - "mysql", - "oci8", - "oracle", - "pdo", - "pgsql", - "postgresql", - "queryobject", - "sasql", - "sql", - "sqlite", - "sqlserver", - "sqlsrv" - ], - "support": { - "issues": "https://github.com/doctrine/dbal/issues", - "source": "https://github.com/doctrine/dbal/tree/4.4.2" - }, - "funding": [ - { - "url": "https://www.doctrine-project.org/sponsorship.html", - "type": "custom" - }, - { - "url": "https://www.patreon.com/phpdoctrine", - "type": "patreon" - }, - { - "url": "https://tidelift.com/funding/github/packagist/doctrine%2Fdbal", - "type": "tidelift" - } - ], - "time": "2026-02-26T12:12:19+00:00" - }, - { - "name": "doctrine/deprecations", - "version": "1.1.6", - "source": { - "type": "git", - "url": "https://github.com/doctrine/deprecations.git", - "reference": "d4fe3e6fd9bb9e72557a19674f44d8ac7db4c6ca" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/doctrine/deprecations/zipball/d4fe3e6fd9bb9e72557a19674f44d8ac7db4c6ca", - "reference": "d4fe3e6fd9bb9e72557a19674f44d8ac7db4c6ca", - "shasum": "" - }, - "require": { - "php": "^7.1 || ^8.0" - }, - "conflict": { - "phpunit/phpunit": "<=7.5 || >=14" - }, - "require-dev": { - "doctrine/coding-standard": "^9 || ^12 || ^14", - "phpstan/phpstan": "1.4.10 || 2.1.30", - "phpstan/phpstan-phpunit": "^1.0 || ^2", - "phpunit/phpunit": "^7.5 || ^8.5 || ^9.6 || ^10.5 || ^11.5 || ^12.4 || ^13.0", - "psr/log": "^1 || ^2 || ^3" - }, - "suggest": { - "psr/log": "Allows logging deprecations via PSR-3 logger implementation" - }, - "type": "library", - "autoload": { - "psr-4": { - "Doctrine\\Deprecations\\": "src" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "description": "A small layer on top of trigger_error(E_USER_DEPRECATED) or PSR-3 logging with options to disable all deprecations or selectively for packages.", - "homepage": "https://www.doctrine-project.org/", - "support": { - "issues": "https://github.com/doctrine/deprecations/issues", - "source": "https://github.com/doctrine/deprecations/tree/1.1.6" - }, - "time": "2026-02-07T07:09:04+00:00" - }, - { - "name": "doctrine/doctrine-bundle", - "version": "2.18.2", - "source": { - "type": "git", - "url": "https://github.com/doctrine/DoctrineBundle.git", - "reference": "0ff098b29b8b3c68307c8987dcaed7fd829c6546" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/doctrine/DoctrineBundle/zipball/0ff098b29b8b3c68307c8987dcaed7fd829c6546", - "reference": "0ff098b29b8b3c68307c8987dcaed7fd829c6546", - "shasum": "" - }, - "require": { - "doctrine/dbal": "^3.7.0 || ^4.0", - "doctrine/deprecations": "^1.0", - "doctrine/persistence": "^3.1 || ^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" - }, - "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" - }, - "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", - "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" - }, - "suggest": { - "doctrine/orm": "The Doctrine ORM integration is optional in the bundle.", - "ext-pdo": "*", - "symfony/web-profiler-bundle": "To use the data collector." - }, - "type": "symfony-bundle", - "autoload": { - "psr-4": { - "Doctrine\\Bundle\\DoctrineBundle\\": "src" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Fabien Potencier", - "email": "fabien@symfony.com" - }, - { - "name": "Benjamin Eberlei", - "email": "kontakt@beberlei.de" - }, - { - "name": "Symfony Community", - "homepage": "https://symfony.com/contributors" - }, - { - "name": "Doctrine Project", - "homepage": "https://www.doctrine-project.org/" - } - ], - "description": "Symfony DoctrineBundle", - "homepage": "https://www.doctrine-project.org", - "keywords": [ - "database", - "dbal", - "orm", - "persistence" - ], - "support": { - "issues": "https://github.com/doctrine/DoctrineBundle/issues", - "source": "https://github.com/doctrine/DoctrineBundle/tree/2.18.2" - }, - "funding": [ - { - "url": "https://www.doctrine-project.org/sponsorship.html", - "type": "custom" - }, - { - "url": "https://www.patreon.com/phpdoctrine", - "type": "patreon" - }, - { - "url": "https://tidelift.com/funding/github/packagist/doctrine%2Fdoctrine-bundle", - "type": "tidelift" - } - ], - "time": "2025-12-20T21:35:32+00:00" - }, - { - "name": "doctrine/doctrine-migrations-bundle", - "version": "3.7.0", - "source": { - "type": "git", - "url": "https://github.com/doctrine/DoctrineMigrationsBundle.git", - "reference": "1e380c6dd8ac8488217f39cff6b77e367f1a644b" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/doctrine/DoctrineMigrationsBundle/zipball/1e380c6dd8ac8488217f39cff6b77e367f1a644b", - "reference": "1e380c6dd8ac8488217f39cff6b77e367f1a644b", - "shasum": "" - }, - "require": { - "doctrine/doctrine-bundle": "^2.4 || ^3.0", - "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" - }, - "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" - }, - "type": "symfony-bundle", - "autoload": { - "psr-4": { - "Doctrine\\Bundle\\MigrationsBundle\\": "src" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Fabien Potencier", - "email": "fabien@symfony.com" - }, - { - "name": "Doctrine Project", - "homepage": "https://www.doctrine-project.org" - }, - { - "name": "Symfony Community", - "homepage": "https://symfony.com/contributors" - } - ], - "description": "Symfony DoctrineMigrationsBundle", - "homepage": "https://www.doctrine-project.org", - "keywords": [ - "dbal", - "migrations", - "schema" - ], - "support": { - "issues": "https://github.com/doctrine/DoctrineMigrationsBundle/issues", - "source": "https://github.com/doctrine/DoctrineMigrationsBundle/tree/3.7.0" - }, - "funding": [ - { - "url": "https://www.doctrine-project.org/sponsorship.html", - "type": "custom" - }, - { - "url": "https://www.patreon.com/phpdoctrine", - "type": "patreon" - }, - { - "url": "https://tidelift.com/funding/github/packagist/doctrine%2Fdoctrine-migrations-bundle", - "type": "tidelift" - } - ], - "time": "2025-11-15T19:02:59+00:00" - }, - { - "name": "doctrine/event-manager", - "version": "2.1.1", - "source": { - "type": "git", - "url": "https://github.com/doctrine/event-manager.git", - "reference": "dda33921b198841ca8dbad2eaa5d4d34769d18cf" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/doctrine/event-manager/zipball/dda33921b198841ca8dbad2eaa5d4d34769d18cf", - "reference": "dda33921b198841ca8dbad2eaa5d4d34769d18cf", - "shasum": "" - }, - "require": { - "php": "^8.1" - }, - "conflict": { - "doctrine/common": "<2.9" - }, - "require-dev": { - "doctrine/coding-standard": "^14", - "phpdocumentor/guides-cli": "^1.4", - "phpstan/phpstan": "^2.1.32", - "phpunit/phpunit": "^10.5.58" - }, - "type": "library", - "autoload": { - "psr-4": { - "Doctrine\\Common\\": "src" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Guilherme Blanco", - "email": "guilhermeblanco@gmail.com" - }, - { - "name": "Roman Borschel", - "email": "roman@code-factory.org" - }, - { - "name": "Benjamin Eberlei", - "email": "kontakt@beberlei.de" - }, - { - "name": "Jonathan Wage", - "email": "jonwage@gmail.com" - }, - { - "name": "Johannes Schmitt", - "email": "schmittjoh@gmail.com" - }, - { - "name": "Marco Pivetta", - "email": "ocramius@gmail.com" - } - ], - "description": "The Doctrine Event Manager is a simple PHP event system that was built to be used with the various Doctrine projects.", - "homepage": "https://www.doctrine-project.org/projects/event-manager.html", - "keywords": [ - "event", - "event dispatcher", - "event manager", - "event system", - "events" - ], - "support": { - "issues": "https://github.com/doctrine/event-manager/issues", - "source": "https://github.com/doctrine/event-manager/tree/2.1.1" - }, - "funding": [ - { - "url": "https://www.doctrine-project.org/sponsorship.html", - "type": "custom" - }, - { - "url": "https://www.patreon.com/phpdoctrine", - "type": "patreon" - }, - { - "url": "https://tidelift.com/funding/github/packagist/doctrine%2Fevent-manager", - "type": "tidelift" - } - ], - "time": "2026-01-29T07:11:08+00:00" - }, - { - "name": "doctrine/inflector", - "version": "2.1.0", - "source": { - "type": "git", - "url": "https://github.com/doctrine/inflector.git", - "reference": "6d6c96277ea252fc1304627204c3d5e6e15faa3b" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/doctrine/inflector/zipball/6d6c96277ea252fc1304627204c3d5e6e15faa3b", - "reference": "6d6c96277ea252fc1304627204c3d5e6e15faa3b", - "shasum": "" - }, - "require": { - "php": "^7.2 || ^8.0" - }, - "require-dev": { - "doctrine/coding-standard": "^12.0 || ^13.0", - "phpstan/phpstan": "^1.12 || ^2.0", - "phpstan/phpstan-phpunit": "^1.4 || ^2.0", - "phpstan/phpstan-strict-rules": "^1.6 || ^2.0", - "phpunit/phpunit": "^8.5 || ^12.2" - }, - "type": "library", - "autoload": { - "psr-4": { - "Doctrine\\Inflector\\": "src" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Guilherme Blanco", - "email": "guilhermeblanco@gmail.com" - }, - { - "name": "Roman Borschel", - "email": "roman@code-factory.org" - }, - { - "name": "Benjamin Eberlei", - "email": "kontakt@beberlei.de" - }, - { - "name": "Jonathan Wage", - "email": "jonwage@gmail.com" - }, - { - "name": "Johannes Schmitt", - "email": "schmittjoh@gmail.com" - } - ], - "description": "PHP Doctrine Inflector is a small library that can perform string manipulations with regard to upper/lowercase and singular/plural forms of words.", - "homepage": "https://www.doctrine-project.org/projects/inflector.html", - "keywords": [ - "inflection", - "inflector", - "lowercase", - "manipulation", - "php", - "plural", - "singular", - "strings", - "uppercase", - "words" - ], - "support": { - "issues": "https://github.com/doctrine/inflector/issues", - "source": "https://github.com/doctrine/inflector/tree/2.1.0" - }, - "funding": [ - { - "url": "https://www.doctrine-project.org/sponsorship.html", - "type": "custom" - }, - { - "url": "https://www.patreon.com/phpdoctrine", - "type": "patreon" - }, - { - "url": "https://tidelift.com/funding/github/packagist/doctrine%2Finflector", - "type": "tidelift" - } - ], - "time": "2025-08-10T19:31:58+00:00" - }, - { - "name": "doctrine/instantiator", - "version": "2.0.0", - "source": { - "type": "git", - "url": "https://github.com/doctrine/instantiator.git", - "reference": "c6222283fa3f4ac679f8b9ced9a4e23f163e80d0" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/doctrine/instantiator/zipball/c6222283fa3f4ac679f8b9ced9a4e23f163e80d0", - "reference": "c6222283fa3f4ac679f8b9ced9a4e23f163e80d0", - "shasum": "" - }, - "require": { - "php": "^8.1" - }, - "require-dev": { - "doctrine/coding-standard": "^11", - "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" - }, - "type": "library", - "autoload": { - "psr-4": { - "Doctrine\\Instantiator\\": "src/Doctrine/Instantiator/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Marco Pivetta", - "email": "ocramius@gmail.com", - "homepage": "https://ocramius.github.io/" - } - ], - "description": "A small, lightweight utility to instantiate objects in PHP without invoking their constructors", - "homepage": "https://www.doctrine-project.org/projects/instantiator.html", - "keywords": [ - "constructor", - "instantiate" - ], - "support": { - "issues": "https://github.com/doctrine/instantiator/issues", - "source": "https://github.com/doctrine/instantiator/tree/2.0.0" - }, - "funding": [ - { - "url": "https://www.doctrine-project.org/sponsorship.html", - "type": "custom" - }, - { - "url": "https://www.patreon.com/phpdoctrine", - "type": "patreon" - }, - { - "url": "https://tidelift.com/funding/github/packagist/doctrine%2Finstantiator", - "type": "tidelift" - } - ], - "time": "2022-12-30T00:23:10+00:00" - }, - { - "name": "doctrine/lexer", - "version": "3.0.1", - "source": { - "type": "git", - "url": "https://github.com/doctrine/lexer.git", - "reference": "31ad66abc0fc9e1a1f2d9bc6a42668d2fbbcd6dd" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/doctrine/lexer/zipball/31ad66abc0fc9e1a1f2d9bc6a42668d2fbbcd6dd", - "reference": "31ad66abc0fc9e1a1f2d9bc6a42668d2fbbcd6dd", - "shasum": "" - }, - "require": { - "php": "^8.1" - }, - "require-dev": { - "doctrine/coding-standard": "^12", - "phpstan/phpstan": "^1.10", - "phpunit/phpunit": "^10.5", - "psalm/plugin-phpunit": "^0.18.3", - "vimeo/psalm": "^5.21" - }, - "type": "library", - "autoload": { - "psr-4": { - "Doctrine\\Common\\Lexer\\": "src" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Guilherme Blanco", - "email": "guilhermeblanco@gmail.com" - }, - { - "name": "Roman Borschel", - "email": "roman@code-factory.org" - }, - { - "name": "Johannes Schmitt", - "email": "schmittjoh@gmail.com" - } - ], - "description": "PHP Doctrine Lexer parser library that can be used in Top-Down, Recursive Descent Parsers.", - "homepage": "https://www.doctrine-project.org/projects/lexer.html", - "keywords": [ - "annotations", - "docblock", - "lexer", - "parser", - "php" - ], - "support": { - "issues": "https://github.com/doctrine/lexer/issues", - "source": "https://github.com/doctrine/lexer/tree/3.0.1" - }, - "funding": [ - { - "url": "https://www.doctrine-project.org/sponsorship.html", - "type": "custom" - }, - { - "url": "https://www.patreon.com/phpdoctrine", - "type": "patreon" - }, - { - "url": "https://tidelift.com/funding/github/packagist/doctrine%2Flexer", - "type": "tidelift" - } - ], - "time": "2024-02-05T11:56:58+00:00" - }, - { - "name": "doctrine/migrations", - "version": "3.9.6", - "source": { - "type": "git", - "url": "https://github.com/doctrine/migrations.git", - "reference": "ffd8355cdd8505fc650d9604f058bf62aedd80a1" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/doctrine/migrations/zipball/ffd8355cdd8505fc650d9604f058bf62aedd80a1", - "reference": "ffd8355cdd8505fc650d9604f058bf62aedd80a1", - "shasum": "" - }, - "require": { - "composer-runtime-api": "^2", - "doctrine/dbal": "^3.6 || ^4", - "doctrine/deprecations": "^0.5.3 || ^1", - "doctrine/event-manager": "^1.2 || ^2.0", - "php": "^8.1", - "psr/log": "^1.1.3 || ^2 || ^3", - "symfony/console": "^5.4 || ^6.0 || ^7.0 || ^8.0", - "symfony/stopwatch": "^5.4 || ^6.0 || ^7.0 || ^8.0", - "symfony/var-exporter": "^6.2 || ^7.0 || ^8.0" - }, - "conflict": { - "doctrine/orm": "<2.12 || >=4" - }, - "require-dev": { - "doctrine/coding-standard": "^14", - "doctrine/orm": "^2.13 || ^3", - "doctrine/persistence": "^2 || ^3 || ^4", - "doctrine/sql-formatter": "^1.0", - "ext-pdo_sqlite": "*", - "fig/log-test": "^1", - "phpstan/phpstan": "^2", - "phpstan/phpstan-deprecation-rules": "^2", - "phpstan/phpstan-phpunit": "^2", - "phpstan/phpstan-strict-rules": "^2", - "phpstan/phpstan-symfony": "^2", - "phpunit/phpunit": "^10.3 || ^11.0 || ^12.0", - "symfony/cache": "^5.4 || ^6.0 || ^7.0 || ^8.0", - "symfony/process": "^5.4 || ^6.0 || ^7.0 || ^8.0", - "symfony/yaml": "^5.4 || ^6.0 || ^7.0 || ^8.0" - }, - "suggest": { - "doctrine/sql-formatter": "Allows to generate formatted SQL with the diff command.", - "symfony/yaml": "Allows the use of yaml for migration configuration files." - }, - "bin": [ - "bin/doctrine-migrations" - ], - "type": "library", - "autoload": { - "psr-4": { - "Doctrine\\Migrations\\": "src" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Benjamin Eberlei", - "email": "kontakt@beberlei.de" - }, - { - "name": "Jonathan Wage", - "email": "jonwage@gmail.com" - }, - { - "name": "Michael Simonson", - "email": "contact@mikesimonson.com" - } - ], - "description": "PHP Doctrine Migrations project offer additional functionality on top of the database abstraction layer (DBAL) for versioning your database schema and easily deploying changes to it. It is a very easy to use and a powerful tool.", - "homepage": "https://www.doctrine-project.org/projects/migrations.html", - "keywords": [ - "database", - "dbal", - "migrations" - ], - "support": { - "issues": "https://github.com/doctrine/migrations/issues", - "source": "https://github.com/doctrine/migrations/tree/3.9.6" - }, - "funding": [ - { - "url": "https://www.doctrine-project.org/sponsorship.html", - "type": "custom" - }, - { - "url": "https://www.patreon.com/phpdoctrine", - "type": "patreon" - }, - { - "url": "https://tidelift.com/funding/github/packagist/doctrine%2Fmigrations", - "type": "tidelift" - } - ], - "time": "2026-02-11T06:46:11+00:00" - }, - { - "name": "doctrine/orm", - "version": "3.6.2", - "source": { - "type": "git", - "url": "https://github.com/doctrine/orm.git", - "reference": "4262eb495b4d2a53b45de1ac58881e0091f2970f" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/doctrine/orm/zipball/4262eb495b4d2a53b45de1ac58881e0091f2970f", - "reference": "4262eb495b4d2a53b45de1ac58881e0091f2970f", - "shasum": "" - }, - "require": { - "composer-runtime-api": "^2", - "doctrine/collections": "^2.2", - "doctrine/dbal": "^3.8.2 || ^4", - "doctrine/deprecations": "^0.5.3 || ^1", - "doctrine/event-manager": "^1.2 || ^2", - "doctrine/inflector": "^1.4 || ^2.0", - "doctrine/instantiator": "^1.3 || ^2", - "doctrine/lexer": "^3", - "doctrine/persistence": "^3.3.1 || ^4", - "ext-ctype": "*", - "php": "^8.1", - "psr/cache": "^1 || ^2 || ^3", - "symfony/console": "^5.4 || ^6.0 || ^7.0 || ^8.0", - "symfony/var-exporter": "^6.3.9 || ^7.0 || ^8.0" - }, - "require-dev": { - "doctrine/coding-standard": "^14.0", - "phpbench/phpbench": "^1.0", - "phpstan/extension-installer": "^1.4", - "phpstan/phpstan": "2.1.23", - "phpstan/phpstan-deprecation-rules": "^2", - "phpunit/phpunit": "^10.5.0 || ^11.5", - "psr/log": "^1 || ^2 || ^3", - "symfony/cache": "^5.4 || ^6.2 || ^7.0 || ^8.0" - }, - "suggest": { - "ext-dom": "Provides support for XSD validation for XML mapping files", - "symfony/cache": "Provides cache support for Setup Tool with doctrine/cache 2.0" - }, - "type": "library", - "autoload": { - "psr-4": { - "Doctrine\\ORM\\": "src" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Guilherme Blanco", - "email": "guilhermeblanco@gmail.com" - }, - { - "name": "Roman Borschel", - "email": "roman@code-factory.org" - }, - { - "name": "Benjamin Eberlei", - "email": "kontakt@beberlei.de" - }, - { - "name": "Jonathan Wage", - "email": "jonwage@gmail.com" - }, - { - "name": "Marco Pivetta", - "email": "ocramius@gmail.com" - } - ], - "description": "Object-Relational-Mapper for PHP", - "homepage": "https://www.doctrine-project.org/projects/orm.html", - "keywords": [ - "database", - "orm" - ], - "support": { - "issues": "https://github.com/doctrine/orm/issues", - "source": "https://github.com/doctrine/orm/tree/3.6.2" - }, - "time": "2026-01-30T21:41:41+00:00" - }, - { - "name": "doctrine/persistence", - "version": "4.1.1", - "source": { - "type": "git", - "url": "https://github.com/doctrine/persistence.git", - "reference": "b9c49ad3558bb77ef973f4e173f2e9c2eca9be09" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/doctrine/persistence/zipball/b9c49ad3558bb77ef973f4e173f2e9c2eca9be09", - "reference": "b9c49ad3558bb77ef973f4e173f2e9c2eca9be09", - "shasum": "" - }, - "require": { - "doctrine/event-manager": "^1 || ^2", - "php": "^8.1", - "psr/cache": "^1.0 || ^2.0 || ^3.0" - }, - "require-dev": { - "doctrine/coding-standard": "^14", - "phpstan/phpstan": "2.1.30", - "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" - }, - "type": "library", - "autoload": { - "psr-4": { - "Doctrine\\Persistence\\": "src/Persistence" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Guilherme Blanco", - "email": "guilhermeblanco@gmail.com" - }, - { - "name": "Roman Borschel", - "email": "roman@code-factory.org" - }, - { - "name": "Benjamin Eberlei", - "email": "kontakt@beberlei.de" - }, - { - "name": "Jonathan Wage", - "email": "jonwage@gmail.com" - }, - { - "name": "Johannes Schmitt", - "email": "schmittjoh@gmail.com" - }, - { - "name": "Marco Pivetta", - "email": "ocramius@gmail.com" - } - ], - "description": "The Doctrine Persistence project is a set of shared interfaces and functionality that the different Doctrine object mappers share.", - "homepage": "https://www.doctrine-project.org/projects/persistence.html", - "keywords": [ - "mapper", - "object", - "odm", - "orm", - "persistence" - ], - "support": { - "issues": "https://github.com/doctrine/persistence/issues", - "source": "https://github.com/doctrine/persistence/tree/4.1.1" - }, - "funding": [ - { - "url": "https://www.doctrine-project.org/sponsorship.html", - "type": "custom" - }, - { - "url": "https://www.patreon.com/phpdoctrine", - "type": "patreon" - }, - { - "url": "https://tidelift.com/funding/github/packagist/doctrine%2Fpersistence", - "type": "tidelift" - } - ], - "time": "2025-10-16T20:13:18+00:00" - }, - { - "name": "doctrine/sql-formatter", - "version": "1.5.4", - "source": { - "type": "git", - "url": "https://github.com/doctrine/sql-formatter.git", - "reference": "9563949f5cd3bd12a17d12fb980528bc141c5806" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/doctrine/sql-formatter/zipball/9563949f5cd3bd12a17d12fb980528bc141c5806", - "reference": "9563949f5cd3bd12a17d12fb980528bc141c5806", - "shasum": "" - }, - "require": { - "php": "^8.1" - }, - "require-dev": { - "doctrine/coding-standard": "^14", - "ergebnis/phpunit-slow-test-detector": "^2.20", - "phpstan/phpstan": "^2.1.31", - "phpunit/phpunit": "^10.5.58" - }, - "bin": [ - "bin/sql-formatter" - ], - "type": "library", - "autoload": { - "psr-4": { - "Doctrine\\SqlFormatter\\": "src" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Jeremy Dorn", - "email": "jeremy@jeremydorn.com", - "homepage": "https://jeremydorn.com/" - } - ], - "description": "a PHP SQL highlighting library", - "homepage": "https://github.com/doctrine/sql-formatter/", - "keywords": [ - "highlight", - "sql" - ], - "support": { - "issues": "https://github.com/doctrine/sql-formatter/issues", - "source": "https://github.com/doctrine/sql-formatter/tree/1.5.4" - }, - "time": "2026-02-08T16:21:46+00:00" - }, - { - "name": "monolog/monolog", - "version": "3.10.0", - "source": { - "type": "git", - "url": "https://github.com/Seldaek/monolog.git", - "reference": "b321dd6749f0bf7189444158a3ce785cc16d69b0" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/Seldaek/monolog/zipball/b321dd6749f0bf7189444158a3ce785cc16d69b0", - "reference": "b321dd6749f0bf7189444158a3ce785cc16d69b0", - "shasum": "" - }, - "require": { - "php": ">=8.1", - "psr/log": "^2.0 || ^3.0" - }, - "provide": { - "psr/log-implementation": "3.0.0" - }, - "require-dev": { - "aws/aws-sdk-php": "^3.0", - "doctrine/couchdb": "~1.0@dev", - "elasticsearch/elasticsearch": "^7 || ^8", - "ext-json": "*", - "graylog2/gelf-php": "^1.4.2 || ^2.0", - "guzzlehttp/guzzle": "^7.4.5", - "guzzlehttp/psr7": "^2.2", - "mongodb/mongodb": "^1.8 || ^2.0", - "php-amqplib/php-amqplib": "~2.4 || ^3", - "php-console/php-console": "^3.1.8", - "phpstan/phpstan": "^2", - "phpstan/phpstan-deprecation-rules": "^2", - "phpstan/phpstan-strict-rules": "^2", - "phpunit/phpunit": "^10.5.17 || ^11.0.7", - "predis/predis": "^1.1 || ^2", - "rollbar/rollbar": "^4.0", - "ruflin/elastica": "^7 || ^8", - "symfony/mailer": "^5.4 || ^6", - "symfony/mime": "^5.4 || ^6" - }, - "suggest": { - "aws/aws-sdk-php": "Allow sending log messages to AWS services like DynamoDB", - "doctrine/couchdb": "Allow sending log messages to a CouchDB server", - "elasticsearch/elasticsearch": "Allow sending log messages to an Elasticsearch server via official client", - "ext-amqp": "Allow sending log messages to an AMQP server (1.0+ required)", - "ext-curl": "Required to send log messages using the IFTTTHandler, the LogglyHandler, the SendGridHandler, the SlackWebhookHandler or the TelegramBotHandler", - "ext-mbstring": "Allow to work properly with unicode symbols", - "ext-mongodb": "Allow sending log messages to a MongoDB server (via driver)", - "ext-openssl": "Required to send log messages using SSL", - "ext-sockets": "Allow sending log messages to a Syslog server (via UDP driver)", - "graylog2/gelf-php": "Allow sending log messages to a GrayLog2 server", - "mongodb/mongodb": "Allow sending log messages to a MongoDB server (via library)", - "php-amqplib/php-amqplib": "Allow sending log messages to an AMQP server using php-amqplib", - "rollbar/rollbar": "Allow sending log messages to Rollbar", - "ruflin/elastica": "Allow sending log messages to an Elastic Search server" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-main": "3.x-dev" - } - }, - "autoload": { - "psr-4": { - "Monolog\\": "src/Monolog" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Jordi Boggiano", - "email": "j.boggiano@seld.be", - "homepage": "https://seld.be" - } - ], - "description": "Sends your logs to files, sockets, inboxes, databases and various web services", - "homepage": "https://github.com/Seldaek/monolog", - "keywords": [ - "log", - "logging", - "psr-3" - ], - "support": { - "issues": "https://github.com/Seldaek/monolog/issues", - "source": "https://github.com/Seldaek/monolog/tree/3.10.0" - }, - "funding": [ - { - "url": "https://github.com/Seldaek", - "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/monolog/monolog", - "type": "tidelift" - } - ], - "time": "2026-01-02T08:56:05+00:00" - }, - { - "name": "psr/cache", - "version": "3.0.0", - "source": { - "type": "git", - "url": "https://github.com/php-fig/cache.git", - "reference": "aa5030cfa5405eccfdcb1083ce040c2cb8d253bf" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/php-fig/cache/zipball/aa5030cfa5405eccfdcb1083ce040c2cb8d253bf", - "reference": "aa5030cfa5405eccfdcb1083ce040c2cb8d253bf", - "shasum": "" - }, - "require": { - "php": ">=8.0.0" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.0.x-dev" - } - }, - "autoload": { - "psr-4": { - "Psr\\Cache\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "PHP-FIG", - "homepage": "https://www.php-fig.org/" - } - ], - "description": "Common interface for caching libraries", - "keywords": [ - "cache", - "psr", - "psr-6" - ], - "support": { - "source": "https://github.com/php-fig/cache/tree/3.0.0" - }, - "time": "2021-02-03T23:26:27+00:00" - }, - { - "name": "psr/container", - "version": "2.0.2", - "source": { - "type": "git", - "url": "https://github.com/php-fig/container.git", - "reference": "c71ecc56dfe541dbd90c5360474fbc405f8d5963" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/php-fig/container/zipball/c71ecc56dfe541dbd90c5360474fbc405f8d5963", - "reference": "c71ecc56dfe541dbd90c5360474fbc405f8d5963", - "shasum": "" - }, - "require": { - "php": ">=7.4.0" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "2.0.x-dev" - } - }, - "autoload": { - "psr-4": { - "Psr\\Container\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "PHP-FIG", - "homepage": "https://www.php-fig.org/" - } - ], - "description": "Common Container Interface (PHP FIG PSR-11)", - "homepage": "https://github.com/php-fig/container", - "keywords": [ - "PSR-11", - "container", - "container-interface", - "container-interop", - "psr" - ], - "support": { - "issues": "https://github.com/php-fig/container/issues", - "source": "https://github.com/php-fig/container/tree/2.0.2" - }, - "time": "2021-11-05T16:47:00+00:00" - }, - { - "name": "psr/event-dispatcher", - "version": "1.0.0", - "source": { - "type": "git", - "url": "https://github.com/php-fig/event-dispatcher.git", - "reference": "dbefd12671e8a14ec7f180cab83036ed26714bb0" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/php-fig/event-dispatcher/zipball/dbefd12671e8a14ec7f180cab83036ed26714bb0", - "reference": "dbefd12671e8a14ec7f180cab83036ed26714bb0", - "shasum": "" - }, - "require": { - "php": ">=7.2.0" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.0.x-dev" - } - }, - "autoload": { - "psr-4": { - "Psr\\EventDispatcher\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "PHP-FIG", - "homepage": "http://www.php-fig.org/" - } - ], - "description": "Standard interfaces for event handling.", - "keywords": [ - "events", - "psr", - "psr-14" - ], - "support": { - "issues": "https://github.com/php-fig/event-dispatcher/issues", - "source": "https://github.com/php-fig/event-dispatcher/tree/1.0.0" - }, - "time": "2019-01-08T18:20:26+00:00" - }, - { - "name": "psr/log", - "version": "3.0.2", - "source": { - "type": "git", - "url": "https://github.com/php-fig/log.git", - "reference": "f16e1d5863e37f8d8c2a01719f5b34baa2b714d3" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/php-fig/log/zipball/f16e1d5863e37f8d8c2a01719f5b34baa2b714d3", - "reference": "f16e1d5863e37f8d8c2a01719f5b34baa2b714d3", - "shasum": "" - }, - "require": { - "php": ">=8.0.0" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "3.x-dev" - } - }, - "autoload": { - "psr-4": { - "Psr\\Log\\": "src" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "PHP-FIG", - "homepage": "https://www.php-fig.org/" - } - ], - "description": "Common interface for logging libraries", - "homepage": "https://github.com/php-fig/log", - "keywords": [ - "log", - "psr", - "psr-3" - ], - "support": { - "source": "https://github.com/php-fig/log/tree/3.0.2" - }, - "time": "2024-09-11T13:17:53+00:00" - }, - { - "name": "symfony/asset", - "version": "v7.4.6", - "source": { - "type": "git", - "url": "https://github.com/symfony/asset.git", - "reference": "d944ae87e4697af05aadeacfc5e603c3c18ef4fb" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/asset/zipball/d944ae87e4697af05aadeacfc5e603c3c18ef4fb", - "reference": "d944ae87e4697af05aadeacfc5e603c3c18ef4fb", - "shasum": "" - }, - "require": { - "php": ">=8.2" - }, - "conflict": { - "symfony/http-foundation": "<6.4" - }, - "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" - }, - "type": "library", - "autoload": { - "psr-4": { - "Symfony\\Component\\Asset\\": "" - }, - "exclude-from-classmap": [ - "/Tests/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Fabien Potencier", - "email": "fabien@symfony.com" - }, - { - "name": "Symfony Community", - "homepage": "https://symfony.com/contributors" - } - ], - "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" - }, - "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-02-09T09:33:46+00:00" - }, - { - "name": "symfony/cache", - "version": "v7.4.7", - "source": { - "type": "git", - "url": "https://github.com/symfony/cache.git", - "reference": "665522ec357540e66c294c08583b40ee576574f0" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/cache/zipball/665522ec357540e66c294c08583b40ee576574f0", - "reference": "665522ec357540e66c294c08583b40ee576574f0", - "shasum": "" - }, - "require": { - "php": ">=8.2", - "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" - }, - "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" - }, - "provide": { - "psr/cache-implementation": "2.0|3.0", - "psr/simple-cache-implementation": "1.0|2.0|3.0", - "symfony/cache-implementation": "1.1|2.0|3.0" - }, - "require-dev": { - "cache/integration-tests": "dev-master", - "doctrine/dbal": "^3.6|^4", - "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" - }, - "type": "library", - "autoload": { - "psr-4": { - "Symfony\\Component\\Cache\\": "" - }, - "classmap": [ - "Traits/ValueWrapper.php" - ], - "exclude-from-classmap": [ - "/Tests/" - ] - }, - "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": "Provides extended PSR-6, PSR-16 (and tags) implementations", - "homepage": "https://symfony.com", - "keywords": [ - "caching", - "psr6" - ], - "support": { - "source": "https://github.com/symfony/cache/tree/v7.4.7" - }, - "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-03-06T08:14:57+00:00" - }, - { - "name": "symfony/cache-contracts", - "version": "v3.6.0", - "source": { - "type": "git", - "url": "https://github.com/symfony/cache-contracts.git", - "reference": "5d68a57d66910405e5c0b63d6f0af941e66fc868" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/cache-contracts/zipball/5d68a57d66910405e5c0b63d6f0af941e66fc868", - "reference": "5d68a57d66910405e5c0b63d6f0af941e66fc868", - "shasum": "" - }, - "require": { - "php": ">=8.1", - "psr/cache": "^3.0" - }, - "type": "library", - "extra": { - "thanks": { - "url": "https://github.com/symfony/contracts", - "name": "symfony/contracts" - }, - "branch-alias": { - "dev-main": "3.6-dev" - } - }, - "autoload": { - "psr-4": { - "Symfony\\Contracts\\Cache\\": "" - } - }, - "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": "Generic abstractions related to caching", - "homepage": "https://symfony.com", - "keywords": [ - "abstractions", - "contracts", - "decoupling", - "interfaces", - "interoperability", - "standards" - ], - "support": { - "source": "https://github.com/symfony/cache-contracts/tree/v3.6.0" - }, - "funding": [ - { - "url": "https://symfony.com/sponsor", - "type": "custom" - }, - { - "url": "https://github.com/fabpot", - "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", - "type": "tidelift" - } - ], - "time": "2025-03-13T15:25:07+00:00" - }, - { - "name": "symfony/config", - "version": "v7.4.7", - "source": { - "type": "git", - "url": "https://github.com/symfony/config.git", - "reference": "6c17162555bfb58957a55bb0e43e00035b6ae3d5" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/config/zipball/6c17162555bfb58957a55bb0e43e00035b6ae3d5", - "reference": "6c17162555bfb58957a55bb0e43e00035b6ae3d5", - "shasum": "" - }, - "require": { - "php": ">=8.2", - "symfony/deprecation-contracts": "^2.5|^3", - "symfony/filesystem": "^7.1|^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/service-contracts": "^2.5|^3", - "symfony/yaml": "^6.4|^7.0|^8.0" - }, - "type": "library", - "autoload": { - "psr-4": { - "Symfony\\Component\\Config\\": "" - }, - "exclude-from-classmap": [ - "/Tests/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Fabien Potencier", - "email": "fabien@symfony.com" - }, - { - "name": "Symfony Community", - "homepage": "https://symfony.com/contributors" - } - ], - "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" - }, - "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-03-06T10:41:14+00:00" - }, - { - "name": "symfony/console", - "version": "v7.4.7", - "source": { - "type": "git", - "url": "https://github.com/symfony/console.git", - "reference": "e1e6770440fb9c9b0cf725f81d1361ad1835329d" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/console/zipball/e1e6770440fb9c9b0cf725f81d1361ad1835329d", - "reference": "e1e6770440fb9c9b0cf725f81d1361ad1835329d", - "shasum": "" - }, - "require": { - "php": ">=8.2", - "symfony/deprecation-contracts": "^2.5|^3", - "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" - }, - "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" - }, - "type": "library", - "autoload": { - "psr-4": { - "Symfony\\Component\\Console\\": "" - }, - "exclude-from-classmap": [ - "/Tests/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Fabien Potencier", - "email": "fabien@symfony.com" - }, - { - "name": "Symfony Community", - "homepage": "https://symfony.com/contributors" - } - ], - "description": "Eases the creation of beautiful and testable command line interfaces", - "homepage": "https://symfony.com", - "keywords": [ - "cli", - "command-line", - "console", - "terminal" - ], - "support": { - "source": "https://github.com/symfony/console/tree/v7.4.7" - }, - "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-03-06T14:06:20+00:00" - }, - { - "name": "symfony/dependency-injection", - "version": "v7.4.7", - "source": { - "type": "git", - "url": "https://github.com/symfony/dependency-injection.git", - "reference": "0f651e58f4917fb0e2cd261ccbfe3d71e6e0f5db" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/dependency-injection/zipball/0f651e58f4917fb0e2cd261ccbfe3d71e6e0f5db", - "reference": "0f651e58f4917fb0e2cd261ccbfe3d71e6e0f5db", - "shasum": "" - }, - "require": { - "php": ">=8.2", - "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" - }, - "conflict": { - "ext-psr": "<1.1|>=2", - "symfony/config": "<6.4", - "symfony/finder": "<6.4", - "symfony/yaml": "<6.4" - }, - "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" - }, - "type": "library", - "autoload": { - "psr-4": { - "Symfony\\Component\\DependencyInjection\\": "" - }, - "exclude-from-classmap": [ - "/Tests/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Fabien Potencier", - "email": "fabien@symfony.com" - }, - { - "name": "Symfony Community", - "homepage": "https://symfony.com/contributors" - } - ], - "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" - }, - "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-03-03T07:48:48+00:00" - }, - { - "name": "symfony/deprecation-contracts", - "version": "v3.6.0", - "source": { - "type": "git", - "url": "https://github.com/symfony/deprecation-contracts.git", - "reference": "63afe740e99a13ba87ec199bb07bbdee937a5b62" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/63afe740e99a13ba87ec199bb07bbdee937a5b62", - "reference": "63afe740e99a13ba87ec199bb07bbdee937a5b62", - "shasum": "" - }, - "require": { - "php": ">=8.1" - }, - "type": "library", - "extra": { - "thanks": { - "url": "https://github.com/symfony/contracts", - "name": "symfony/contracts" - }, - "branch-alias": { - "dev-main": "3.6-dev" - } - }, - "autoload": { - "files": [ - "function.php" - ] - }, - "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": "A generic function and convention to trigger deprecation notices", - "homepage": "https://symfony.com", - "support": { - "source": "https://github.com/symfony/deprecation-contracts/tree/v3.6.0" - }, - "funding": [ - { - "url": "https://symfony.com/sponsor", - "type": "custom" - }, - { - "url": "https://github.com/fabpot", - "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", - "type": "tidelift" - } - ], - "time": "2024-09-25T14:21:43+00:00" - }, - { - "name": "symfony/doctrine-bridge", - "version": "v7.4.7", - "source": { - "type": "git", - "url": "https://github.com/symfony/doctrine-bridge.git", - "reference": "4fc5e2dd41be3c0b6321e0373072782edeff45ed" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/doctrine-bridge/zipball/4fc5e2dd41be3c0b6321e0373072782edeff45ed", - "reference": "4fc5e2dd41be3c0b6321e0373072782edeff45ed", - "shasum": "" - }, - "require": { - "doctrine/event-manager": "^2", - "doctrine/persistence": "^3.1|^4", - "php": ">=8.2", - "symfony/deprecation-contracts": "^2.5|^3", - "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/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" - }, - "require-dev": { - "doctrine/collections": "^1.8|^2.0", - "doctrine/data-fixtures": "^1.1|^2", - "doctrine/dbal": "^3.6|^4", - "doctrine/orm": "^2.15|^3", - "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/validator": "^7.4|^8.0", - "symfony/var-dumper": "^6.4|^7.0|^8.0" - }, - "type": "symfony-bridge", - "autoload": { - "psr-4": { - "Symfony\\Bridge\\Doctrine\\": "" - }, - "exclude-from-classmap": [ - "/Tests/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Fabien Potencier", - "email": "fabien@symfony.com" - }, - { - "name": "Symfony Community", - "homepage": "https://symfony.com/contributors" - } - ], - "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" - }, - "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-03-05T08:16:50+00:00" - }, - { - "name": "symfony/error-handler", - "version": "v7.4.4", - "source": { - "type": "git", - "url": "https://github.com/symfony/error-handler.git", - "reference": "8da531f364ddfee53e36092a7eebbbd0b775f6b8" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/error-handler/zipball/8da531f364ddfee53e36092a7eebbbd0b775f6b8", - "reference": "8da531f364ddfee53e36092a7eebbbd0b775f6b8", - "shasum": "" - }, - "require": { - "php": ">=8.2", - "psr/log": "^1|^2|^3", - "symfony/polyfill-php85": "^1.32", - "symfony/var-dumper": "^6.4|^7.0|^8.0" - }, - "conflict": { - "symfony/deprecation-contracts": "<2.5", - "symfony/http-kernel": "<6.4" - }, - "require-dev": { - "symfony/console": "^6.4|^7.0|^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/webpack-encore-bundle": "^1.0|^2.0" - }, - "bin": [ - "Resources/bin/patch-type-declarations" - ], - "type": "library", - "autoload": { - "psr-4": { - "Symfony\\Component\\ErrorHandler\\": "" - }, - "exclude-from-classmap": [ - "/Tests/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Fabien Potencier", - "email": "fabien@symfony.com" - }, - { - "name": "Symfony Community", - "homepage": "https://symfony.com/contributors" - } - ], - "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.4" - }, - "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-01-20T16:42:42+00:00" - }, - { - "name": "symfony/event-dispatcher", - "version": "v7.4.4", - "source": { - "type": "git", - "url": "https://github.com/symfony/event-dispatcher.git", - "reference": "dc2c0eba1af673e736bb851d747d266108aea746" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/dc2c0eba1af673e736bb851d747d266108aea746", - "reference": "dc2c0eba1af673e736bb851d747d266108aea746", - "shasum": "" - }, - "require": { - "php": ">=8.2", - "symfony/event-dispatcher-contracts": "^2.5|^3" - }, - "conflict": { - "symfony/dependency-injection": "<6.4", - "symfony/service-contracts": "<2.5" - }, - "provide": { - "psr/event-dispatcher-implementation": "1.0", - "symfony/event-dispatcher-implementation": "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/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/service-contracts": "^2.5|^3", - "symfony/stopwatch": "^6.4|^7.0|^8.0" - }, - "type": "library", - "autoload": { - "psr-4": { - "Symfony\\Component\\EventDispatcher\\": "" - }, - "exclude-from-classmap": [ - "/Tests/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Fabien Potencier", - "email": "fabien@symfony.com" - }, - { - "name": "Symfony Community", - "homepage": "https://symfony.com/contributors" - } - ], - "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.4" - }, - "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-01-05T11:45:34+00:00" - }, - { - "name": "symfony/event-dispatcher-contracts", - "version": "v3.6.0", - "source": { - "type": "git", - "url": "https://github.com/symfony/event-dispatcher-contracts.git", - "reference": "59eb412e93815df44f05f342958efa9f46b1e586" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/event-dispatcher-contracts/zipball/59eb412e93815df44f05f342958efa9f46b1e586", - "reference": "59eb412e93815df44f05f342958efa9f46b1e586", - "shasum": "" - }, - "require": { - "php": ">=8.1", - "psr/event-dispatcher": "^1" - }, - "type": "library", - "extra": { - "thanks": { - "url": "https://github.com/symfony/contracts", - "name": "symfony/contracts" - }, - "branch-alias": { - "dev-main": "3.6-dev" - } - }, - "autoload": { - "psr-4": { - "Symfony\\Contracts\\EventDispatcher\\": "" - } - }, - "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": "Generic abstractions related to dispatching event", - "homepage": "https://symfony.com", - "keywords": [ - "abstractions", - "contracts", - "decoupling", - "interfaces", - "interoperability", - "standards" - ], - "support": { - "source": "https://github.com/symfony/event-dispatcher-contracts/tree/v3.6.0" - }, - "funding": [ - { - "url": "https://symfony.com/sponsor", - "type": "custom" - }, - { - "url": "https://github.com/fabpot", - "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", - "type": "tidelift" - } - ], - "time": "2024-09-25T14:21:43+00:00" - }, - { - "name": "symfony/filesystem", - "version": "v7.4.6", - "source": { - "type": "git", - "url": "https://github.com/symfony/filesystem.git", - "reference": "3ebc794fa5315e59fd122561623c2e2e4280538e" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/filesystem/zipball/3ebc794fa5315e59fd122561623c2e2e4280538e", - "reference": "3ebc794fa5315e59fd122561623c2e2e4280538e", - "shasum": "" - }, - "require": { - "php": ">=8.2", - "symfony/polyfill-ctype": "~1.8", - "symfony/polyfill-mbstring": "~1.8" - }, - "require-dev": { - "symfony/process": "^6.4|^7.0|^8.0" - }, - "type": "library", - "autoload": { - "psr-4": { - "Symfony\\Component\\Filesystem\\": "" - }, - "exclude-from-classmap": [ - "/Tests/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Fabien Potencier", - "email": "fabien@symfony.com" - }, - { - "name": "Symfony Community", - "homepage": "https://symfony.com/contributors" - } - ], - "description": "Provides basic utilities for the filesystem", - "homepage": "https://symfony.com", - "support": { - "source": "https://github.com/symfony/filesystem/tree/v7.4.6" - }, - "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-02-25T16:50:00+00:00" - }, - { - "name": "symfony/finder", - "version": "v7.4.6", - "source": { - "type": "git", - "url": "https://github.com/symfony/finder.git", - "reference": "8655bf1076b7a3a346cb11413ffdabff50c7ffcf" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/finder/zipball/8655bf1076b7a3a346cb11413ffdabff50c7ffcf", - "reference": "8655bf1076b7a3a346cb11413ffdabff50c7ffcf", - "shasum": "" - }, - "require": { - "php": ">=8.2" - }, - "require-dev": { - "symfony/filesystem": "^6.4|^7.0|^8.0" - }, - "type": "library", - "autoload": { - "psr-4": { - "Symfony\\Component\\Finder\\": "" - }, - "exclude-from-classmap": [ - "/Tests/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Fabien Potencier", - "email": "fabien@symfony.com" - }, - { - "name": "Symfony Community", - "homepage": "https://symfony.com/contributors" - } - ], - "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" - }, - "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-01-29T09:40:50+00:00" - }, - { - "name": "symfony/form", - "version": "v7.4.7", - "source": { - "type": "git", - "url": "https://github.com/symfony/form.git", - "reference": "5f24175103fd0a62b98442207c240688210fd88b" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/form/zipball/5f24175103fd0a62b98442207c240688210fd88b", - "reference": "5f24175103fd0a62b98442207c240688210fd88b", - "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", - "symfony/polyfill-intl-icu": "^1.21", - "symfony/polyfill-mbstring": "~1.0", - "symfony/property-access": "^6.4|^7.0|^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" - }, - "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/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" - }, - "type": "library", - "autoload": { - "psr-4": { - "Symfony\\Component\\Form\\": "" - }, - "exclude-from-classmap": [ - "/Tests/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Fabien Potencier", - "email": "fabien@symfony.com" - }, - { - "name": "Symfony Community", - "homepage": "https://symfony.com/contributors" - } - ], - "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" - }, - "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-03-05T12:30:09+00:00" - }, - { - "name": "symfony/framework-bundle", - "version": "v7.4.7", - "source": { - "type": "git", - "url": "https://github.com/symfony/framework-bundle.git", - "reference": "c94bc78c85d76af67918404a95d44940f66a7c2f" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/framework-bundle/zipball/c94bc78c85d76af67918404a95d44940f66a7c2f", - "reference": "c94bc78c85d76af67918404a95d44940f66a7c2f", - "shasum": "" - }, - "require": { - "composer-runtime-api": ">=2.1", - "ext-xml": "*", - "php": ">=8.2", - "symfony/cache": "^6.4.12|^7.0|^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/http-foundation": "^7.4|^8.0", - "symfony/http-kernel": "^7.4|^8.0", - "symfony/polyfill-mbstring": "~1.0", - "symfony/polyfill-php85": "^1.32", - "symfony/routing": "^7.4|^8.0" - }, - "conflict": { - "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/form": "<7.4", - "symfony/http-client": "<6.4", - "symfony/lock": "<6.4", - "symfony/mailer": "<6.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/workflow": "<7.4" - }, - "require-dev": { - "doctrine/persistence": "^1.3|^2|^3", - "dragonmantank/cron-expression": "^3.1", - "phpdocumentor/reflection-docblock": "^5.2|^6.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/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/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/validator": "^7.4|^8.0", - "symfony/web-link": "^6.4|^7.0|^8.0", - "symfony/webhook": "^7.2|^8.0", - "symfony/workflow": "^7.4|^8.0", - "symfony/yaml": "^7.3|^8.0", - "twig/twig": "^3.12" - }, - "type": "symfony-bundle", - "autoload": { - "psr-4": { - "Symfony\\Bundle\\FrameworkBundle\\": "" - }, - "exclude-from-classmap": [ - "/Tests/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Fabien Potencier", - "email": "fabien@symfony.com" - }, - { - "name": "Symfony Community", - "homepage": "https://symfony.com/contributors" - } - ], - "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" - }, - "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-03-06T15:39:55+00:00" - }, - { - "name": "symfony/http-foundation", - "version": "v7.4.7", - "source": { - "type": "git", - "url": "https://github.com/symfony/http-foundation.git", - "reference": "f94b3e7b7dafd40e666f0c9ff2084133bae41e81" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/http-foundation/zipball/f94b3e7b7dafd40e666f0c9ff2084133bae41e81", - "reference": "f94b3e7b7dafd40e666f0c9ff2084133bae41e81", - "shasum": "" - }, - "require": { - "php": ">=8.2", - "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" - }, - "require-dev": { - "doctrine/dbal": "^3.6|^4", - "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" - }, - "type": "library", - "autoload": { - "psr-4": { - "Symfony\\Component\\HttpFoundation\\": "" - }, - "exclude-from-classmap": [ - "/Tests/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Fabien Potencier", - "email": "fabien@symfony.com" - }, - { - "name": "Symfony Community", - "homepage": "https://symfony.com/contributors" - } - ], - "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.7" - }, - "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-03-06T13:15:18+00:00" - }, - { - "name": "symfony/http-kernel", - "version": "v7.4.7", - "source": { - "type": "git", - "url": "https://github.com/symfony/http-kernel.git", - "reference": "3b3fcf386c809be990c922e10e4c620d6367cab1" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/http-kernel/zipball/3b3fcf386c809be990c922e10e4c620d6367cab1", - "reference": "3b3fcf386c809be990c922e10e4c620d6367cab1", - "shasum": "" - }, - "require": { - "php": ">=8.2", - "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/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" - }, - "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/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/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" - }, - "type": "library", - "autoload": { - "psr-4": { - "Symfony\\Component\\HttpKernel\\": "" - }, - "exclude-from-classmap": [ - "/Tests/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Fabien Potencier", - "email": "fabien@symfony.com" - }, - { - "name": "Symfony Community", - "homepage": "https://symfony.com/contributors" - } - ], - "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.7" - }, - "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-03-06T16:33:18+00:00" - }, - { - "name": "symfony/options-resolver", - "version": "v7.4.0", - "source": { - "type": "git", - "url": "https://github.com/symfony/options-resolver.git", - "reference": "b38026df55197f9e39a44f3215788edf83187b80" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/options-resolver/zipball/b38026df55197f9e39a44f3215788edf83187b80", - "reference": "b38026df55197f9e39a44f3215788edf83187b80", - "shasum": "" - }, - "require": { - "php": ">=8.2", - "symfony/deprecation-contracts": "^2.5|^3" - }, - "type": "library", - "autoload": { - "psr-4": { - "Symfony\\Component\\OptionsResolver\\": "" - }, - "exclude-from-classmap": [ - "/Tests/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Fabien Potencier", - "email": "fabien@symfony.com" - }, - { - "name": "Symfony Community", - "homepage": "https://symfony.com/contributors" - } - ], - "description": "Provides an improved replacement for the array_replace PHP function", - "homepage": "https://symfony.com", - "keywords": [ - "config", - "configuration", - "options" - ], - "support": { - "source": "https://github.com/symfony/options-resolver/tree/v7.4.0" - }, - "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": "2025-11-12T15:39:26+00:00" - }, - { - "name": "symfony/orm-pack", - "version": "v2.7.0", - "source": { - "type": "git", - "url": "https://github.com/symfony/orm-pack.git", - "reference": "79a540bbaf8bf386ea112d35694dd4ea3911277e" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/orm-pack/zipball/79a540bbaf8bf386ea112d35694dd4ea3911277e", - "reference": "79a540bbaf8bf386ea112d35694dd4ea3911277e", - "shasum": "" - }, - "require": { - "doctrine/doctrine-bundle": "*", - "doctrine/doctrine-migrations-bundle": "*", - "doctrine/orm": "*" - }, - "conflict": { - "php": "<8.1" - }, - "type": "symfony-pack", - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "description": "A pack for the Doctrine ORM", - "support": { - "issues": "https://github.com/symfony/orm-pack/issues", - "source": "https://github.com/symfony/orm-pack/tree/v2.7.0" - }, - "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-01-07T18:00:45+00:00" - }, - { - "name": "symfony/password-hasher", - "version": "v7.4.6", - "source": { - "type": "git", - "url": "https://github.com/symfony/password-hasher.git", - "reference": "376755eb9c9857d78aedb68341ad2f46d1908b29" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/password-hasher/zipball/376755eb9c9857d78aedb68341ad2f46d1908b29", - "reference": "376755eb9c9857d78aedb68341ad2f46d1908b29", - "shasum": "" - }, - "require": { - "php": ">=8.2" - }, - "conflict": { - "symfony/security-core": "<6.4" - }, - "require-dev": { - "symfony/console": "^6.4|^7.0|^8.0", - "symfony/security-core": "^6.4|^7.0|^8.0" - }, - "type": "library", - "autoload": { - "psr-4": { - "Symfony\\Component\\PasswordHasher\\": "" - }, - "exclude-from-classmap": [ - "/Tests/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Robin Chalas", - "email": "robin.chalas@gmail.com" - }, - { - "name": "Symfony Community", - "homepage": "https://symfony.com/contributors" - } - ], - "description": "Provides password hashing utilities", - "homepage": "https://symfony.com", - "keywords": [ - "hashing", - "password" - ], - "support": { - "source": "https://github.com/symfony/password-hasher/tree/v7.4.6" - }, - "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-02-11T16:03:16+00:00" - }, - { - "name": "symfony/polyfill-ctype", - "version": "v1.33.0", - "source": { - "type": "git", - "url": "https://github.com/symfony/polyfill-ctype.git", - "reference": "a3cc8b044a6ea513310cbd48ef7333b384945638" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/a3cc8b044a6ea513310cbd48ef7333b384945638", - "reference": "a3cc8b044a6ea513310cbd48ef7333b384945638", - "shasum": "" - }, - "require": { - "php": ">=7.2" - }, - "provide": { - "ext-ctype": "*" - }, - "suggest": { - "ext-ctype": "For best performance" - }, - "type": "library", - "extra": { - "thanks": { - "url": "https://github.com/symfony/polyfill", - "name": "symfony/polyfill" - } - }, - "autoload": { - "files": [ - "bootstrap.php" - ], - "psr-4": { - "Symfony\\Polyfill\\Ctype\\": "" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Gert de Pagter", - "email": "BackEndTea@gmail.com" - }, - { - "name": "Symfony Community", - "homepage": "https://symfony.com/contributors" - } - ], - "description": "Symfony polyfill for ctype functions", - "homepage": "https://symfony.com", - "keywords": [ - "compatibility", - "ctype", - "polyfill", - "portable" - ], - "support": { - "source": "https://github.com/symfony/polyfill-ctype/tree/v1.33.0" - }, - "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": "2024-09-09T11:45:10+00:00" - }, - { - "name": "symfony/polyfill-intl-grapheme", - "version": "v1.33.0", - "source": { - "type": "git", - "url": "https://github.com/symfony/polyfill-intl-grapheme.git", - "reference": "380872130d3a5dd3ace2f4010d95125fde5d5c70" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-intl-grapheme/zipball/380872130d3a5dd3ace2f4010d95125fde5d5c70", - "reference": "380872130d3a5dd3ace2f4010d95125fde5d5c70", - "shasum": "" - }, - "require": { - "php": ">=7.2" - }, - "suggest": { - "ext-intl": "For best performance" - }, - "type": "library", - "extra": { - "thanks": { - "url": "https://github.com/symfony/polyfill", - "name": "symfony/polyfill" - } - }, - "autoload": { - "files": [ - "bootstrap.php" - ], - "psr-4": { - "Symfony\\Polyfill\\Intl\\Grapheme\\": "" - } - }, - "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 for intl's grapheme_* functions", - "homepage": "https://symfony.com", - "keywords": [ - "compatibility", - "grapheme", - "intl", - "polyfill", - "portable", - "shim" - ], - "support": { - "source": "https://github.com/symfony/polyfill-intl-grapheme/tree/v1.33.0" - }, - "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": "2025-06-27T09:58:17+00:00" - }, - { - "name": "symfony/polyfill-intl-icu", - "version": "v1.33.0", - "source": { - "type": "git", - "url": "https://github.com/symfony/polyfill-intl-icu.git", - "reference": "bfc8fa13dbaf21d69114b0efcd72ab700fb04d0c" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-intl-icu/zipball/bfc8fa13dbaf21d69114b0efcd72ab700fb04d0c", - "reference": "bfc8fa13dbaf21d69114b0efcd72ab700fb04d0c", - "shasum": "" - }, - "require": { - "php": ">=7.2" - }, - "suggest": { - "ext-intl": "For best performance and support of other locales than \"en\"" - }, - "type": "library", - "extra": { - "thanks": { - "url": "https://github.com/symfony/polyfill", - "name": "symfony/polyfill" - } - }, - "autoload": { - "files": [ - "bootstrap.php" - ], - "psr-4": { - "Symfony\\Polyfill\\Intl\\Icu\\": "" - }, - "classmap": [ - "Resources/stubs" - ], - "exclude-from-classmap": [ - "/Tests/" - ] - }, - "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 for intl's ICU-related data and classes", - "homepage": "https://symfony.com", - "keywords": [ - "compatibility", - "icu", - "intl", - "polyfill", - "portable", - "shim" - ], - "support": { - "source": "https://github.com/symfony/polyfill-intl-icu/tree/v1.33.0" - }, - "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": "2025-06-20T22:24:30+00:00" - }, - { - "name": "symfony/polyfill-intl-normalizer", - "version": "v1.33.0", - "source": { - "type": "git", - "url": "https://github.com/symfony/polyfill-intl-normalizer.git", - "reference": "3833d7255cc303546435cb650316bff708a1c75c" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-intl-normalizer/zipball/3833d7255cc303546435cb650316bff708a1c75c", - "reference": "3833d7255cc303546435cb650316bff708a1c75c", - "shasum": "" - }, - "require": { - "php": ">=7.2" - }, - "suggest": { - "ext-intl": "For best performance" - }, - "type": "library", - "extra": { - "thanks": { - "url": "https://github.com/symfony/polyfill", - "name": "symfony/polyfill" - } - }, - "autoload": { - "files": [ - "bootstrap.php" - ], - "psr-4": { - "Symfony\\Polyfill\\Intl\\Normalizer\\": "" - }, - "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 for intl's Normalizer class and related functions", - "homepage": "https://symfony.com", - "keywords": [ - "compatibility", - "intl", - "normalizer", - "polyfill", - "portable", - "shim" - ], - "support": { - "source": "https://github.com/symfony/polyfill-intl-normalizer/tree/v1.33.0" - }, - "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": "2024-09-09T11:45:10+00:00" - }, - { - "name": "symfony/polyfill-mbstring", - "version": "v1.33.0", - "source": { - "type": "git", - "url": "https://github.com/symfony/polyfill-mbstring.git", - "reference": "6d857f4d76bd4b343eac26d6b539585d2bc56493" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/6d857f4d76bd4b343eac26d6b539585d2bc56493", - "reference": "6d857f4d76bd4b343eac26d6b539585d2bc56493", - "shasum": "" - }, - "require": { - "ext-iconv": "*", - "php": ">=7.2" - }, - "provide": { - "ext-mbstring": "*" - }, - "suggest": { - "ext-mbstring": "For best performance" - }, - "type": "library", - "extra": { - "thanks": { - "url": "https://github.com/symfony/polyfill", - "name": "symfony/polyfill" - } - }, - "autoload": { - "files": [ - "bootstrap.php" - ], - "psr-4": { - "Symfony\\Polyfill\\Mbstring\\": "" - } - }, - "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 for the Mbstring extension", - "homepage": "https://symfony.com", - "keywords": [ - "compatibility", - "mbstring", - "polyfill", - "portable", - "shim" - ], - "support": { - "source": "https://github.com/symfony/polyfill-mbstring/tree/v1.33.0" - }, - "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": "2024-12-23T08:48:59+00:00" - }, - { - "name": "symfony/polyfill-php83", - "version": "v1.33.0", - "source": { - "type": "git", - "url": "https://github.com/symfony/polyfill-php83.git", - "reference": "17f6f9a6b1735c0f163024d959f700cfbc5155e5" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-php83/zipball/17f6f9a6b1735c0f163024d959f700cfbc5155e5", - "reference": "17f6f9a6b1735c0f163024d959f700cfbc5155e5", - "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.33.0" - }, - "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": "2025-07-08T02:45:35+00:00" - }, - { - "name": "symfony/polyfill-php84", - "version": "v1.33.0", - "source": { - "type": "git", - "url": "https://github.com/symfony/polyfill-php84.git", - "reference": "d8ced4d875142b6a7426000426b8abc631d6b191" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-php84/zipball/d8ced4d875142b6a7426000426b8abc631d6b191", - "reference": "d8ced4d875142b6a7426000426b8abc631d6b191", - "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\\Php84\\": "" - }, - "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.4+ features to lower PHP versions", - "homepage": "https://symfony.com", - "keywords": [ - "compatibility", - "polyfill", - "portable", - "shim" - ], - "support": { - "source": "https://github.com/symfony/polyfill-php84/tree/v1.33.0" - }, - "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": "2025-06-24T13:30:11+00:00" - }, - { - "name": "symfony/polyfill-php85", - "version": "v1.33.0", - "source": { - "type": "git", - "url": "https://github.com/symfony/polyfill-php85.git", - "reference": "d4e5fcd4ab3d998ab16c0db48e6cbb9a01993f91" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-php85/zipball/d4e5fcd4ab3d998ab16c0db48e6cbb9a01993f91", - "reference": "d4e5fcd4ab3d998ab16c0db48e6cbb9a01993f91", - "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\\Php85\\": "" - }, - "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.5+ features to lower PHP versions", - "homepage": "https://symfony.com", - "keywords": [ - "compatibility", - "polyfill", - "portable", - "shim" - ], - "support": { - "source": "https://github.com/symfony/polyfill-php85/tree/v1.33.0" - }, - "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": "2025-06-23T16:12:55+00:00" - }, - { - "name": "symfony/property-access", - "version": "v7.4.4", - "source": { - "type": "git", - "url": "https://github.com/symfony/property-access.git", - "reference": "fa49bf1ca8fce1ba0e2dba4e4658554cfb9364b1" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/property-access/zipball/fa49bf1ca8fce1ba0e2dba4e4658554cfb9364b1", - "reference": "fa49bf1ca8fce1ba0e2dba4e4658554cfb9364b1", - "shasum": "" - }, - "require": { - "php": ">=8.2", - "symfony/property-info": "^6.4.32|~7.3.10|^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" - }, - "type": "library", - "autoload": { - "psr-4": { - "Symfony\\Component\\PropertyAccess\\": "" - }, - "exclude-from-classmap": [ - "/Tests/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Fabien Potencier", - "email": "fabien@symfony.com" - }, - { - "name": "Symfony Community", - "homepage": "https://symfony.com/contributors" - } - ], - "description": "Provides functions to read and write from/to an object or array using a simple string notation", - "homepage": "https://symfony.com", - "keywords": [ - "access", - "array", - "extraction", - "index", - "injection", - "object", - "property", - "property-path", - "reflection" - ], - "support": { - "source": "https://github.com/symfony/property-access/tree/v7.4.4" - }, - "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-01-05T08:47:25+00:00" - }, - { - "name": "symfony/property-info", - "version": "v7.4.7", - "source": { - "type": "git", - "url": "https://github.com/symfony/property-info.git", - "reference": "02501d75fd834345da3ecdd8e3200ced39e370f8" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/property-info/zipball/02501d75fd834345da3ecdd8e3200ced39e370f8", - "reference": "02501d75fd834345da3ecdd8e3200ced39e370f8", - "shasum": "" - }, - "require": { - "php": ">=8.2", - "symfony/deprecation-contracts": "^2.5|^3", - "symfony/string": "^6.4|^7.0|^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" - }, - "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" - }, - "type": "library", - "autoload": { - "psr-4": { - "Symfony\\Component\\PropertyInfo\\": "" - }, - "exclude-from-classmap": [ - "/Tests/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Kévin Dunglas", - "email": "dunglas@gmail.com" - }, - { - "name": "Symfony Community", - "homepage": "https://symfony.com/contributors" - } - ], - "description": "Extracts information about PHP class' properties using metadata of popular sources", - "homepage": "https://symfony.com", - "keywords": [ - "doctrine", - "phpdoc", - "property", - "symfony", - "type", - "validator" - ], - "support": { - "source": "https://github.com/symfony/property-info/tree/v7.4.7" - }, - "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-03-04T15:53:26+00:00" - }, - { - "name": "symfony/routing", - "version": "v7.4.6", - "source": { - "type": "git", - "url": "https://github.com/symfony/routing.git", - "reference": "238d749c56b804b31a9bf3e26519d93b65a60938" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/routing/zipball/238d749c56b804b31a9bf3e26519d93b65a60938", - "reference": "238d749c56b804b31a9bf3e26519d93b65a60938", - "shasum": "" - }, - "require": { - "php": ">=8.2", - "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" - }, - "type": "library", - "autoload": { - "psr-4": { - "Symfony\\Component\\Routing\\": "" - }, - "exclude-from-classmap": [ - "/Tests/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Fabien Potencier", - "email": "fabien@symfony.com" - }, - { - "name": "Symfony Community", - "homepage": "https://symfony.com/contributors" - } - ], - "description": "Maps an HTTP request to a set of configuration variables", - "homepage": "https://symfony.com", - "keywords": [ - "router", - "routing", - "uri", - "url" - ], - "support": { - "source": "https://github.com/symfony/routing/tree/v7.4.6" - }, - "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-02-25T16:50:00+00:00" - }, - { - "name": "symfony/security-core", - "version": "v7.4.4", - "source": { - "type": "git", - "url": "https://github.com/symfony/security-core.git", - "reference": "958a70725a8d669bec6721f4cd318d209712e944" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/security-core/zipball/958a70725a8d669bec6721f4cd318d209712e944", - "reference": "958a70725a8d669bec6721f4cd318d209712e944", - "shasum": "" - }, - "require": { - "php": ">=8.2", - "symfony/deprecation-contracts": "^2.5|^3", - "symfony/event-dispatcher-contracts": "^2.5|^3", - "symfony/password-hasher": "^6.4|^7.0|^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" - }, - "type": "library", - "autoload": { - "psr-4": { - "Symfony\\Component\\Security\\Core\\": "" - }, - "exclude-from-classmap": [ - "/Tests/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Fabien Potencier", - "email": "fabien@symfony.com" - }, - { - "name": "Symfony Community", - "homepage": "https://symfony.com/contributors" - } - ], - "description": "Symfony Security Component - Core Library", - "homepage": "https://symfony.com", - "support": { - "source": "https://github.com/symfony/security-core/tree/v7.4.4" - }, - "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-01-14T09:36:49+00:00" - }, - { - "name": "symfony/security-csrf", - "version": "v7.4.6", - "source": { - "type": "git", - "url": "https://github.com/symfony/security-csrf.git", - "reference": "d01adcd3141bec95e4cfd338f6b4482f1dd6a42b" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/security-csrf/zipball/d01adcd3141bec95e4cfd338f6b4482f1dd6a42b", - "reference": "d01adcd3141bec95e4cfd338f6b4482f1dd6a42b", - "shasum": "" - }, - "require": { - "php": ">=8.2", - "symfony/security-core": "^6.4|^7.0|^8.0" - }, - "conflict": { - "symfony/http-foundation": "<6.4" - }, - "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" - }, - "type": "library", - "autoload": { - "psr-4": { - "Symfony\\Component\\Security\\Csrf\\": "" - }, - "exclude-from-classmap": [ - "/Tests/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Fabien Potencier", - "email": "fabien@symfony.com" - }, - { - "name": "Symfony Community", - "homepage": "https://symfony.com/contributors" - } - ], - "description": "Symfony Security Component - CSRF Library", - "homepage": "https://symfony.com", - "support": { - "source": "https://github.com/symfony/security-csrf/tree/v7.4.6" - }, - "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-02-11T16:03:16+00:00" - }, - { - "name": "symfony/service-contracts", - "version": "v3.6.1", - "source": { - "type": "git", - "url": "https://github.com/symfony/service-contracts.git", - "reference": "45112560a3ba2d715666a509a0bc9521d10b6c43" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/service-contracts/zipball/45112560a3ba2d715666a509a0bc9521d10b6c43", - "reference": "45112560a3ba2d715666a509a0bc9521d10b6c43", - "shasum": "" - }, - "require": { - "php": ">=8.1", - "psr/container": "^1.1|^2.0", - "symfony/deprecation-contracts": "^2.5|^3" - }, - "conflict": { - "ext-psr": "<1.1|>=2" - }, - "type": "library", - "extra": { - "thanks": { - "url": "https://github.com/symfony/contracts", - "name": "symfony/contracts" - }, - "branch-alias": { - "dev-main": "3.6-dev" - } - }, - "autoload": { - "psr-4": { - "Symfony\\Contracts\\Service\\": "" - }, - "exclude-from-classmap": [ - "/Test/" - ] - }, - "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": "Generic abstractions related to writing services", - "homepage": "https://symfony.com", - "keywords": [ - "abstractions", - "contracts", - "decoupling", - "interfaces", - "interoperability", - "standards" - ], - "support": { - "source": "https://github.com/symfony/service-contracts/tree/v3.6.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": "2025-07-15T11:30:57+00:00" - }, - { - "name": "symfony/stopwatch", - "version": "v7.4.0", - "source": { - "type": "git", - "url": "https://github.com/symfony/stopwatch.git", - "reference": "8a24af0a2e8a872fb745047180649b8418303084" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/stopwatch/zipball/8a24af0a2e8a872fb745047180649b8418303084", - "reference": "8a24af0a2e8a872fb745047180649b8418303084", - "shasum": "" - }, - "require": { - "php": ">=8.2", - "symfony/service-contracts": "^2.5|^3" - }, - "type": "library", - "autoload": { - "psr-4": { - "Symfony\\Component\\Stopwatch\\": "" - }, - "exclude-from-classmap": [ - "/Tests/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Fabien Potencier", - "email": "fabien@symfony.com" - }, - { - "name": "Symfony Community", - "homepage": "https://symfony.com/contributors" - } - ], - "description": "Provides a way to profile code", - "homepage": "https://symfony.com", - "support": { - "source": "https://github.com/symfony/stopwatch/tree/v7.4.0" - }, - "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": "2025-08-04T07:05:15+00:00" - }, - { - "name": "symfony/string", - "version": "v7.4.6", - "source": { - "type": "git", - "url": "https://github.com/symfony/string.git", - "reference": "9f209231affa85aa930a5e46e6eb03381424b30b" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/string/zipball/9f209231affa85aa930a5e46e6eb03381424b30b", - "reference": "9f209231affa85aa930a5e46e6eb03381424b30b", - "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" - }, - "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/translation-contracts": "^2.5|^3.0", - "symfony/var-exporter": "^6.4|^7.0|^8.0" - }, - "type": "library", - "autoload": { - "files": [ - "Resources/functions.php" - ], - "psr-4": { - "Symfony\\Component\\String\\": "" - }, - "exclude-from-classmap": [ - "/Tests/" - ] - }, - "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": "Provides an object-oriented API to strings and deals with bytes, UTF-8 code points and grapheme clusters in a unified way", - "homepage": "https://symfony.com", - "keywords": [ - "grapheme", - "i18n", - "string", - "unicode", - "utf-8", - "utf8" - ], - "support": { - "source": "https://github.com/symfony/string/tree/v7.4.6" - }, - "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-02-09T09:33:46+00:00" - }, - { - "name": "symfony/translation", - "version": "v7.4.6", - "source": { - "type": "git", - "url": "https://github.com/symfony/translation.git", - "reference": "1888cf064399868af3784b9e043240f1d89d25ce" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/translation/zipball/1888cf064399868af3784b9e043240f1d89d25ce", - "reference": "1888cf064399868af3784b9e043240f1d89d25ce", - "shasum": "" - }, - "require": { - "php": ">=8.2", - "symfony/deprecation-contracts": "^2.5|^3", - "symfony/polyfill-mbstring": "~1.0", - "symfony/translation-contracts": "^2.5.3|^3.3" - }, - "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" - }, - "provide": { - "symfony/translation-implementation": "2.3|3.0" - }, - "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/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/polyfill-intl-icu": "^1.21", - "symfony/routing": "^6.4|^7.0|^8.0", - "symfony/service-contracts": "^2.5|^3", - "symfony/yaml": "^6.4|^7.0|^8.0" - }, - "type": "library", - "autoload": { - "files": [ - "Resources/functions.php" - ], - "psr-4": { - "Symfony\\Component\\Translation\\": "" - }, - "exclude-from-classmap": [ - "/Tests/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Fabien Potencier", - "email": "fabien@symfony.com" - }, - { - "name": "Symfony Community", - "homepage": "https://symfony.com/contributors" - } - ], - "description": "Provides tools to internationalize your application", - "homepage": "https://symfony.com", - "support": { - "source": "https://github.com/symfony/translation/tree/v7.4.6" - }, - "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-02-17T07:53:42+00:00" - }, - { - "name": "symfony/translation-contracts", - "version": "v3.6.1", - "source": { - "type": "git", - "url": "https://github.com/symfony/translation-contracts.git", - "reference": "65a8bc82080447fae78373aa10f8d13b38338977" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/translation-contracts/zipball/65a8bc82080447fae78373aa10f8d13b38338977", - "reference": "65a8bc82080447fae78373aa10f8d13b38338977", - "shasum": "" - }, - "require": { - "php": ">=8.1" - }, - "type": "library", - "extra": { - "thanks": { - "url": "https://github.com/symfony/contracts", - "name": "symfony/contracts" - }, - "branch-alias": { - "dev-main": "3.6-dev" - } - }, - "autoload": { - "psr-4": { - "Symfony\\Contracts\\Translation\\": "" - }, - "exclude-from-classmap": [ - "/Test/" - ] - }, - "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": "Generic abstractions related to translation", - "homepage": "https://symfony.com", - "keywords": [ - "abstractions", - "contracts", - "decoupling", - "interfaces", - "interoperability", - "standards" - ], - "support": { - "source": "https://github.com/symfony/translation-contracts/tree/v3.6.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": "2025-07-15T13:41:35+00:00" - }, - { - "name": "symfony/twig-bridge", - "version": "v7.4.7", - "source": { - "type": "git", - "url": "https://github.com/symfony/twig-bridge.git", - "reference": "c67219ca6b79a57b64e36bbb2cd8ba741286587e" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/twig-bridge/zipball/c67219ca6b79a57b64e36bbb2cd8ba741286587e", - "reference": "c67219ca6b79a57b64e36bbb2cd8ba741286587e", - "shasum": "" - }, - "require": { - "php": ">=8.2", - "symfony/deprecation-contracts": "^2.5|^3", - "symfony/translation-contracts": "^2.5|^3", - "twig/twig": "^3.21" - }, - "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" - }, - "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/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", - "twig/cssinliner-extra": "^3", - "twig/inky-extra": "^3", - "twig/markdown-extra": "^3" - }, - "type": "symfony-bridge", - "autoload": { - "psr-4": { - "Symfony\\Bridge\\Twig\\": "" - }, - "exclude-from-classmap": [ - "/Tests/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Fabien Potencier", - "email": "fabien@symfony.com" - }, - { - "name": "Symfony Community", - "homepage": "https://symfony.com/contributors" - } - ], - "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" - }, - "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-03-04T15:37:05+00:00" - }, - { - "name": "symfony/twig-bundle", - "version": "v7.4.4", - "source": { - "type": "git", - "url": "https://github.com/symfony/twig-bundle.git", - "reference": "e8829e02ff96a391ed0703bac9e7ff0537480b6b" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/twig-bundle/zipball/e8829e02ff96a391ed0703bac9e7ff0537480b6b", - "reference": "e8829e02ff96a391ed0703bac9e7ff0537480b6b", - "shasum": "" - }, - "require": { - "composer-runtime-api": ">=2.1", - "php": ">=8.2", - "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" - }, - "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" - }, - "type": "symfony-bundle", - "autoload": { - "psr-4": { - "Symfony\\Bundle\\TwigBundle\\": "" - }, - "exclude-from-classmap": [ - "/Tests/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Fabien Potencier", - "email": "fabien@symfony.com" - }, - { - "name": "Symfony Community", - "homepage": "https://symfony.com/contributors" - } - ], - "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" - }, - "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-01-06T12:34:24+00:00" - }, - { - "name": "symfony/type-info", - "version": "v7.4.7", - "source": { - "type": "git", - "url": "https://github.com/symfony/type-info.git", - "reference": "31f1e40cbf7851c7354281c90eb1b352c4cb8269" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/type-info/zipball/31f1e40cbf7851c7354281c90eb1b352c4cb8269", - "reference": "31f1e40cbf7851c7354281c90eb1b352c4cb8269", - "shasum": "" - }, - "require": { - "php": ">=8.2", - "psr/container": "^1.1|^2.0", - "symfony/deprecation-contracts": "^2.5|^3" - }, - "conflict": { - "phpstan/phpdoc-parser": "<1.30" - }, - "require-dev": { - "phpstan/phpdoc-parser": "^1.30|^2.0" - }, - "type": "library", - "autoload": { - "psr-4": { - "Symfony\\Component\\TypeInfo\\": "" - }, - "exclude-from-classmap": [ - "/Tests/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Mathias Arlaud", - "email": "mathias.arlaud@gmail.com" - }, - { - "name": "Baptiste LEDUC", - "email": "baptiste.leduc@gmail.com" - }, - { - "name": "Symfony Community", - "homepage": "https://symfony.com/contributors" - } - ], - "description": "Extracts PHP types information.", - "homepage": "https://symfony.com", - "keywords": [ - "PHPStan", - "phpdoc", - "symfony", - "type" - ], - "support": { - "source": "https://github.com/symfony/type-info/tree/v7.4.7" - }, - "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-03-04T12:49:16+00:00" - }, - { - "name": "symfony/validator", - "version": "v7.4.7", - "source": { - "type": "git", - "url": "https://github.com/symfony/validator.git", - "reference": "3a1a460a9f8c5e5611e15c52c4baa5a62fa3c203" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/validator/zipball/3a1a460a9f8c5e5611e15c52c4baa5a62fa3c203", - "reference": "3a1a460a9f8c5e5611e15c52c4baa5a62fa3c203", - "shasum": "" - }, - "require": { - "php": ">=8.2", - "symfony/deprecation-contracts": "^2.5|^3", - "symfony/polyfill-ctype": "~1.8", - "symfony/polyfill-mbstring": "~1.0", - "symfony/polyfill-php83": "^1.27", - "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" - }, - "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" - }, - "type": "library", - "autoload": { - "psr-4": { - "Symfony\\Component\\Validator\\": "" - }, - "exclude-from-classmap": [ - "/Tests/", - "/Resources/bin/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Fabien Potencier", - "email": "fabien@symfony.com" - }, - { - "name": "Symfony Community", - "homepage": "https://symfony.com/contributors" - } - ], - "description": "Provides tools to validate values", - "homepage": "https://symfony.com", - "support": { - "source": "https://github.com/symfony/validator/tree/v7.4.7" - }, - "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-03-06T11:10:17+00:00" - }, - { - "name": "symfony/var-dumper", - "version": "v7.4.6", - "source": { - "type": "git", - "url": "https://github.com/symfony/var-dumper.git", - "reference": "045321c440ac18347b136c63d2e9bf28a2dc0291" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/var-dumper/zipball/045321c440ac18347b136c63d2e9bf28a2dc0291", - "reference": "045321c440ac18347b136c63d2e9bf28a2dc0291", - "shasum": "" - }, - "require": { - "php": ">=8.2", - "symfony/deprecation-contracts": "^2.5|^3", - "symfony/polyfill-mbstring": "~1.0" - }, - "conflict": { - "symfony/console": "<6.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", - "twig/twig": "^3.12" - }, - "bin": [ - "Resources/bin/var-dump-server" - ], - "type": "library", - "autoload": { - "files": [ - "Resources/functions/dump.php" - ], - "psr-4": { - "Symfony\\Component\\VarDumper\\": "" - }, - "exclude-from-classmap": [ - "/Tests/" - ] - }, - "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": "Provides mechanisms for walking through any arbitrary PHP variable", - "homepage": "https://symfony.com", - "keywords": [ - "debug", - "dump" - ], - "support": { - "source": "https://github.com/symfony/var-dumper/tree/v7.4.6" - }, - "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-02-15T10:53:20+00:00" - }, - { - "name": "symfony/var-exporter", - "version": "v7.4.0", - "source": { - "type": "git", - "url": "https://github.com/symfony/var-exporter.git", - "reference": "03a60f169c79a28513a78c967316fbc8bf17816f" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/var-exporter/zipball/03a60f169c79a28513a78c967316fbc8bf17816f", - "reference": "03a60f169c79a28513a78c967316fbc8bf17816f", - "shasum": "" - }, - "require": { - "php": ">=8.2", - "symfony/deprecation-contracts": "^2.5|^3" - }, - "require-dev": { - "symfony/property-access": "^6.4|^7.0|^8.0", - "symfony/serializer": "^6.4|^7.0|^8.0", - "symfony/var-dumper": "^6.4|^7.0|^8.0" - }, - "type": "library", - "autoload": { - "psr-4": { - "Symfony\\Component\\VarExporter\\": "" - }, - "exclude-from-classmap": [ - "/Tests/" - ] - }, - "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": "Allows exporting any serializable PHP data structure to plain PHP code", - "homepage": "https://symfony.com", - "keywords": [ - "clone", - "construct", - "export", - "hydrate", - "instantiate", - "lazy-loading", - "proxy", - "serialize" - ], - "support": { - "source": "https://github.com/symfony/var-exporter/tree/v7.4.0" - }, - "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": "2025-09-11T10:15:23+00:00" - }, - { - "name": "symfony/yaml", - "version": "v7.4.6", - "source": { - "type": "git", - "url": "https://github.com/symfony/yaml.git", - "reference": "58751048de17bae71c5aa0d13cb19d79bca26391" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/yaml/zipball/58751048de17bae71c5aa0d13cb19d79bca26391", - "reference": "58751048de17bae71c5aa0d13cb19d79bca26391", - "shasum": "" - }, - "require": { - "php": ">=8.2", - "symfony/deprecation-contracts": "^2.5|^3", - "symfony/polyfill-ctype": "^1.8" - }, - "conflict": { - "symfony/console": "<6.4" - }, - "require-dev": { - "symfony/console": "^6.4|^7.0|^8.0" - }, - "bin": [ - "Resources/bin/yaml-lint" - ], - "type": "library", - "autoload": { - "psr-4": { - "Symfony\\Component\\Yaml\\": "" - }, - "exclude-from-classmap": [ - "/Tests/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Fabien Potencier", - "email": "fabien@symfony.com" - }, - { - "name": "Symfony Community", - "homepage": "https://symfony.com/contributors" - } - ], - "description": "Loads and dumps YAML files", - "homepage": "https://symfony.com", - "support": { - "source": "https://github.com/symfony/yaml/tree/v7.4.6" - }, - "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-02-09T09:33:46+00:00" - }, - { - "name": "twig/twig", - "version": "v3.23.0", - "source": { - "type": "git", - "url": "https://github.com/twigphp/Twig.git", - "reference": "a64dc5d2cc7d6cafb9347f6cd802d0d06d0351c9" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/twigphp/Twig/zipball/a64dc5d2cc7d6cafb9347f6cd802d0d06d0351c9", - "reference": "a64dc5d2cc7d6cafb9347f6cd802d0d06d0351c9", - "shasum": "" - }, - "require": { - "php": ">=8.1.0", - "symfony/deprecation-contracts": "^2.5|^3", - "symfony/polyfill-ctype": "^1.8", - "symfony/polyfill-mbstring": "^1.3" - }, - "require-dev": { - "phpstan/phpstan": "^2.0", - "psr/container": "^1.0|^2.0", - "symfony/phpunit-bridge": "^5.4.9|^6.4|^7.0" - }, - "type": "library", - "autoload": { - "files": [ - "src/Resources/core.php", - "src/Resources/debug.php", - "src/Resources/escaper.php", - "src/Resources/string_loader.php" - ], - "psr-4": { - "Twig\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Fabien Potencier", - "email": "fabien@symfony.com", - "homepage": "http://fabien.potencier.org", - "role": "Lead Developer" - }, - { - "name": "Twig Team", - "role": "Contributors" - }, - { - "name": "Armin Ronacher", - "email": "armin.ronacher@active-4.com", - "role": "Project Founder" - } - ], - "description": "Twig, the flexible, fast, and secure template language for PHP", - "homepage": "https://twig.symfony.com", - "keywords": [ - "templating" - ], - "support": { - "issues": "https://github.com/twigphp/Twig/issues", - "source": "https://github.com/twigphp/Twig/tree/v3.23.0" - }, - "funding": [ - { - "url": "https://github.com/fabpot", - "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/twig/twig", - "type": "tidelift" - } - ], - "time": "2026-01-23T21:00:41+00:00" - } - ], - "packages-dev": [ - { - "name": "clue/ndjson-react", - "version": "v1.3.0", - "source": { - "type": "git", - "url": "https://github.com/clue/reactphp-ndjson.git", - "reference": "392dc165fce93b5bb5c637b67e59619223c931b0" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/clue/reactphp-ndjson/zipball/392dc165fce93b5bb5c637b67e59619223c931b0", - "reference": "392dc165fce93b5bb5c637b67e59619223c931b0", - "shasum": "" - }, - "require": { - "php": ">=5.3", - "react/stream": "^1.2" - }, - "require-dev": { - "phpunit/phpunit": "^9.5 || ^5.7 || ^4.8.35", - "react/event-loop": "^1.2" - }, - "type": "library", - "autoload": { - "psr-4": { - "Clue\\React\\NDJson\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Christian Lück", - "email": "christian@clue.engineering" - } - ], - "description": "Streaming newline-delimited JSON (NDJSON) parser and encoder for ReactPHP.", - "homepage": "https://github.com/clue/reactphp-ndjson", - "keywords": [ - "NDJSON", - "json", - "jsonlines", - "newline", - "reactphp", - "streaming" - ], - "support": { - "issues": "https://github.com/clue/reactphp-ndjson/issues", - "source": "https://github.com/clue/reactphp-ndjson/tree/v1.3.0" - }, - "funding": [ - { - "url": "https://clue.engineering/support", - "type": "custom" - }, - { - "url": "https://github.com/clue", - "type": "github" - } - ], - "time": "2022-12-23T10:58:28+00:00" - }, - { - "name": "composer/pcre", - "version": "3.3.2", - "source": { - "type": "git", - "url": "https://github.com/composer/pcre.git", - "reference": "b2bed4734f0cc156ee1fe9c0da2550420d99a21e" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/composer/pcre/zipball/b2bed4734f0cc156ee1fe9c0da2550420d99a21e", - "reference": "b2bed4734f0cc156ee1fe9c0da2550420d99a21e", - "shasum": "" - }, - "require": { - "php": "^7.4 || ^8.0" - }, - "conflict": { - "phpstan/phpstan": "<1.11.10" - }, - "require-dev": { - "phpstan/phpstan": "^1.12 || ^2", - "phpstan/phpstan-strict-rules": "^1 || ^2", - "phpunit/phpunit": "^8 || ^9" - }, - "type": "library", - "extra": { - "phpstan": { - "includes": [ - "extension.neon" - ] - }, - "branch-alias": { - "dev-main": "3.x-dev" - } - }, - "autoload": { - "psr-4": { - "Composer\\Pcre\\": "src" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Jordi Boggiano", - "email": "j.boggiano@seld.be", - "homepage": "http://seld.be" - } - ], - "description": "PCRE wrapping library that offers type-safe preg_* replacements.", - "keywords": [ - "PCRE", - "preg", - "regex", - "regular expression" - ], - "support": { - "issues": "https://github.com/composer/pcre/issues", - "source": "https://github.com/composer/pcre/tree/3.3.2" - }, - "funding": [ - { - "url": "https://packagist.com", - "type": "custom" - }, - { - "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" - }, - { - "name": "composer/semver", - "version": "3.4.4", - "source": { - "type": "git", - "url": "https://github.com/composer/semver.git", - "reference": "198166618906cb2de69b95d7d47e5fa8aa1b2b95" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/composer/semver/zipball/198166618906cb2de69b95d7d47e5fa8aa1b2b95", - "reference": "198166618906cb2de69b95d7d47e5fa8aa1b2b95", - "shasum": "" - }, - "require": { - "php": "^5.3.2 || ^7.0 || ^8.0" - }, - "require-dev": { - "phpstan/phpstan": "^1.11", - "symfony/phpunit-bridge": "^3 || ^7" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-main": "3.x-dev" - } - }, - "autoload": { - "psr-4": { - "Composer\\Semver\\": "src" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Nils Adermann", - "email": "naderman@naderman.de", - "homepage": "http://www.naderman.de" - }, - { - "name": "Jordi Boggiano", - "email": "j.boggiano@seld.be", - "homepage": "http://seld.be" - }, - { - "name": "Rob Bast", - "email": "rob.bast@gmail.com", - "homepage": "http://robbast.nl" - } - ], - "description": "Semver library that offers utilities, version constraint parsing and validation.", - "keywords": [ - "semantic", - "semver", - "validation", - "versioning" - ], - "support": { - "irc": "ircs://irc.libera.chat:6697/composer", - "issues": "https://github.com/composer/semver/issues", - "source": "https://github.com/composer/semver/tree/3.4.4" - }, - "funding": [ - { - "url": "https://packagist.com", - "type": "custom" - }, - { - "url": "https://github.com/composer", - "type": "github" - } - ], - "time": "2025-08-20T19:15:30+00:00" - }, - { - "name": "composer/xdebug-handler", - "version": "3.0.5", - "source": { - "type": "git", - "url": "https://github.com/composer/xdebug-handler.git", - "reference": "6c1925561632e83d60a44492e0b344cf48ab85ef" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/composer/xdebug-handler/zipball/6c1925561632e83d60a44492e0b344cf48ab85ef", - "reference": "6c1925561632e83d60a44492e0b344cf48ab85ef", - "shasum": "" - }, - "require": { - "composer/pcre": "^1 || ^2 || ^3", - "php": "^7.2.5 || ^8.0", - "psr/log": "^1 || ^2 || ^3" - }, - "require-dev": { - "phpstan/phpstan": "^1.0", - "phpstan/phpstan-strict-rules": "^1.1", - "phpunit/phpunit": "^8.5 || ^9.6 || ^10.5" - }, - "type": "library", - "autoload": { - "psr-4": { - "Composer\\XdebugHandler\\": "src" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "John Stevenson", - "email": "john-stevenson@blueyonder.co.uk" - } - ], - "description": "Restarts a process without Xdebug.", - "keywords": [ - "Xdebug", - "performance" - ], - "support": { - "irc": "ircs://irc.libera.chat:6697/composer", - "issues": "https://github.com/composer/xdebug-handler/issues", - "source": "https://github.com/composer/xdebug-handler/tree/3.0.5" - }, - "funding": [ - { - "url": "https://packagist.com", - "type": "custom" - }, - { - "url": "https://github.com/composer", - "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/composer/composer", - "type": "tidelift" - } - ], - "time": "2024-05-06T16:37:16+00:00" - }, - { - "name": "doctrine/annotations", - "version": "2.0.2", - "source": { - "type": "git", - "url": "https://github.com/doctrine/annotations.git", - "reference": "901c2ee5d26eb64ff43c47976e114bf00843acf7" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/doctrine/annotations/zipball/901c2ee5d26eb64ff43c47976e114bf00843acf7", - "reference": "901c2ee5d26eb64ff43c47976e114bf00843acf7", - "shasum": "" - }, - "require": { - "doctrine/lexer": "^2 || ^3", - "ext-tokenizer": "*", - "php": "^7.2 || ^8.0", - "psr/cache": "^1 || ^2 || ^3" - }, - "require-dev": { - "doctrine/cache": "^2.0", - "doctrine/coding-standard": "^10", - "phpstan/phpstan": "^1.10.28", - "phpunit/phpunit": "^7.5 || ^8.5 || ^9.5", - "symfony/cache": "^5.4 || ^6.4 || ^7", - "vimeo/psalm": "^4.30 || ^5.14" - }, - "suggest": { - "php": "PHP 8.0 or higher comes with attributes, a native replacement for annotations" - }, - "type": "library", - "autoload": { - "psr-4": { - "Doctrine\\Common\\Annotations\\": "lib/Doctrine/Common/Annotations" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Guilherme Blanco", - "email": "guilhermeblanco@gmail.com" - }, - { - "name": "Roman Borschel", - "email": "roman@code-factory.org" - }, - { - "name": "Benjamin Eberlei", - "email": "kontakt@beberlei.de" - }, - { - "name": "Jonathan Wage", - "email": "jonwage@gmail.com" - }, - { - "name": "Johannes Schmitt", - "email": "schmittjoh@gmail.com" - } - ], - "description": "Docblock Annotations Parser", - "homepage": "https://www.doctrine-project.org/projects/annotations.html", - "keywords": [ - "annotations", - "docblock", - "parser" - ], - "support": { - "issues": "https://github.com/doctrine/annotations/issues", - "source": "https://github.com/doctrine/annotations/tree/2.0.2" - }, - "abandoned": true, - "time": "2024-09-05T10:17:24+00:00" - }, - { - "name": "doctrine/cache", - "version": "2.2.0", - "source": { - "type": "git", - "url": "https://github.com/doctrine/cache.git", - "reference": "1ca8f21980e770095a31456042471a57bc4c68fb" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/doctrine/cache/zipball/1ca8f21980e770095a31456042471a57bc4c68fb", - "reference": "1ca8f21980e770095a31456042471a57bc4c68fb", - "shasum": "" - }, - "require": { - "php": "~7.1 || ^8.0" - }, - "conflict": { - "doctrine/common": ">2.2,<2.4" - }, - "require-dev": { - "cache/integration-tests": "dev-master", - "doctrine/coding-standard": "^9", - "phpunit/phpunit": "^7.5 || ^8.5 || ^9.5", - "psr/cache": "^1.0 || ^2.0 || ^3.0", - "symfony/cache": "^4.4 || ^5.4 || ^6", - "symfony/var-exporter": "^4.4 || ^5.4 || ^6" - }, - "type": "library", - "autoload": { - "psr-4": { - "Doctrine\\Common\\Cache\\": "lib/Doctrine/Common/Cache" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Guilherme Blanco", - "email": "guilhermeblanco@gmail.com" - }, - { - "name": "Roman Borschel", - "email": "roman@code-factory.org" - }, - { - "name": "Benjamin Eberlei", - "email": "kontakt@beberlei.de" - }, - { - "name": "Jonathan Wage", - "email": "jonwage@gmail.com" - }, - { - "name": "Johannes Schmitt", - "email": "schmittjoh@gmail.com" - } - ], - "description": "PHP Doctrine Cache library is a popular cache implementation that supports many different drivers such as redis, memcache, apc, mongodb and others.", - "homepage": "https://www.doctrine-project.org/projects/cache.html", - "keywords": [ - "abstraction", - "apcu", - "cache", - "caching", - "couchdb", - "memcached", - "php", - "redis", - "xcache" - ], - "support": { - "issues": "https://github.com/doctrine/cache/issues", - "source": "https://github.com/doctrine/cache/tree/2.2.0" - }, - "funding": [ - { - "url": "https://www.doctrine-project.org/sponsorship.html", - "type": "custom" - }, - { - "url": "https://www.patreon.com/phpdoctrine", - "type": "patreon" - }, - { - "url": "https://tidelift.com/funding/github/packagist/doctrine%2Fcache", - "type": "tidelift" - } - ], - "abandoned": true, - "time": "2022-05-20T20:07:39+00:00" - }, - { - "name": "doctrine/data-fixtures", - "version": "2.2.0", - "source": { - "type": "git", - "url": "https://github.com/doctrine/data-fixtures.git", - "reference": "7a615ba135e45d67674bb623d90f34f6c7b6bd97" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/doctrine/data-fixtures/zipball/7a615ba135e45d67674bb623d90f34f6c7b6bd97", - "reference": "7a615ba135e45d67674bb623d90f34f6c7b6bd97", - "shasum": "" - }, - "require": { - "doctrine/persistence": "^3.1 || ^4.0", - "php": "^8.1", - "psr/log": "^1.1 || ^2 || ^3" - }, - "conflict": { - "doctrine/dbal": "<3.5 || >=5", - "doctrine/orm": "<2.14 || >=4", - "doctrine/phpcr-odm": "<1.3.0" - }, - "require-dev": { - "doctrine/coding-standard": "^14", - "doctrine/dbal": "^3.5 || ^4", - "doctrine/mongodb-odm": "^1.3.0 || ^2.0.0", - "doctrine/orm": "^2.14 || ^3", - "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" - }, - "suggest": { - "alcaeus/mongo-php-adapter": "For using MongoDB ODM 1.3 with PHP 7 (deprecated)", - "doctrine/mongodb-odm": "For loading MongoDB ODM fixtures", - "doctrine/orm": "For loading ORM fixtures", - "doctrine/phpcr-odm": "For loading PHPCR ODM fixtures" - }, - "type": "library", - "autoload": { - "psr-4": { - "Doctrine\\Common\\DataFixtures\\": "src" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Jonathan Wage", - "email": "jonwage@gmail.com" - } - ], - "description": "Data Fixtures for all Doctrine Object Managers", - "homepage": "https://www.doctrine-project.org", - "keywords": [ - "database" - ], - "support": { - "issues": "https://github.com/doctrine/data-fixtures/issues", - "source": "https://github.com/doctrine/data-fixtures/tree/2.2.0" - }, - "funding": [ - { - "url": "https://www.doctrine-project.org/sponsorship.html", - "type": "custom" - }, - { - "url": "https://www.patreon.com/phpdoctrine", - "type": "patreon" - }, - { - "url": "https://tidelift.com/funding/github/packagist/doctrine%2Fdata-fixtures", - "type": "tidelift" - } - ], - "time": "2025-10-17T20:06:20+00:00" - }, - { - "name": "doctrine/mongodb-odm", - "version": "2.16.1", - "source": { - "type": "git", - "url": "https://github.com/doctrine/mongodb-odm.git", - "reference": "b34f2dce3ca5b2de8903419a31ad48837d852b74" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/doctrine/mongodb-odm/zipball/b34f2dce3ca5b2de8903419a31ad48837d852b74", - "reference": "b34f2dce3ca5b2de8903419a31ad48837d852b74", - "shasum": "" - }, - "require": { - "doctrine/collections": "^2.1", - "doctrine/event-manager": "^1.0 || ^2.0", - "doctrine/instantiator": "^1.1 || ^2", - "doctrine/persistence": "^3.2 || ^4", - "ext-mongodb": "^1.21 || ^2.0", - "friendsofphp/proxy-manager-lts": "^1.0", - "jean85/pretty-package-versions": "^1.3.0 || ^2.0.1", - "mongodb/mongodb": "^1.21.2 || ^2.1.1", - "php": "^8.1", - "psr/cache": "^1.0 || ^2.0 || ^3.0", - "symfony/console": "^5.4 || ^6.4 || ^7.0 || ^8.0", - "symfony/deprecation-contracts": "^2.2 || ^3.0", - "symfony/polyfill-php84": "^1.33", - "symfony/var-dumper": "^5.4 || ^6.4 || ^7.0 || ^8.0", - "symfony/var-exporter": "^6.4.1 || ^7.0 || ^8.0" - }, - "conflict": { - "doctrine/annotations": "<1.12 || >=3.0", - "doctrine/cache": "<1.11", - "doctrine/mongodb-odm-bundle": "<5" - }, - "require-dev": { - "doctrine/annotations": "^1.12 || ^2.0", - "doctrine/cache": "^2.0", - "doctrine/coding-standard": "^14.0", - "doctrine/orm": "^3.2", - "ext-bcmath": "*", - "jmikola/geojson": "^1.0", - "phpbench/phpbench": "^1.4.0", - "phpstan/phpstan": "^2.1", - "phpstan/phpstan-deprecation-rules": "^2.0", - "phpstan/phpstan-phpunit": "^2.0", - "phpunit/phpunit": "^10.5.58|^11.5.43", - "squizlabs/php_codesniffer": "^4", - "symfony/cache": "^5.4 || ^6.0 || ^7.0 || ^8.0", - "symfony/uid": "^5.4 || ^6.0 || ^7.0 || ^8.0" - }, - "suggest": { - "doctrine/annotations": "For annotation mapping support", - "ext-bcmath": "Decimal128 type support" - }, - "type": "library", - "autoload": { - "psr-4": { - "Doctrine\\ODM\\MongoDB\\": "src" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Jeremy Mikola", - "email": "jmikola@gmail.com" - }, - { - "name": "Maciej Malarz", - "email": "malarzm@gmail.com" - }, - { - "name": "Andreas Braun", - "email": "alcaeus@alcaeus.org" - }, - { - "name": "Ion Bazan", - "email": "ion.bazan@gmail.com" - }, - { - "name": "Fran Moreno", - "email": "franmomu@gmail.com" - } - ], - "description": "PHP Doctrine MongoDB Object Document Mapper (ODM) provides transparent persistence for PHP objects to MongoDB.", - "homepage": "https://www.doctrine-project.org/projects/mongodb-odm.html", - "keywords": [ - "data", - "mapper", - "mapping", - "mongodb", - "object", - "odm", - "php" - ], - "support": { - "issues": "https://github.com/doctrine/mongodb-odm/issues", - "source": "https://github.com/doctrine/mongodb-odm/tree/2.16.1" - }, - "funding": [ - { - "url": "https://www.doctrine-project.org/sponsorship.html", - "type": "custom" - }, - { - "url": "https://www.patreon.com/phpdoctrine", - "type": "patreon" - }, - { - "url": "https://tidelift.com/funding/github/packagist/doctrine%2Fmongodb-odm", - "type": "tidelift" - } - ], - "time": "2026-01-29T11:33:08+00:00" - }, - { - "name": "doctrine/mongodb-odm-bundle", - "version": "5.6.0", - "source": { - "type": "git", - "url": "https://github.com/doctrine/DoctrineMongoDBBundle.git", - "reference": "72a40244a4d4e13a54cb8d839ad73df4050b71e7" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/doctrine/DoctrineMongoDBBundle/zipball/72a40244a4d4e13a54cb8d839ad73df4050b71e7", - "reference": "72a40244a4d4e13a54cb8d839ad73df4050b71e7", - "shasum": "" - }, - "require": { - "composer-runtime-api": "^2.0", - "doctrine/mongodb-odm": "^2.6", - "doctrine/persistence": "^3.0 || ^4.0", - "ext-mongodb": "^1.21 || ^2", - "php": "^8.1", - "psr/log": "^1.0 || ^2.0 || ^3.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 || ^7.0 || ^8.0", - "symfony/framework-bundle": "^6.4 || ^7.0 || ^8.0", - "symfony/http-kernel": "^6.4 || ^7.0 || ^8.0", - "symfony/options-resolver": "^6.4 || ^7.0 || ^8.0" - }, - "conflict": { - "doctrine/data-fixtures": "<1.8 || >=3" - }, - "require-dev": { - "composer/semver": "^3.4", - "doctrine/coding-standard": "^14.0", - "doctrine/data-fixtures": "^1.8 || ^2.0", - "phpstan/phpstan": "^2.1", - "phpunit/phpunit": "^10.5", - "squizlabs/php_codesniffer": "^4", - "symfony/browser-kit": "^6.4 || ^7.0 || ^8.0", - "symfony/form": "^6.4 || ^7.0 || ^8.0", - "symfony/messenger": "^6.4 || ^7.0 || ^8.0", - "symfony/phpunit-bridge": "^6.4.1 || ^7.0.1", - "symfony/security-bundle": "^6.4 || ^7.0 || ^8.0", - "symfony/stopwatch": "^6.4 || ^7.0 || ^8.0", - "symfony/validator": "^6.4 || ^7.0 || ^8.0", - "symfony/yaml": "^6.4 || ^7.0 || ^8.0" - }, - "suggest": { - "doctrine/data-fixtures": "Load data fixtures" - }, - "type": "symfony-bundle", - "autoload": { - "psr-4": { - "Doctrine\\Bundle\\MongoDBBundle\\": "src" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Bulat Shakirzyanov", - "email": "mallluhuct@gmail.com" - }, - { - "name": "Kris Wallsmith", - "email": "kris@symfony.com" - }, - { - "name": "Jonathan H. Wage", - "email": "jonwage@gmail.com" - } - ], - "description": "Symfony Doctrine MongoDB Bundle", - "homepage": "http://www.doctrine-project.org", - "keywords": [ - "mongodb", - "persistence", - "symfony" - ], - "support": { - "issues": "https://github.com/doctrine/DoctrineMongoDBBundle/issues", - "source": "https://github.com/doctrine/DoctrineMongoDBBundle/tree/5.6.0" - }, - "time": "2026-01-26T10:21:57+00:00" - }, - { - "name": "evenement/evenement", - "version": "v3.0.2", - "source": { - "type": "git", - "url": "https://github.com/igorw/evenement.git", - "reference": "0a16b0d71ab13284339abb99d9d2bd813640efbc" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/igorw/evenement/zipball/0a16b0d71ab13284339abb99d9d2bd813640efbc", - "reference": "0a16b0d71ab13284339abb99d9d2bd813640efbc", - "shasum": "" - }, - "require": { - "php": ">=7.0" - }, - "require-dev": { - "phpunit/phpunit": "^9 || ^6" - }, - "type": "library", - "autoload": { - "psr-4": { - "Evenement\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Igor Wiedler", - "email": "igor@wiedler.ch" - } - ], - "description": "Événement is a very simple event dispatching library for PHP", - "keywords": [ - "event-dispatcher", - "event-emitter" - ], - "support": { - "issues": "https://github.com/igorw/evenement/issues", - "source": "https://github.com/igorw/evenement/tree/v3.0.2" - }, - "time": "2023-08-08T05:53:35+00:00" - }, - { - "name": "fidry/cpu-core-counter", - "version": "1.3.0", - "source": { - "type": "git", - "url": "https://github.com/theofidry/cpu-core-counter.git", - "reference": "db9508f7b1474469d9d3c53b86f817e344732678" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/theofidry/cpu-core-counter/zipball/db9508f7b1474469d9d3c53b86f817e344732678", - "reference": "db9508f7b1474469d9d3c53b86f817e344732678", - "shasum": "" - }, - "require": { - "php": "^7.2 || ^8.0" - }, - "require-dev": { - "fidry/makefile": "^0.2.0", - "fidry/php-cs-fixer-config": "^1.1.2", - "phpstan/extension-installer": "^1.2.0", - "phpstan/phpstan": "^2.0", - "phpstan/phpstan-deprecation-rules": "^2.0.0", - "phpstan/phpstan-phpunit": "^2.0", - "phpstan/phpstan-strict-rules": "^2.0", - "phpunit/phpunit": "^8.5.31 || ^9.5.26", - "webmozarts/strict-phpunit": "^7.5" - }, - "type": "library", - "autoload": { - "psr-4": { - "Fidry\\CpuCoreCounter\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Théo FIDRY", - "email": "theo.fidry@gmail.com" - } - ], - "description": "Tiny utility to get the number of CPU cores.", - "keywords": [ - "CPU", - "core" - ], - "support": { - "issues": "https://github.com/theofidry/cpu-core-counter/issues", - "source": "https://github.com/theofidry/cpu-core-counter/tree/1.3.0" - }, - "funding": [ - { - "url": "https://github.com/theofidry", - "type": "github" - } - ], - "time": "2025-08-14T07:29:31+00:00" - }, - { - "name": "friendsofphp/php-cs-fixer", - "version": "v3.94.2", - "source": { - "type": "git", - "url": "https://github.com/PHP-CS-Fixer/PHP-CS-Fixer.git", - "reference": "7787ceff91365ba7d623ec410b8f429cdebb4f63" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/PHP-CS-Fixer/PHP-CS-Fixer/zipball/7787ceff91365ba7d623ec410b8f429cdebb4f63", - "reference": "7787ceff91365ba7d623ec410b8f429cdebb4f63", - "shasum": "" - }, - "require": { - "clue/ndjson-react": "^1.3", - "composer/semver": "^3.4", - "composer/xdebug-handler": "^3.0.5", - "ext-filter": "*", - "ext-hash": "*", - "ext-json": "*", - "ext-tokenizer": "*", - "fidry/cpu-core-counter": "^1.3", - "php": "^7.4 || ^8.0", - "react/child-process": "^0.6.6", - "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", - "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/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", - "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" - }, - "suggest": { - "ext-dom": "For handling output formats in XML", - "ext-mbstring": "For handling non-UTF8 characters." - }, - "bin": [ - "php-cs-fixer" - ], - "type": "application", - "autoload": { - "psr-4": { - "PhpCsFixer\\": "src/" - }, - "exclude-from-classmap": [ - "src/**/Internal/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Fabien Potencier", - "email": "fabien@symfony.com" - }, - { - "name": "Dariusz Rumiński", - "email": "dariusz.ruminski@gmail.com" - } - ], - "description": "A tool to automatically fix PHP code style", - "keywords": [ - "Static code analysis", - "fixer", - "standards", - "static analysis" - ], - "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" - }, - "funding": [ - { - "url": "https://github.com/keradus", - "type": "github" - } - ], - "time": "2026-02-20T16:13:53+00:00" - }, - { - "name": "friendsofphp/proxy-manager-lts", - "version": "v1.0.19", - "source": { - "type": "git", - "url": "https://github.com/FriendsOfPHP/proxy-manager-lts.git", - "reference": "c20299aa9f48a622052964a75c5a4cef017398b2" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/FriendsOfPHP/proxy-manager-lts/zipball/c20299aa9f48a622052964a75c5a4cef017398b2", - "reference": "c20299aa9f48a622052964a75c5a4cef017398b2", - "shasum": "" - }, - "require": { - "laminas/laminas-code": "~3.4.1|^4.0", - "php": ">=7.1", - "symfony/filesystem": "^4.4.17|^5.0|^6.0|^7.0|^8.0" - }, - "conflict": { - "laminas/laminas-stdlib": "<3.2.1", - "zendframework/zend-stdlib": "<3.2.1" - }, - "replace": { - "ocramius/proxy-manager": "^2.1" - }, - "require-dev": { - "ext-phar": "*", - "symfony/phpunit-bridge": "^5.4|^6.0|^7.0" - }, - "type": "library", - "extra": { - "thanks": { - "url": "https://github.com/Ocramius/ProxyManager", - "name": "ocramius/proxy-manager" - } - }, - "autoload": { - "psr-4": { - "ProxyManager\\": "src/ProxyManager" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Marco Pivetta", - "email": "ocramius@gmail.com", - "homepage": "https://ocramius.github.io/" - }, - { - "name": "Nicolas Grekas", - "email": "p@tchwork.com" - } - ], - "description": "Adding support for a wider range of PHP versions to ocramius/proxy-manager", - "homepage": "https://github.com/FriendsOfPHP/proxy-manager-lts", - "keywords": [ - "aop", - "lazy loading", - "proxy", - "proxy pattern", - "service proxies" - ], - "support": { - "issues": "https://github.com/FriendsOfPHP/proxy-manager-lts/issues", - "source": "https://github.com/FriendsOfPHP/proxy-manager-lts/tree/v1.0.19" - }, - "funding": [ - { - "url": "https://github.com/Ocramius", - "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/ocramius/proxy-manager", - "type": "tidelift" - } - ], - "time": "2025-10-28T10:28:17+00:00" - }, - { - "name": "jean85/pretty-package-versions", - "version": "2.1.1", - "source": { - "type": "git", - "url": "https://github.com/Jean85/pretty-package-versions.git", - "reference": "4d7aa5dab42e2a76d99559706022885de0e18e1a" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/Jean85/pretty-package-versions/zipball/4d7aa5dab42e2a76d99559706022885de0e18e1a", - "reference": "4d7aa5dab42e2a76d99559706022885de0e18e1a", - "shasum": "" - }, - "require": { - "composer-runtime-api": "^2.1.0", - "php": "^7.4|^8.0" - }, - "require-dev": { - "friendsofphp/php-cs-fixer": "^3.2", - "jean85/composer-provided-replaced-stub-package": "^1.0", - "phpstan/phpstan": "^2.0", - "phpunit/phpunit": "^7.5|^8.5|^9.6", - "rector/rector": "^2.0", - "vimeo/psalm": "^4.3 || ^5.0" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.x-dev" - } - }, - "autoload": { - "psr-4": { - "Jean85\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Alessandro Lai", - "email": "alessandro.lai85@gmail.com" - } - ], - "description": "A library to get pretty versions strings of installed dependencies", - "keywords": [ - "composer", - "package", - "release", - "versions" - ], - "support": { - "issues": "https://github.com/Jean85/pretty-package-versions/issues", - "source": "https://github.com/Jean85/pretty-package-versions/tree/2.1.1" - }, - "time": "2025-03-19T14:43:43+00:00" - }, - { - "name": "laminas/laminas-code", - "version": "4.17.0", - "source": { - "type": "git", - "url": "https://github.com/laminas/laminas-code.git", - "reference": "40d61e2899ec17c5d08bbc0a2d586b3ca17ab9bd" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/laminas/laminas-code/zipball/40d61e2899ec17c5d08bbc0a2d586b3ca17ab9bd", - "reference": "40d61e2899ec17c5d08bbc0a2d586b3ca17ab9bd", - "shasum": "" - }, - "require": { - "php": "~8.2.0 || ~8.3.0 || ~8.4.0 || ~8.5.0" - }, - "require-dev": { - "doctrine/annotations": "^2.0.1", - "ext-phar": "*", - "laminas/laminas-coding-standard": "^3.0.0", - "laminas/laminas-stdlib": "^3.18.0", - "phpunit/phpunit": "^10.5.58", - "psalm/plugin-phpunit": "^0.19.0", - "vimeo/psalm": "^5.15.0" - }, - "suggest": { - "doctrine/annotations": "Doctrine\\Common\\Annotations >=1.0 for annotation features", - "laminas/laminas-stdlib": "Laminas\\Stdlib component" - }, - "type": "library", - "autoload": { - "psr-4": { - "Laminas\\Code\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "description": "Extensions to the PHP Reflection API, static code scanning, and code generation", - "homepage": "https://laminas.dev", - "keywords": [ - "code", - "laminas", - "laminasframework" - ], - "support": { - "chat": "https://laminas.dev/chat", - "docs": "https://docs.laminas.dev/laminas-code/", - "forum": "https://discourse.laminas.dev", - "issues": "https://github.com/laminas/laminas-code/issues", - "rss": "https://github.com/laminas/laminas-code/releases.atom", - "source": "https://github.com/laminas/laminas-code" - }, - "funding": [ - { - "url": "https://funding.communitybridge.org/projects/laminas-project", - "type": "community_bridge" - } - ], - "time": "2025-11-01T09:38:14+00:00" - }, - { - "name": "mikey179/vfsstream", - "version": "v1.6.12", - "source": { - "type": "git", - "url": "https://github.com/bovigo/vfsStream.git", - "reference": "fe695ec993e0a55c3abdda10a9364eb31c6f1bf0" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/bovigo/vfsStream/zipball/fe695ec993e0a55c3abdda10a9364eb31c6f1bf0", - "reference": "fe695ec993e0a55c3abdda10a9364eb31c6f1bf0", - "shasum": "" - }, - "require": { - "php": ">=7.1.0" - }, - "require-dev": { - "phpunit/phpunit": "^7.5||^8.5||^9.6", - "yoast/phpunit-polyfills": "^2.0" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.6.x-dev" - } - }, - "autoload": { - "psr-0": { - "org\\bovigo\\vfs\\": "src/main/php" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Frank Kleine", - "homepage": "http://frankkleine.de/", - "role": "Developer" - } - ], - "description": "Virtual file system to mock the real file system in unit tests.", - "homepage": "http://vfs.bovigo.org/", - "support": { - "issues": "https://github.com/bovigo/vfsStream/issues", - "source": "https://github.com/bovigo/vfsStream/tree/master", - "wiki": "https://github.com/bovigo/vfsStream/wiki" - }, - "time": "2024-08-29T18:43:31+00:00" - }, - { - "name": "mongodb/mongodb", - "version": "2.1.2", - "source": { - "type": "git", - "url": "https://github.com/mongodb/mongo-php-library.git", - "reference": "0a2472ba9cbb932f7e43a8770aedb2fc30612a67" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/mongodb/mongo-php-library/zipball/0a2472ba9cbb932f7e43a8770aedb2fc30612a67", - "reference": "0a2472ba9cbb932f7e43a8770aedb2fc30612a67", - "shasum": "" - }, - "require": { - "composer-runtime-api": "^2.0", - "ext-mongodb": "^2.1", - "php": "^8.1", - "psr/log": "^1.1.4|^2|^3", - "symfony/polyfill-php85": "^1.32" - }, - "replace": { - "mongodb/builder": "*" - }, - "require-dev": { - "doctrine/coding-standard": "^12.0", - "phpunit/phpunit": "^10.5.35", - "rector/rector": "^2.1.4", - "squizlabs/php_codesniffer": "^3.7", - "vimeo/psalm": "6.5.*" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.x-dev" - } - }, - "autoload": { - "files": [ - "src/functions.php" - ], - "psr-4": { - "MongoDB\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "Apache-2.0" - ], - "authors": [ - { - "name": "Andreas Braun", - "email": "andreas.braun@mongodb.com" - }, - { - "name": "Jeremy Mikola", - "email": "jmikola@gmail.com" - }, - { - "name": "Jérôme Tamarelle", - "email": "jerome.tamarelle@mongodb.com" - } - ], - "description": "MongoDB driver library", - "homepage": "https://jira.mongodb.org/browse/PHPLIB", - "keywords": [ - "database", - "driver", - "mongodb", - "persistence" - ], - "support": { - "issues": "https://github.com/mongodb/mongo-php-library/issues", - "source": "https://github.com/mongodb/mongo-php-library/tree/2.1.2" - }, - "time": "2025-10-06T12:12:40+00:00" - }, - { - "name": "myclabs/deep-copy", - "version": "1.13.4", - "source": { - "type": "git", - "url": "https://github.com/myclabs/DeepCopy.git", - "reference": "07d290f0c47959fd5eed98c95ee5602db07e0b6a" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/07d290f0c47959fd5eed98c95ee5602db07e0b6a", - "reference": "07d290f0c47959fd5eed98c95ee5602db07e0b6a", - "shasum": "" - }, - "require": { - "php": "^7.1 || ^8.0" - }, - "conflict": { - "doctrine/collections": "<1.6.8", - "doctrine/common": "<2.13.3 || >=3 <3.2.2" - }, - "require-dev": { - "doctrine/collections": "^1.6.8", - "doctrine/common": "^2.13.3 || ^3.2.2", - "phpspec/prophecy": "^1.10", - "phpunit/phpunit": "^7.5.20 || ^8.5.23 || ^9.5.13" - }, - "type": "library", - "autoload": { - "files": [ - "src/DeepCopy/deep_copy.php" - ], - "psr-4": { - "DeepCopy\\": "src/DeepCopy/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "description": "Create deep copies (clones) of your objects", - "keywords": [ - "clone", - "copy", - "duplicate", - "object", - "object graph" - ], - "support": { - "issues": "https://github.com/myclabs/DeepCopy/issues", - "source": "https://github.com/myclabs/DeepCopy/tree/1.13.4" - }, - "funding": [ - { - "url": "https://tidelift.com/funding/github/packagist/myclabs/deep-copy", - "type": "tidelift" - } - ], - "time": "2025-08-01T08:46:24+00:00" - }, - { - "name": "nikic/php-parser", - "version": "v5.7.0", - "source": { - "type": "git", - "url": "https://github.com/nikic/PHP-Parser.git", - "reference": "dca41cd15c2ac9d055ad70dbfd011130757d1f82" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/dca41cd15c2ac9d055ad70dbfd011130757d1f82", - "reference": "dca41cd15c2ac9d055ad70dbfd011130757d1f82", - "shasum": "" - }, - "require": { - "ext-ctype": "*", - "ext-json": "*", - "ext-tokenizer": "*", - "php": ">=7.4" - }, - "require-dev": { - "ircmaxell/php-yacc": "^0.0.7", - "phpunit/phpunit": "^9.0" - }, - "bin": [ - "bin/php-parse" - ], - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "5.x-dev" - } - }, - "autoload": { - "psr-4": { - "PhpParser\\": "lib/PhpParser" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Nikita Popov" - } - ], - "description": "A PHP parser written in PHP", - "keywords": [ - "parser", - "php" - ], - "support": { - "issues": "https://github.com/nikic/PHP-Parser/issues", - "source": "https://github.com/nikic/PHP-Parser/tree/v5.7.0" - }, - "time": "2025-12-06T11:56:16+00:00" - }, - { - "name": "phar-io/manifest", - "version": "2.0.4", - "source": { - "type": "git", - "url": "https://github.com/phar-io/manifest.git", - "reference": "54750ef60c58e43759730615a392c31c80e23176" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/phar-io/manifest/zipball/54750ef60c58e43759730615a392c31c80e23176", - "reference": "54750ef60c58e43759730615a392c31c80e23176", - "shasum": "" - }, - "require": { - "ext-dom": "*", - "ext-libxml": "*", - "ext-phar": "*", - "ext-xmlwriter": "*", - "phar-io/version": "^3.0.1", - "php": "^7.2 || ^8.0" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "2.0.x-dev" - } - }, - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Arne Blankerts", - "email": "arne@blankerts.de", - "role": "Developer" - }, - { - "name": "Sebastian Heuer", - "email": "sebastian@phpeople.de", - "role": "Developer" - }, - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de", - "role": "Developer" - } - ], - "description": "Component for reading phar.io manifest information from a PHP Archive (PHAR)", - "support": { - "issues": "https://github.com/phar-io/manifest/issues", - "source": "https://github.com/phar-io/manifest/tree/2.0.4" - }, - "funding": [ - { - "url": "https://github.com/theseer", - "type": "github" - } - ], - "time": "2024-03-03T12:33:53+00:00" - }, - { - "name": "phar-io/version", - "version": "3.2.1", - "source": { - "type": "git", - "url": "https://github.com/phar-io/version.git", - "reference": "4f7fd7836c6f332bb2933569e566a0d6c4cbed74" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/phar-io/version/zipball/4f7fd7836c6f332bb2933569e566a0d6c4cbed74", - "reference": "4f7fd7836c6f332bb2933569e566a0d6c4cbed74", - "shasum": "" - }, - "require": { - "php": "^7.2 || ^8.0" - }, - "type": "library", - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Arne Blankerts", - "email": "arne@blankerts.de", - "role": "Developer" - }, - { - "name": "Sebastian Heuer", - "email": "sebastian@phpeople.de", - "role": "Developer" - }, - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de", - "role": "Developer" - } - ], - "description": "Library for handling version information and constraints", - "support": { - "issues": "https://github.com/phar-io/version/issues", - "source": "https://github.com/phar-io/version/tree/3.2.1" - }, - "time": "2022-02-21T01:04:05+00:00" - }, - { - "name": "phpstan/phpstan", - "version": "2.1.40", - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/phpstan/phpstan/zipball/9b2c7aeb83a75d8680ea5e7c9b7fca88052b766b", - "reference": "9b2c7aeb83a75d8680ea5e7c9b7fca88052b766b", - "shasum": "" - }, - "require": { - "php": "^7.4|^8.0" - }, - "conflict": { - "phpstan/phpstan-shim": "*" - }, - "bin": [ - "phpstan", - "phpstan.phar" - ], - "type": "library", - "autoload": { - "files": [ - "bootstrap.php" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "description": "PHPStan - PHP Static Analysis Tool", - "keywords": [ - "dev", - "static analysis" - ], - "support": { - "docs": "https://phpstan.org/user-guide/getting-started", - "forum": "https://github.com/phpstan/phpstan/discussions", - "issues": "https://github.com/phpstan/phpstan/issues", - "security": "https://github.com/phpstan/phpstan/security/policy", - "source": "https://github.com/phpstan/phpstan-src" - }, - "funding": [ - { - "url": "https://github.com/ondrejmirtes", - "type": "github" - }, - { - "url": "https://github.com/phpstan", - "type": "github" - } - ], - "time": "2026-02-23T15:04:35+00:00" - }, - { - "name": "phpunit/php-code-coverage", - "version": "10.1.16", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/php-code-coverage.git", - "reference": "7e308268858ed6baedc8704a304727d20bc07c77" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/7e308268858ed6baedc8704a304727d20bc07c77", - "reference": "7e308268858ed6baedc8704a304727d20bc07c77", - "shasum": "" - }, - "require": { - "ext-dom": "*", - "ext-libxml": "*", - "ext-xmlwriter": "*", - "nikic/php-parser": "^4.19.1 || ^5.1.0", - "php": ">=8.1", - "phpunit/php-file-iterator": "^4.1.0", - "phpunit/php-text-template": "^3.0.1", - "sebastian/code-unit-reverse-lookup": "^3.0.0", - "sebastian/complexity": "^3.2.0", - "sebastian/environment": "^6.1.0", - "sebastian/lines-of-code": "^2.0.2", - "sebastian/version": "^4.0.1", - "theseer/tokenizer": "^1.2.3" - }, - "require-dev": { - "phpunit/phpunit": "^10.1" - }, - "suggest": { - "ext-pcov": "PHP extension that provides line coverage", - "ext-xdebug": "PHP extension that provides line coverage as well as branch and path coverage" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-main": "10.1.x-dev" - } - }, - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de", - "role": "lead" - } - ], - "description": "Library that provides collection, processing, and rendering functionality for PHP code coverage information.", - "homepage": "https://github.com/sebastianbergmann/php-code-coverage", - "keywords": [ - "coverage", - "testing", - "xunit" - ], - "support": { - "issues": "https://github.com/sebastianbergmann/php-code-coverage/issues", - "security": "https://github.com/sebastianbergmann/php-code-coverage/security/policy", - "source": "https://github.com/sebastianbergmann/php-code-coverage/tree/10.1.16" - }, - "funding": [ - { - "url": "https://github.com/sebastianbergmann", - "type": "github" - } - ], - "time": "2024-08-22T04:31:57+00:00" - }, - { - "name": "phpunit/php-file-iterator", - "version": "4.1.0", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/php-file-iterator.git", - "reference": "a95037b6d9e608ba092da1b23931e537cadc3c3c" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-file-iterator/zipball/a95037b6d9e608ba092da1b23931e537cadc3c3c", - "reference": "a95037b6d9e608ba092da1b23931e537cadc3c3c", - "shasum": "" - }, - "require": { - "php": ">=8.1" - }, - "require-dev": { - "phpunit/phpunit": "^10.0" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-main": "4.0-dev" - } - }, - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de", - "role": "lead" - } - ], - "description": "FilterIterator implementation that filters files based on a list of suffixes.", - "homepage": "https://github.com/sebastianbergmann/php-file-iterator/", - "keywords": [ - "filesystem", - "iterator" - ], - "support": { - "issues": "https://github.com/sebastianbergmann/php-file-iterator/issues", - "security": "https://github.com/sebastianbergmann/php-file-iterator/security/policy", - "source": "https://github.com/sebastianbergmann/php-file-iterator/tree/4.1.0" - }, - "funding": [ - { - "url": "https://github.com/sebastianbergmann", - "type": "github" - } - ], - "time": "2023-08-31T06:24:48+00:00" - }, - { - "name": "phpunit/php-invoker", - "version": "4.0.0", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/php-invoker.git", - "reference": "f5e568ba02fa5ba0ddd0f618391d5a9ea50b06d7" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-invoker/zipball/f5e568ba02fa5ba0ddd0f618391d5a9ea50b06d7", - "reference": "f5e568ba02fa5ba0ddd0f618391d5a9ea50b06d7", - "shasum": "" - }, - "require": { - "php": ">=8.1" - }, - "require-dev": { - "ext-pcntl": "*", - "phpunit/phpunit": "^10.0" - }, - "suggest": { - "ext-pcntl": "*" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-main": "4.0-dev" - } - }, - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de", - "role": "lead" - } - ], - "description": "Invoke callables with a timeout", - "homepage": "https://github.com/sebastianbergmann/php-invoker/", - "keywords": [ - "process" - ], - "support": { - "issues": "https://github.com/sebastianbergmann/php-invoker/issues", - "source": "https://github.com/sebastianbergmann/php-invoker/tree/4.0.0" - }, - "funding": [ - { - "url": "https://github.com/sebastianbergmann", - "type": "github" - } - ], - "time": "2023-02-03T06:56:09+00:00" - }, - { - "name": "phpunit/php-text-template", - "version": "3.0.1", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/php-text-template.git", - "reference": "0c7b06ff49e3d5072f057eb1fa59258bf287a748" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-text-template/zipball/0c7b06ff49e3d5072f057eb1fa59258bf287a748", - "reference": "0c7b06ff49e3d5072f057eb1fa59258bf287a748", - "shasum": "" - }, - "require": { - "php": ">=8.1" - }, - "require-dev": { - "phpunit/phpunit": "^10.0" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-main": "3.0-dev" - } - }, - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de", - "role": "lead" - } - ], - "description": "Simple template engine.", - "homepage": "https://github.com/sebastianbergmann/php-text-template/", - "keywords": [ - "template" - ], - "support": { - "issues": "https://github.com/sebastianbergmann/php-text-template/issues", - "security": "https://github.com/sebastianbergmann/php-text-template/security/policy", - "source": "https://github.com/sebastianbergmann/php-text-template/tree/3.0.1" - }, - "funding": [ - { - "url": "https://github.com/sebastianbergmann", - "type": "github" - } - ], - "time": "2023-08-31T14:07:24+00:00" - }, - { - "name": "phpunit/php-timer", - "version": "6.0.0", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/php-timer.git", - "reference": "e2a2d67966e740530f4a3343fe2e030ffdc1161d" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-timer/zipball/e2a2d67966e740530f4a3343fe2e030ffdc1161d", - "reference": "e2a2d67966e740530f4a3343fe2e030ffdc1161d", - "shasum": "" - }, - "require": { - "php": ">=8.1" - }, - "require-dev": { - "phpunit/phpunit": "^10.0" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-main": "6.0-dev" - } - }, - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de", - "role": "lead" - } - ], - "description": "Utility class for timing", - "homepage": "https://github.com/sebastianbergmann/php-timer/", - "keywords": [ - "timer" - ], - "support": { - "issues": "https://github.com/sebastianbergmann/php-timer/issues", - "source": "https://github.com/sebastianbergmann/php-timer/tree/6.0.0" - }, - "funding": [ - { - "url": "https://github.com/sebastianbergmann", - "type": "github" - } - ], - "time": "2023-02-03T06:57:52+00:00" - }, - { - "name": "phpunit/phpunit", - "version": "10.5.63", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/phpunit.git", - "reference": "33198268dad71e926626b618f3ec3966661e4d90" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/33198268dad71e926626b618f3ec3966661e4d90", - "reference": "33198268dad71e926626b618f3ec3966661e4d90", - "shasum": "" - }, - "require": { - "ext-dom": "*", - "ext-json": "*", - "ext-libxml": "*", - "ext-mbstring": "*", - "ext-xml": "*", - "ext-xmlwriter": "*", - "myclabs/deep-copy": "^1.13.4", - "phar-io/manifest": "^2.0.4", - "phar-io/version": "^3.2.1", - "php": ">=8.1", - "phpunit/php-code-coverage": "^10.1.16", - "phpunit/php-file-iterator": "^4.1.0", - "phpunit/php-invoker": "^4.0.0", - "phpunit/php-text-template": "^3.0.1", - "phpunit/php-timer": "^6.0.0", - "sebastian/cli-parser": "^2.0.1", - "sebastian/code-unit": "^2.0.0", - "sebastian/comparator": "^5.0.5", - "sebastian/diff": "^5.1.1", - "sebastian/environment": "^6.1.0", - "sebastian/exporter": "^5.1.4", - "sebastian/global-state": "^6.0.2", - "sebastian/object-enumerator": "^5.0.0", - "sebastian/recursion-context": "^5.0.1", - "sebastian/type": "^4.0.0", - "sebastian/version": "^4.0.1" - }, - "suggest": { - "ext-soap": "To be able to generate mocks based on WSDL files" - }, - "bin": [ - "phpunit" - ], - "type": "library", - "extra": { - "branch-alias": { - "dev-main": "10.5-dev" - } - }, - "autoload": { - "files": [ - "src/Framework/Assert/Functions.php" - ], - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de", - "role": "lead" - } - ], - "description": "The PHP Unit Testing framework.", - "homepage": "https://phpunit.de/", - "keywords": [ - "phpunit", - "testing", - "xunit" - ], - "support": { - "issues": "https://github.com/sebastianbergmann/phpunit/issues", - "security": "https://github.com/sebastianbergmann/phpunit/security/policy", - "source": "https://github.com/sebastianbergmann/phpunit/tree/10.5.63" - }, - "funding": [ - { - "url": "https://phpunit.de/sponsors.html", - "type": "custom" - }, - { - "url": "https://github.com/sebastianbergmann", - "type": "github" - }, - { - "url": "https://liberapay.com/sebastianbergmann", - "type": "liberapay" - }, - { - "url": "https://thanks.dev/u/gh/sebastianbergmann", - "type": "thanks_dev" - }, - { - "url": "https://tidelift.com/funding/github/packagist/phpunit/phpunit", - "type": "tidelift" - } - ], - "time": "2026-01-27T05:48:37+00:00" - }, - { - "name": "react/cache", - "version": "v1.2.0", - "source": { - "type": "git", - "url": "https://github.com/reactphp/cache.git", - "reference": "d47c472b64aa5608225f47965a484b75c7817d5b" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/reactphp/cache/zipball/d47c472b64aa5608225f47965a484b75c7817d5b", - "reference": "d47c472b64aa5608225f47965a484b75c7817d5b", - "shasum": "" - }, - "require": { - "php": ">=5.3.0", - "react/promise": "^3.0 || ^2.0 || ^1.1" - }, - "require-dev": { - "phpunit/phpunit": "^9.5 || ^5.7 || ^4.8.35" - }, - "type": "library", - "autoload": { - "psr-4": { - "React\\Cache\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Christian Lück", - "email": "christian@clue.engineering", - "homepage": "https://clue.engineering/" - }, - { - "name": "Cees-Jan Kiewiet", - "email": "reactphp@ceesjankiewiet.nl", - "homepage": "https://wyrihaximus.net/" - }, - { - "name": "Jan Sorgalla", - "email": "jsorgalla@gmail.com", - "homepage": "https://sorgalla.com/" - }, - { - "name": "Chris Boden", - "email": "cboden@gmail.com", - "homepage": "https://cboden.dev/" - } - ], - "description": "Async, Promise-based cache interface for ReactPHP", - "keywords": [ - "cache", - "caching", - "promise", - "reactphp" - ], - "support": { - "issues": "https://github.com/reactphp/cache/issues", - "source": "https://github.com/reactphp/cache/tree/v1.2.0" - }, - "funding": [ - { - "url": "https://opencollective.com/reactphp", - "type": "open_collective" - } - ], - "time": "2022-11-30T15:59:55+00:00" - }, - { - "name": "react/child-process", - "version": "v0.6.7", - "source": { - "type": "git", - "url": "https://github.com/reactphp/child-process.git", - "reference": "970f0e71945556422ee4570ccbabaedc3cf04ad3" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/reactphp/child-process/zipball/970f0e71945556422ee4570ccbabaedc3cf04ad3", - "reference": "970f0e71945556422ee4570ccbabaedc3cf04ad3", - "shasum": "" - }, - "require": { - "evenement/evenement": "^3.0 || ^2.0 || ^1.0", - "php": ">=5.3.0", - "react/event-loop": "^1.2", - "react/stream": "^1.4" - }, - "require-dev": { - "phpunit/phpunit": "^9.6 || ^5.7 || ^4.8.36", - "react/socket": "^1.16", - "sebastian/environment": "^5.0 || ^3.0 || ^2.0 || ^1.0" - }, - "type": "library", - "autoload": { - "psr-4": { - "React\\ChildProcess\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Christian Lück", - "email": "christian@clue.engineering", - "homepage": "https://clue.engineering/" - }, - { - "name": "Cees-Jan Kiewiet", - "email": "reactphp@ceesjankiewiet.nl", - "homepage": "https://wyrihaximus.net/" - }, - { - "name": "Jan Sorgalla", - "email": "jsorgalla@gmail.com", - "homepage": "https://sorgalla.com/" - }, - { - "name": "Chris Boden", - "email": "cboden@gmail.com", - "homepage": "https://cboden.dev/" - } - ], - "description": "Event-driven library for executing child processes with ReactPHP.", - "keywords": [ - "event-driven", - "process", - "reactphp" - ], - "support": { - "issues": "https://github.com/reactphp/child-process/issues", - "source": "https://github.com/reactphp/child-process/tree/v0.6.7" - }, - "funding": [ - { - "url": "https://opencollective.com/reactphp", - "type": "open_collective" - } - ], - "time": "2025-12-23T15:25:20+00:00" - }, - { - "name": "react/dns", - "version": "v1.14.0", - "source": { - "type": "git", - "url": "https://github.com/reactphp/dns.git", - "reference": "7562c05391f42701c1fccf189c8225fece1cd7c3" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/reactphp/dns/zipball/7562c05391f42701c1fccf189c8225fece1cd7c3", - "reference": "7562c05391f42701c1fccf189c8225fece1cd7c3", - "shasum": "" - }, - "require": { - "php": ">=5.3.0", - "react/cache": "^1.0 || ^0.6 || ^0.5", - "react/event-loop": "^1.2", - "react/promise": "^3.2 || ^2.7 || ^1.2.1" - }, - "require-dev": { - "phpunit/phpunit": "^9.6 || ^5.7 || ^4.8.36", - "react/async": "^4.3 || ^3 || ^2", - "react/promise-timer": "^1.11" - }, - "type": "library", - "autoload": { - "psr-4": { - "React\\Dns\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Christian Lück", - "email": "christian@clue.engineering", - "homepage": "https://clue.engineering/" - }, - { - "name": "Cees-Jan Kiewiet", - "email": "reactphp@ceesjankiewiet.nl", - "homepage": "https://wyrihaximus.net/" - }, - { - "name": "Jan Sorgalla", - "email": "jsorgalla@gmail.com", - "homepage": "https://sorgalla.com/" - }, - { - "name": "Chris Boden", - "email": "cboden@gmail.com", - "homepage": "https://cboden.dev/" - } - ], - "description": "Async DNS resolver for ReactPHP", - "keywords": [ - "async", - "dns", - "dns-resolver", - "reactphp" - ], - "support": { - "issues": "https://github.com/reactphp/dns/issues", - "source": "https://github.com/reactphp/dns/tree/v1.14.0" - }, - "funding": [ - { - "url": "https://opencollective.com/reactphp", - "type": "open_collective" - } - ], - "time": "2025-11-18T19:34:28+00:00" - }, - { - "name": "react/event-loop", - "version": "v1.6.0", - "source": { - "type": "git", - "url": "https://github.com/reactphp/event-loop.git", - "reference": "ba276bda6083df7e0050fd9b33f66ad7a4ac747a" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/reactphp/event-loop/zipball/ba276bda6083df7e0050fd9b33f66ad7a4ac747a", - "reference": "ba276bda6083df7e0050fd9b33f66ad7a4ac747a", - "shasum": "" - }, - "require": { - "php": ">=5.3.0" - }, - "require-dev": { - "phpunit/phpunit": "^9.6 || ^5.7 || ^4.8.36" - }, - "suggest": { - "ext-pcntl": "For signal handling support when using the StreamSelectLoop" - }, - "type": "library", - "autoload": { - "psr-4": { - "React\\EventLoop\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Christian Lück", - "email": "christian@clue.engineering", - "homepage": "https://clue.engineering/" - }, - { - "name": "Cees-Jan Kiewiet", - "email": "reactphp@ceesjankiewiet.nl", - "homepage": "https://wyrihaximus.net/" - }, - { - "name": "Jan Sorgalla", - "email": "jsorgalla@gmail.com", - "homepage": "https://sorgalla.com/" - }, - { - "name": "Chris Boden", - "email": "cboden@gmail.com", - "homepage": "https://cboden.dev/" - } - ], - "description": "ReactPHP's core reactor event loop that libraries can use for evented I/O.", - "keywords": [ - "asynchronous", - "event-loop" - ], - "support": { - "issues": "https://github.com/reactphp/event-loop/issues", - "source": "https://github.com/reactphp/event-loop/tree/v1.6.0" - }, - "funding": [ - { - "url": "https://opencollective.com/reactphp", - "type": "open_collective" - } - ], - "time": "2025-11-17T20:46:25+00:00" - }, - { - "name": "react/promise", - "version": "v3.3.0", - "source": { - "type": "git", - "url": "https://github.com/reactphp/promise.git", - "reference": "23444f53a813a3296c1368bb104793ce8d88f04a" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/reactphp/promise/zipball/23444f53a813a3296c1368bb104793ce8d88f04a", - "reference": "23444f53a813a3296c1368bb104793ce8d88f04a", - "shasum": "" - }, - "require": { - "php": ">=7.1.0" - }, - "require-dev": { - "phpstan/phpstan": "1.12.28 || 1.4.10", - "phpunit/phpunit": "^9.6 || ^7.5" - }, - "type": "library", - "autoload": { - "files": [ - "src/functions_include.php" - ], - "psr-4": { - "React\\Promise\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Jan Sorgalla", - "email": "jsorgalla@gmail.com", - "homepage": "https://sorgalla.com/" - }, - { - "name": "Christian Lück", - "email": "christian@clue.engineering", - "homepage": "https://clue.engineering/" - }, - { - "name": "Cees-Jan Kiewiet", - "email": "reactphp@ceesjankiewiet.nl", - "homepage": "https://wyrihaximus.net/" - }, - { - "name": "Chris Boden", - "email": "cboden@gmail.com", - "homepage": "https://cboden.dev/" - } - ], - "description": "A lightweight implementation of CommonJS Promises/A for PHP", - "keywords": [ - "promise", - "promises" - ], - "support": { - "issues": "https://github.com/reactphp/promise/issues", - "source": "https://github.com/reactphp/promise/tree/v3.3.0" - }, - "funding": [ - { - "url": "https://opencollective.com/reactphp", - "type": "open_collective" - } - ], - "time": "2025-08-19T18:57:03+00:00" - }, - { - "name": "react/socket", - "version": "v1.17.0", - "source": { - "type": "git", - "url": "https://github.com/reactphp/socket.git", - "reference": "ef5b17b81f6f60504c539313f94f2d826c5faa08" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/reactphp/socket/zipball/ef5b17b81f6f60504c539313f94f2d826c5faa08", - "reference": "ef5b17b81f6f60504c539313f94f2d826c5faa08", - "shasum": "" - }, - "require": { - "evenement/evenement": "^3.0 || ^2.0 || ^1.0", - "php": ">=5.3.0", - "react/dns": "^1.13", - "react/event-loop": "^1.2", - "react/promise": "^3.2 || ^2.6 || ^1.2.1", - "react/stream": "^1.4" - }, - "require-dev": { - "phpunit/phpunit": "^9.6 || ^5.7 || ^4.8.36", - "react/async": "^4.3 || ^3.3 || ^2", - "react/promise-stream": "^1.4", - "react/promise-timer": "^1.11" - }, - "type": "library", - "autoload": { - "psr-4": { - "React\\Socket\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Christian Lück", - "email": "christian@clue.engineering", - "homepage": "https://clue.engineering/" - }, - { - "name": "Cees-Jan Kiewiet", - "email": "reactphp@ceesjankiewiet.nl", - "homepage": "https://wyrihaximus.net/" - }, - { - "name": "Jan Sorgalla", - "email": "jsorgalla@gmail.com", - "homepage": "https://sorgalla.com/" - }, - { - "name": "Chris Boden", - "email": "cboden@gmail.com", - "homepage": "https://cboden.dev/" - } - ], - "description": "Async, streaming plaintext TCP/IP and secure TLS socket server and client connections for ReactPHP", - "keywords": [ - "Connection", - "Socket", - "async", - "reactphp", - "stream" - ], - "support": { - "issues": "https://github.com/reactphp/socket/issues", - "source": "https://github.com/reactphp/socket/tree/v1.17.0" - }, - "funding": [ - { - "url": "https://opencollective.com/reactphp", - "type": "open_collective" - } - ], - "time": "2025-11-19T20:47:34+00:00" - }, - { - "name": "react/stream", - "version": "v1.4.0", - "source": { - "type": "git", - "url": "https://github.com/reactphp/stream.git", - "reference": "1e5b0acb8fe55143b5b426817155190eb6f5b18d" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/reactphp/stream/zipball/1e5b0acb8fe55143b5b426817155190eb6f5b18d", - "reference": "1e5b0acb8fe55143b5b426817155190eb6f5b18d", - "shasum": "" - }, - "require": { - "evenement/evenement": "^3.0 || ^2.0 || ^1.0", - "php": ">=5.3.8", - "react/event-loop": "^1.2" - }, - "require-dev": { - "clue/stream-filter": "~1.2", - "phpunit/phpunit": "^9.6 || ^5.7 || ^4.8.36" - }, - "type": "library", - "autoload": { - "psr-4": { - "React\\Stream\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Christian Lück", - "email": "christian@clue.engineering", - "homepage": "https://clue.engineering/" - }, - { - "name": "Cees-Jan Kiewiet", - "email": "reactphp@ceesjankiewiet.nl", - "homepage": "https://wyrihaximus.net/" - }, - { - "name": "Jan Sorgalla", - "email": "jsorgalla@gmail.com", - "homepage": "https://sorgalla.com/" - }, - { - "name": "Chris Boden", - "email": "cboden@gmail.com", - "homepage": "https://cboden.dev/" - } - ], - "description": "Event-driven readable and writable streams for non-blocking I/O in ReactPHP", - "keywords": [ - "event-driven", - "io", - "non-blocking", - "pipe", - "reactphp", - "readable", - "stream", - "writable" - ], - "support": { - "issues": "https://github.com/reactphp/stream/issues", - "source": "https://github.com/reactphp/stream/tree/v1.4.0" - }, - "funding": [ - { - "url": "https://opencollective.com/reactphp", - "type": "open_collective" - } - ], - "time": "2024-06-11T12:45:25+00:00" - }, - { - "name": "rector/rector", - "version": "2.3.8", - "source": { - "type": "git", - "url": "https://github.com/rectorphp/rector.git", - "reference": "bbd37aedd8df749916cffa2a947cfc4714d1ba2c" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/rectorphp/rector/zipball/bbd37aedd8df749916cffa2a947cfc4714d1ba2c", - "reference": "bbd37aedd8df749916cffa2a947cfc4714d1ba2c", - "shasum": "" - }, - "require": { - "php": "^7.4|^8.0", - "phpstan/phpstan": "^2.1.38" - }, - "conflict": { - "rector/rector-doctrine": "*", - "rector/rector-downgrade-php": "*", - "rector/rector-phpunit": "*", - "rector/rector-symfony": "*" - }, - "suggest": { - "ext-dom": "To manipulate phpunit.xml via the custom-rule command" - }, - "bin": [ - "bin/rector" - ], - "type": "library", - "autoload": { - "files": [ - "bootstrap.php" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "description": "Instant Upgrade and Automated Refactoring of any PHP code", - "homepage": "https://getrector.com/", - "keywords": [ - "automation", - "dev", - "migration", - "refactoring" - ], - "support": { - "issues": "https://github.com/rectorphp/rector/issues", - "source": "https://github.com/rectorphp/rector/tree/2.3.8" - }, - "funding": [ - { - "url": "https://github.com/tomasvotruba", - "type": "github" - } - ], - "time": "2026-02-22T09:45:50+00:00" - }, - { - "name": "sebastian/cli-parser", - "version": "2.0.1", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/cli-parser.git", - "reference": "c34583b87e7b7a8055bf6c450c2c77ce32a24084" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/cli-parser/zipball/c34583b87e7b7a8055bf6c450c2c77ce32a24084", - "reference": "c34583b87e7b7a8055bf6c450c2c77ce32a24084", - "shasum": "" - }, - "require": { - "php": ">=8.1" - }, - "require-dev": { - "phpunit/phpunit": "^10.0" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-main": "2.0-dev" - } - }, - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de", - "role": "lead" - } - ], - "description": "Library for parsing CLI options", - "homepage": "https://github.com/sebastianbergmann/cli-parser", - "support": { - "issues": "https://github.com/sebastianbergmann/cli-parser/issues", - "security": "https://github.com/sebastianbergmann/cli-parser/security/policy", - "source": "https://github.com/sebastianbergmann/cli-parser/tree/2.0.1" - }, - "funding": [ - { - "url": "https://github.com/sebastianbergmann", - "type": "github" - } - ], - "time": "2024-03-02T07:12:49+00:00" - }, - { - "name": "sebastian/code-unit", - "version": "2.0.0", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/code-unit.git", - "reference": "a81fee9eef0b7a76af11d121767abc44c104e503" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/code-unit/zipball/a81fee9eef0b7a76af11d121767abc44c104e503", - "reference": "a81fee9eef0b7a76af11d121767abc44c104e503", - "shasum": "" - }, - "require": { - "php": ">=8.1" - }, - "require-dev": { - "phpunit/phpunit": "^10.0" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-main": "2.0-dev" - } - }, - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de", - "role": "lead" - } - ], - "description": "Collection of value objects that represent the PHP code units", - "homepage": "https://github.com/sebastianbergmann/code-unit", - "support": { - "issues": "https://github.com/sebastianbergmann/code-unit/issues", - "source": "https://github.com/sebastianbergmann/code-unit/tree/2.0.0" - }, - "funding": [ - { - "url": "https://github.com/sebastianbergmann", - "type": "github" - } - ], - "time": "2023-02-03T06:58:43+00:00" - }, - { - "name": "sebastian/code-unit-reverse-lookup", - "version": "3.0.0", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/code-unit-reverse-lookup.git", - "reference": "5e3a687f7d8ae33fb362c5c0743794bbb2420a1d" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/code-unit-reverse-lookup/zipball/5e3a687f7d8ae33fb362c5c0743794bbb2420a1d", - "reference": "5e3a687f7d8ae33fb362c5c0743794bbb2420a1d", - "shasum": "" - }, - "require": { - "php": ">=8.1" - }, - "require-dev": { - "phpunit/phpunit": "^10.0" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-main": "3.0-dev" - } - }, - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de" - } - ], - "description": "Looks up which function or method a line of code belongs to", - "homepage": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/", - "support": { - "issues": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/issues", - "source": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/tree/3.0.0" - }, - "funding": [ - { - "url": "https://github.com/sebastianbergmann", - "type": "github" - } - ], - "time": "2023-02-03T06:59:15+00:00" - }, - { - "name": "sebastian/comparator", - "version": "5.0.5", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/comparator.git", - "reference": "55dfef806eb7dfeb6e7a6935601fef866f8ca48d" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/55dfef806eb7dfeb6e7a6935601fef866f8ca48d", - "reference": "55dfef806eb7dfeb6e7a6935601fef866f8ca48d", - "shasum": "" - }, - "require": { - "ext-dom": "*", - "ext-mbstring": "*", - "php": ">=8.1", - "sebastian/diff": "^5.0", - "sebastian/exporter": "^5.0" - }, - "require-dev": { - "phpunit/phpunit": "^10.5" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-main": "5.0-dev" - } - }, - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de" - }, - { - "name": "Jeff Welch", - "email": "whatthejeff@gmail.com" - }, - { - "name": "Volker Dusch", - "email": "github@wallbash.com" - }, - { - "name": "Bernhard Schussek", - "email": "bschussek@2bepublished.at" - } - ], - "description": "Provides the functionality to compare PHP values for equality", - "homepage": "https://github.com/sebastianbergmann/comparator", - "keywords": [ - "comparator", - "compare", - "equality" - ], - "support": { - "issues": "https://github.com/sebastianbergmann/comparator/issues", - "security": "https://github.com/sebastianbergmann/comparator/security/policy", - "source": "https://github.com/sebastianbergmann/comparator/tree/5.0.5" - }, - "funding": [ - { - "url": "https://github.com/sebastianbergmann", - "type": "github" - }, - { - "url": "https://liberapay.com/sebastianbergmann", - "type": "liberapay" - }, - { - "url": "https://thanks.dev/u/gh/sebastianbergmann", - "type": "thanks_dev" - }, - { - "url": "https://tidelift.com/funding/github/packagist/sebastian/comparator", - "type": "tidelift" - } - ], - "time": "2026-01-24T09:25:16+00:00" - }, - { - "name": "sebastian/complexity", - "version": "3.2.0", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/complexity.git", - "reference": "68ff824baeae169ec9f2137158ee529584553799" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/complexity/zipball/68ff824baeae169ec9f2137158ee529584553799", - "reference": "68ff824baeae169ec9f2137158ee529584553799", - "shasum": "" - }, - "require": { - "nikic/php-parser": "^4.18 || ^5.0", - "php": ">=8.1" - }, - "require-dev": { - "phpunit/phpunit": "^10.0" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-main": "3.2-dev" - } - }, - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de", - "role": "lead" - } - ], - "description": "Library for calculating the complexity of PHP code units", - "homepage": "https://github.com/sebastianbergmann/complexity", - "support": { - "issues": "https://github.com/sebastianbergmann/complexity/issues", - "security": "https://github.com/sebastianbergmann/complexity/security/policy", - "source": "https://github.com/sebastianbergmann/complexity/tree/3.2.0" - }, - "funding": [ - { - "url": "https://github.com/sebastianbergmann", - "type": "github" - } - ], - "time": "2023-12-21T08:37:17+00:00" - }, - { - "name": "sebastian/diff", - "version": "5.1.1", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/diff.git", - "reference": "c41e007b4b62af48218231d6c2275e4c9b975b2e" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/c41e007b4b62af48218231d6c2275e4c9b975b2e", - "reference": "c41e007b4b62af48218231d6c2275e4c9b975b2e", - "shasum": "" - }, - "require": { - "php": ">=8.1" - }, - "require-dev": { - "phpunit/phpunit": "^10.0", - "symfony/process": "^6.4" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-main": "5.1-dev" - } - }, - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de" - }, - { - "name": "Kore Nordmann", - "email": "mail@kore-nordmann.de" - } - ], - "description": "Diff implementation", - "homepage": "https://github.com/sebastianbergmann/diff", - "keywords": [ - "diff", - "udiff", - "unidiff", - "unified diff" - ], - "support": { - "issues": "https://github.com/sebastianbergmann/diff/issues", - "security": "https://github.com/sebastianbergmann/diff/security/policy", - "source": "https://github.com/sebastianbergmann/diff/tree/5.1.1" - }, - "funding": [ - { - "url": "https://github.com/sebastianbergmann", - "type": "github" - } - ], - "time": "2024-03-02T07:15:17+00:00" - }, - { - "name": "sebastian/environment", - "version": "6.1.0", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/environment.git", - "reference": "8074dbcd93529b357029f5cc5058fd3e43666984" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/environment/zipball/8074dbcd93529b357029f5cc5058fd3e43666984", - "reference": "8074dbcd93529b357029f5cc5058fd3e43666984", - "shasum": "" - }, - "require": { - "php": ">=8.1" - }, - "require-dev": { - "phpunit/phpunit": "^10.0" - }, - "suggest": { - "ext-posix": "*" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-main": "6.1-dev" - } - }, - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de" - } - ], - "description": "Provides functionality to handle HHVM/PHP environments", - "homepage": "https://github.com/sebastianbergmann/environment", - "keywords": [ - "Xdebug", - "environment", - "hhvm" - ], - "support": { - "issues": "https://github.com/sebastianbergmann/environment/issues", - "security": "https://github.com/sebastianbergmann/environment/security/policy", - "source": "https://github.com/sebastianbergmann/environment/tree/6.1.0" - }, - "funding": [ - { - "url": "https://github.com/sebastianbergmann", - "type": "github" - } - ], - "time": "2024-03-23T08:47:14+00:00" - }, - { - "name": "sebastian/exporter", - "version": "5.1.4", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/exporter.git", - "reference": "0735b90f4da94969541dac1da743446e276defa6" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/0735b90f4da94969541dac1da743446e276defa6", - "reference": "0735b90f4da94969541dac1da743446e276defa6", - "shasum": "" - }, - "require": { - "ext-mbstring": "*", - "php": ">=8.1", - "sebastian/recursion-context": "^5.0" - }, - "require-dev": { - "phpunit/phpunit": "^10.5" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-main": "5.1-dev" - } - }, - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de" - }, - { - "name": "Jeff Welch", - "email": "whatthejeff@gmail.com" - }, - { - "name": "Volker Dusch", - "email": "github@wallbash.com" - }, - { - "name": "Adam Harvey", - "email": "aharvey@php.net" - }, - { - "name": "Bernhard Schussek", - "email": "bschussek@gmail.com" - } - ], - "description": "Provides the functionality to export PHP variables for visualization", - "homepage": "https://www.github.com/sebastianbergmann/exporter", - "keywords": [ - "export", - "exporter" - ], - "support": { - "issues": "https://github.com/sebastianbergmann/exporter/issues", - "security": "https://github.com/sebastianbergmann/exporter/security/policy", - "source": "https://github.com/sebastianbergmann/exporter/tree/5.1.4" - }, - "funding": [ - { - "url": "https://github.com/sebastianbergmann", - "type": "github" - }, - { - "url": "https://liberapay.com/sebastianbergmann", - "type": "liberapay" - }, - { - "url": "https://thanks.dev/u/gh/sebastianbergmann", - "type": "thanks_dev" - }, - { - "url": "https://tidelift.com/funding/github/packagist/sebastian/exporter", - "type": "tidelift" - } - ], - "time": "2025-09-24T06:09:11+00:00" - }, - { - "name": "sebastian/global-state", - "version": "6.0.2", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/global-state.git", - "reference": "987bafff24ecc4c9ac418cab1145b96dd6e9cbd9" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/global-state/zipball/987bafff24ecc4c9ac418cab1145b96dd6e9cbd9", - "reference": "987bafff24ecc4c9ac418cab1145b96dd6e9cbd9", - "shasum": "" - }, - "require": { - "php": ">=8.1", - "sebastian/object-reflector": "^3.0", - "sebastian/recursion-context": "^5.0" - }, - "require-dev": { - "ext-dom": "*", - "phpunit/phpunit": "^10.0" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-main": "6.0-dev" - } - }, - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de" - } - ], - "description": "Snapshotting of global state", - "homepage": "https://www.github.com/sebastianbergmann/global-state", - "keywords": [ - "global state" - ], - "support": { - "issues": "https://github.com/sebastianbergmann/global-state/issues", - "security": "https://github.com/sebastianbergmann/global-state/security/policy", - "source": "https://github.com/sebastianbergmann/global-state/tree/6.0.2" - }, - "funding": [ - { - "url": "https://github.com/sebastianbergmann", - "type": "github" - } - ], - "time": "2024-03-02T07:19:19+00:00" - }, - { - "name": "sebastian/lines-of-code", - "version": "2.0.2", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/lines-of-code.git", - "reference": "856e7f6a75a84e339195d48c556f23be2ebf75d0" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/lines-of-code/zipball/856e7f6a75a84e339195d48c556f23be2ebf75d0", - "reference": "856e7f6a75a84e339195d48c556f23be2ebf75d0", - "shasum": "" - }, - "require": { - "nikic/php-parser": "^4.18 || ^5.0", - "php": ">=8.1" - }, - "require-dev": { - "phpunit/phpunit": "^10.0" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-main": "2.0-dev" - } - }, - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de", - "role": "lead" - } - ], - "description": "Library for counting the lines of code in PHP source code", - "homepage": "https://github.com/sebastianbergmann/lines-of-code", - "support": { - "issues": "https://github.com/sebastianbergmann/lines-of-code/issues", - "security": "https://github.com/sebastianbergmann/lines-of-code/security/policy", - "source": "https://github.com/sebastianbergmann/lines-of-code/tree/2.0.2" - }, - "funding": [ - { - "url": "https://github.com/sebastianbergmann", - "type": "github" - } - ], - "time": "2023-12-21T08:38:20+00:00" - }, - { - "name": "sebastian/object-enumerator", - "version": "5.0.0", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/object-enumerator.git", - "reference": "202d0e344a580d7f7d04b3fafce6933e59dae906" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/object-enumerator/zipball/202d0e344a580d7f7d04b3fafce6933e59dae906", - "reference": "202d0e344a580d7f7d04b3fafce6933e59dae906", - "shasum": "" - }, - "require": { - "php": ">=8.1", - "sebastian/object-reflector": "^3.0", - "sebastian/recursion-context": "^5.0" - }, - "require-dev": { - "phpunit/phpunit": "^10.0" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-main": "5.0-dev" - } - }, - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de" - } - ], - "description": "Traverses array structures and object graphs to enumerate all referenced objects", - "homepage": "https://github.com/sebastianbergmann/object-enumerator/", - "support": { - "issues": "https://github.com/sebastianbergmann/object-enumerator/issues", - "source": "https://github.com/sebastianbergmann/object-enumerator/tree/5.0.0" - }, - "funding": [ - { - "url": "https://github.com/sebastianbergmann", - "type": "github" - } - ], - "time": "2023-02-03T07:08:32+00:00" - }, - { - "name": "sebastian/object-reflector", - "version": "3.0.0", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/object-reflector.git", - "reference": "24ed13d98130f0e7122df55d06c5c4942a577957" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/object-reflector/zipball/24ed13d98130f0e7122df55d06c5c4942a577957", - "reference": "24ed13d98130f0e7122df55d06c5c4942a577957", - "shasum": "" - }, - "require": { - "php": ">=8.1" - }, - "require-dev": { - "phpunit/phpunit": "^10.0" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-main": "3.0-dev" - } - }, - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de" - } - ], - "description": "Allows reflection of object attributes, including inherited and non-public ones", - "homepage": "https://github.com/sebastianbergmann/object-reflector/", - "support": { - "issues": "https://github.com/sebastianbergmann/object-reflector/issues", - "source": "https://github.com/sebastianbergmann/object-reflector/tree/3.0.0" - }, - "funding": [ - { - "url": "https://github.com/sebastianbergmann", - "type": "github" - } - ], - "time": "2023-02-03T07:06:18+00:00" - }, - { - "name": "sebastian/recursion-context", - "version": "5.0.1", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/recursion-context.git", - "reference": "47e34210757a2f37a97dcd207d032e1b01e64c7a" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/recursion-context/zipball/47e34210757a2f37a97dcd207d032e1b01e64c7a", - "reference": "47e34210757a2f37a97dcd207d032e1b01e64c7a", - "shasum": "" - }, - "require": { - "php": ">=8.1" - }, - "require-dev": { - "phpunit/phpunit": "^10.5" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-main": "5.0-dev" - } - }, - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de" - }, - { - "name": "Jeff Welch", - "email": "whatthejeff@gmail.com" - }, - { - "name": "Adam Harvey", - "email": "aharvey@php.net" - } - ], - "description": "Provides functionality to recursively process PHP variables", - "homepage": "https://github.com/sebastianbergmann/recursion-context", - "support": { - "issues": "https://github.com/sebastianbergmann/recursion-context/issues", - "security": "https://github.com/sebastianbergmann/recursion-context/security/policy", - "source": "https://github.com/sebastianbergmann/recursion-context/tree/5.0.1" - }, - "funding": [ - { - "url": "https://github.com/sebastianbergmann", - "type": "github" - }, - { - "url": "https://liberapay.com/sebastianbergmann", - "type": "liberapay" - }, - { - "url": "https://thanks.dev/u/gh/sebastianbergmann", - "type": "thanks_dev" - }, - { - "url": "https://tidelift.com/funding/github/packagist/sebastian/recursion-context", - "type": "tidelift" - } - ], - "time": "2025-08-10T07:50:56+00:00" - }, - { - "name": "sebastian/type", - "version": "4.0.0", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/type.git", - "reference": "462699a16464c3944eefc02ebdd77882bd3925bf" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/type/zipball/462699a16464c3944eefc02ebdd77882bd3925bf", - "reference": "462699a16464c3944eefc02ebdd77882bd3925bf", - "shasum": "" - }, - "require": { - "php": ">=8.1" - }, - "require-dev": { - "phpunit/phpunit": "^10.0" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-main": "4.0-dev" - } - }, - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de", - "role": "lead" - } - ], - "description": "Collection of value objects that represent the types of the PHP type system", - "homepage": "https://github.com/sebastianbergmann/type", - "support": { - "issues": "https://github.com/sebastianbergmann/type/issues", - "source": "https://github.com/sebastianbergmann/type/tree/4.0.0" - }, - "funding": [ - { - "url": "https://github.com/sebastianbergmann", - "type": "github" - } - ], - "time": "2023-02-03T07:10:45+00:00" - }, - { - "name": "sebastian/version", - "version": "4.0.1", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/version.git", - "reference": "c51fa83a5d8f43f1402e3f32a005e6262244ef17" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/version/zipball/c51fa83a5d8f43f1402e3f32a005e6262244ef17", - "reference": "c51fa83a5d8f43f1402e3f32a005e6262244ef17", - "shasum": "" - }, - "require": { - "php": ">=8.1" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-main": "4.0-dev" - } - }, - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de", - "role": "lead" - } - ], - "description": "Library that helps with managing the version number of Git-hosted PHP projects", - "homepage": "https://github.com/sebastianbergmann/version", - "support": { - "issues": "https://github.com/sebastianbergmann/version/issues", - "source": "https://github.com/sebastianbergmann/version/tree/4.0.1" - }, - "funding": [ - { - "url": "https://github.com/sebastianbergmann", - "type": "github" - } - ], - "time": "2023-02-07T11:34:05+00:00" - }, - { - "name": "symfony/polyfill-php80", - "version": "v1.33.0", - "source": { - "type": "git", - "url": "https://github.com/symfony/polyfill-php80.git", - "reference": "0cc9dd0f17f61d8131e7df6b84bd344899fe2608" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/0cc9dd0f17f61d8131e7df6b84bd344899fe2608", - "reference": "0cc9dd0f17f61d8131e7df6b84bd344899fe2608", - "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\\Php80\\": "" - }, - "classmap": [ - "Resources/stubs" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Ion Bazan", - "email": "ion.bazan@gmail.com" - }, - { - "name": "Nicolas Grekas", - "email": "p@tchwork.com" - }, - { - "name": "Symfony Community", - "homepage": "https://symfony.com/contributors" - } - ], - "description": "Symfony polyfill backporting some PHP 8.0+ features to lower PHP versions", - "homepage": "https://symfony.com", - "keywords": [ - "compatibility", - "polyfill", - "portable", - "shim" - ], - "support": { - "source": "https://github.com/symfony/polyfill-php80/tree/v1.33.0" - }, - "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": "2025-01-02T08:10:11+00:00" - }, - { - "name": "symfony/polyfill-php81", - "version": "v1.33.0", - "source": { - "type": "git", - "url": "https://github.com/symfony/polyfill-php81.git", - "reference": "4a4cfc2d253c21a5ad0e53071df248ed48c6ce5c" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-php81/zipball/4a4cfc2d253c21a5ad0e53071df248ed48c6ce5c", - "reference": "4a4cfc2d253c21a5ad0e53071df248ed48c6ce5c", - "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\\Php81\\": "" - }, - "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.1+ features to lower PHP versions", - "homepage": "https://symfony.com", - "keywords": [ - "compatibility", - "polyfill", - "portable", - "shim" - ], - "support": { - "source": "https://github.com/symfony/polyfill-php81/tree/v1.33.0" - }, - "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": "2024-09-09T11:45:10+00:00" - }, - { - "name": "symfony/process", - "version": "v7.4.5", - "source": { - "type": "git", - "url": "https://github.com/symfony/process.git", - "reference": "608476f4604102976d687c483ac63a79ba18cc97" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/process/zipball/608476f4604102976d687c483ac63a79ba18cc97", - "reference": "608476f4604102976d687c483ac63a79ba18cc97", - "shasum": "" - }, - "require": { - "php": ">=8.2" - }, - "type": "library", - "autoload": { - "psr-4": { - "Symfony\\Component\\Process\\": "" - }, - "exclude-from-classmap": [ - "/Tests/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Fabien Potencier", - "email": "fabien@symfony.com" - }, - { - "name": "Symfony Community", - "homepage": "https://symfony.com/contributors" - } - ], - "description": "Executes commands in sub-processes", - "homepage": "https://symfony.com", - "support": { - "source": "https://github.com/symfony/process/tree/v7.4.5" - }, - "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-01-26T15:07:59+00:00" - }, - { - "name": "theseer/tokenizer", - "version": "1.3.1", - "source": { - "type": "git", - "url": "https://github.com/theseer/tokenizer.git", - "reference": "b7489ce515e168639d17feec34b8847c326b0b3c" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/theseer/tokenizer/zipball/b7489ce515e168639d17feec34b8847c326b0b3c", - "reference": "b7489ce515e168639d17feec34b8847c326b0b3c", - "shasum": "" - }, - "require": { - "ext-dom": "*", - "ext-tokenizer": "*", - "ext-xmlwriter": "*", - "php": "^7.2 || ^8.0" - }, - "type": "library", - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Arne Blankerts", - "email": "arne@blankerts.de", - "role": "Developer" - } - ], - "description": "A small library for converting tokenized PHP source code into XML and potentially other formats", - "support": { - "issues": "https://github.com/theseer/tokenizer/issues", - "source": "https://github.com/theseer/tokenizer/tree/1.3.1" - }, - "funding": [ - { - "url": "https://github.com/theseer", - "type": "github" - } - ], - "time": "2025-11-17T20:03:58+00:00" - } - ], - "aliases": [], - "minimum-stability": "alpha", - "stability-flags": {}, - "prefer-stable": true, - "prefer-lowest": false, - "platform": { - "php": "^8.1|^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" -} 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