+ {% if dump.label is defined and '' != dump.label %}
+ {{ dump.label }} in
+ {% endif %}
{% if dump.file %}
{% set link = dump.file|file_link(dump.line) %}
{% if link %}
@@ -45,7 +48,12 @@
{% for dump in collector.getDumps('html') %}
- In
+
+ {% if dump.label is defined and '' != dump.label %}
+ {{ dump.label }} in
+ {% else %}
+ In
+ {% endif %}
{% if dump.line %}
{% set link = dump.file|file_link(dump.line) %}
{% if link %}
diff --git a/src/Symfony/Bundle/FrameworkBundle/CacheWarmer/AnnotationsCacheWarmer.php b/src/Symfony/Bundle/FrameworkBundle/CacheWarmer/AnnotationsCacheWarmer.php
index e489a0bbbec2b..01fd71125ce7b 100644
--- a/src/Symfony/Bundle/FrameworkBundle/CacheWarmer/AnnotationsCacheWarmer.php
+++ b/src/Symfony/Bundle/FrameworkBundle/CacheWarmer/AnnotationsCacheWarmer.php
@@ -32,7 +32,7 @@ class AnnotationsCacheWarmer extends AbstractPhpFileCacheWarmer
/**
* @param string $phpArrayFile The PHP file where annotations are cached
*/
- public function __construct(Reader $annotationReader, string $phpArrayFile, string $excludeRegexp = null, bool $debug = false)
+ public function __construct(Reader $annotationReader, string $phpArrayFile, ?string $excludeRegexp = null, bool $debug = false)
{
parent::__construct($phpArrayFile);
$this->annotationReader = $annotationReader;
diff --git a/src/Symfony/Bundle/FrameworkBundle/CacheWarmer/ConfigBuilderCacheWarmer.php b/src/Symfony/Bundle/FrameworkBundle/CacheWarmer/ConfigBuilderCacheWarmer.php
index 0ed0a93821a76..2b6655aef8eff 100644
--- a/src/Symfony/Bundle/FrameworkBundle/CacheWarmer/ConfigBuilderCacheWarmer.php
+++ b/src/Symfony/Bundle/FrameworkBundle/CacheWarmer/ConfigBuilderCacheWarmer.php
@@ -31,7 +31,7 @@ class ConfigBuilderCacheWarmer implements CacheWarmerInterface
private KernelInterface $kernel;
private ?LoggerInterface $logger;
- public function __construct(KernelInterface $kernel, LoggerInterface $logger = null)
+ public function __construct(KernelInterface $kernel, ?LoggerInterface $logger = null)
{
$this->kernel = $kernel;
$this->logger = $logger;
@@ -42,7 +42,7 @@ public function __construct(KernelInterface $kernel, LoggerInterface $logger = n
*/
public function warmUp(string $cacheDir): array
{
- $generator = new ConfigBuilderGenerator($cacheDir);
+ $generator = new ConfigBuilderGenerator($this->kernel->getBuildDir());
foreach ($this->kernel->getBundles() as $bundle) {
$extension = $bundle->getContainerExtension();
diff --git a/src/Symfony/Bundle/FrameworkBundle/Command/AboutCommand.php b/src/Symfony/Bundle/FrameworkBundle/Command/AboutCommand.php
index 4f68228ee5200..5cc13269ea301 100644
--- a/src/Symfony/Bundle/FrameworkBundle/Command/AboutCommand.php
+++ b/src/Symfony/Bundle/FrameworkBundle/Command/AboutCommand.php
@@ -101,6 +101,10 @@ private static function formatFileSize(string $path): string
if (is_file($path)) {
$size = filesize($path) ?: 0;
} else {
+ if (!is_dir($path)) {
+ return 'n/a';
+ }
+
$size = 0;
foreach (new \RecursiveIteratorIterator(new \RecursiveDirectoryIterator($path, \RecursiveDirectoryIterator::SKIP_DOTS | \RecursiveDirectoryIterator::FOLLOW_SYMLINKS)) as $file) {
if ($file->isReadable()) {
diff --git a/src/Symfony/Bundle/FrameworkBundle/Command/AbstractConfigCommand.php b/src/Symfony/Bundle/FrameworkBundle/Command/AbstractConfigCommand.php
index 5774a7c6f5906..f6f5bb23ba20e 100644
--- a/src/Symfony/Bundle/FrameworkBundle/Command/AbstractConfigCommand.php
+++ b/src/Symfony/Bundle/FrameworkBundle/Command/AbstractConfigCommand.php
@@ -52,6 +52,44 @@ protected function listBundles(OutputInterface|StyleInterface $output)
}
}
+ protected function listNonBundleExtensions(OutputInterface|StyleInterface $output): void
+ {
+ $title = 'Available registered non-bundle extension aliases';
+ $headers = ['Extension alias'];
+ $rows = [];
+
+ $kernel = $this->getApplication()->getKernel();
+
+ $bundleExtensions = [];
+ foreach ($kernel->getBundles() as $bundle) {
+ if ($extension = $bundle->getContainerExtension()) {
+ $bundleExtensions[\get_class($extension)] = true;
+ }
+ }
+
+ $extensions = $this->getContainerBuilder($kernel)->getExtensions();
+
+ foreach ($extensions as $alias => $extension) {
+ if (isset($bundleExtensions[\get_class($extension)])) {
+ continue;
+ }
+ $rows[] = [$alias];
+ }
+
+ if (!$rows) {
+ return;
+ }
+
+ if ($output instanceof StyleInterface) {
+ $output->title($title);
+ $output->table($headers, $rows);
+ } else {
+ $output->writeln($title);
+ $table = new Table($output);
+ $table->setHeaders($headers)->setRows($rows)->render();
+ }
+ }
+
protected function findExtension(string $name): ExtensionInterface
{
$bundles = $this->initializeBundles();
diff --git a/src/Symfony/Bundle/FrameworkBundle/Command/BuildDebugContainerTrait.php b/src/Symfony/Bundle/FrameworkBundle/Command/BuildDebugContainerTrait.php
index 0b1038e1cb424..83268ae71f1ef 100644
--- a/src/Symfony/Bundle/FrameworkBundle/Command/BuildDebugContainerTrait.php
+++ b/src/Symfony/Bundle/FrameworkBundle/Command/BuildDebugContainerTrait.php
@@ -26,7 +26,7 @@
*/
trait BuildDebugContainerTrait
{
- protected $containerBuilder;
+ protected ContainerBuilder $container;
/**
* Loads the ContainerBuilder from the cache.
@@ -35,8 +35,8 @@ trait BuildDebugContainerTrait
*/
protected function getContainerBuilder(KernelInterface $kernel): ContainerBuilder
{
- if ($this->containerBuilder) {
- return $this->containerBuilder;
+ if (isset($this->container)) {
+ return $this->container;
}
if (!$kernel->isDebug() || !$kernel->getContainer()->getParameter('debug.container.dump') || !(new ConfigCache($kernel->getContainer()->getParameter('debug.container.dump'), true))->isFresh()) {
@@ -50,7 +50,14 @@ protected function getContainerBuilder(KernelInterface $kernel): ContainerBuilde
$container->getCompilerPassConfig()->setAfterRemovingPasses([]);
$container->compile();
} else {
- (new XmlFileLoader($container = new ContainerBuilder(), new FileLocator()))->load($kernel->getContainer()->getParameter('debug.container.dump'));
+ $buildContainer = \Closure::bind(function () {
+ $containerBuilder = $this->getContainerBuilder();
+ $this->prepareContainer($containerBuilder);
+
+ return $containerBuilder;
+ }, $kernel, \get_class($kernel));
+ $container = $buildContainer();
+ (new XmlFileLoader($container, new FileLocator()))->load($kernel->getContainer()->getParameter('debug.container.dump'));
$locatorPass = new ServiceLocatorTagPass();
$locatorPass->process($container);
@@ -59,6 +66,6 @@ protected function getContainerBuilder(KernelInterface $kernel): ContainerBuilde
$container->getCompilerPassConfig()->setBeforeRemovingPasses([]);
}
- return $this->containerBuilder = $container;
+ return $this->container = $container;
}
}
diff --git a/src/Symfony/Bundle/FrameworkBundle/Command/CacheClearCommand.php b/src/Symfony/Bundle/FrameworkBundle/Command/CacheClearCommand.php
index 612105dfba59c..0026a69036c77 100644
--- a/src/Symfony/Bundle/FrameworkBundle/Command/CacheClearCommand.php
+++ b/src/Symfony/Bundle/FrameworkBundle/Command/CacheClearCommand.php
@@ -40,7 +40,7 @@ class CacheClearCommand extends Command
private CacheClearerInterface $cacheClearer;
private Filesystem $filesystem;
- public function __construct(CacheClearerInterface $cacheClearer, Filesystem $filesystem = null)
+ public function __construct(CacheClearerInterface $cacheClearer, ?Filesystem $filesystem = null)
{
parent::__construct();
@@ -129,14 +129,7 @@ protected function execute(InputInterface $input, OutputInterface $output): int
if ($output->isVerbose()) {
$io->comment('Warming up optional cache...');
}
- $warmer = $kernel->getContainer()->get('cache_warmer');
- // non optional warmers already ran during container compilation
- $warmer->enableOnlyOptionalWarmers();
- $preload = (array) $warmer->warmUp($realCacheDir, $io);
-
- if ($preload && file_exists($preloadFile = $realCacheDir.'/'.$kernel->getContainer()->getParameter('kernel.container_class').'.preload.php')) {
- Preloader::append($preloadFile, $preload);
- }
+ $this->warmupOptionals($realCacheDir, $realBuildDir, $io);
}
} else {
$fs->mkdir($warmupDir);
@@ -145,7 +138,14 @@ protected function execute(InputInterface $input, OutputInterface $output): int
if ($output->isVerbose()) {
$io->comment('Warming up cache...');
}
- $this->warmup($io, $warmupDir, $realCacheDir, !$input->getOption('no-optional-warmers'));
+ $this->warmup($warmupDir, $realBuildDir);
+
+ if (!$input->getOption('no-optional-warmers')) {
+ if ($output->isVerbose()) {
+ $io->comment('Warming up optional cache...');
+ }
+ $this->warmupOptionals($useBuildDir ? $realCacheDir : $warmupDir, $warmupDir, $io);
+ }
}
if (!$fs->exists($warmupDir.'/'.$containerDir)) {
@@ -219,7 +219,7 @@ private function isNfs(string $dir): bool
return false;
}
- private function warmup(SymfonyStyle $io, string $warmupDir, string $realBuildDir, bool $enableOptionalWarmers = true): void
+ private function warmup(string $warmupDir, string $realBuildDir): void
{
// create a temporary kernel
$kernel = $this->getApplication()->getKernel();
@@ -228,18 +228,6 @@ private function warmup(SymfonyStyle $io, string $warmupDir, string $realBuildDi
}
$kernel->reboot($warmupDir);
- // warmup temporary dir
- if ($enableOptionalWarmers) {
- $warmer = $kernel->getContainer()->get('cache_warmer');
- // non optional warmers already ran during container compilation
- $warmer->enableOnlyOptionalWarmers();
- $preload = (array) $warmer->warmUp($warmupDir, $io);
-
- if ($preload && file_exists($preloadFile = $warmupDir.'/'.$kernel->getContainer()->getParameter('kernel.container_class').'.preload.php')) {
- Preloader::append($preloadFile, $preload);
- }
- }
-
// fix references to cached files with the real cache directory name
$search = [$warmupDir, str_replace('\\', '\\\\', $warmupDir)];
$replace = str_replace('\\', '/', $realBuildDir);
@@ -250,4 +238,17 @@ private function warmup(SymfonyStyle $io, string $warmupDir, string $realBuildDi
}
}
}
+
+ private function warmupOptionals(string $cacheDir, string $warmupDir, SymfonyStyle $io): void
+ {
+ $kernel = $this->getApplication()->getKernel();
+ $warmer = $kernel->getContainer()->get('cache_warmer');
+ // non optional warmers already ran during container compilation
+ $warmer->enableOnlyOptionalWarmers();
+ $preload = (array) $warmer->warmUp($cacheDir, $io);
+
+ if ($preload && file_exists($preloadFile = $warmupDir.'/'.$kernel->getContainer()->getParameter('kernel.container_class').'.preload.php')) {
+ Preloader::append($preloadFile, $preload);
+ }
+ }
}
diff --git a/src/Symfony/Bundle/FrameworkBundle/Command/CachePoolClearCommand.php b/src/Symfony/Bundle/FrameworkBundle/Command/CachePoolClearCommand.php
index 5569a5ab19ffe..b7baf29188a92 100644
--- a/src/Symfony/Bundle/FrameworkBundle/Command/CachePoolClearCommand.php
+++ b/src/Symfony/Bundle/FrameworkBundle/Command/CachePoolClearCommand.php
@@ -38,7 +38,7 @@ final class CachePoolClearCommand extends Command
/**
* @param string[]|null $poolNames
*/
- public function __construct(Psr6CacheClearer $poolClearer, array $poolNames = null)
+ public function __construct(Psr6CacheClearer $poolClearer, ?array $poolNames = null)
{
parent::__construct();
@@ -70,7 +70,7 @@ protected function execute(InputInterface $input, OutputInterface $output): int
$clearers = [];
$poolNames = $input->getArgument('pools');
- if ($input->getOption('all')) {
+ if ($clearAll = $input->getOption('all')) {
if (!$this->poolNames) {
throw new InvalidArgumentException('Could not clear all cache pools, try specifying a specific pool or cache clearer.');
}
@@ -84,7 +84,7 @@ protected function execute(InputInterface $input, OutputInterface $output): int
foreach ($poolNames as $id) {
if ($this->poolClearer->hasPool($id)) {
$pools[$id] = $id;
- } else {
+ } elseif (!$clearAll || $kernel->getContainer()->has($id)) {
$pool = $kernel->getContainer()->get($id);
if ($pool instanceof CacheItemPoolInterface) {
diff --git a/src/Symfony/Bundle/FrameworkBundle/Command/CachePoolDeleteCommand.php b/src/Symfony/Bundle/FrameworkBundle/Command/CachePoolDeleteCommand.php
index 7b53ceb8ba94d..dfa307bc0b73c 100644
--- a/src/Symfony/Bundle/FrameworkBundle/Command/CachePoolDeleteCommand.php
+++ b/src/Symfony/Bundle/FrameworkBundle/Command/CachePoolDeleteCommand.php
@@ -35,7 +35,7 @@ final class CachePoolDeleteCommand extends Command
/**
* @param string[]|null $poolNames
*/
- public function __construct(Psr6CacheClearer $poolClearer, array $poolNames = null)
+ public function __construct(Psr6CacheClearer $poolClearer, ?array $poolNames = null)
{
parent::__construct();
diff --git a/src/Symfony/Bundle/FrameworkBundle/Command/CachePoolInvalidateTagsCommand.php b/src/Symfony/Bundle/FrameworkBundle/Command/CachePoolInvalidateTagsCommand.php
index a69624c8372c4..9e6ef9330e24a 100644
--- a/src/Symfony/Bundle/FrameworkBundle/Command/CachePoolInvalidateTagsCommand.php
+++ b/src/Symfony/Bundle/FrameworkBundle/Command/CachePoolInvalidateTagsCommand.php
@@ -92,12 +92,12 @@ protected function execute(InputInterface $input, OutputInterface $output): int
if ($errors) {
$io->error('Done but with errors.');
- return self::FAILURE;
+ return 1;
}
$io->success('Successfully invalidated cache tags.');
- return self::SUCCESS;
+ return 0;
}
public function complete(CompletionInput $input, CompletionSuggestions $suggestions): void
diff --git a/src/Symfony/Bundle/FrameworkBundle/Command/CacheWarmupCommand.php b/src/Symfony/Bundle/FrameworkBundle/Command/CacheWarmupCommand.php
index d094902c36c55..c40e3938608d8 100644
--- a/src/Symfony/Bundle/FrameworkBundle/Command/CacheWarmupCommand.php
+++ b/src/Symfony/Bundle/FrameworkBundle/Command/CacheWarmupCommand.php
@@ -19,6 +19,7 @@
use Symfony\Component\Console\Style\SymfonyStyle;
use Symfony\Component\DependencyInjection\Dumper\Preloader;
use Symfony\Component\HttpKernel\CacheWarmer\CacheWarmerAggregate;
+use Symfony\Component\HttpKernel\CacheWarmer\WarmableInterface;
/**
* Warmup the cache.
@@ -65,8 +66,13 @@ protected function execute(InputInterface $input, OutputInterface $output): int
if (!$input->getOption('no-optional-warmers')) {
$this->cacheWarmer->enableOptionalWarmers();
}
+ $cacheDir = $kernel->getContainer()->getParameter('kernel.cache_dir');
- $preload = $this->cacheWarmer->warmUp($cacheDir = $kernel->getContainer()->getParameter('kernel.cache_dir'));
+ if ($kernel instanceof WarmableInterface) {
+ $kernel->warmUp($cacheDir);
+ }
+
+ $preload = $this->cacheWarmer->warmUp($cacheDir);
if ($preload && file_exists($preloadFile = $cacheDir.'/'.$kernel->getContainer()->getParameter('kernel.container_class').'.preload.php')) {
Preloader::append($preloadFile, $preload);
diff --git a/src/Symfony/Bundle/FrameworkBundle/Command/ConfigDebugCommand.php b/src/Symfony/Bundle/FrameworkBundle/Command/ConfigDebugCommand.php
index f3eab9d6085cc..3982d78a8be29 100644
--- a/src/Symfony/Bundle/FrameworkBundle/Command/ConfigDebugCommand.php
+++ b/src/Symfony/Bundle/FrameworkBundle/Command/ConfigDebugCommand.php
@@ -49,7 +49,7 @@ protected function configure(): void
new InputArgument('name', InputArgument::OPTIONAL, 'The bundle name or the extension alias'),
new InputArgument('path', InputArgument::OPTIONAL, 'The configuration option path'),
new InputOption('resolve-env', null, InputOption::VALUE_NONE, 'Display resolved environment variable values instead of placeholders'),
- new InputOption('format', null, InputOption::VALUE_REQUIRED, sprintf('The output format ("%s")', implode('", "', $this->getAvailableFormatOptions())), class_exists(Yaml::class) ? 'yaml' : 'json'),
+ new InputOption('format', null, InputOption::VALUE_REQUIRED, sprintf('The output format ("%s")', implode('", "', $this->getAvailableFormatOptions())), class_exists(Yaml::class) ? 'txt' : 'json'),
])
->setHelp(<<%command.name% command dumps the current configuration for an
@@ -81,14 +81,7 @@ protected function execute(InputInterface $input, OutputInterface $output): int
if (null === $name = $input->getArgument('name')) {
$this->listBundles($errorIo);
-
- $kernel = $this->getApplication()->getKernel();
- if ($kernel instanceof ExtensionInterface
- && ($kernel instanceof ConfigurationInterface || $kernel instanceof ConfigurationExtensionInterface)
- && $kernel->getAlias()
- ) {
- $errorIo->table(['Kernel Extension'], [[$kernel->getAlias()]]);
- }
+ $this->listNonBundleExtensions($errorIo);
$errorIo->comment('Provide the name of a bundle as the first argument of this command to dump its configuration. (e.g. debug:config FrameworkBundle)');
$errorIo->comment('For dumping a specific option, add its path as the second argument of this command. (e.g. debug:config FrameworkBundle serializer to dump the framework.serializer configuration)');
@@ -104,16 +97,18 @@ protected function execute(InputInterface $input, OutputInterface $output): int
$format = $input->getOption('format');
- if ('yaml' === $format && !class_exists(Yaml::class)) {
- $errorIo->error('Setting the "format" option to "yaml" requires the Symfony Yaml component. Try running "composer install symfony/yaml" or use "--format=json" instead.');
+ if (\in_array($format, ['txt', 'yml'], true) && !class_exists(Yaml::class)) {
+ $errorIo->error('Setting the "format" option to "txt" or "yaml" requires the Symfony Yaml component. Try running "composer install symfony/yaml" or use "--format=json" instead.');
return 1;
}
if (null === $path = $input->getArgument('path')) {
- $io->title(
- sprintf('Current configuration for %s', $name === $extensionAlias ? sprintf('extension with alias "%s"', $extensionAlias) : sprintf('"%s"', $name))
- );
+ if ('txt' === $input->getOption('format')) {
+ $io->title(
+ sprintf('Current configuration for %s', $name === $extensionAlias ? sprintf('extension with alias "%s"', $extensionAlias) : sprintf('"%s"', $name))
+ );
+ }
$io->writeln($this->convertToFormat([$extensionAlias => $config], $format));
@@ -138,7 +133,7 @@ protected function execute(InputInterface $input, OutputInterface $output): int
private function convertToFormat(mixed $config, string $format): string
{
return match ($format) {
- 'yaml' => Yaml::dump($config, 10),
+ 'txt', 'yaml' => Yaml::dump($config, 10),
'json' => json_encode($config, \JSON_PRETTY_PRINT | \JSON_UNESCAPED_SLASHES | \JSON_UNESCAPED_UNICODE),
default => throw new InvalidArgumentException(sprintf('Supported formats are "%s".', implode('", "', $this->getAvailableFormatOptions()))),
};
@@ -194,12 +189,12 @@ private function getConfigForExtension(ExtensionInterface $extension, ContainerB
// Fall back to default config if the extension has one
- if (!$extension instanceof ConfigurationExtensionInterface) {
+ if (!$extension instanceof ConfigurationExtensionInterface && !$extension instanceof ConfigurationInterface) {
throw new \LogicException(sprintf('The extension with alias "%s" does not have configuration.', $extensionAlias));
}
$configs = $container->getExtensionConfig($extensionAlias);
- $configuration = $extension->getConfiguration($configs, $container);
+ $configuration = $extension instanceof ConfigurationInterface ? $extension : $extension->getConfiguration($configs, $container);
$this->validateConfiguration($extension, $configuration);
return (new Processor())->processConfiguration($configuration, $configs);
@@ -208,7 +203,8 @@ private function getConfigForExtension(ExtensionInterface $extension, ContainerB
public function complete(CompletionInput $input, CompletionSuggestions $suggestions): void
{
if ($input->mustSuggestArgumentValuesFor('name')) {
- $suggestions->suggestValues($this->getAvailableBundles(!preg_match('/^[A-Z]/', $input->getCompletionValue())));
+ $suggestions->suggestValues($this->getAvailableExtensions());
+ $suggestions->suggestValues($this->getAvailableBundles());
return;
}
@@ -227,11 +223,23 @@ public function complete(CompletionInput $input, CompletionSuggestions $suggesti
}
}
- private function getAvailableBundles(bool $alias): array
+ private function getAvailableExtensions(): array
+ {
+ $kernel = $this->getApplication()->getKernel();
+
+ $extensions = [];
+ foreach ($this->getContainerBuilder($kernel)->getExtensions() as $alias => $extension) {
+ $extensions[] = $alias;
+ }
+
+ return $extensions;
+ }
+
+ private function getAvailableBundles(): array
{
$availableBundles = [];
foreach ($this->getApplication()->getKernel()->getBundles() as $bundle) {
- $availableBundles[] = $alias ? $bundle->getContainerExtension()->getAlias() : $bundle->getName();
+ $availableBundles[] = $bundle->getName();
}
return $availableBundles;
@@ -262,6 +270,6 @@ private static function buildPathsCompletion(array $paths, string $prefix = ''):
private function getAvailableFormatOptions(): array
{
- return ['yaml', 'json'];
+ return ['txt', 'yaml', 'json'];
}
}
diff --git a/src/Symfony/Bundle/FrameworkBundle/Command/ConfigDumpReferenceCommand.php b/src/Symfony/Bundle/FrameworkBundle/Command/ConfigDumpReferenceCommand.php
index 11a0668561a22..59219905bf4cd 100644
--- a/src/Symfony/Bundle/FrameworkBundle/Command/ConfigDumpReferenceCommand.php
+++ b/src/Symfony/Bundle/FrameworkBundle/Command/ConfigDumpReferenceCommand.php
@@ -23,8 +23,6 @@
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Style\SymfonyStyle;
-use Symfony\Component\DependencyInjection\Extension\ConfigurationExtensionInterface;
-use Symfony\Component\DependencyInjection\Extension\ExtensionInterface;
use Symfony\Component\Yaml\Yaml;
/**
@@ -83,14 +81,7 @@ protected function execute(InputInterface $input, OutputInterface $output): int
if (null === $name = $input->getArgument('name')) {
$this->listBundles($errorIo);
-
- $kernel = $this->getApplication()->getKernel();
- if ($kernel instanceof ExtensionInterface
- && ($kernel instanceof ConfigurationInterface || $kernel instanceof ConfigurationExtensionInterface)
- && $kernel->getAlias()
- ) {
- $errorIo->table(['Kernel Extension'], [[$kernel->getAlias()]]);
- }
+ $this->listNonBundleExtensions($errorIo);
$errorIo->comment([
'Provide the name of a bundle as the first argument of this command to dump its default configuration. (e.g. config:dump-reference FrameworkBundle)',
@@ -158,6 +149,7 @@ protected function execute(InputInterface $input, OutputInterface $output): int
public function complete(CompletionInput $input, CompletionSuggestions $suggestions): void
{
if ($input->mustSuggestArgumentValuesFor('name')) {
+ $suggestions->suggestValues($this->getAvailableExtensions());
$suggestions->suggestValues($this->getAvailableBundles());
}
@@ -166,13 +158,24 @@ public function complete(CompletionInput $input, CompletionSuggestions $suggesti
}
}
+ private function getAvailableExtensions(): array
+ {
+ $kernel = $this->getApplication()->getKernel();
+
+ $extensions = [];
+ foreach ($this->getContainerBuilder($kernel)->getExtensions() as $alias => $extension) {
+ $extensions[] = $alias;
+ }
+
+ return $extensions;
+ }
+
private function getAvailableBundles(): array
{
$bundles = [];
foreach ($this->getApplication()->getKernel()->getBundles() as $bundle) {
$bundles[] = $bundle->getName();
- $bundles[] = $bundle->getContainerExtension()->getAlias();
}
return $bundles;
diff --git a/src/Symfony/Bundle/FrameworkBundle/Command/ContainerDebugCommand.php b/src/Symfony/Bundle/FrameworkBundle/Command/ContainerDebugCommand.php
index 300fae1b8aa79..cd1af0d5d43c0 100644
--- a/src/Symfony/Bundle/FrameworkBundle/Command/ContainerDebugCommand.php
+++ b/src/Symfony/Bundle/FrameworkBundle/Command/ContainerDebugCommand.php
@@ -261,15 +261,15 @@ protected function validateInput(InputInterface $input): void
}
}
- private function findProperServiceName(InputInterface $input, SymfonyStyle $io, ContainerBuilder $builder, string $name, bool $showHidden): string
+ private function findProperServiceName(InputInterface $input, SymfonyStyle $io, ContainerBuilder $container, string $name, bool $showHidden): string
{
$name = ltrim($name, '\\');
- if ($builder->has($name) || !$input->isInteractive()) {
+ if ($container->has($name) || !$input->isInteractive()) {
return $name;
}
- $matchingServices = $this->findServiceIdsContaining($builder, $name, $showHidden);
+ $matchingServices = $this->findServiceIdsContaining($container, $name, $showHidden);
if (!$matchingServices) {
throw new InvalidArgumentException(sprintf('No services found that match "%s".', $name));
}
@@ -281,13 +281,13 @@ private function findProperServiceName(InputInterface $input, SymfonyStyle $io,
return $io->choice('Select one of the following services to display its information', $matchingServices);
}
- private function findProperTagName(InputInterface $input, SymfonyStyle $io, ContainerBuilder $builder, string $tagName): string
+ private function findProperTagName(InputInterface $input, SymfonyStyle $io, ContainerBuilder $container, string $tagName): string
{
- if (\in_array($tagName, $builder->findTags(), true) || !$input->isInteractive()) {
+ if (\in_array($tagName, $container->findTags(), true) || !$input->isInteractive()) {
return $tagName;
}
- $matchingTags = $this->findTagsContaining($builder, $tagName);
+ $matchingTags = $this->findTagsContaining($container, $tagName);
if (!$matchingTags) {
throw new InvalidArgumentException(sprintf('No tags found that match "%s".', $tagName));
}
@@ -299,15 +299,15 @@ private function findProperTagName(InputInterface $input, SymfonyStyle $io, Cont
return $io->choice('Select one of the following tags to display its information', $matchingTags);
}
- private function findServiceIdsContaining(ContainerBuilder $builder, string $name, bool $showHidden): array
+ private function findServiceIdsContaining(ContainerBuilder $container, string $name, bool $showHidden): array
{
- $serviceIds = $builder->getServiceIds();
+ $serviceIds = $container->getServiceIds();
$foundServiceIds = $foundServiceIdsIgnoringBackslashes = [];
foreach ($serviceIds as $serviceId) {
if (!$showHidden && str_starts_with($serviceId, '.')) {
continue;
}
- if (!$showHidden && $builder->hasDefinition($serviceId) && $builder->getDefinition($serviceId)->hasTag('container.excluded')) {
+ if (!$showHidden && $container->hasDefinition($serviceId) && $container->getDefinition($serviceId)->hasTag('container.excluded')) {
continue;
}
if (false !== stripos(str_replace('\\', '', $serviceId), $name)) {
@@ -321,9 +321,9 @@ private function findServiceIdsContaining(ContainerBuilder $builder, string $nam
return $foundServiceIds ?: $foundServiceIdsIgnoringBackslashes;
}
- private function findTagsContaining(ContainerBuilder $builder, string $tagName): array
+ private function findTagsContaining(ContainerBuilder $container, string $tagName): array
{
- $tags = $builder->findTags();
+ $tags = $container->findTags();
$foundTags = [];
foreach ($tags as $tag) {
if (str_contains($tag, $tagName)) {
diff --git a/src/Symfony/Bundle/FrameworkBundle/Command/ContainerLintCommand.php b/src/Symfony/Bundle/FrameworkBundle/Command/ContainerLintCommand.php
index af08235512e33..b63ebe431787e 100644
--- a/src/Symfony/Bundle/FrameworkBundle/Command/ContainerLintCommand.php
+++ b/src/Symfony/Bundle/FrameworkBundle/Command/ContainerLintCommand.php
@@ -21,6 +21,7 @@
use Symfony\Component\Console\Style\SymfonyStyle;
use Symfony\Component\DependencyInjection\Compiler\CheckTypeDeclarationsPass;
use Symfony\Component\DependencyInjection\Compiler\PassConfig;
+use Symfony\Component\DependencyInjection\Compiler\ResolveFactoryClassPass;
use Symfony\Component\DependencyInjection\Container;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Exception\InvalidArgumentException;
@@ -31,7 +32,7 @@
#[AsCommand(name: 'lint:container', description: 'Ensure that arguments injected into services match type declarations')]
final class ContainerLintCommand extends Command
{
- private ContainerBuilder $containerBuilder;
+ private ContainerBuilder $container;
protected function configure(): void
{
@@ -70,8 +71,8 @@ protected function execute(InputInterface $input, OutputInterface $output): int
private function getContainerBuilder(): ContainerBuilder
{
- if (isset($this->containerBuilder)) {
- return $this->containerBuilder;
+ if (isset($this->container)) {
+ return $this->container;
}
$kernel = $this->getApplication()->getKernel();
@@ -88,8 +89,6 @@ private function getContainerBuilder(): ContainerBuilder
return $this->buildContainer();
}, $kernel, $kernel::class);
$container = $buildContainer();
-
- $skippedIds = [];
} else {
if (!$kernelContainer instanceof Container) {
throw new RuntimeException(sprintf('This command does not support the application container: "%s" does not extend "%s".', get_debug_type($kernelContainer), Container::class));
@@ -100,23 +99,16 @@ private function getContainerBuilder(): ContainerBuilder
$refl = new \ReflectionProperty($parameterBag, 'resolved');
$refl->setValue($parameterBag, true);
- $skippedIds = [];
- foreach ($container->getServiceIds() as $serviceId) {
- if (str_starts_with($serviceId, '.errored.')) {
- $skippedIds[$serviceId] = true;
- }
- }
-
$container->getCompilerPassConfig()->setBeforeOptimizationPasses([]);
- $container->getCompilerPassConfig()->setOptimizationPasses([]);
+ $container->getCompilerPassConfig()->setOptimizationPasses([new ResolveFactoryClassPass()]);
$container->getCompilerPassConfig()->setBeforeRemovingPasses([]);
}
$container->setParameter('container.build_hash', 'lint_container');
$container->setParameter('container.build_id', 'lint_container');
- $container->addCompilerPass(new CheckTypeDeclarationsPass(true, $skippedIds), PassConfig::TYPE_AFTER_REMOVING, -100);
+ $container->addCompilerPass(new CheckTypeDeclarationsPass(true), PassConfig::TYPE_AFTER_REMOVING, -100);
- return $this->containerBuilder = $container;
+ return $this->container = $container;
}
}
diff --git a/src/Symfony/Bundle/FrameworkBundle/Command/DebugAutowiringCommand.php b/src/Symfony/Bundle/FrameworkBundle/Command/DebugAutowiringCommand.php
index 185278a662e1c..f9fa8a4ad7dd7 100644
--- a/src/Symfony/Bundle/FrameworkBundle/Command/DebugAutowiringCommand.php
+++ b/src/Symfony/Bundle/FrameworkBundle/Command/DebugAutowiringCommand.php
@@ -36,7 +36,7 @@ class DebugAutowiringCommand extends ContainerDebugCommand
private bool $supportsHref;
private ?FileLinkFormatter $fileLinkFormatter;
- public function __construct(string $name = null, FileLinkFormatter $fileLinkFormatter = null)
+ public function __construct(?string $name = null, ?FileLinkFormatter $fileLinkFormatter = null)
{
$this->supportsHref = method_exists(OutputFormatterStyle::class, 'setHref');
$this->fileLinkFormatter = $fileLinkFormatter;
@@ -70,8 +70,8 @@ protected function execute(InputInterface $input, OutputInterface $output): int
$io = new SymfonyStyle($input, $output);
$errorIo = $io->getErrorStyle();
- $builder = $this->getContainerBuilder($this->getApplication()->getKernel());
- $serviceIds = $builder->getServiceIds();
+ $container = $this->getContainerBuilder($this->getApplication()->getKernel());
+ $serviceIds = $container->getServiceIds();
$serviceIds = array_filter($serviceIds, $this->filterToServiceTypes(...));
if ($search = $input->getArgument('search')) {
@@ -98,7 +98,7 @@ protected function execute(InputInterface $input, OutputInterface $output): int
$previousId = '-';
$serviceIdsNb = 0;
foreach ($serviceIds as $serviceId) {
- if ($builder->hasDefinition($serviceId) && $builder->getDefinition($serviceId)->hasTag('container.excluded')) {
+ if ($container->hasDefinition($serviceId) && $container->getDefinition($serviceId)->hasTag('container.excluded')) {
continue;
}
$text = [];
@@ -119,11 +119,11 @@ protected function execute(InputInterface $input, OutputInterface $output): int
$serviceLine = sprintf('%s>', $fileLink, $serviceId);
}
- if ($builder->hasAlias($serviceId)) {
+ if ($container->hasAlias($serviceId)) {
$hasAlias[$serviceId] = true;
- $serviceAlias = $builder->getAlias($serviceId);
+ $serviceAlias = $container->getAlias($serviceId);
- if ($builder->hasDefinition($serviceAlias) && $decorated = $builder->getDefinition($serviceAlias)->getTag('container.decorator')) {
+ if ($container->hasDefinition($serviceAlias) && $decorated = $container->getDefinition($serviceAlias)->getTag('container.decorator')) {
$serviceLine .= ' ('.$decorated[0]['id'].')>';
} else {
$serviceLine .= ' ('.$serviceAlias.')>';
@@ -135,7 +135,7 @@ protected function execute(InputInterface $input, OutputInterface $output): int
} elseif (!$all) {
++$serviceIdsNb;
continue;
- } elseif ($builder->getDefinition($serviceId)->isDeprecated()) {
+ } elseif ($container->getDefinition($serviceId)->isDeprecated()) {
$serviceLine .= ' - deprecated>';
}
$text[] = $serviceLine;
@@ -169,9 +169,9 @@ private function getFileLink(string $class): string
public function complete(CompletionInput $input, CompletionSuggestions $suggestions): void
{
if ($input->mustSuggestArgumentValuesFor('search')) {
- $builder = $this->getContainerBuilder($this->getApplication()->getKernel());
+ $container = $this->getContainerBuilder($this->getApplication()->getKernel());
- $suggestions->suggestValues(array_filter($builder->getServiceIds(), $this->filterToServiceTypes(...)));
+ $suggestions->suggestValues(array_filter($container->getServiceIds(), $this->filterToServiceTypes(...)));
}
}
}
diff --git a/src/Symfony/Bundle/FrameworkBundle/Command/RouterDebugCommand.php b/src/Symfony/Bundle/FrameworkBundle/Command/RouterDebugCommand.php
index 27d16e636d9c0..9d948abd75409 100644
--- a/src/Symfony/Bundle/FrameworkBundle/Command/RouterDebugCommand.php
+++ b/src/Symfony/Bundle/FrameworkBundle/Command/RouterDebugCommand.php
@@ -42,7 +42,7 @@ class RouterDebugCommand extends Command
private RouterInterface $router;
private ?FileLinkFormatter $fileLinkFormatter;
- public function __construct(RouterInterface $router, FileLinkFormatter $fileLinkFormatter = null)
+ public function __construct(RouterInterface $router, ?FileLinkFormatter $fileLinkFormatter = null)
{
parent::__construct();
diff --git a/src/Symfony/Bundle/FrameworkBundle/Command/SecretsDecryptToLocalCommand.php b/src/Symfony/Bundle/FrameworkBundle/Command/SecretsDecryptToLocalCommand.php
index 22be8950244de..ac711e3dbd850 100644
--- a/src/Symfony/Bundle/FrameworkBundle/Command/SecretsDecryptToLocalCommand.php
+++ b/src/Symfony/Bundle/FrameworkBundle/Command/SecretsDecryptToLocalCommand.php
@@ -31,7 +31,7 @@ final class SecretsDecryptToLocalCommand extends Command
private AbstractVault $vault;
private ?AbstractVault $localVault;
- public function __construct(AbstractVault $vault, AbstractVault $localVault = null)
+ public function __construct(AbstractVault $vault, ?AbstractVault $localVault = null)
{
$this->vault = $vault;
$this->localVault = $localVault;
diff --git a/src/Symfony/Bundle/FrameworkBundle/Command/SecretsEncryptFromLocalCommand.php b/src/Symfony/Bundle/FrameworkBundle/Command/SecretsEncryptFromLocalCommand.php
index 4c613ef7b27b6..46e0baffc9242 100644
--- a/src/Symfony/Bundle/FrameworkBundle/Command/SecretsEncryptFromLocalCommand.php
+++ b/src/Symfony/Bundle/FrameworkBundle/Command/SecretsEncryptFromLocalCommand.php
@@ -30,7 +30,7 @@ final class SecretsEncryptFromLocalCommand extends Command
private AbstractVault $vault;
private ?AbstractVault $localVault;
- public function __construct(AbstractVault $vault, AbstractVault $localVault = null)
+ public function __construct(AbstractVault $vault, ?AbstractVault $localVault = null)
{
$this->vault = $vault;
$this->localVault = $localVault;
diff --git a/src/Symfony/Bundle/FrameworkBundle/Command/SecretsGenerateKeysCommand.php b/src/Symfony/Bundle/FrameworkBundle/Command/SecretsGenerateKeysCommand.php
index 761f6c260cd7b..989eff9fd2977 100644
--- a/src/Symfony/Bundle/FrameworkBundle/Command/SecretsGenerateKeysCommand.php
+++ b/src/Symfony/Bundle/FrameworkBundle/Command/SecretsGenerateKeysCommand.php
@@ -33,7 +33,7 @@ final class SecretsGenerateKeysCommand extends Command
private AbstractVault $vault;
private ?AbstractVault $localVault;
- public function __construct(AbstractVault $vault, AbstractVault $localVault = null)
+ public function __construct(AbstractVault $vault, ?AbstractVault $localVault = null)
{
$this->vault = $vault;
$this->localVault = $localVault;
diff --git a/src/Symfony/Bundle/FrameworkBundle/Command/SecretsListCommand.php b/src/Symfony/Bundle/FrameworkBundle/Command/SecretsListCommand.php
index 8422d2c91a023..1872014944b91 100644
--- a/src/Symfony/Bundle/FrameworkBundle/Command/SecretsListCommand.php
+++ b/src/Symfony/Bundle/FrameworkBundle/Command/SecretsListCommand.php
@@ -34,7 +34,7 @@ final class SecretsListCommand extends Command
private AbstractVault $vault;
private ?AbstractVault $localVault;
- public function __construct(AbstractVault $vault, AbstractVault $localVault = null)
+ public function __construct(AbstractVault $vault, ?AbstractVault $localVault = null)
{
$this->vault = $vault;
$this->localVault = $localVault;
diff --git a/src/Symfony/Bundle/FrameworkBundle/Command/SecretsRemoveCommand.php b/src/Symfony/Bundle/FrameworkBundle/Command/SecretsRemoveCommand.php
index e03afcd0cf902..1789f2981b11b 100644
--- a/src/Symfony/Bundle/FrameworkBundle/Command/SecretsRemoveCommand.php
+++ b/src/Symfony/Bundle/FrameworkBundle/Command/SecretsRemoveCommand.php
@@ -35,7 +35,7 @@ final class SecretsRemoveCommand extends Command
private AbstractVault $vault;
private ?AbstractVault $localVault;
- public function __construct(AbstractVault $vault, AbstractVault $localVault = null)
+ public function __construct(AbstractVault $vault, ?AbstractVault $localVault = null)
{
$this->vault = $vault;
$this->localVault = $localVault;
diff --git a/src/Symfony/Bundle/FrameworkBundle/Command/SecretsSetCommand.php b/src/Symfony/Bundle/FrameworkBundle/Command/SecretsSetCommand.php
index 0e831a343d2f7..2d2b8c5cb6b42 100644
--- a/src/Symfony/Bundle/FrameworkBundle/Command/SecretsSetCommand.php
+++ b/src/Symfony/Bundle/FrameworkBundle/Command/SecretsSetCommand.php
@@ -36,7 +36,7 @@ final class SecretsSetCommand extends Command
private AbstractVault $vault;
private ?AbstractVault $localVault;
- public function __construct(AbstractVault $vault, AbstractVault $localVault = null)
+ public function __construct(AbstractVault $vault, ?AbstractVault $localVault = null)
{
$this->vault = $vault;
$this->localVault = $localVault;
diff --git a/src/Symfony/Bundle/FrameworkBundle/Command/TranslationDebugCommand.php b/src/Symfony/Bundle/FrameworkBundle/Command/TranslationDebugCommand.php
index 70d3a13e1db84..a5cfc04d7c887 100644
--- a/src/Symfony/Bundle/FrameworkBundle/Command/TranslationDebugCommand.php
+++ b/src/Symfony/Bundle/FrameworkBundle/Command/TranslationDebugCommand.php
@@ -59,7 +59,7 @@ class TranslationDebugCommand extends Command
private array $codePaths;
private array $enabledLocales;
- public function __construct(TranslatorInterface $translator, TranslationReaderInterface $reader, ExtractorInterface $extractor, string $defaultTransPath = null, string $defaultViewsPath = null, array $transPaths = [], array $codePaths = [], array $enabledLocales = [])
+ public function __construct(TranslatorInterface $translator, TranslationReaderInterface $reader, ExtractorInterface $extractor, ?string $defaultTransPath = null, ?string $defaultViewsPath = null, array $transPaths = [], array $codePaths = [], array $enabledLocales = [])
{
parent::__construct();
diff --git a/src/Symfony/Bundle/FrameworkBundle/Command/TranslationUpdateCommand.php b/src/Symfony/Bundle/FrameworkBundle/Command/TranslationUpdateCommand.php
index 15c536ea98a92..7ae3b82bfb0c4 100644
--- a/src/Symfony/Bundle/FrameworkBundle/Command/TranslationUpdateCommand.php
+++ b/src/Symfony/Bundle/FrameworkBundle/Command/TranslationUpdateCommand.php
@@ -60,7 +60,7 @@ class TranslationUpdateCommand extends Command
private array $codePaths;
private array $enabledLocales;
- public function __construct(TranslationWriterInterface $writer, TranslationReaderInterface $reader, ExtractorInterface $extractor, string $defaultLocale, string $defaultTransPath = null, string $defaultViewsPath = null, array $transPaths = [], array $codePaths = [], array $enabledLocales = [])
+ public function __construct(TranslationWriterInterface $writer, TranslationReaderInterface $reader, ExtractorInterface $extractor, string $defaultLocale, ?string $defaultTransPath = null, ?string $defaultViewsPath = null, array $transPaths = [], array $codePaths = [], array $enabledLocales = [])
{
parent::__construct();
diff --git a/src/Symfony/Bundle/FrameworkBundle/Console/Application.php b/src/Symfony/Bundle/FrameworkBundle/Console/Application.php
index cdbb90a3a967a..e35e49b686ee3 100644
--- a/src/Symfony/Bundle/FrameworkBundle/Console/Application.php
+++ b/src/Symfony/Bundle/FrameworkBundle/Console/Application.php
@@ -121,7 +121,7 @@ public function get(string $name): Command
return $command;
}
- public function all(string $namespace = null): array
+ public function all(?string $namespace = null): array
{
$this->registerCommands();
@@ -130,7 +130,7 @@ public function all(string $namespace = null): array
public function getLongVersion(): string
{
- return parent::getLongVersion().sprintf(' (env: %s>, debug: %s>) #StandWith>Ukraine> https://sf.to/ukraine>', $this->kernel->getEnvironment(), $this->kernel->isDebug() ? 'true' : 'false');
+ return parent::getLongVersion().sprintf(' (env: %s>, debug: %s>)', $this->kernel->getEnvironment(), $this->kernel->isDebug() ? 'true' : 'false');
}
public function add(Command $command): ?Command
diff --git a/src/Symfony/Bundle/FrameworkBundle/Console/Descriptor/Descriptor.php b/src/Symfony/Bundle/FrameworkBundle/Console/Descriptor/Descriptor.php
index 7dd2c72206853..d380f06eb5df0 100644
--- a/src/Symfony/Bundle/FrameworkBundle/Console/Descriptor/Descriptor.php
+++ b/src/Symfony/Bundle/FrameworkBundle/Console/Descriptor/Descriptor.php
@@ -84,7 +84,7 @@ abstract protected function describeRoute(Route $route, array $options = []): vo
abstract protected function describeContainerParameters(ParameterBag $parameters, array $options = []): void;
- abstract protected function describeContainerTags(ContainerBuilder $builder, array $options = []): void;
+ abstract protected function describeContainerTags(ContainerBuilder $container, array $options = []): void;
/**
* Describes a container service by its name.
@@ -94,7 +94,7 @@ abstract protected function describeContainerTags(ContainerBuilder $builder, arr
*
* @param Definition|Alias|object $service
*/
- abstract protected function describeContainerService(object $service, array $options = [], ContainerBuilder $builder = null): void;
+ abstract protected function describeContainerService(object $service, array $options = [], ?ContainerBuilder $container = null): void;
/**
* Describes container services.
@@ -102,13 +102,13 @@ abstract protected function describeContainerService(object $service, array $opt
* Common options are:
* * tag: filters described services by given tag
*/
- abstract protected function describeContainerServices(ContainerBuilder $builder, array $options = []): void;
+ abstract protected function describeContainerServices(ContainerBuilder $container, array $options = []): void;
- abstract protected function describeContainerDeprecations(ContainerBuilder $builder, array $options = []): void;
+ abstract protected function describeContainerDeprecations(ContainerBuilder $container, array $options = []): void;
- abstract protected function describeContainerDefinition(Definition $definition, array $options = [], ContainerBuilder $builder = null): void;
+ abstract protected function describeContainerDefinition(Definition $definition, array $options = [], ?ContainerBuilder $container = null): void;
- abstract protected function describeContainerAlias(Alias $alias, array $options = [], ContainerBuilder $builder = null): void;
+ abstract protected function describeContainerAlias(Alias $alias, array $options = [], ?ContainerBuilder $container = null): void;
abstract protected function describeContainerParameter(mixed $parameter, array $options = []): void;
@@ -170,15 +170,15 @@ protected function formatParameter(mixed $value): string
return (string) $value;
}
- protected function resolveServiceDefinition(ContainerBuilder $builder, string $serviceId): mixed
+ protected function resolveServiceDefinition(ContainerBuilder $container, string $serviceId): mixed
{
- if ($builder->hasDefinition($serviceId)) {
- return $builder->getDefinition($serviceId);
+ if ($container->hasDefinition($serviceId)) {
+ return $container->getDefinition($serviceId);
}
// Some service IDs don't have a Definition, they're aliases
- if ($builder->hasAlias($serviceId)) {
- return $builder->getAlias($serviceId);
+ if ($container->hasAlias($serviceId)) {
+ return $container->getAlias($serviceId);
}
if ('service_container' === $serviceId) {
@@ -186,18 +186,18 @@ protected function resolveServiceDefinition(ContainerBuilder $builder, string $s
}
// the service has been injected in some special way, just return the service
- return $builder->get($serviceId);
+ return $container->get($serviceId);
}
- protected function findDefinitionsByTag(ContainerBuilder $builder, bool $showHidden): array
+ protected function findDefinitionsByTag(ContainerBuilder $container, bool $showHidden): array
{
$definitions = [];
- $tags = $builder->findTags();
+ $tags = $container->findTags();
asort($tags);
foreach ($tags as $tag) {
- foreach ($builder->findTaggedServiceIds($tag) as $serviceId => $attributes) {
- $definition = $this->resolveServiceDefinition($builder, $serviceId);
+ foreach ($container->findTaggedServiceIds($tag) as $serviceId => $attributes) {
+ $definition = $this->resolveServiceDefinition($container, $serviceId);
if ($showHidden xor '.' === ($serviceId[0] ?? null)) {
continue;
@@ -263,7 +263,7 @@ protected function sortByPriority(array $tag): array
return $tag;
}
- public static function getClassDescription(string $class, string &$resolvedClass = null): string
+ public static function getClassDescription(string $class, ?string &$resolvedClass = null): string
{
$resolvedClass = $class;
try {
@@ -334,10 +334,13 @@ private function getContainerEnvVars(ContainerBuilder $container): array
return array_values($envs);
}
- protected function getServiceEdges(ContainerBuilder $builder, string $serviceId): array
+ protected function getServiceEdges(ContainerBuilder $container, string $serviceId): array
{
try {
- return array_map(fn (ServiceReferenceGraphEdge $edge) => $edge->getSourceNode()->getId(), $builder->getCompiler()->getServiceReferenceGraph()->getNode($serviceId)->getInEdges());
+ return array_values(array_unique(array_map(
+ fn (ServiceReferenceGraphEdge $edge) => $edge->getSourceNode()->getId(),
+ $container->getCompiler()->getServiceReferenceGraph()->getNode($serviceId)->getInEdges()
+ )));
} catch (InvalidArgumentException $exception) {
return [];
}
diff --git a/src/Symfony/Bundle/FrameworkBundle/Console/Descriptor/JsonDescriptor.php b/src/Symfony/Bundle/FrameworkBundle/Console/Descriptor/JsonDescriptor.php
index 5806fd32f8ad8..5eda4bfc03515 100644
--- a/src/Symfony/Bundle/FrameworkBundle/Console/Descriptor/JsonDescriptor.php
+++ b/src/Symfony/Bundle/FrameworkBundle/Console/Descriptor/JsonDescriptor.php
@@ -52,41 +52,41 @@ protected function describeContainerParameters(ParameterBag $parameters, array $
$this->writeData($this->sortParameters($parameters), $options);
}
- protected function describeContainerTags(ContainerBuilder $builder, array $options = []): void
+ protected function describeContainerTags(ContainerBuilder $container, array $options = []): void
{
$showHidden = isset($options['show_hidden']) && $options['show_hidden'];
$data = [];
- foreach ($this->findDefinitionsByTag($builder, $showHidden) as $tag => $definitions) {
+ foreach ($this->findDefinitionsByTag($container, $showHidden) as $tag => $definitions) {
$data[$tag] = [];
foreach ($definitions as $definition) {
- $data[$tag][] = $this->getContainerDefinitionData($definition, true, false, $builder, $options['id'] ?? null);
+ $data[$tag][] = $this->getContainerDefinitionData($definition, true, false, $container, $options['id'] ?? null);
}
}
$this->writeData($data, $options);
}
- protected function describeContainerService(object $service, array $options = [], ContainerBuilder $builder = null): void
+ protected function describeContainerService(object $service, array $options = [], ?ContainerBuilder $container = null): void
{
if (!isset($options['id'])) {
throw new \InvalidArgumentException('An "id" option must be provided.');
}
if ($service instanceof Alias) {
- $this->describeContainerAlias($service, $options, $builder);
+ $this->describeContainerAlias($service, $options, $container);
} elseif ($service instanceof Definition) {
- $this->writeData($this->getContainerDefinitionData($service, isset($options['omit_tags']) && $options['omit_tags'], isset($options['show_arguments']) && $options['show_arguments'], $builder, $options['id']), $options);
+ $this->writeData($this->getContainerDefinitionData($service, isset($options['omit_tags']) && $options['omit_tags'], isset($options['show_arguments']) && $options['show_arguments'], $container, $options['id']), $options);
} else {
$this->writeData($service::class, $options);
}
}
- protected function describeContainerServices(ContainerBuilder $builder, array $options = []): void
+ protected function describeContainerServices(ContainerBuilder $container, array $options = []): void
{
$serviceIds = isset($options['tag']) && $options['tag']
- ? $this->sortTaggedServicesByPriority($builder->findTaggedServiceIds($options['tag']))
- : $this->sortServiceIds($builder->getServiceIds());
+ ? $this->sortTaggedServicesByPriority($container->findTaggedServiceIds($options['tag']))
+ : $this->sortServiceIds($container->getServiceIds());
$showHidden = isset($options['show_hidden']) && $options['show_hidden'];
$omitTags = isset($options['omit_tags']) && $options['omit_tags'];
$showArguments = isset($options['show_arguments']) && $options['show_arguments'];
@@ -97,7 +97,7 @@ protected function describeContainerServices(ContainerBuilder $builder, array $o
}
foreach ($serviceIds as $serviceId) {
- $service = $this->resolveServiceDefinition($builder, $serviceId);
+ $service = $this->resolveServiceDefinition($container, $serviceId);
if ($showHidden xor '.' === ($serviceId[0] ?? null)) {
continue;
@@ -106,7 +106,10 @@ protected function describeContainerServices(ContainerBuilder $builder, array $o
if ($service instanceof Alias) {
$data['aliases'][$serviceId] = $this->getContainerAliasData($service);
} elseif ($service instanceof Definition) {
- $data['definitions'][$serviceId] = $this->getContainerDefinitionData($service, $omitTags, $showArguments, $builder, $serviceId);
+ if ($service->hasTag('container.excluded')) {
+ continue;
+ }
+ $data['definitions'][$serviceId] = $this->getContainerDefinitionData($service, $omitTags, $showArguments, $container, $serviceId);
} else {
$data['services'][$serviceId] = $service::class;
}
@@ -115,21 +118,21 @@ protected function describeContainerServices(ContainerBuilder $builder, array $o
$this->writeData($data, $options);
}
- protected function describeContainerDefinition(Definition $definition, array $options = [], ContainerBuilder $builder = null): void
+ protected function describeContainerDefinition(Definition $definition, array $options = [], ?ContainerBuilder $container = null): void
{
- $this->writeData($this->getContainerDefinitionData($definition, isset($options['omit_tags']) && $options['omit_tags'], isset($options['show_arguments']) && $options['show_arguments'], $builder, $options['id'] ?? null), $options);
+ $this->writeData($this->getContainerDefinitionData($definition, isset($options['omit_tags']) && $options['omit_tags'], isset($options['show_arguments']) && $options['show_arguments'], $container, $options['id'] ?? null), $options);
}
- protected function describeContainerAlias(Alias $alias, array $options = [], ContainerBuilder $builder = null): void
+ protected function describeContainerAlias(Alias $alias, array $options = [], ?ContainerBuilder $container = null): void
{
- if (!$builder) {
+ if (!$container) {
$this->writeData($this->getContainerAliasData($alias), $options);
return;
}
$this->writeData(
- [$this->getContainerAliasData($alias), $this->getContainerDefinitionData($builder->getDefinition((string) $alias), isset($options['omit_tags']) && $options['omit_tags'], isset($options['show_arguments']) && $options['show_arguments'], $builder, (string) $alias)],
+ [$this->getContainerAliasData($alias), $this->getContainerDefinitionData($container->getDefinition((string) $alias), isset($options['omit_tags']) && $options['omit_tags'], isset($options['show_arguments']) && $options['show_arguments'], $container, (string) $alias)],
array_merge($options, ['id' => (string) $alias])
);
}
@@ -156,9 +159,9 @@ protected function describeContainerEnvVars(array $envs, array $options = []): v
throw new LogicException('Using the JSON format to debug environment variables is not supported.');
}
- protected function describeContainerDeprecations(ContainerBuilder $builder, array $options = []): void
+ protected function describeContainerDeprecations(ContainerBuilder $container, array $options = []): void
{
- $containerDeprecationFilePath = sprintf('%s/%sDeprecations.log', $builder->getParameter('kernel.build_dir'), $builder->getParameter('kernel.container_class'));
+ $containerDeprecationFilePath = sprintf('%s/%sDeprecations.log', $container->getParameter('kernel.build_dir'), $container->getParameter('kernel.container_class'));
if (!file_exists($containerDeprecationFilePath)) {
throw new RuntimeException('The deprecation file does not exist, please try warming the cache first.');
}
@@ -217,7 +220,7 @@ protected function getRouteData(Route $route): array
return $data;
}
- private function getContainerDefinitionData(Definition $definition, bool $omitTags = false, bool $showArguments = false, ContainerBuilder $builder = null, string $id = null): array
+ private function getContainerDefinitionData(Definition $definition, bool $omitTags = false, bool $showArguments = false, ?ContainerBuilder $container = null, ?string $id = null): array
{
$data = [
'class' => (string) $definition->getClass(),
@@ -242,7 +245,7 @@ private function getContainerDefinitionData(Definition $definition, bool $omitTa
}
if ($showArguments) {
- $data['arguments'] = $this->describeValue($definition->getArguments(), $omitTags, $showArguments, $builder, $id);
+ $data['arguments'] = $this->describeValue($definition->getArguments(), $omitTags, $showArguments, $container, $id);
}
$data['file'] = $definition->getFile();
@@ -279,7 +282,7 @@ private function getContainerDefinitionData(Definition $definition, bool $omitTa
}
}
- $data['usages'] = null !== $builder && null !== $id ? $this->getServiceEdges($builder, $id) : [];
+ $data['usages'] = null !== $container && null !== $id ? $this->getServiceEdges($container, $id) : [];
return $data;
}
@@ -390,12 +393,12 @@ private function getCallableData(mixed $callable): array
throw new \InvalidArgumentException('Callable is not describable.');
}
- private function describeValue($value, bool $omitTags, bool $showArguments, ContainerBuilder $builder = null, string $id = null): mixed
+ private function describeValue($value, bool $omitTags, bool $showArguments, ?ContainerBuilder $container = null, ?string $id = null): mixed
{
if (\is_array($value)) {
$data = [];
foreach ($value as $k => $v) {
- $data[$k] = $this->describeValue($v, $omitTags, $showArguments, $builder, $id);
+ $data[$k] = $this->describeValue($v, $omitTags, $showArguments, $container, $id);
}
return $data;
@@ -417,11 +420,11 @@ private function describeValue($value, bool $omitTags, bool $showArguments, Cont
}
if ($value instanceof ArgumentInterface) {
- return $this->describeValue($value->getValues(), $omitTags, $showArguments, $builder, $id);
+ return $this->describeValue($value->getValues(), $omitTags, $showArguments, $container, $id);
}
if ($value instanceof Definition) {
- return $this->getContainerDefinitionData($value, $omitTags, $showArguments, $builder, $id);
+ return $this->getContainerDefinitionData($value, $omitTags, $showArguments, $container, $id);
}
return $value;
diff --git a/src/Symfony/Bundle/FrameworkBundle/Console/Descriptor/MarkdownDescriptor.php b/src/Symfony/Bundle/FrameworkBundle/Console/Descriptor/MarkdownDescriptor.php
index 4581e0e198b99..5036988555409 100644
--- a/src/Symfony/Bundle/FrameworkBundle/Console/Descriptor/MarkdownDescriptor.php
+++ b/src/Symfony/Bundle/FrameworkBundle/Console/Descriptor/MarkdownDescriptor.php
@@ -74,21 +74,21 @@ protected function describeContainerParameters(ParameterBag $parameters, array $
}
}
- protected function describeContainerTags(ContainerBuilder $builder, array $options = []): void
+ protected function describeContainerTags(ContainerBuilder $container, array $options = []): void
{
$showHidden = isset($options['show_hidden']) && $options['show_hidden'];
$this->write("Container tags\n==============");
- foreach ($this->findDefinitionsByTag($builder, $showHidden) as $tag => $definitions) {
+ foreach ($this->findDefinitionsByTag($container, $showHidden) as $tag => $definitions) {
$this->write("\n\n".$tag."\n".str_repeat('-', \strlen($tag)));
foreach ($definitions as $serviceId => $definition) {
$this->write("\n\n");
- $this->describeContainerDefinition($definition, ['omit_tags' => true, 'id' => $serviceId], $builder);
+ $this->describeContainerDefinition($definition, ['omit_tags' => true, 'id' => $serviceId], $container);
}
}
}
- protected function describeContainerService(object $service, array $options = [], ContainerBuilder $builder = null): void
+ protected function describeContainerService(object $service, array $options = [], ?ContainerBuilder $container = null): void
{
if (!isset($options['id'])) {
throw new \InvalidArgumentException('An "id" option must be provided.');
@@ -97,17 +97,17 @@ protected function describeContainerService(object $service, array $options = []
$childOptions = array_merge($options, ['id' => $options['id'], 'as_array' => true]);
if ($service instanceof Alias) {
- $this->describeContainerAlias($service, $childOptions, $builder);
+ $this->describeContainerAlias($service, $childOptions, $container);
} elseif ($service instanceof Definition) {
- $this->describeContainerDefinition($service, $childOptions, $builder);
+ $this->describeContainerDefinition($service, $childOptions, $container);
} else {
$this->write(sprintf('**`%s`:** `%s`', $options['id'], $service::class));
}
}
- protected function describeContainerDeprecations(ContainerBuilder $builder, array $options = []): void
+ protected function describeContainerDeprecations(ContainerBuilder $container, array $options = []): void
{
- $containerDeprecationFilePath = sprintf('%s/%sDeprecations.log', $builder->getParameter('kernel.build_dir'), $builder->getParameter('kernel.container_class'));
+ $containerDeprecationFilePath = sprintf('%s/%sDeprecations.log', $container->getParameter('kernel.build_dir'), $container->getParameter('kernel.container_class'));
if (!file_exists($containerDeprecationFilePath)) {
throw new RuntimeException('The deprecation file does not exist, please try warming the cache first.');
}
@@ -132,7 +132,7 @@ protected function describeContainerDeprecations(ContainerBuilder $builder, arra
}
}
- protected function describeContainerServices(ContainerBuilder $builder, array $options = []): void
+ protected function describeContainerServices(ContainerBuilder $container, array $options = []): void
{
$showHidden = isset($options['show_hidden']) && $options['show_hidden'];
@@ -143,8 +143,8 @@ protected function describeContainerServices(ContainerBuilder $builder, array $o
$this->write($title."\n".str_repeat('=', \strlen($title)));
$serviceIds = isset($options['tag']) && $options['tag']
- ? $this->sortTaggedServicesByPriority($builder->findTaggedServiceIds($options['tag']))
- : $this->sortServiceIds($builder->getServiceIds());
+ ? $this->sortTaggedServicesByPriority($container->findTaggedServiceIds($options['tag']))
+ : $this->sortServiceIds($container->getServiceIds());
$showArguments = isset($options['show_arguments']) && $options['show_arguments'];
$services = ['definitions' => [], 'aliases' => [], 'services' => []];
@@ -153,7 +153,7 @@ protected function describeContainerServices(ContainerBuilder $builder, array $o
}
foreach ($serviceIds as $serviceId) {
- $service = $this->resolveServiceDefinition($builder, $serviceId);
+ $service = $this->resolveServiceDefinition($container, $serviceId);
if ($showHidden xor '.' === ($serviceId[0] ?? null)) {
continue;
@@ -162,6 +162,9 @@ protected function describeContainerServices(ContainerBuilder $builder, array $o
if ($service instanceof Alias) {
$services['aliases'][$serviceId] = $service;
} elseif ($service instanceof Definition) {
+ if ($service->hasTag('container.excluded')) {
+ continue;
+ }
$services['definitions'][$serviceId] = $service;
} else {
$services['services'][$serviceId] = $service;
@@ -172,7 +175,7 @@ protected function describeContainerServices(ContainerBuilder $builder, array $o
$this->write("\n\nDefinitions\n-----------\n");
foreach ($services['definitions'] as $id => $service) {
$this->write("\n");
- $this->describeContainerDefinition($service, ['id' => $id, 'show_arguments' => $showArguments], $builder);
+ $this->describeContainerDefinition($service, ['id' => $id, 'show_arguments' => $showArguments], $container);
}
}
@@ -193,7 +196,7 @@ protected function describeContainerServices(ContainerBuilder $builder, array $o
}
}
- protected function describeContainerDefinition(Definition $definition, array $options = [], ContainerBuilder $builder = null): void
+ protected function describeContainerDefinition(Definition $definition, array $options = [], ?ContainerBuilder $container = null): void
{
$output = '';
@@ -251,19 +254,19 @@ protected function describeContainerDefinition(Definition $definition, array $op
foreach ($tagData as $parameters) {
$output .= "\n".'- Tag: `'.$tagName.'`';
foreach ($parameters as $name => $value) {
- $output .= "\n".' - '.ucfirst($name).': '.$value;
+ $output .= "\n".' - '.ucfirst($name).': '.(\is_array($value) ? $this->formatParameter($value) : $value);
}
}
}
}
- $inEdges = null !== $builder && isset($options['id']) ? $this->getServiceEdges($builder, $options['id']) : [];
+ $inEdges = null !== $container && isset($options['id']) ? $this->getServiceEdges($container, $options['id']) : [];
$output .= "\n".'- Usages: '.($inEdges ? implode(', ', $inEdges) : 'none');
$this->write(isset($options['id']) ? sprintf("### %s\n\n%s\n", $options['id'], $output) : $output);
}
- protected function describeContainerAlias(Alias $alias, array $options = [], ContainerBuilder $builder = null): void
+ protected function describeContainerAlias(Alias $alias, array $options = [], ?ContainerBuilder $container = null): void
{
$output = '- Service: `'.$alias.'`'
."\n".'- Public: '.($alias->isPublic() && !$alias->isPrivate() ? 'yes' : 'no');
@@ -276,12 +279,12 @@ protected function describeContainerAlias(Alias $alias, array $options = [], Con
$this->write(sprintf("### %s\n\n%s\n", $options['id'], $output));
- if (!$builder) {
+ if (!$container) {
return;
}
$this->write("\n");
- $this->describeContainerDefinition($builder->getDefinition((string) $alias), array_merge($options, ['id' => (string) $alias]), $builder);
+ $this->describeContainerDefinition($container->getDefinition((string) $alias), array_merge($options, ['id' => (string) $alias]), $container);
}
protected function describeContainerParameter(mixed $parameter, array $options = []): void
diff --git a/src/Symfony/Bundle/FrameworkBundle/Console/Descriptor/TextDescriptor.php b/src/Symfony/Bundle/FrameworkBundle/Console/Descriptor/TextDescriptor.php
index f555e7220901c..ca6ce5350cd36 100644
--- a/src/Symfony/Bundle/FrameworkBundle/Console/Descriptor/TextDescriptor.php
+++ b/src/Symfony/Bundle/FrameworkBundle/Console/Descriptor/TextDescriptor.php
@@ -39,7 +39,7 @@ class TextDescriptor extends Descriptor
{
private ?FileLinkFormatter $fileLinkFormatter;
- public function __construct(FileLinkFormatter $fileLinkFormatter = null)
+ public function __construct(?FileLinkFormatter $fileLinkFormatter = null)
{
$this->fileLinkFormatter = $fileLinkFormatter;
}
@@ -125,7 +125,7 @@ protected function describeContainerParameters(ParameterBag $parameters, array $
$options['output']->table($tableHeaders, $tableRows);
}
- protected function describeContainerTags(ContainerBuilder $builder, array $options = []): void
+ protected function describeContainerTags(ContainerBuilder $container, array $options = []): void
{
$showHidden = isset($options['show_hidden']) && $options['show_hidden'];
@@ -135,22 +135,22 @@ protected function describeContainerTags(ContainerBuilder $builder, array $optio
$options['output']->title('Symfony Container Tags');
}
- foreach ($this->findDefinitionsByTag($builder, $showHidden) as $tag => $definitions) {
+ foreach ($this->findDefinitionsByTag($container, $showHidden) as $tag => $definitions) {
$options['output']->section(sprintf('"%s" tag', $tag));
$options['output']->listing(array_keys($definitions));
}
}
- protected function describeContainerService(object $service, array $options = [], ContainerBuilder $builder = null): void
+ protected function describeContainerService(object $service, array $options = [], ?ContainerBuilder $container = null): void
{
if (!isset($options['id'])) {
throw new \InvalidArgumentException('An "id" option must be provided.');
}
if ($service instanceof Alias) {
- $this->describeContainerAlias($service, $options, $builder);
+ $this->describeContainerAlias($service, $options, $container);
} elseif ($service instanceof Definition) {
- $this->describeContainerDefinition($service, $options, $builder);
+ $this->describeContainerDefinition($service, $options, $container);
} else {
$options['output']->title(sprintf('Information for Service "%s"', $options['id']));
$options['output']->table(
@@ -162,7 +162,7 @@ protected function describeContainerService(object $service, array $options = []
}
}
- protected function describeContainerServices(ContainerBuilder $builder, array $options = []): void
+ protected function describeContainerServices(ContainerBuilder $container, array $options = []): void
{
$showHidden = isset($options['show_hidden']) && $options['show_hidden'];
$showTag = $options['tag'] ?? null;
@@ -180,8 +180,8 @@ protected function describeContainerServices(ContainerBuilder $builder, array $o
$options['output']->title($title);
$serviceIds = isset($options['tag']) && $options['tag']
- ? $this->sortTaggedServicesByPriority($builder->findTaggedServiceIds($options['tag']))
- : $this->sortServiceIds($builder->getServiceIds());
+ ? $this->sortTaggedServicesByPriority($container->findTaggedServiceIds($options['tag']))
+ : $this->sortServiceIds($container->getServiceIds());
$maxTags = [];
if (isset($options['filter'])) {
@@ -189,7 +189,7 @@ protected function describeContainerServices(ContainerBuilder $builder, array $o
}
foreach ($serviceIds as $key => $serviceId) {
- $definition = $this->resolveServiceDefinition($builder, $serviceId);
+ $definition = $this->resolveServiceDefinition($container, $serviceId);
// filter out hidden services unless shown explicitly
if ($showHidden xor '.' === ($serviceId[0] ?? null)) {
@@ -198,6 +198,10 @@ protected function describeContainerServices(ContainerBuilder $builder, array $o
}
if ($definition instanceof Definition) {
+ if ($definition->hasTag('container.excluded')) {
+ unset($serviceIds[$key]);
+ continue;
+ }
if ($showTag) {
$tags = $definition->getTag($showTag);
foreach ($tags as $tag) {
@@ -205,6 +209,10 @@ protected function describeContainerServices(ContainerBuilder $builder, array $o
if (!isset($maxTags[$key])) {
$maxTags[$key] = \strlen($key);
}
+ if (\is_array($value)) {
+ $value = $this->formatParameter($value);
+ }
+
if (\strlen($value) > $maxTags[$key]) {
$maxTags[$key] = \strlen($value);
}
@@ -221,7 +229,7 @@ protected function describeContainerServices(ContainerBuilder $builder, array $o
$tableRows = [];
$rawOutput = isset($options['raw_text']) && $options['raw_text'];
foreach ($serviceIds as $serviceId) {
- $definition = $this->resolveServiceDefinition($builder, $serviceId);
+ $definition = $this->resolveServiceDefinition($container, $serviceId);
$styledServiceId = $rawOutput ? $serviceId : sprintf('%s', OutputFormatter::escape($serviceId));
if ($definition instanceof Definition) {
@@ -229,7 +237,11 @@ protected function describeContainerServices(ContainerBuilder $builder, array $o
foreach ($this->sortByPriority($definition->getTag($showTag)) as $key => $tag) {
$tagValues = [];
foreach ($tagsNames as $tagName) {
- $tagValues[] = $tag[$tagName] ?? '';
+ if (\is_array($tagValue = $tag[$tagName] ?? '')) {
+ $tagValue = $this->formatParameter($tagValue);
+ }
+
+ $tagValues[] = $tagValue;
}
if (0 === $key) {
$tableRows[] = array_merge([$serviceId], $tagValues, [$definition->getClass()]);
@@ -251,7 +263,7 @@ protected function describeContainerServices(ContainerBuilder $builder, array $o
$options['output']->table($tableHeaders, $tableRows);
}
- protected function describeContainerDefinition(Definition $definition, array $options = [], ContainerBuilder $builder = null): void
+ protected function describeContainerDefinition(Definition $definition, array $options = [], ?ContainerBuilder $container = null): void
{
if (isset($options['id'])) {
$options['output']->title(sprintf('Information for Service "%s"', $options['id']));
@@ -271,7 +283,7 @@ protected function describeContainerDefinition(Definition $definition, array $op
$tagInformation = [];
foreach ($tags as $tagName => $tagData) {
foreach ($tagData as $tagParameters) {
- $parameters = array_map(fn ($key, $value) => sprintf('%s: %s', $key, $value), array_keys($tagParameters), array_values($tagParameters));
+ $parameters = array_map(fn ($key, $value) => sprintf('%s: %s', $key, \is_array($value) ? $this->formatParameter($value) : $value), array_keys($tagParameters), array_values($tagParameters));
$parameters = implode(', ', $parameters);
if ('' === $parameters) {
@@ -358,15 +370,15 @@ protected function describeContainerDefinition(Definition $definition, array $op
$tableRows[] = ['Arguments', implode("\n", $argumentsInformation)];
}
- $inEdges = null !== $builder && isset($options['id']) ? $this->getServiceEdges($builder, $options['id']) : [];
+ $inEdges = null !== $container && isset($options['id']) ? $this->getServiceEdges($container, $options['id']) : [];
$tableRows[] = ['Usages', $inEdges ? implode(\PHP_EOL, $inEdges) : 'none'];
$options['output']->table($tableHeaders, $tableRows);
}
- protected function describeContainerDeprecations(ContainerBuilder $builder, array $options = []): void
+ protected function describeContainerDeprecations(ContainerBuilder $container, array $options = []): void
{
- $containerDeprecationFilePath = sprintf('%s/%sDeprecations.log', $builder->getParameter('kernel.build_dir'), $builder->getParameter('kernel.container_class'));
+ $containerDeprecationFilePath = sprintf('%s/%sDeprecations.log', $container->getParameter('kernel.build_dir'), $container->getParameter('kernel.container_class'));
if (!file_exists($containerDeprecationFilePath)) {
$options['output']->warning('The deprecation file does not exist, please try warming the cache first.');
@@ -390,7 +402,7 @@ protected function describeContainerDeprecations(ContainerBuilder $builder, arra
$options['output']->listing($formattedLogs);
}
- protected function describeContainerAlias(Alias $alias, array $options = [], ContainerBuilder $builder = null): void
+ protected function describeContainerAlias(Alias $alias, array $options = [], ?ContainerBuilder $container = null): void
{
if ($alias->isPublic() && !$alias->isPrivate()) {
$options['output']->comment(sprintf('This service is a public alias for the service %s', (string) $alias));
@@ -398,11 +410,11 @@ protected function describeContainerAlias(Alias $alias, array $options = [], Con
$options['output']->comment(sprintf('This service is a private alias for the service %s', (string) $alias));
}
- if (!$builder) {
+ if (!$container) {
return;
}
- $this->describeContainerDefinition($builder->getDefinition((string) $alias), array_merge($options, ['id' => (string) $alias]), $builder);
+ $this->describeContainerDefinition($container->getDefinition((string) $alias), array_merge($options, ['id' => (string) $alias]), $container);
}
protected function describeContainerParameter(mixed $parameter, array $options = []): void
@@ -542,7 +554,7 @@ private function formatRouterConfig(array $config): string
return trim($configAsString);
}
- private function formatControllerLink(mixed $controller, string $anchorText, callable $getContainer = null): string
+ private function formatControllerLink(mixed $controller, string $anchorText, ?callable $getContainer = null): string
{
if (null === $this->fileLinkFormatter) {
return $anchorText;
diff --git a/src/Symfony/Bundle/FrameworkBundle/Console/Descriptor/XmlDescriptor.php b/src/Symfony/Bundle/FrameworkBundle/Console/Descriptor/XmlDescriptor.php
index 17870bb96a69b..c15ccde164321 100644
--- a/src/Symfony/Bundle/FrameworkBundle/Console/Descriptor/XmlDescriptor.php
+++ b/src/Symfony/Bundle/FrameworkBundle/Console/Descriptor/XmlDescriptor.php
@@ -48,42 +48,42 @@ protected function describeContainerParameters(ParameterBag $parameters, array $
$this->writeDocument($this->getContainerParametersDocument($parameters));
}
- protected function describeContainerTags(ContainerBuilder $builder, array $options = []): void
+ protected function describeContainerTags(ContainerBuilder $container, array $options = []): void
{
- $this->writeDocument($this->getContainerTagsDocument($builder, isset($options['show_hidden']) && $options['show_hidden']));
+ $this->writeDocument($this->getContainerTagsDocument($container, isset($options['show_hidden']) && $options['show_hidden']));
}
- protected function describeContainerService(object $service, array $options = [], ContainerBuilder $builder = null): void
+ protected function describeContainerService(object $service, array $options = [], ?ContainerBuilder $container = null): void
{
if (!isset($options['id'])) {
throw new \InvalidArgumentException('An "id" option must be provided.');
}
- $this->writeDocument($this->getContainerServiceDocument($service, $options['id'], $builder, isset($options['show_arguments']) && $options['show_arguments']));
+ $this->writeDocument($this->getContainerServiceDocument($service, $options['id'], $container, isset($options['show_arguments']) && $options['show_arguments']));
}
- protected function describeContainerServices(ContainerBuilder $builder, array $options = []): void
+ protected function describeContainerServices(ContainerBuilder $container, array $options = []): void
{
- $this->writeDocument($this->getContainerServicesDocument($builder, $options['tag'] ?? null, isset($options['show_hidden']) && $options['show_hidden'], isset($options['show_arguments']) && $options['show_arguments'], $options['filter'] ?? null, $options['id'] ?? null));
+ $this->writeDocument($this->getContainerServicesDocument($container, $options['tag'] ?? null, isset($options['show_hidden']) && $options['show_hidden'], isset($options['show_arguments']) && $options['show_arguments'], $options['filter'] ?? null, $options['id'] ?? null));
}
- protected function describeContainerDefinition(Definition $definition, array $options = [], ContainerBuilder $builder = null): void
+ protected function describeContainerDefinition(Definition $definition, array $options = [], ?ContainerBuilder $container = null): void
{
- $this->writeDocument($this->getContainerDefinitionDocument($definition, $options['id'] ?? null, isset($options['omit_tags']) && $options['omit_tags'], isset($options['show_arguments']) && $options['show_arguments'], $builder));
+ $this->writeDocument($this->getContainerDefinitionDocument($definition, $options['id'] ?? null, isset($options['omit_tags']) && $options['omit_tags'], isset($options['show_arguments']) && $options['show_arguments'], $container));
}
- protected function describeContainerAlias(Alias $alias, array $options = [], ContainerBuilder $builder = null): void
+ protected function describeContainerAlias(Alias $alias, array $options = [], ?ContainerBuilder $container = null): void
{
$dom = new \DOMDocument('1.0', 'UTF-8');
$dom->appendChild($dom->importNode($this->getContainerAliasDocument($alias, $options['id'] ?? null)->childNodes->item(0), true));
- if (!$builder) {
+ if (!$container) {
$this->writeDocument($dom);
return;
}
- $dom->appendChild($dom->importNode($this->getContainerDefinitionDocument($builder->getDefinition((string) $alias), (string) $alias, false, false, $builder)->childNodes->item(0), true));
+ $dom->appendChild($dom->importNode($this->getContainerDefinitionDocument($container->getDefinition((string) $alias), (string) $alias, false, false, $container)->childNodes->item(0), true));
$this->writeDocument($dom);
}
@@ -108,9 +108,9 @@ protected function describeContainerEnvVars(array $envs, array $options = []): v
throw new LogicException('Using the XML format to debug environment variables is not supported.');
}
- protected function describeContainerDeprecations(ContainerBuilder $builder, array $options = []): void
+ protected function describeContainerDeprecations(ContainerBuilder $container, array $options = []): void
{
- $containerDeprecationFilePath = sprintf('%s/%sDeprecations.log', $builder->getParameter('kernel.build_dir'), $builder->getParameter('kernel.container_class'));
+ $containerDeprecationFilePath = sprintf('%s/%sDeprecations.log', $container->getParameter('kernel.build_dir'), $container->getParameter('kernel.container_class'));
if (!file_exists($containerDeprecationFilePath)) {
throw new RuntimeException('The deprecation file does not exist, please try warming the cache first.');
}
@@ -154,7 +154,7 @@ private function getRouteCollectionDocument(RouteCollection $routes): \DOMDocume
return $dom;
}
- private function getRouteDocument(Route $route, string $name = null): \DOMDocument
+ private function getRouteDocument(Route $route, ?string $name = null): \DOMDocument
{
$dom = new \DOMDocument('1.0', 'UTF-8');
$dom->appendChild($routeXML = $dom->createElement('route'));
@@ -236,17 +236,17 @@ private function getContainerParametersDocument(ParameterBag $parameters): \DOMD
return $dom;
}
- private function getContainerTagsDocument(ContainerBuilder $builder, bool $showHidden = false): \DOMDocument
+ private function getContainerTagsDocument(ContainerBuilder $container, bool $showHidden = false): \DOMDocument
{
$dom = new \DOMDocument('1.0', 'UTF-8');
$dom->appendChild($containerXML = $dom->createElement('container'));
- foreach ($this->findDefinitionsByTag($builder, $showHidden) as $tag => $definitions) {
+ foreach ($this->findDefinitionsByTag($container, $showHidden) as $tag => $definitions) {
$containerXML->appendChild($tagXML = $dom->createElement('tag'));
$tagXML->setAttribute('name', $tag);
foreach ($definitions as $serviceId => $definition) {
- $definitionXML = $this->getContainerDefinitionDocument($definition, $serviceId, true, false, $builder);
+ $definitionXML = $this->getContainerDefinitionDocument($definition, $serviceId, true, false, $container);
$tagXML->appendChild($dom->importNode($definitionXML->childNodes->item(0), true));
}
}
@@ -254,17 +254,17 @@ private function getContainerTagsDocument(ContainerBuilder $builder, bool $showH
return $dom;
}
- private function getContainerServiceDocument(object $service, string $id, ContainerBuilder $builder = null, bool $showArguments = false): \DOMDocument
+ private function getContainerServiceDocument(object $service, string $id, ?ContainerBuilder $container = null, bool $showArguments = false): \DOMDocument
{
$dom = new \DOMDocument('1.0', 'UTF-8');
if ($service instanceof Alias) {
$dom->appendChild($dom->importNode($this->getContainerAliasDocument($service, $id)->childNodes->item(0), true));
- if ($builder) {
- $dom->appendChild($dom->importNode($this->getContainerDefinitionDocument($builder->getDefinition((string) $service), (string) $service, false, $showArguments, $builder)->childNodes->item(0), true));
+ if ($container) {
+ $dom->appendChild($dom->importNode($this->getContainerDefinitionDocument($container->getDefinition((string) $service), (string) $service, false, $showArguments, $container)->childNodes->item(0), true));
}
} elseif ($service instanceof Definition) {
- $dom->appendChild($dom->importNode($this->getContainerDefinitionDocument($service, $id, false, $showArguments, $builder)->childNodes->item(0), true));
+ $dom->appendChild($dom->importNode($this->getContainerDefinitionDocument($service, $id, false, $showArguments, $container)->childNodes->item(0), true));
} else {
$dom->appendChild($serviceXML = $dom->createElement('service'));
$serviceXML->setAttribute('id', $id);
@@ -274,25 +274,29 @@ private function getContainerServiceDocument(object $service, string $id, Contai
return $dom;
}
- private function getContainerServicesDocument(ContainerBuilder $builder, string $tag = null, bool $showHidden = false, bool $showArguments = false, callable $filter = null, string $id = null): \DOMDocument
+ private function getContainerServicesDocument(ContainerBuilder $container, ?string $tag = null, bool $showHidden = false, bool $showArguments = false, ?callable $filter = null, ?string $id = null): \DOMDocument
{
$dom = new \DOMDocument('1.0', 'UTF-8');
$dom->appendChild($containerXML = $dom->createElement('container'));
$serviceIds = $tag
- ? $this->sortTaggedServicesByPriority($builder->findTaggedServiceIds($tag))
- : $this->sortServiceIds($builder->getServiceIds());
+ ? $this->sortTaggedServicesByPriority($container->findTaggedServiceIds($tag))
+ : $this->sortServiceIds($container->getServiceIds());
if ($filter) {
$serviceIds = array_filter($serviceIds, $filter);
}
foreach ($serviceIds as $serviceId) {
- $service = $this->resolveServiceDefinition($builder, $serviceId);
+ $service = $this->resolveServiceDefinition($container, $serviceId);
if ($showHidden xor '.' === ($serviceId[0] ?? null)) {
continue;
}
+ if ($service instanceof Definition && $service->hasTag('container.excluded')) {
+ continue;
+ }
+
$serviceXML = $this->getContainerServiceDocument($service, $serviceId, null, $showArguments);
$containerXML->appendChild($containerXML->ownerDocument->importNode($serviceXML->childNodes->item(0), true));
}
@@ -300,7 +304,7 @@ private function getContainerServicesDocument(ContainerBuilder $builder, string
return $dom;
}
- private function getContainerDefinitionDocument(Definition $definition, string $id = null, bool $omitTags = false, bool $showArguments = false, ContainerBuilder $builder = null): \DOMDocument
+ private function getContainerDefinitionDocument(Definition $definition, ?string $id = null, bool $omitTags = false, bool $showArguments = false, ?ContainerBuilder $container = null): \DOMDocument
{
$dom = new \DOMDocument('1.0', 'UTF-8');
$dom->appendChild($serviceXML = $dom->createElement('definition'));
@@ -361,7 +365,7 @@ private function getContainerDefinitionDocument(Definition $definition, string $
}
if ($showArguments) {
- foreach ($this->getArgumentNodes($definition->getArguments(), $dom, $builder) as $node) {
+ foreach ($this->getArgumentNodes($definition->getArguments(), $dom, $container) as $node) {
$serviceXML->appendChild($node);
}
}
@@ -383,8 +387,8 @@ private function getContainerDefinitionDocument(Definition $definition, string $
}
}
- if (null !== $builder && null !== $id) {
- $edges = $this->getServiceEdges($builder, $id);
+ if (null !== $container && null !== $id) {
+ $edges = $this->getServiceEdges($container, $id);
if ($edges) {
$serviceXML->appendChild($usagesXML = $dom->createElement('usages'));
foreach ($edges as $edge) {
@@ -400,7 +404,7 @@ private function getContainerDefinitionDocument(Definition $definition, string $
/**
* @return \DOMNode[]
*/
- private function getArgumentNodes(array $arguments, \DOMDocument $dom, ContainerBuilder $builder = null): array
+ private function getArgumentNodes(array $arguments, \DOMDocument $dom, ?ContainerBuilder $container = null): array
{
$nodes = [];
@@ -421,18 +425,18 @@ private function getArgumentNodes(array $arguments, \DOMDocument $dom, Container
} elseif ($argument instanceof IteratorArgument || $argument instanceof ServiceLocatorArgument) {
$argumentXML->setAttribute('type', $argument instanceof IteratorArgument ? 'iterator' : 'service_locator');
- foreach ($this->getArgumentNodes($argument->getValues(), $dom, $builder) as $childArgumentXML) {
+ foreach ($this->getArgumentNodes($argument->getValues(), $dom, $container) as $childArgumentXML) {
$argumentXML->appendChild($childArgumentXML);
}
} elseif ($argument instanceof Definition) {
- $argumentXML->appendChild($dom->importNode($this->getContainerDefinitionDocument($argument, null, false, true, $builder)->childNodes->item(0), true));
+ $argumentXML->appendChild($dom->importNode($this->getContainerDefinitionDocument($argument, null, false, true, $container)->childNodes->item(0), true));
} elseif ($argument instanceof AbstractArgument) {
$argumentXML->setAttribute('type', 'abstract');
$argumentXML->appendChild(new \DOMText($argument->getText()));
} elseif (\is_array($argument)) {
$argumentXML->setAttribute('type', 'collection');
- foreach ($this->getArgumentNodes($argument, $dom, $builder) as $childArgumentXML) {
+ foreach ($this->getArgumentNodes($argument, $dom, $container) as $childArgumentXML) {
$argumentXML->appendChild($childArgumentXML);
}
} elseif ($argument instanceof \UnitEnum) {
@@ -448,7 +452,7 @@ private function getArgumentNodes(array $arguments, \DOMDocument $dom, Container
return $nodes;
}
- private function getContainerAliasDocument(Alias $alias, string $id = null): \DOMDocument
+ private function getContainerAliasDocument(Alias $alias, ?string $id = null): \DOMDocument
{
$dom = new \DOMDocument('1.0', 'UTF-8');
$dom->appendChild($aliasXML = $dom->createElement('alias'));
diff --git a/src/Symfony/Bundle/FrameworkBundle/Console/Helper/DescriptorHelper.php b/src/Symfony/Bundle/FrameworkBundle/Console/Helper/DescriptorHelper.php
index 1f17c999424d3..ca303e12d2368 100644
--- a/src/Symfony/Bundle/FrameworkBundle/Console/Helper/DescriptorHelper.php
+++ b/src/Symfony/Bundle/FrameworkBundle/Console/Helper/DescriptorHelper.php
@@ -25,7 +25,7 @@
*/
class DescriptorHelper extends BaseDescriptorHelper
{
- public function __construct(FileLinkFormatter $fileLinkFormatter = null)
+ public function __construct(?FileLinkFormatter $fileLinkFormatter = null)
{
$this
->register('txt', new TextDescriptor($fileLinkFormatter))
diff --git a/src/Symfony/Bundle/FrameworkBundle/Controller/AbstractController.php b/src/Symfony/Bundle/FrameworkBundle/Controller/AbstractController.php
index 2a2c1983166b0..f4492fb94f26a 100644
--- a/src/Symfony/Bundle/FrameworkBundle/Controller/AbstractController.php
+++ b/src/Symfony/Bundle/FrameworkBundle/Controller/AbstractController.php
@@ -44,6 +44,7 @@
use Symfony\Component\WebLink\EventListener\AddLinkHeaderListener;
use Symfony\Component\WebLink\GenericLinkProvider;
use Symfony\Component\WebLink\HttpHeaderSerializer;
+use Symfony\Component\WebLink\Link;
use Symfony\Contracts\Service\Attribute\Required;
use Symfony\Contracts\Service\ServiceSubscriberInterface;
use Twig\Environment;
@@ -111,7 +112,7 @@ protected function generateUrl(string $route, array $parameters = [], int $refer
/**
* Forwards the request to another controller.
*
- * @param string $controller The controller name (a string like Bundle\BlogBundle\Controller\PostController::indexAction)
+ * @param string $controller The controller name (a string like "App\Controller\PostController::index" or "App\Controller\PostController" if it is invokable)
*/
protected function forward(string $controller, array $path = [], array $query = []): Response
{
@@ -163,7 +164,7 @@ protected function json(mixed $data, int $status = 200, array $headers = [], arr
/**
* Returns a BinaryFileResponse object with original or customized file name and disposition header.
*/
- protected function file(\SplFileInfo|string $file, string $fileName = null, string $disposition = ResponseHeaderBag::DISPOSITION_ATTACHMENT): BinaryFileResponse
+ protected function file(\SplFileInfo|string $file, ?string $fileName = null, string $disposition = ResponseHeaderBag::DISPOSITION_ATTACHMENT): BinaryFileResponse
{
$response = new BinaryFileResponse($file);
$response->setContentDisposition($disposition, $fileName ?? $response->getFile()->getFilename());
@@ -248,7 +249,7 @@ protected function renderView(string $view, array $parameters = []): string
* If an invalid form is found in the list of parameters, a 422 status code is returned.
* Forms found in parameters are auto-cast to form views.
*/
- protected function render(string $view, array $parameters = [], Response $response = null): Response
+ protected function render(string $view, array $parameters = [], ?Response $response = null): Response
{
$content = $this->renderView($view, $parameters);
$response ??= new Response();
@@ -274,7 +275,7 @@ protected function render(string $view, array $parameters = [], Response $respon
*
* @deprecated since Symfony 6.2, use render() instead
*/
- protected function renderForm(string $view, array $parameters = [], Response $response = null): Response
+ protected function renderForm(string $view, array $parameters = [], ?Response $response = null): Response
{
trigger_deprecation('symfony/framework-bundle', '6.2', 'The "%s::renderForm()" method is deprecated, use "render()" instead.', get_debug_type($this));
@@ -284,7 +285,7 @@ protected function renderForm(string $view, array $parameters = [], Response $re
/**
* Streams a view.
*/
- protected function stream(string $view, array $parameters = [], StreamedResponse $response = null): StreamedResponse
+ protected function stream(string $view, array $parameters = [], ?StreamedResponse $response = null): StreamedResponse
{
if (!$this->container->has('twig')) {
throw new \LogicException('You cannot use the "stream" method if the Twig Bundle is not available. Try running "composer require symfony/twig-bundle".');
@@ -312,7 +313,7 @@ protected function stream(string $view, array $parameters = [], StreamedResponse
*
* throw $this->createNotFoundException('Page not found!');
*/
- protected function createNotFoundException(string $message = 'Not Found', \Throwable $previous = null): NotFoundHttpException
+ protected function createNotFoundException(string $message = 'Not Found', ?\Throwable $previous = null): NotFoundHttpException
{
return new NotFoundHttpException($message, $previous);
}
@@ -326,7 +327,7 @@ protected function createNotFoundException(string $message = 'Not Found', \Throw
*
* @throws \LogicException If the Security component is not available
*/
- protected function createAccessDeniedException(string $message = 'Access Denied.', \Throwable $previous = null): AccessDeniedException
+ protected function createAccessDeniedException(string $message = 'Access Denied.', ?\Throwable $previous = null): AccessDeniedException
{
if (!class_exists(AccessDeniedException::class)) {
throw new \LogicException('You cannot use the "createAccessDeniedException" method if the Security component is not available. Try running "composer require symfony/security-bundle".');
@@ -409,7 +410,7 @@ protected function addLink(Request $request, LinkInterface $link): void
/**
* @param LinkInterface[] $links
*/
- protected function sendEarlyHints(iterable $links, Response $response = null): Response
+ protected function sendEarlyHints(iterable $links = [], ?Response $response = null): Response
{
if (!$this->container->has('web_link.http_header_serializer')) {
throw new \LogicException('You cannot use the "sendEarlyHints" method if the WebLink component is not available. Try running "composer require symfony/web-link".');
diff --git a/src/Symfony/Bundle/FrameworkBundle/Controller/RedirectController.php b/src/Symfony/Bundle/FrameworkBundle/Controller/RedirectController.php
index f5f42a7f77c8c..fbb52ead7507d 100644
--- a/src/Symfony/Bundle/FrameworkBundle/Controller/RedirectController.php
+++ b/src/Symfony/Bundle/FrameworkBundle/Controller/RedirectController.php
@@ -31,7 +31,7 @@ class RedirectController
private ?int $httpPort;
private ?int $httpsPort;
- public function __construct(UrlGeneratorInterface $router = null, int $httpPort = null, int $httpsPort = null)
+ public function __construct(?UrlGeneratorInterface $router = null, ?int $httpPort = null, ?int $httpsPort = null)
{
$this->router = $router;
$this->httpPort = $httpPort;
@@ -107,7 +107,7 @@ public function redirectAction(Request $request, string $route, bool $permanent
*
* @throws HttpException In case the path is empty
*/
- public function urlRedirectAction(Request $request, string $path, bool $permanent = false, string $scheme = null, int $httpPort = null, int $httpsPort = null, bool $keepRequestMethod = false): Response
+ public function urlRedirectAction(Request $request, string $path, bool $permanent = false, ?string $scheme = null, ?int $httpPort = null, ?int $httpsPort = null, bool $keepRequestMethod = false): Response
{
if ('' == $path) {
throw new HttpException($permanent ? 410 : 404);
diff --git a/src/Symfony/Bundle/FrameworkBundle/Controller/TemplateController.php b/src/Symfony/Bundle/FrameworkBundle/Controller/TemplateController.php
index 437458a499255..97631572c9c62 100644
--- a/src/Symfony/Bundle/FrameworkBundle/Controller/TemplateController.php
+++ b/src/Symfony/Bundle/FrameworkBundle/Controller/TemplateController.php
@@ -25,7 +25,7 @@ class TemplateController
{
private ?Environment $twig;
- public function __construct(Environment $twig = null)
+ public function __construct(?Environment $twig = null)
{
$this->twig = $twig;
}
@@ -40,7 +40,7 @@ public function __construct(Environment $twig = null)
* @param array $context The context (arguments) of the template
* @param int $statusCode The HTTP status code to return with the response (200 "OK" by default)
*/
- public function templateAction(string $template, int $maxAge = null, int $sharedAge = null, bool $private = null, array $context = [], int $statusCode = 200): Response
+ public function templateAction(string $template, ?int $maxAge = null, ?int $sharedAge = null, ?bool $private = null, array $context = [], int $statusCode = 200): Response
{
if (null === $this->twig) {
throw new \LogicException('You cannot use the TemplateController if the Twig Bundle is not available. Try running "composer require symfony/twig-bundle".');
@@ -68,7 +68,7 @@ public function templateAction(string $template, int $maxAge = null, int $shared
/**
* @param int $statusCode The HTTP status code (200 "OK" by default)
*/
- public function __invoke(string $template, int $maxAge = null, int $sharedAge = null, bool $private = null, array $context = [], int $statusCode = 200): Response
+ public function __invoke(string $template, ?int $maxAge = null, ?int $sharedAge = null, ?bool $private = null, array $context = [], int $statusCode = 200): Response
{
return $this->templateAction($template, $maxAge, $sharedAge, $private, $context, $statusCode);
}
diff --git a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Compiler/ErrorLoggerCompilerPass.php b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Compiler/ErrorLoggerCompilerPass.php
new file mode 100644
index 0000000000000..09f2dba82f6bb
--- /dev/null
+++ b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Compiler/ErrorLoggerCompilerPass.php
@@ -0,0 +1,37 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Bundle\FrameworkBundle\DependencyInjection\Compiler;
+
+use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
+use Symfony\Component\DependencyInjection\ContainerBuilder;
+use Symfony\Component\DependencyInjection\Reference;
+
+/**
+ * @internal
+ */
+class ErrorLoggerCompilerPass implements CompilerPassInterface
+{
+ public function process(ContainerBuilder $container): void
+ {
+ if (!$container->hasDefinition('debug.error_handler_configurator')) {
+ return;
+ }
+
+ $definition = $container->getDefinition('debug.error_handler_configurator');
+ if ($container->hasDefinition('monolog.logger.php')) {
+ $definition->replaceArgument(0, new Reference('monolog.logger.php'));
+ }
+ if ($container->hasDefinition('monolog.logger.deprecation')) {
+ $definition->replaceArgument(5, new Reference('monolog.logger.deprecation'));
+ }
+ }
+}
diff --git a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Compiler/TestServiceContainerRealRefPass.php b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Compiler/TestServiceContainerRealRefPass.php
index 09f272daa940e..aed3b13404bd5 100644
--- a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Compiler/TestServiceContainerRealRefPass.php
+++ b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Compiler/TestServiceContainerRealRefPass.php
@@ -41,6 +41,9 @@ public function process(ContainerBuilder $container)
if ($id !== $target) {
$renamedIds[$id] = $target;
}
+ if ($inner = $definitions[$target]->getTag('container.decorator')[0]['inner'] ?? null) {
+ $renamedIds[$id] = $inner;
+ }
} else {
unset($privateServices[$id]);
}
diff --git a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Compiler/UnusedTagsPass.php b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Compiler/UnusedTagsPass.php
index 9da5b91bb3bb0..b04516410fbf4 100644
--- a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Compiler/UnusedTagsPass.php
+++ b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Compiler/UnusedTagsPass.php
@@ -24,6 +24,8 @@ class UnusedTagsPass implements CompilerPassInterface
private const KNOWN_TAGS = [
'annotations.cached_reader',
'assets.package',
+ 'asset_mapper.compiler',
+ 'asset_mapper.importmap.resolver',
'auto_alias',
'cache.pool',
'cache.pool.clearer',
@@ -84,7 +86,6 @@ class UnusedTagsPass implements CompilerPassInterface
'scheduler.schedule_provider',
'security.authenticator.login_linker',
'security.expression_language_provider',
- 'security.remember_me_aware',
'security.remember_me_handler',
'security.voter',
'serializer.encoder',
diff --git a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Configuration.php b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Configuration.php
index c5378238b92a4..702fe834bbe5d 100644
--- a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Configuration.php
+++ b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Configuration.php
@@ -16,6 +16,8 @@
use Psr\Log\LogLevel;
use Symfony\Bundle\FullStack;
use Symfony\Component\Asset\Package;
+use Symfony\Component\AssetMapper\AssetMapper;
+use Symfony\Component\AssetMapper\ImportMap\ImportMapManager;
use Symfony\Component\Cache\Adapter\DoctrineAdapter;
use Symfony\Component\Config\Definition\Builder\ArrayNodeDefinition;
use Symfony\Component\Config\Definition\Builder\NodeBuilder;
@@ -101,7 +103,7 @@ public function getConfigTreeBuilder(): TreeBuilder
->info('Set true to enable support for xsendfile in binary file responses.')
->defaultFalse()
->end()
- ->scalarNode('ide')->defaultValue('%env(default::SYMFONY_IDE)%')->end()
+ ->scalarNode('ide')->defaultValue($this->debug ? '%env(default::SYMFONY_IDE)%' : null)->end()
->booleanNode('test')->end()
->scalarNode('default_locale')->defaultValue('en')->end()
->booleanNode('set_locale_from_accept_language')
@@ -140,7 +142,7 @@ public function getConfigTreeBuilder(): TreeBuilder
->end()
;
- $willBeAvailable = static function (string $package, string $class, string $parentPackage = null) {
+ $willBeAvailable = static function (string $package, string $class, ?string $parentPackage = null) {
$parentPackages = (array) $parentPackage;
$parentPackages[] = 'symfony/framework-bundle';
@@ -161,6 +163,7 @@ public function getConfigTreeBuilder(): TreeBuilder
$this->addSessionSection($rootNode);
$this->addRequestSection($rootNode);
$this->addAssetsSection($rootNode, $enableIfStandalone);
+ $this->addAssetMapperSection($rootNode, $enableIfStandalone);
$this->addTranslatorSection($rootNode, $enableIfStandalone);
$this->addValidationSection($rootNode, $enableIfStandalone);
$this->addAnnotationsSection($rootNode, $willBeAvailable);
@@ -462,6 +465,10 @@ private function addWorkflowSection(ArrayNodeDefinition $rootNode): void
->beforeNormalization()
->always()
->then(function ($places) {
+ if (!\is_array($places)) {
+ throw new InvalidConfigurationException('The "places" option must be an array in workflow configuration.');
+ }
+
// It's an indexed array of shape ['place1', 'place2']
if (isset($places[0]) && \is_string($places[0])) {
return array_map(function (string $place) {
@@ -507,6 +514,10 @@ private function addWorkflowSection(ArrayNodeDefinition $rootNode): void
->beforeNormalization()
->always()
->then(function ($transitions) {
+ if (!\is_array($transitions)) {
+ throw new InvalidConfigurationException('The "transitions" option must be an array in workflow configuration.');
+ }
+
// It's an indexed array, we let the validation occur
if (isset($transitions[0]) && \is_array($transitions[0])) {
return $transitions;
@@ -810,6 +821,104 @@ private function addAssetsSection(ArrayNodeDefinition $rootNode, callable $enabl
;
}
+ private function addAssetMapperSection(ArrayNodeDefinition $rootNode, callable $enableIfStandalone): void
+ {
+ $rootNode
+ ->children()
+ ->arrayNode('asset_mapper')
+ ->info('Asset Mapper configuration')
+ ->{$enableIfStandalone('symfony/asset-mapper', AssetMapper::class)}()
+ ->fixXmlConfig('path')
+ ->fixXmlConfig('excluded_pattern')
+ ->fixXmlConfig('extension')
+ ->fixXmlConfig('importmap_script_attribute')
+ ->children()
+ // add array node called "paths" that will be an array of strings
+ ->arrayNode('paths')
+ ->info('Directories that hold assets that should be in the mapper. Can be a simple array of an array of ["path/to/assets": "namespace"]')
+ ->example(['assets/'])
+ ->normalizeKeys(false)
+ ->useAttributeAsKey('namespace')
+ ->beforeNormalization()
+ ->always()
+ ->then(function ($v) {
+ $result = [];
+ foreach ($v as $key => $item) {
+ // "dir" => "namespace"
+ if (\is_string($key)) {
+ $result[$key] = $item;
+
+ continue;
+ }
+
+ if (\is_array($item)) {
+ // $item = ["namespace" => "the/namespace", "value" => "the/dir"]
+ $result[$item['value']] = $item['namespace'] ?? '';
+ } else {
+ // $item = "the/dir"
+ $result[$item] = '';
+ }
+ }
+
+ return $result;
+ })
+ ->end()
+ ->prototype('scalar')->end()
+ ->end()
+ ->arrayNode('excluded_patterns')
+ ->info('Array of glob patterns of asset file paths that should not be in the asset mapper')
+ ->prototype('scalar')->end()
+ ->example(['*/assets/build/*', '*/*_.scss'])
+ ->end()
+ ->booleanNode('server')
+ ->info('If true, a "dev server" will return the assets from the public directory (true in "debug" mode only by default)')
+ ->defaultValue($this->debug)
+ ->end()
+ ->scalarNode('public_prefix')
+ ->info('The public path where the assets will be written to (and served from when "server" is true)')
+ ->defaultValue('/assets/')
+ ->end()
+ ->enumNode('missing_import_mode')
+ ->values(['strict', 'warn', 'ignore'])
+ ->info('Behavior if an asset cannot be found when imported from JavaScript or CSS files - e.g. "import \'./non-existent.js\'". "strict" means an exception is thrown, "warn" means a warning is logged, "ignore" means the import is left as-is.')
+ ->defaultValue('warn')
+ ->end()
+ ->arrayNode('extensions')
+ ->info('Key-value pair of file extensions set to their mime type.')
+ ->normalizeKeys(false)
+ ->useAttributeAsKey('extension')
+ ->example(['.zip' => 'application/zip'])
+ ->prototype('scalar')->end()
+ ->end()
+ ->scalarNode('importmap_path')
+ ->info('The path of the importmap.php file.')
+ ->defaultValue('%kernel.project_dir%/importmap.php')
+ ->end()
+ ->scalarNode('importmap_polyfill')
+ ->info('URL of the ES Module Polyfill to use, false to disable. Defaults to using a CDN URL.')
+ ->defaultValue(null)
+ ->end()
+ ->arrayNode('importmap_script_attributes')
+ ->info('Key-value pair of attributes to add to script tags output for the importmap.')
+ ->normalizeKeys(false)
+ ->useAttributeAsKey('key')
+ ->example(['data-turbo-track' => 'reload'])
+ ->prototype('scalar')->end()
+ ->end()
+ ->scalarNode('vendor_dir')
+ ->info('The directory to store JavaScript vendors.')
+ ->defaultValue('%kernel.project_dir%/assets/vendor')
+ ->end()
+ ->scalarNode('provider')
+ ->info('The provider (CDN) to use'.(class_exists(ImportMapManager::class) ? sprintf(' (e.g.: "%s").', implode('", "', ImportMapManager::PROVIDERS)) : '.'))
+ ->defaultValue('jsdelivr.esm')
+ ->end()
+ ->end()
+ ->end()
+ ->end()
+ ;
+ }
+
private function addTranslatorSection(ArrayNodeDefinition $rootNode, callable $enableIfStandalone): void
{
$rootNode
@@ -1723,7 +1832,7 @@ private function addHttpClientSection(ArrayNodeDefinition $rootNode, callable $e
->info('A network interface name, IP address, a host name or a UNIX socket to bind to.')
->end()
->booleanNode('verify_peer')
- ->info('Indicates if the peer should be verified in an SSL/TLS context.')
+ ->info('Indicates if the peer should be verified in a TLS context.')
->end()
->booleanNode('verify_host')
->info('Indicates if the host should exist as a certificate common name.')
@@ -1744,7 +1853,7 @@ private function addHttpClientSection(ArrayNodeDefinition $rootNode, callable $e
->info('The passphrase used to encrypt the "local_pk" file.')
->end()
->scalarNode('ciphers')
- ->info('A list of SSL/TLS ciphers separated by colons, commas or spaces (e.g. "RC3-SHA:TLS13-AES-128-GCM-SHA256"...)')
+ ->info('A list of TLS ciphers separated by colons, commas or spaces (e.g. "RC3-SHA:TLS13-AES-128-GCM-SHA256"...)')
->end()
->arrayNode('peer_fingerprint')
->info('Associative array: hashing algorithm => hash(es).')
@@ -1755,6 +1864,9 @@ private function addHttpClientSection(ArrayNodeDefinition $rootNode, callable $e
->variableNode('md5')->end()
->end()
->end()
+ ->scalarNode('crypto_method')
+ ->info('The minimum version of TLS to accept; must be one of STREAM_CRYPTO_METHOD_TLSv*_CLIENT constants.')
+ ->end()
->arrayNode('extra')
->info('Extra options for specific HTTP client')
->normalizeKeys(false)
@@ -1871,7 +1983,7 @@ private function addHttpClientSection(ArrayNodeDefinition $rootNode, callable $e
->info('A network interface name, IP address, a host name or a UNIX socket to bind to.')
->end()
->booleanNode('verify_peer')
- ->info('Indicates if the peer should be verified in an SSL/TLS context.')
+ ->info('Indicates if the peer should be verified in a TLS context.')
->end()
->booleanNode('verify_host')
->info('Indicates if the host should exist as a certificate common name.')
@@ -1892,7 +2004,7 @@ private function addHttpClientSection(ArrayNodeDefinition $rootNode, callable $e
->info('The passphrase used to encrypt the "local_pk" file.')
->end()
->scalarNode('ciphers')
- ->info('A list of SSL/TLS ciphers separated by colons, commas or spaces (e.g. "RC3-SHA:TLS13-AES-128-GCM-SHA256"...)')
+ ->info('A list of TLS ciphers separated by colons, commas or spaces (e.g. "RC3-SHA:TLS13-AES-128-GCM-SHA256"...)')
->end()
->arrayNode('peer_fingerprint')
->info('Associative array: hashing algorithm => hash(es).')
diff --git a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php
index 36622ee23d604..b5c6b1ecc8215 100644
--- a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php
+++ b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php
@@ -31,6 +31,10 @@
use Symfony\Bundle\FullStack;
use Symfony\Bundle\MercureBundle\MercureBundle;
use Symfony\Component\Asset\PackageInterface;
+use Symfony\Component\AssetMapper\AssetMapper;
+use Symfony\Component\AssetMapper\Compiler\AssetCompilerInterface;
+use Symfony\Component\AssetMapper\ImportMap\ImportMapManager;
+use Symfony\Component\AssetMapper\ImportMap\Resolver\PackageResolverInterface;
use Symfony\Component\BrowserKit\AbstractBrowser;
use Symfony\Component\Cache\Adapter\AdapterInterface;
use Symfony\Component\Cache\Adapter\ArrayAdapter;
@@ -45,6 +49,7 @@
use Symfony\Component\Config\FileLocator;
use Symfony\Component\Config\Loader\LoaderInterface;
use Symfony\Component\Config\Resource\DirectoryResource;
+use Symfony\Component\Config\Resource\FileResource;
use Symfony\Component\Config\ResourceCheckerInterface;
use Symfony\Component\Console\Application;
use Symfony\Component\Console\Command\Command;
@@ -68,6 +73,7 @@
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\ExpressionLanguage\ExpressionLanguage;
use Symfony\Component\Finder\Finder;
+use Symfony\Component\Finder\Glob;
use Symfony\Component\Form\ChoiceList\Factory\CachingFactoryDecorator;
use Symfony\Component\Form\Extension\HtmlSanitizer\Type\TextTypeHtmlSanitizerExtension;
use Symfony\Component\Form\Form;
@@ -277,11 +283,11 @@ public function load(array $configs, ContainerBuilder $container)
// If the slugger is used but the String component is not available, we should throw an error
if (!ContainerBuilder::willBeAvailable('symfony/string', SluggerInterface::class, ['symfony/framework-bundle'])) {
- $container->register('slugger', 'stdClass')
+ $container->register('slugger', SluggerInterface::class)
->addError('You cannot use the "slugger" service since the String component is not installed. Try running "composer require symfony/string".');
} else {
if (!ContainerBuilder::willBeAvailable('symfony/translation', LocaleAwareInterface::class, ['symfony/framework-bundle'])) {
- $container->register('slugger', 'stdClass')
+ $container->register('slugger', SluggerInterface::class)
->addError('You cannot use the "slugger" service since the Translation contracts are not installed. Try running "composer require symfony/translation".');
}
@@ -330,6 +336,16 @@ public function load(array $configs, ContainerBuilder $container)
$this->registerAssetsConfiguration($config['assets'], $container, $loader);
}
+ if ($this->readConfigEnabled('asset_mapper', $container, $config['asset_mapper'])) {
+ if (!class_exists(AssetMapper::class)) {
+ throw new LogicException('AssetMapper support cannot be enabled as the AssetMapper component is not installed. Try running "composer require symfony/asset-mapper".');
+ }
+
+ $this->registerAssetMapperConfiguration($config['asset_mapper'], $container, $loader, $this->readConfigEnabled('assets', $container, $config['assets']));
+ } else {
+ $container->removeDefinition('cache.asset_mapper');
+ }
+
if ($this->readConfigEnabled('http_client', $container, $config['http_client'])) {
$this->registerHttpClientConfiguration($config['http_client'], $container, $loader);
}
@@ -364,13 +380,13 @@ public function load(array $configs, ContainerBuilder $container)
$this->registerSerializerConfiguration($config['serializer'], $container, $loader);
} else {
- $container->register('.argument_resolver.request_payload.no_serializer', Serializer::class)
- ->addError('You can neither use "#[MapRequestPayload]" nor "#[MapQueryString]" since the Serializer component is not '
- .(class_exists(Serializer::class) ? 'enabled. Try setting "framework.serializer" to true.' : 'installed. Try running "composer require symfony/serializer-pack".')
- );
-
$container->getDefinition('argument_resolver.request_payload')
- ->replaceArgument(0, new Reference('.argument_resolver.request_payload.no_serializer', ContainerInterface::RUNTIME_EXCEPTION_ON_INVALID_REFERENCE));
+ ->setArguments([])
+ ->addError('You can neither use "#[MapRequestPayload]" nor "#[MapQueryString]" since the Serializer component is not '
+ .(class_exists(Serializer::class) ? 'enabled. Try setting "framework.serializer.enabled" to true.' : 'installed. Try running "composer require symfony/serializer-pack".')
+ )
+ ->addTag('container.error')
+ ->clearTag('kernel.event_subscriber');
$container->removeDefinition('console.command.serializer_debug');
}
@@ -471,6 +487,7 @@ public function load(array $configs, ContainerBuilder $container)
}
$this->registerSchedulerConfiguration($config['scheduler'], $container, $loader);
} else {
+ $container->removeDefinition('cache.scheduler');
$container->removeDefinition('console.command.scheduler_debug');
}
@@ -519,6 +536,24 @@ public function load(array $configs, ContainerBuilder $container)
if ($this->readConfigEnabled('webhook', $container, $config['webhook'])) {
$this->registerWebhookConfiguration($config['webhook'], $container, $loader);
+
+ // If Webhook is installed but the HttpClient or Serializer components are not available, we should throw an error
+ if (!$this->readConfigEnabled('http_client', $container, $config['http_client'])) {
+ $container->getDefinition('webhook.transport')
+ ->setArguments([])
+ ->addError('You cannot use the "webhook transport" service since the HttpClient component is not '
+ .(class_exists(ScopingHttpClient::class) ? 'enabled. Try setting "framework.http_client.enabled" to true.' : 'installed. Try running "composer require symfony/http-client".')
+ )
+ ->addTag('container.error');
+ }
+ if (!$this->readConfigEnabled('serializer', $container, $config['serializer'])) {
+ $container->getDefinition('webhook.body_configurator.json')
+ ->setArguments([])
+ ->addError('You cannot use the "webhook transport" service since the Serializer component is not '
+ .(class_exists(Serializer::class) ? 'enabled. Try setting "framework.serializer.enabled" to true.' : 'installed. Try running "composer require symfony/serializer-pack".')
+ )
+ ->addTag('container.error');
+ }
}
if ($this->readConfigEnabled('remote-event', $container, $config['remote-event'])) {
@@ -547,6 +582,8 @@ public function load(array $configs, ContainerBuilder $container)
$container->registerForAutoconfiguration(PackageInterface::class)
->addTag('assets.package');
+ $container->registerForAutoconfiguration(AssetCompilerInterface::class)
+ ->addTag('asset_mapper.compiler');
$container->registerForAutoconfiguration(Command::class)
->addTag('console.command');
$container->registerForAutoconfiguration(ResourceCheckerInterface::class)
@@ -957,6 +994,7 @@ private function registerWorkflowConfiguration(array $config, ContainerBuilder $
$definitionDefinition->addArgument(new Reference(sprintf('%s.metadata_store', $workflowId)));
// Create MarkingStore
+ $markingStoreDefinition = null;
if (isset($workflow['marking_store']['type'])) {
$markingStoreDefinition = new ChildDefinition('workflow.marking_store.method');
$markingStoreDefinition->setArguments([
@@ -970,7 +1008,7 @@ private function registerWorkflowConfiguration(array $config, ContainerBuilder $
// Create Workflow
$workflowDefinition = new ChildDefinition(sprintf('%s.abstract', $type));
$workflowDefinition->replaceArgument(0, new Reference(sprintf('%s.definition', $workflowId)));
- $workflowDefinition->replaceArgument(1, $markingStoreDefinition ?? null);
+ $workflowDefinition->replaceArgument(1, $markingStoreDefinition);
$workflowDefinition->replaceArgument(3, $name);
$workflowDefinition->replaceArgument(4, $workflow['events_to_dispatch']);
@@ -1231,6 +1269,72 @@ private function registerAssetsConfiguration(array $config, ContainerBuilder $co
}
}
+ private function registerAssetMapperConfiguration(array $config, ContainerBuilder $container, PhpFileLoader $loader, bool $assetEnabled): void
+ {
+ $loader->load('asset_mapper.php');
+
+ if (!$assetEnabled) {
+ $container->removeDefinition('asset_mapper.asset_package');
+ }
+
+ $paths = $config['paths'];
+ foreach ($container->getParameter('kernel.bundles_metadata') as $name => $bundle) {
+ if ($container->fileExists($dir = $bundle['path'].'/Resources/public') || $container->fileExists($dir = $bundle['path'].'/public')) {
+ $paths[$dir] = sprintf('bundles/%s', preg_replace('/bundle$/', '', strtolower($name)));
+ }
+ }
+ $excludedPathPatterns = [];
+ foreach ($config['excluded_patterns'] as $path) {
+ $excludedPathPatterns[] = Glob::toRegex($path, true, false);
+ }
+
+ $container->getDefinition('asset_mapper.repository')
+ ->setArgument(0, $paths)
+ ->setArgument(2, $excludedPathPatterns);
+
+ $publicDirName = $this->getPublicDirectoryName($container);
+ $container->getDefinition('asset_mapper.public_assets_path_resolver')
+ ->setArgument(1, $config['public_prefix'])
+ ->setArgument(2, $publicDirName);
+
+ $container->getDefinition('asset_mapper.command.compile')
+ ->setArgument(5, $publicDirName);
+
+ if (!$config['server']) {
+ $container->removeDefinition('asset_mapper.dev_server_subscriber');
+ } else {
+ $container->getDefinition('asset_mapper.dev_server_subscriber')
+ ->setArgument(1, $config['public_prefix'])
+ ->setArgument(2, $config['extensions']);
+ }
+
+ $container->getDefinition('asset_mapper.compiler.css_asset_url_compiler')
+ ->setArgument(0, $config['missing_import_mode']);
+
+ $container->getDefinition('asset_mapper.compiler.javascript_import_path_compiler')
+ ->setArgument(0, $config['missing_import_mode']);
+
+ $container
+ ->getDefinition('asset_mapper.importmap.manager')
+ ->replaceArgument(2, $config['importmap_path'])
+ ->replaceArgument(3, $config['vendor_dir'])
+ ;
+
+ $container
+ ->getDefinition('asset_mapper.importmap.resolver')
+ ->replaceArgument(0, $config['provider'])
+ ;
+
+ $container
+ ->getDefinition('asset_mapper.importmap.renderer')
+ ->replaceArgument(2, $config['importmap_polyfill'] ?? ImportMapManager::POLYFILL_URL)
+ ->replaceArgument(3, $config['importmap_script_attributes'])
+ ;
+
+ $container->registerForAutoconfiguration(PackageResolverInterface::class)
+ ->addTag('asset_mapper.importmap.resolver');
+ }
+
/**
* Returns a definition for an asset package.
*/
@@ -1763,6 +1867,10 @@ private function registerSerializerConfiguration(array $config, ContainerBuilder
$container->removeDefinition('serializer.normalizer.mime_message');
}
+ if ($container->getParameter('kernel.debug')) {
+ $container->removeDefinition('serializer.mapping.cache_class_metadata_factory');
+ }
+
// compat with Symfony < 6.3
if (!is_subclass_of(ProblemNormalizer::class, SerializerAwareInterface::class)) {
$container->getDefinition('serializer.normalizer.problem')
@@ -1771,10 +1879,6 @@ private function registerSerializerConfiguration(array $config, ContainerBuilder
$serializerLoaders = [];
if (isset($config['enable_annotations']) && $config['enable_annotations']) {
- if ($container->getParameter('kernel.debug')) {
- $container->removeDefinition('serializer.mapping.cache_class_metadata_factory');
- }
-
$annotationLoader = new Definition(
AnnotationLoader::class,
[new Reference('annotation_reader', ContainerInterface::NULL_ON_INVALID_REFERENCE)]
@@ -1823,21 +1927,23 @@ private function registerSerializerConfiguration(array $config, ContainerBuilder
$container->getDefinition('serializer.name_converter.metadata_aware')->setArgument(1, new Reference($config['name_converter']));
}
+ $defaultContext = $config['default_context'] ?? [];
+
+ if ($defaultContext) {
+ $container->setParameter('serializer.default_context', $defaultContext);
+ }
+
if (isset($config['circular_reference_handler']) && $config['circular_reference_handler']) {
$arguments = $container->getDefinition('serializer.normalizer.object')->getArguments();
- $context = ($arguments[6] ?? []) + ['circular_reference_handler' => new Reference($config['circular_reference_handler'])];
+ $context = ($arguments[6] ?? $defaultContext) + ['circular_reference_handler' => new Reference($config['circular_reference_handler'])];
$container->getDefinition('serializer.normalizer.object')->setArgument(5, null);
$container->getDefinition('serializer.normalizer.object')->setArgument(6, $context);
}
if ($config['max_depth_handler'] ?? false) {
- $defaultContext = $container->getDefinition('serializer.normalizer.object')->getArgument(6);
- $defaultContext += ['max_depth_handler' => new Reference($config['max_depth_handler'])];
- $container->getDefinition('serializer.normalizer.object')->replaceArgument(6, $defaultContext);
- }
-
- if (isset($config['default_context']) && $config['default_context']) {
- $container->setParameter('serializer.default_context', $config['default_context']);
+ $arguments = $container->getDefinition('serializer.normalizer.object')->getArguments();
+ $context = ($arguments[6] ?? $defaultContext) + ['max_depth_handler' => new Reference($config['max_depth_handler'])];
+ $container->getDefinition('serializer.normalizer.object')->setArgument(6, $context);
}
}
@@ -1994,6 +2100,16 @@ private function registerMessengerConfiguration(array $config, ContainerBuilder
$container->getDefinition('messenger.transport.beanstalkd.factory')->addTag('messenger.transport_factory');
}
+ if ($config['stop_worker_on_signals'] && $this->hasConsole()) {
+ $container->getDefinition('console.command.messenger_consume_messages')
+ ->replaceArgument(8, $config['stop_worker_on_signals']);
+ $container->getDefinition('console.command.messenger_failed_messages_retry')
+ ->replaceArgument(6, $config['stop_worker_on_signals']);
+ }
+
+ if ($this->hasConsole() && $container->hasDefinition('messenger.listener.stop_worker_signals_listener')) {
+ $container->getDefinition('messenger.listener.stop_worker_signals_listener')->clearTag('kernel.event_subscriber');
+ }
if ($config['stop_worker_on_signals']) {
$container->getDefinition('messenger.listener.stop_worker_signals_listener')->replaceArgument(0, $config['stop_worker_on_signals']);
}
@@ -2185,12 +2301,14 @@ private function registerMessengerConfiguration(array $config, ContainerBuilder
}
if (\count($failureTransports) > 0) {
- $container->getDefinition('console.command.messenger_failed_messages_retry')
- ->replaceArgument(0, $config['failure_transport']);
- $container->getDefinition('console.command.messenger_failed_messages_show')
- ->replaceArgument(0, $config['failure_transport']);
- $container->getDefinition('console.command.messenger_failed_messages_remove')
- ->replaceArgument(0, $config['failure_transport']);
+ if ($this->hasConsole()) {
+ $container->getDefinition('console.command.messenger_failed_messages_retry')
+ ->replaceArgument(0, $config['failure_transport']);
+ $container->getDefinition('console.command.messenger_failed_messages_show')
+ ->replaceArgument(0, $config['failure_transport']);
+ $container->getDefinition('console.command.messenger_failed_messages_remove')
+ ->replaceArgument(0, $config['failure_transport']);
+ }
$failureTransportsByTransportNameServiceLocator = ServiceLocatorTagPass::register($container, $failureTransportReferencesByTransportName);
$container->getDefinition('messenger.failure.send_failed_message_to_failure_transport_listener')
@@ -2514,7 +2632,7 @@ private function registerMailerConfiguration(array $config, ContainerBuilder $co
];
foreach ($webhookRequestParsers as $class => $service) {
- $package = substr($service, \strlen('mailer.transport_factory.'));
+ $package = substr($service, \strlen('mailer.webhook.request_parser.'));
if (!ContainerBuilder::willBeAvailable(sprintf('symfony/%s-mailer', 'gmail' === $package ? 'google' : $package), $class, ['symfony/framework-bundle', 'symfony/mailer'])) {
$container->removeDefinition($service);
@@ -2619,6 +2737,7 @@ private function registerNotifierConfiguration(array $config, ContainerBuilder $
NotifierBridge\Bandwidth\BandwidthTransportFactory::class => 'notifier.transport_factory.bandwidth',
NotifierBridge\Chatwork\ChatworkTransportFactory::class => 'notifier.transport_factory.chatwork',
NotifierBridge\Clickatell\ClickatellTransportFactory::class => 'notifier.transport_factory.clickatell',
+ NotifierBridge\ClickSend\ClickSendTransportFactory::class => 'notifier.transport_factory.click-send',
NotifierBridge\ContactEveryone\ContactEveryoneTransportFactory::class => 'notifier.transport_factory.contact-everyone',
NotifierBridge\Discord\DiscordTransportFactory::class => 'notifier.transport_factory.discord',
NotifierBridge\Engagespot\EngagespotTransportFactory::class => 'notifier.transport_factory.engagespot',
@@ -2643,7 +2762,7 @@ private function registerNotifierConfiguration(array $config, ContainerBuilder $
NotifierBridge\Mastodon\MastodonTransportFactory::class => 'notifier.transport_factory.mastodon',
NotifierBridge\Mattermost\MattermostTransportFactory::class => 'notifier.transport_factory.mattermost',
NotifierBridge\Mercure\MercureTransportFactory::class => 'notifier.transport_factory.mercure',
- NotifierBridge\MessageBird\MessageBirdTransport::class => 'notifier.transport_factory.message-bird',
+ NotifierBridge\MessageBird\MessageBirdTransportFactory::class => 'notifier.transport_factory.message-bird',
NotifierBridge\MessageMedia\MessageMediaTransportFactory::class => 'notifier.transport_factory.message-media',
NotifierBridge\MicrosoftTeams\MicrosoftTeamsTransportFactory::class => 'notifier.transport_factory.microsoft-teams',
NotifierBridge\Mobyt\MobytTransportFactory::class => 'notifier.transport_factory.mobyt',
@@ -2666,11 +2785,12 @@ private function registerNotifierConfiguration(array $config, ContainerBuilder $
NotifierBridge\SmsBiuras\SmsBiurasTransportFactory::class => 'notifier.transport_factory.sms-biuras',
NotifierBridge\Smsc\SmscTransportFactory::class => 'notifier.transport_factory.smsc',
NotifierBridge\SmsFactor\SmsFactorTransportFactory::class => 'notifier.transport_factory.sms-factor',
+ NotifierBridge\Smsmode\SmsmodeTransportFactory::class => 'notifier.transport_factory.smsmode',
NotifierBridge\SpotHit\SpotHitTransportFactory::class => 'notifier.transport_factory.spot-hit',
NotifierBridge\Telegram\TelegramTransportFactory::class => 'notifier.transport_factory.telegram',
NotifierBridge\Telnyx\TelnyxTransportFactory::class => 'notifier.transport_factory.telnyx',
NotifierBridge\Termii\TermiiTransportFactory::class => 'notifier.transport_factory.termii',
- NotifierBridge\TurboSms\TurboSmsTransport::class => 'notifier.transport_factory.turbo-sms',
+ NotifierBridge\TurboSms\TurboSmsTransportFactory::class => 'notifier.transport_factory.turbo-sms',
NotifierBridge\Twilio\TwilioTransportFactory::class => 'notifier.transport_factory.twilio',
NotifierBridge\Twitter\TwitterTransportFactory::class => 'notifier.transport_factory.twitter',
NotifierBridge\Vonage\VonageTransportFactory::class => 'notifier.transport_factory.vonage',
@@ -2691,21 +2811,27 @@ private function registerNotifierConfiguration(array $config, ContainerBuilder $
if (ContainerBuilder::willBeAvailable('symfony/mercure-notifier', NotifierBridge\Mercure\MercureTransportFactory::class, $parentPackages) && ContainerBuilder::willBeAvailable('symfony/mercure-bundle', MercureBundle::class, $parentPackages) && \in_array(MercureBundle::class, $container->getParameter('kernel.bundles'), true)) {
$container->getDefinition($classToServices[NotifierBridge\Mercure\MercureTransportFactory::class])
- ->replaceArgument('$registry', new Reference(HubRegistry::class));
+ ->replaceArgument(0, new Reference(HubRegistry::class))
+ ->replaceArgument(1, new Reference('event_dispatcher', ContainerBuilder::NULL_ON_INVALID_REFERENCE))
+ ->addArgument(new Reference('http_client', ContainerBuilder::NULL_ON_INVALID_REFERENCE));
} elseif (ContainerBuilder::willBeAvailable('symfony/mercure-notifier', NotifierBridge\Mercure\MercureTransportFactory::class, $parentPackages)) {
$container->removeDefinition($classToServices[NotifierBridge\Mercure\MercureTransportFactory::class]);
}
if (ContainerBuilder::willBeAvailable('symfony/fake-chat-notifier', NotifierBridge\FakeChat\FakeChatTransportFactory::class, ['symfony/framework-bundle', 'symfony/notifier', 'symfony/mailer'])) {
$container->getDefinition($classToServices[NotifierBridge\FakeChat\FakeChatTransportFactory::class])
- ->replaceArgument('$mailer', new Reference('mailer'))
- ->replaceArgument('$logger', new Reference('logger'));
+ ->replaceArgument(0, new Reference('mailer'))
+ ->replaceArgument(1, new Reference('logger'))
+ ->addArgument(new Reference('event_dispatcher', ContainerBuilder::NULL_ON_INVALID_REFERENCE))
+ ->addArgument(new Reference('http_client', ContainerBuilder::NULL_ON_INVALID_REFERENCE));
}
if (ContainerBuilder::willBeAvailable('symfony/fake-sms-notifier', NotifierBridge\FakeSms\FakeSmsTransportFactory::class, ['symfony/framework-bundle', 'symfony/notifier', 'symfony/mailer'])) {
$container->getDefinition($classToServices[NotifierBridge\FakeSms\FakeSmsTransportFactory::class])
- ->replaceArgument('$mailer', new Reference('mailer'))
- ->replaceArgument('$logger', new Reference('logger'));
+ ->replaceArgument(0, new Reference('mailer'))
+ ->replaceArgument(1, new Reference('logger'))
+ ->addArgument(new Reference('event_dispatcher', ContainerBuilder::NULL_ON_INVALID_REFERENCE))
+ ->addArgument(new Reference('http_client', ContainerBuilder::NULL_ON_INVALID_REFERENCE));
}
if (isset($config['admin_recipients'])) {
@@ -2719,6 +2845,18 @@ private function registerNotifierConfiguration(array $config, ContainerBuilder $
if ($webhookEnabled) {
$loader->load('notifier_webhook.php');
+
+ $webhookRequestParsers = [
+ NotifierBridge\Twilio\Webhook\TwilioRequestParser::class => 'notifier.webhook.request_parser.twilio',
+ ];
+
+ foreach ($webhookRequestParsers as $class => $service) {
+ $package = substr($service, \strlen('notifier.webhook.request_parser.'));
+
+ if (!ContainerBuilder::willBeAvailable(sprintf('symfony/%s-notifier', $package), $class, ['symfony/framework-bundle', 'symfony/notifier'])) {
+ $container->removeDefinition($service);
+ }
+ }
}
}
@@ -2994,4 +3132,20 @@ private function writeConfigEnabled(string $path, bool $value, array &$config):
$this->configsEnabled[$path] = $value;
$config['enabled'] = $value;
}
+
+ private function getPublicDirectoryName(ContainerBuilder $container): string
+ {
+ $defaultPublicDir = 'public';
+
+ $composerFilePath = $container->getParameter('kernel.project_dir').'/composer.json';
+
+ if (!file_exists($composerFilePath)) {
+ return $defaultPublicDir;
+ }
+
+ $container->addResource(new FileResource($composerFilePath));
+ $composerConfig = json_decode(file_get_contents($composerFilePath), true);
+
+ return $composerConfig['extra']['public-dir'] ?? $defaultPublicDir;
+ }
}
diff --git a/src/Symfony/Bundle/FrameworkBundle/FrameworkBundle.php b/src/Symfony/Bundle/FrameworkBundle/FrameworkBundle.php
index ffb96a23e5f5b..8a0021725026f 100644
--- a/src/Symfony/Bundle/FrameworkBundle/FrameworkBundle.php
+++ b/src/Symfony/Bundle/FrameworkBundle/FrameworkBundle.php
@@ -18,6 +18,7 @@
use Symfony\Bundle\FrameworkBundle\DependencyInjection\Compiler\ContainerBuilderDebugDumpPass;
use Symfony\Bundle\FrameworkBundle\DependencyInjection\Compiler\DataCollectorTranslatorPass;
use Symfony\Bundle\FrameworkBundle\DependencyInjection\Compiler\EnableLoggerDebugModePass;
+use Symfony\Bundle\FrameworkBundle\DependencyInjection\Compiler\ErrorLoggerCompilerPass;
use Symfony\Bundle\FrameworkBundle\DependencyInjection\Compiler\LoggingTranslatorPass;
use Symfony\Bundle\FrameworkBundle\DependencyInjection\Compiler\ProfilerPass;
use Symfony\Bundle\FrameworkBundle\DependencyInjection\Compiler\RemoveUnusedSessionMarshallingHandlerPass;
@@ -95,8 +96,16 @@ class FrameworkBundle extends Bundle
*/
public function boot()
{
+ $_ENV['DOCTRINE_DEPRECATIONS'] = $_SERVER['DOCTRINE_DEPRECATIONS'] ??= 'trigger';
+
$handler = ErrorHandler::register(null, false);
- $this->container->get('debug.error_handler_configurator')->configure($handler);
+
+ // When upgrading an existing Symfony application from 6.2 to 6.3, and
+ // the cache is warmed up, the service is not available yet, so we need
+ // to check if it exists.
+ if ($this->container->has('debug.error_handler_configurator')) {
+ $this->container->get('debug.error_handler_configurator')->configure($handler);
+ }
if ($this->container->getParameter('kernel.http_method_override')) {
Request::enableHttpMethodParameterOverride();
@@ -173,6 +182,8 @@ public function build(ContainerBuilder $container)
$container->addCompilerPass(new RegisterReverseContainerPass(true));
$container->addCompilerPass(new RegisterReverseContainerPass(false), PassConfig::TYPE_AFTER_REMOVING);
$container->addCompilerPass(new RemoveUnusedSessionMarshallingHandlerPass());
+ // must be registered after MonologBundle's LoggerChannelPass
+ $container->addCompilerPass(new ErrorLoggerCompilerPass(), PassConfig::TYPE_BEFORE_OPTIMIZATION, -32);
if ($container->getParameter('kernel.debug')) {
$container->addCompilerPass(new EnableLoggerDebugModePass(), PassConfig::TYPE_BEFORE_OPTIMIZATION, -33);
diff --git a/src/Symfony/Bundle/FrameworkBundle/HttpCache/HttpCache.php b/src/Symfony/Bundle/FrameworkBundle/HttpCache/HttpCache.php
index f312a7afe4946..481e8cf3ce23e 100644
--- a/src/Symfony/Bundle/FrameworkBundle/HttpCache/HttpCache.php
+++ b/src/Symfony/Bundle/FrameworkBundle/HttpCache/HttpCache.php
@@ -37,7 +37,7 @@ class HttpCache extends BaseHttpCache
/**
* @param $cache The cache directory (default used if null) or the storage instance
*/
- public function __construct(KernelInterface $kernel, string|StoreInterface $cache = null, SurrogateInterface $surrogate = null, array $options = null)
+ public function __construct(KernelInterface $kernel, string|StoreInterface|null $cache = null, ?SurrogateInterface $surrogate = null, ?array $options = null)
{
$this->kernel = $kernel;
$this->surrogate = $surrogate;
@@ -60,7 +60,7 @@ public function __construct(KernelInterface $kernel, string|StoreInterface $cach
parent::__construct($kernel, $this->createStore(), $this->createSurrogate(), array_merge($this->options, $this->getOptions()));
}
- protected function forward(Request $request, bool $catch = false, Response $entry = null): Response
+ protected function forward(Request $request, bool $catch = false, ?Response $entry = null): Response
{
$this->getKernel()->boot();
$this->getKernel()->getContainer()->set('cache', $this);
diff --git a/src/Symfony/Bundle/FrameworkBundle/KernelBrowser.php b/src/Symfony/Bundle/FrameworkBundle/KernelBrowser.php
index 0379be8f5bc97..b059b392a5c39 100644
--- a/src/Symfony/Bundle/FrameworkBundle/KernelBrowser.php
+++ b/src/Symfony/Bundle/FrameworkBundle/KernelBrowser.php
@@ -34,7 +34,7 @@ class KernelBrowser extends HttpKernelBrowser
private bool $profiler = false;
private bool $reboot = true;
- public function __construct(KernelInterface $kernel, array $server = [], History $history = null, CookieJar $cookieJar = null)
+ public function __construct(KernelInterface $kernel, array $server = [], ?History $history = null, ?CookieJar $cookieJar = null)
{
parent::__construct($kernel, $server, $history, $cookieJar);
}
diff --git a/src/Symfony/Bundle/FrameworkBundle/Resources/config/asset_mapper.php b/src/Symfony/Bundle/FrameworkBundle/Resources/config/asset_mapper.php
new file mode 100644
index 0000000000000..b73d70fcfcd11
--- /dev/null
+++ b/src/Symfony/Bundle/FrameworkBundle/Resources/config/asset_mapper.php
@@ -0,0 +1,206 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\DependencyInjection\Loader\Configurator;
+
+use Symfony\Component\AssetMapper\AssetMapper;
+use Symfony\Component\AssetMapper\AssetMapperCompiler;
+use Symfony\Component\AssetMapper\AssetMapperDevServerSubscriber;
+use Symfony\Component\AssetMapper\AssetMapperInterface;
+use Symfony\Component\AssetMapper\AssetMapperRepository;
+use Symfony\Component\AssetMapper\Command\AssetMapperCompileCommand;
+use Symfony\Component\AssetMapper\Command\DebugAssetMapperCommand;
+use Symfony\Component\AssetMapper\Command\ImportMapExportCommand;
+use Symfony\Component\AssetMapper\Command\ImportMapRemoveCommand;
+use Symfony\Component\AssetMapper\Command\ImportMapRequireCommand;
+use Symfony\Component\AssetMapper\Command\ImportMapUpdateCommand;
+use Symfony\Component\AssetMapper\Compiler\CssAssetUrlCompiler;
+use Symfony\Component\AssetMapper\Compiler\JavaScriptImportPathCompiler;
+use Symfony\Component\AssetMapper\Compiler\SourceMappingUrlsCompiler;
+use Symfony\Component\AssetMapper\Factory\CachedMappedAssetFactory;
+use Symfony\Component\AssetMapper\Factory\MappedAssetFactory;
+use Symfony\Component\AssetMapper\ImportMap\ImportMapManager;
+use Symfony\Component\AssetMapper\ImportMap\ImportMapRenderer;
+use Symfony\Component\AssetMapper\ImportMap\Resolver\JsDelivrEsmResolver;
+use Symfony\Component\AssetMapper\ImportMap\Resolver\JspmResolver;
+use Symfony\Component\AssetMapper\ImportMap\Resolver\PackageResolver;
+use Symfony\Component\AssetMapper\MapperAwareAssetPackage;
+use Symfony\Component\AssetMapper\Path\PublicAssetsPathResolver;
+use Symfony\Component\HttpKernel\Event\RequestEvent;
+
+return static function (ContainerConfigurator $container) {
+ $container->services()
+ ->set('asset_mapper', AssetMapper::class)
+ ->args([
+ service('asset_mapper.repository'),
+ service('asset_mapper.mapped_asset_factory'),
+ service('asset_mapper.public_assets_path_resolver'),
+ ])
+ ->alias(AssetMapperInterface::class, 'asset_mapper')
+
+ ->set('asset_mapper.mapped_asset_factory', MappedAssetFactory::class)
+ ->args([
+ service('asset_mapper.public_assets_path_resolver'),
+ service('asset_mapper_compiler'),
+ ])
+
+ ->set('asset_mapper.cached_mapped_asset_factory', CachedMappedAssetFactory::class)
+ ->args([
+ service('.inner'),
+ param('kernel.cache_dir').'/asset_mapper',
+ param('kernel.debug'),
+ ])
+ ->decorate('asset_mapper.mapped_asset_factory')
+
+ ->set('asset_mapper.repository', AssetMapperRepository::class)
+ ->args([
+ abstract_arg('array of asset mapper paths'),
+ param('kernel.project_dir'),
+ abstract_arg('array of excluded path patterns'),
+ ])
+
+ ->set('asset_mapper.public_assets_path_resolver', PublicAssetsPathResolver::class)
+ ->args([
+ param('kernel.project_dir'),
+ abstract_arg('asset public prefix'),
+ abstract_arg('public directory name'),
+ ])
+
+ ->set('asset_mapper.asset_package', MapperAwareAssetPackage::class)
+ ->decorate('assets._default_package')
+ ->args([
+ service('.inner'),
+ service('asset_mapper'),
+ ])
+
+ ->set('asset_mapper.dev_server_subscriber', AssetMapperDevServerSubscriber::class)
+ ->args([
+ service('asset_mapper'),
+ abstract_arg('asset public prefix'),
+ abstract_arg('extensions map'),
+ service('cache.asset_mapper'),
+ ])
+ ->tag('kernel.event_subscriber', ['event' => RequestEvent::class])
+
+ ->set('asset_mapper.command.compile', AssetMapperCompileCommand::class)
+ ->args([
+ service('asset_mapper.public_assets_path_resolver'),
+ service('asset_mapper'),
+ service('asset_mapper.importmap.manager'),
+ service('filesystem'),
+ param('kernel.project_dir'),
+ abstract_arg('public directory name'),
+ param('kernel.debug'),
+ ])
+ ->tag('console.command')
+
+ ->set('asset_mapper.command.debug', DebugAssetMapperCommand::class)
+ ->args([
+ service('asset_mapper'),
+ service('asset_mapper.repository'),
+ param('kernel.project_dir'),
+ ])
+ ->tag('console.command')
+
+ ->set('asset_mapper_compiler', AssetMapperCompiler::class)
+ ->args([
+ tagged_iterator('asset_mapper.compiler'),
+ service_closure('asset_mapper'),
+ ])
+
+ ->set('asset_mapper.compiler.css_asset_url_compiler', CssAssetUrlCompiler::class)
+ ->args([
+ abstract_arg('missing import mode'),
+ service('logger'),
+ ])
+ ->tag('asset_mapper.compiler')
+ ->tag('monolog.logger', ['channel' => 'asset_mapper'])
+
+ ->set('asset_mapper.compiler.source_mapping_urls_compiler', SourceMappingUrlsCompiler::class)
+ ->tag('asset_mapper.compiler')
+
+ ->set('asset_mapper.compiler.javascript_import_path_compiler', JavaScriptImportPathCompiler::class)
+ ->args([
+ abstract_arg('missing import mode'),
+ service('logger'),
+ ])
+ ->tag('asset_mapper.compiler')
+ ->tag('monolog.logger', ['channel' => 'asset_mapper'])
+
+ ->set('asset_mapper.importmap.manager', ImportMapManager::class)
+ ->args([
+ service('asset_mapper'),
+ service('asset_mapper.public_assets_path_resolver'),
+ abstract_arg('importmap.php path'),
+ abstract_arg('vendor directory'),
+ service('asset_mapper.importmap.resolver'),
+ ])
+ ->alias(ImportMapManager::class, 'asset_mapper.importmap.manager')
+
+ ->set('asset_mapper.importmap.resolver', PackageResolver::class)
+ ->args([
+ abstract_arg('provider'),
+ tagged_locator('asset_mapper.importmap.resolver'),
+ ])
+
+ ->set('asset_mapper.importmap.resolver.jsdelivr_esm', JsDelivrEsmResolver::class)
+ ->args([service('http_client')])
+ ->tag('asset_mapper.importmap.resolver', ['resolver' => ImportMapManager::PROVIDER_JSDELIVR_ESM])
+
+ ->set('asset_mapper.importmap.resolver.jspm', JspmResolver::class)
+ ->args([service('http_client'), ImportMapManager::PROVIDER_JSPM])
+ ->tag('asset_mapper.importmap.resolver', ['resolver' => ImportMapManager::PROVIDER_JSPM])
+
+ ->set('asset_mapper.importmap.resolver.jspm_system', JspmResolver::class)
+ ->args([service('http_client'), ImportMapManager::PROVIDER_JSPM_SYSTEM])
+ ->tag('asset_mapper.importmap.resolver', ['resolver' => ImportMapManager::PROVIDER_JSPM_SYSTEM])
+
+ ->set('asset_mapper.importmap.resolver.skypack', JspmResolver::class)
+ ->args([service('http_client'), ImportMapManager::PROVIDER_SKYPACK])
+ ->tag('asset_mapper.importmap.resolver', ['resolver' => ImportMapManager::PROVIDER_SKYPACK])
+
+ ->set('asset_mapper.importmap.resolver.jsdelivr', JspmResolver::class)
+ ->args([service('http_client'), ImportMapManager::PROVIDER_JSDELIVR])
+ ->tag('asset_mapper.importmap.resolver', ['resolver' => ImportMapManager::PROVIDER_JSDELIVR])
+
+ ->set('asset_mapper.importmap.resolver.unpkg', JspmResolver::class)
+ ->args([service('http_client'), ImportMapManager::PROVIDER_UNPKG])
+ ->tag('asset_mapper.importmap.resolver', ['resolver' => ImportMapManager::PROVIDER_UNPKG])
+
+ ->set('asset_mapper.importmap.renderer', ImportMapRenderer::class)
+ ->args([
+ service('asset_mapper.importmap.manager'),
+ param('kernel.charset'),
+ abstract_arg('polyfill URL'),
+ abstract_arg('script HTML attributes'),
+ ])
+
+ ->set('asset_mapper.importmap.command.require', ImportMapRequireCommand::class)
+ ->args([
+ service('asset_mapper.importmap.manager'),
+ service('asset_mapper'),
+ param('kernel.project_dir'),
+ ])
+ ->tag('console.command')
+
+ ->set('asset_mapper.importmap.command.remove', ImportMapRemoveCommand::class)
+ ->args([service('asset_mapper.importmap.manager')])
+ ->tag('console.command')
+
+ ->set('asset_mapper.importmap.command.update', ImportMapUpdateCommand::class)
+ ->args([service('asset_mapper.importmap.manager')])
+ ->tag('console.command')
+
+ ->set('asset_mapper.importmap.command.export', ImportMapExportCommand::class)
+ ->args([service('asset_mapper.importmap.manager')])
+ ->tag('console.command')
+ ;
+};
diff --git a/src/Symfony/Bundle/FrameworkBundle/Resources/config/cache.php b/src/Symfony/Bundle/FrameworkBundle/Resources/config/cache.php
index 2ea62a0b71882..87207cf95c59e 100644
--- a/src/Symfony/Bundle/FrameworkBundle/Resources/config/cache.php
+++ b/src/Symfony/Bundle/FrameworkBundle/Resources/config/cache.php
@@ -66,6 +66,11 @@
->private()
->tag('cache.pool')
+ ->set('cache.asset_mapper')
+ ->parent('cache.system')
+ ->private()
+ ->tag('cache.pool')
+
->set('cache.messenger.restart_workers_signal')
->parent('cache.app')
->private()
diff --git a/src/Symfony/Bundle/FrameworkBundle/Resources/config/console.php b/src/Symfony/Bundle/FrameworkBundle/Resources/config/console.php
index bfe7e3bc10b40..b49ed07a0a36c 100644
--- a/src/Symfony/Bundle/FrameworkBundle/Resources/config/console.php
+++ b/src/Symfony/Bundle/FrameworkBundle/Resources/config/console.php
@@ -163,6 +163,7 @@
service('messenger.listener.reset_services')->nullOnInvalid(),
[], // Bus names
service('messenger.rate_limiter_locator')->nullOnInvalid(),
+ null,
])
->tag('console.command')
->tag('monolog.logger', ['channel' => 'messenger'])
@@ -192,10 +193,12 @@
abstract_arg('Receivers'),
service('messenger.routable_message_bus'),
service('event_dispatcher'),
- service('logger'),
+ service('logger')->nullOnInvalid(),
service('messenger.transport.native_php_serializer')->nullOnInvalid(),
+ null,
])
->tag('console.command')
+ ->tag('monolog.logger', ['channel' => 'messenger'])
->set('console.command.messenger_failed_messages_show', FailedMessagesShowCommand::class)
->args([
diff --git a/src/Symfony/Bundle/FrameworkBundle/Resources/config/debug_prod.php b/src/Symfony/Bundle/FrameworkBundle/Resources/config/debug_prod.php
index 7f71e2ee93094..63a760fdb19b9 100644
--- a/src/Symfony/Bundle/FrameworkBundle/Resources/config/debug_prod.php
+++ b/src/Symfony/Bundle/FrameworkBundle/Resources/config/debug_prod.php
@@ -22,12 +22,12 @@
->set('debug.error_handler_configurator', ErrorHandlerConfigurator::class)
->public()
->args([
- service('monolog.logger.php')->nullOnInvalid(),
+ service('logger')->nullOnInvalid(),
null, // Log levels map for enabled error levels
param('debug.error_handler.throw_at'),
param('kernel.debug'),
param('kernel.debug'),
- service('monolog.logger.deprecation')->nullOnInvalid(),
+ null, // Deprecation logger if different from the one above
])
->tag('monolog.logger', ['channel' => 'php'])
diff --git a/src/Symfony/Bundle/FrameworkBundle/Resources/config/messenger.php b/src/Symfony/Bundle/FrameworkBundle/Resources/config/messenger.php
index 0096ff1e099f3..3fe593ac673ff 100644
--- a/src/Symfony/Bundle/FrameworkBundle/Resources/config/messenger.php
+++ b/src/Symfony/Bundle/FrameworkBundle/Resources/config/messenger.php
@@ -209,6 +209,9 @@
->tag('kernel.event_subscriber')
->tag('monolog.logger', ['channel' => 'messenger'])
+ ->alias('messenger.listener.stop_worker_on_sigterm_signal_listener', 'messenger.listener.stop_worker_signals_listener')
+ ->deprecate('6.3', 'symfony/messenger', 'The "%alias_id%" service is deprecated, use "messenger.listener.stop_worker_signals_listener" instead.')
+
->set('messenger.listener.stop_worker_on_stop_exception_listener', StopWorkerOnCustomStopExceptionListener::class)
->tag('kernel.event_subscriber')
diff --git a/src/Symfony/Bundle/FrameworkBundle/Resources/config/notifier_transports.php b/src/Symfony/Bundle/FrameworkBundle/Resources/config/notifier_transports.php
index 474f013f000a5..1573aa0bea0a4 100644
--- a/src/Symfony/Bundle/FrameworkBundle/Resources/config/notifier_transports.php
+++ b/src/Symfony/Bundle/FrameworkBundle/Resources/config/notifier_transports.php
@@ -279,5 +279,13 @@
->set('notifier.transport_factory.simple-textin', Bridge\SimpleTextin\SimpleTextinTransportFactory::class)
->parent('notifier.transport_factory.abstract')
->tag('texter.transport_factory')
+
+ ->set('notifier.transport_factory.click-send', Bridge\ClickSend\ClickSendTransportFactory::class)
+ ->parent('notifier.transport_factory.abstract')
+ ->tag('texter.transport_factory')
+
+ ->set('notifier.transport_factory.smsmode', Bridge\Smsmode\SmsmodeTransportFactory::class)
+ ->parent('notifier.transport_factory.abstract')
+ ->tag('texter.transport_factory')
;
};
diff --git a/src/Symfony/Bundle/FrameworkBundle/Resources/config/routing/webhook.xml b/src/Symfony/Bundle/FrameworkBundle/Resources/config/routing/webhook.xml
index aa71fec2d4c23..dfa95cfac555e 100644
--- a/src/Symfony/Bundle/FrameworkBundle/Resources/config/routing/webhook.xml
+++ b/src/Symfony/Bundle/FrameworkBundle/Resources/config/routing/webhook.xml
@@ -6,5 +6,6 @@
webhook.controller::handle
+ .+
diff --git a/src/Symfony/Bundle/FrameworkBundle/Resources/config/schema/symfony-1.0.xsd b/src/Symfony/Bundle/FrameworkBundle/Resources/config/schema/symfony-1.0.xsd
index 33ac86560b756..03396a4ce0fa0 100644
--- a/src/Symfony/Bundle/FrameworkBundle/Resources/config/schema/symfony-1.0.xsd
+++ b/src/Symfony/Bundle/FrameworkBundle/Resources/config/schema/symfony-1.0.xsd
@@ -10,6 +10,7 @@
+
@@ -48,6 +49,7 @@
+
@@ -186,6 +188,43 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -198,6 +237,7 @@
+
@@ -312,6 +352,7 @@
+
@@ -409,8 +450,6 @@
-
-
@@ -937,6 +976,7 @@
+
diff --git a/src/Symfony/Bundle/FrameworkBundle/Resources/config/services.php b/src/Symfony/Bundle/FrameworkBundle/Resources/config/services.php
index 6d805bfbc7dd1..d7b2ad9029114 100644
--- a/src/Symfony/Bundle/FrameworkBundle/Resources/config/services.php
+++ b/src/Symfony/Bundle/FrameworkBundle/Resources/config/services.php
@@ -120,7 +120,7 @@ class_exists(WorkflowEvents::class) ? WorkflowEvents::ALIASES : []
->set('url_helper', UrlHelper::class)
->args([
service('request_stack'),
- service('router.request_context')->ignoreOnInvalid(),
+ service('router')->ignoreOnInvalid(),
])
->alias(UrlHelper::class, 'url_helper')
diff --git a/src/Symfony/Bundle/FrameworkBundle/Resources/config/web.php b/src/Symfony/Bundle/FrameworkBundle/Resources/config/web.php
index 1044ded974721..a3a6ef7735612 100644
--- a/src/Symfony/Bundle/FrameworkBundle/Resources/config/web.php
+++ b/src/Symfony/Bundle/FrameworkBundle/Resources/config/web.php
@@ -70,6 +70,8 @@
service('translator')->nullOnInvalid(),
])
->tag('controller.targeted_value_resolver', ['name' => RequestPayloadValueResolver::class])
+ ->tag('kernel.event_subscriber')
+ ->lazy()
->set('argument_resolver.request_attribute', RequestAttributeValueResolver::class)
->tag('controller.argument_value_resolver', ['priority' => 100, 'name' => RequestAttributeValueResolver::class])
diff --git a/src/Symfony/Bundle/FrameworkBundle/Routing/Attribute/AsRoutingConditionService.php b/src/Symfony/Bundle/FrameworkBundle/Routing/Attribute/AsRoutingConditionService.php
index d1f1a5f34a654..13f8ff26a2ebd 100644
--- a/src/Symfony/Bundle/FrameworkBundle/Routing/Attribute/AsRoutingConditionService.php
+++ b/src/Symfony/Bundle/FrameworkBundle/Routing/Attribute/AsRoutingConditionService.php
@@ -42,7 +42,7 @@
class AsRoutingConditionService extends AutoconfigureTag
{
public function __construct(
- string $alias = null,
+ ?string $alias = null,
int $priority = 0,
) {
parent::__construct('routing.condition_service', ['alias' => $alias, 'priority' => $priority]);
diff --git a/src/Symfony/Bundle/FrameworkBundle/Routing/DelegatingLoader.php b/src/Symfony/Bundle/FrameworkBundle/Routing/DelegatingLoader.php
index df7e9348c3f1c..3239d1094bba5 100644
--- a/src/Symfony/Bundle/FrameworkBundle/Routing/DelegatingLoader.php
+++ b/src/Symfony/Bundle/FrameworkBundle/Routing/DelegatingLoader.php
@@ -40,7 +40,7 @@ public function __construct(LoaderResolverInterface $resolver, array $defaultOpt
parent::__construct($resolver);
}
- public function load(mixed $resource, string $type = null): RouteCollection
+ public function load(mixed $resource, ?string $type = null): RouteCollection
{
if ($this->loading) {
// This can happen if a fatal error occurs in parent::load().
diff --git a/src/Symfony/Bundle/FrameworkBundle/Routing/RedirectableCompiledUrlMatcher.php b/src/Symfony/Bundle/FrameworkBundle/Routing/RedirectableCompiledUrlMatcher.php
index 538427aae6cf2..609502bcafad2 100644
--- a/src/Symfony/Bundle/FrameworkBundle/Routing/RedirectableCompiledUrlMatcher.php
+++ b/src/Symfony/Bundle/FrameworkBundle/Routing/RedirectableCompiledUrlMatcher.php
@@ -21,7 +21,7 @@
*/
class RedirectableCompiledUrlMatcher extends CompiledUrlMatcher implements RedirectableUrlMatcherInterface
{
- public function redirect(string $path, string $route, string $scheme = null): array
+ public function redirect(string $path, string $route, ?string $scheme = null): array
{
return [
'_controller' => 'Symfony\\Bundle\\FrameworkBundle\\Controller\\RedirectController::urlRedirectAction',
diff --git a/src/Symfony/Bundle/FrameworkBundle/Routing/Router.php b/src/Symfony/Bundle/FrameworkBundle/Routing/Router.php
index f9747a3c489a8..519fa3829d7ef 100644
--- a/src/Symfony/Bundle/FrameworkBundle/Routing/Router.php
+++ b/src/Symfony/Bundle/FrameworkBundle/Routing/Router.php
@@ -40,7 +40,7 @@ class Router extends BaseRouter implements WarmableInterface, ServiceSubscriberI
/**
* @param mixed $resource The main resource to load
*/
- public function __construct(ContainerInterface $container, mixed $resource, array $options = [], RequestContext $context = null, ContainerInterface $parameters = null, LoggerInterface $logger = null, string $defaultLocale = null)
+ public function __construct(ContainerInterface $container, mixed $resource, array $options = [], ?RequestContext $context = null, ?ContainerInterface $parameters = null, ?LoggerInterface $logger = null, ?string $defaultLocale = null)
{
$this->container = $container;
$this->resource = $resource;
diff --git a/src/Symfony/Bundle/FrameworkBundle/Secrets/DotenvVault.php b/src/Symfony/Bundle/FrameworkBundle/Secrets/DotenvVault.php
index db4891c34b337..994b31d18be59 100644
--- a/src/Symfony/Bundle/FrameworkBundle/Secrets/DotenvVault.php
+++ b/src/Symfony/Bundle/FrameworkBundle/Secrets/DotenvVault.php
@@ -52,9 +52,9 @@ public function reveal(string $name): ?string
{
$this->lastMessage = null;
$this->validateName($name);
- $v = \is_string($_SERVER[$name] ?? null) && !str_starts_with($name, 'HTTP_') ? $_SERVER[$name] : ($_ENV[$name] ?? null);
+ $v = $_ENV[$name] ?? (str_starts_with($name, 'HTTP_') ? null : ($_SERVER[$name] ?? null));
- if (null === $v) {
+ if ('' === ($v ?? '')) {
$this->lastMessage = sprintf('Secret "%s" not found in "%s".', $name, $this->getPrettyPath($this->dotenvFile));
return null;
@@ -89,13 +89,13 @@ public function list(bool $reveal = false): array
$secrets = [];
foreach ($_ENV as $k => $v) {
- if (preg_match('/^\w+$/D', $k)) {
+ if ('' !== ($v ?? '') && preg_match('/^\w+$/D', $k)) {
$secrets[$k] = $reveal ? $v : null;
}
}
foreach ($_SERVER as $k => $v) {
- if (\is_string($v) && preg_match('/^\w+$/D', $k)) {
+ if ('' !== ($v ?? '') && preg_match('/^\w+$/D', $k)) {
$secrets[$k] = $reveal ? $v : null;
}
}
diff --git a/src/Symfony/Bundle/FrameworkBundle/Secrets/SodiumVault.php b/src/Symfony/Bundle/FrameworkBundle/Secrets/SodiumVault.php
index b6bb058b3f170..9b8208d90c886 100644
--- a/src/Symfony/Bundle/FrameworkBundle/Secrets/SodiumVault.php
+++ b/src/Symfony/Bundle/FrameworkBundle/Secrets/SodiumVault.php
@@ -30,7 +30,7 @@ class SodiumVault extends AbstractVault implements EnvVarLoaderInterface
* @param $decryptionKey A string or a stringable object that defines the private key to use to decrypt the vault
* or null to store generated keys in the provided $secretsDir
*/
- public function __construct(string $secretsDir, #[\SensitiveParameter] string|\Stringable $decryptionKey = null)
+ public function __construct(string $secretsDir, #[\SensitiveParameter] string|\Stringable|null $decryptionKey = null)
{
$this->pathPrefix = rtrim(strtr($secretsDir, '/', \DIRECTORY_SEPARATOR), \DIRECTORY_SEPARATOR).\DIRECTORY_SEPARATOR.basename($secretsDir).'.';
$this->decryptionKey = $decryptionKey;
diff --git a/src/Symfony/Bundle/FrameworkBundle/Test/BrowserKitAssertionsTrait.php b/src/Symfony/Bundle/FrameworkBundle/Test/BrowserKitAssertionsTrait.php
index 55b95f055994f..9b8db8ca3acf1 100644
--- a/src/Symfony/Bundle/FrameworkBundle/Test/BrowserKitAssertionsTrait.php
+++ b/src/Symfony/Bundle/FrameworkBundle/Test/BrowserKitAssertionsTrait.php
@@ -43,7 +43,7 @@ public static function assertResponseFormatSame(?string $expectedFormat, string
self::assertThatForResponse(new ResponseConstraint\ResponseFormatSame(self::getRequest(), $expectedFormat), $message);
}
- public static function assertResponseRedirects(string $expectedLocation = null, int $expectedCode = null, string $message = ''): void
+ public static function assertResponseRedirects(?string $expectedLocation = null, ?int $expectedCode = null, string $message = ''): void
{
$constraint = new ResponseConstraint\ResponseIsRedirected();
if ($expectedLocation) {
@@ -76,17 +76,17 @@ public static function assertResponseHeaderNotSame(string $headerName, string $e
self::assertThatForResponse(new LogicalNot(new ResponseConstraint\ResponseHeaderSame($headerName, $expectedValue)), $message);
}
- public static function assertResponseHasCookie(string $name, string $path = '/', string $domain = null, string $message = ''): void
+ public static function assertResponseHasCookie(string $name, string $path = '/', ?string $domain = null, string $message = ''): void
{
self::assertThatForResponse(new ResponseConstraint\ResponseHasCookie($name, $path, $domain), $message);
}
- public static function assertResponseNotHasCookie(string $name, string $path = '/', string $domain = null, string $message = ''): void
+ public static function assertResponseNotHasCookie(string $name, string $path = '/', ?string $domain = null, string $message = ''): void
{
self::assertThatForResponse(new LogicalNot(new ResponseConstraint\ResponseHasCookie($name, $path, $domain)), $message);
}
- public static function assertResponseCookieValueSame(string $name, string $expectedValue, string $path = '/', string $domain = null, string $message = ''): void
+ public static function assertResponseCookieValueSame(string $name, string $expectedValue, string $path = '/', ?string $domain = null, string $message = ''): void
{
self::assertThatForResponse(LogicalAnd::fromConstraints(
new ResponseConstraint\ResponseHasCookie($name, $path, $domain),
@@ -99,17 +99,17 @@ public static function assertResponseIsUnprocessable(string $message = ''): void
self::assertThatForResponse(new ResponseConstraint\ResponseIsUnprocessable(), $message);
}
- public static function assertBrowserHasCookie(string $name, string $path = '/', string $domain = null, string $message = ''): void
+ public static function assertBrowserHasCookie(string $name, string $path = '/', ?string $domain = null, string $message = ''): void
{
self::assertThatForClient(new BrowserKitConstraint\BrowserHasCookie($name, $path, $domain), $message);
}
- public static function assertBrowserNotHasCookie(string $name, string $path = '/', string $domain = null, string $message = ''): void
+ public static function assertBrowserNotHasCookie(string $name, string $path = '/', ?string $domain = null, string $message = ''): void
{
self::assertThatForClient(new LogicalNot(new BrowserKitConstraint\BrowserHasCookie($name, $path, $domain)), $message);
}
- public static function assertBrowserCookieValueSame(string $name, string $expectedValue, bool $raw = false, string $path = '/', string $domain = null, string $message = ''): void
+ public static function assertBrowserCookieValueSame(string $name, string $expectedValue, bool $raw = false, string $path = '/', ?string $domain = null, string $message = ''): void
{
self::assertThatForClient(LogicalAnd::fromConstraints(
new BrowserKitConstraint\BrowserHasCookie($name, $path, $domain),
@@ -156,7 +156,7 @@ public static function assertThatForClient(Constraint $constraint, string $messa
self::assertThat(self::getClient(), $constraint, $message);
}
- private static function getClient(AbstractBrowser $newClient = null): ?AbstractBrowser
+ private static function getClient(?AbstractBrowser $newClient = null): ?AbstractBrowser
{
static $client;
diff --git a/src/Symfony/Bundle/FrameworkBundle/Test/MailerAssertionsTrait.php b/src/Symfony/Bundle/FrameworkBundle/Test/MailerAssertionsTrait.php
index d6b29d2b5a0c6..82f0b255e102b 100644
--- a/src/Symfony/Bundle/FrameworkBundle/Test/MailerAssertionsTrait.php
+++ b/src/Symfony/Bundle/FrameworkBundle/Test/MailerAssertionsTrait.php
@@ -20,12 +20,12 @@
trait MailerAssertionsTrait
{
- public static function assertEmailCount(int $count, string $transport = null, string $message = ''): void
+ public static function assertEmailCount(int $count, ?string $transport = null, string $message = ''): void
{
self::assertThat(self::getMessageMailerEvents(), new MailerConstraint\EmailCount($count, $transport), $message);
}
- public static function assertQueuedEmailCount(int $count, string $transport = null, string $message = ''): void
+ public static function assertQueuedEmailCount(int $count, ?string $transport = null, string $message = ''): void
{
self::assertThat(self::getMessageMailerEvents(), new MailerConstraint\EmailCount($count, $transport, true), $message);
}
@@ -93,12 +93,12 @@ public static function assertEmailAddressContains(RawMessage $email, string $hea
/**
* @return MessageEvent[]
*/
- public static function getMailerEvents(string $transport = null): array
+ public static function getMailerEvents(?string $transport = null): array
{
return self::getMessageMailerEvents()->getEvents($transport);
}
- public static function getMailerEvent(int $index = 0, string $transport = null): ?MessageEvent
+ public static function getMailerEvent(int $index = 0, ?string $transport = null): ?MessageEvent
{
return self::getMailerEvents($transport)[$index] ?? null;
}
@@ -106,12 +106,12 @@ public static function getMailerEvent(int $index = 0, string $transport = null):
/**
* @return RawMessage[]
*/
- public static function getMailerMessages(string $transport = null): array
+ public static function getMailerMessages(?string $transport = null): array
{
return self::getMessageMailerEvents()->getMessages($transport);
}
- public static function getMailerMessage(int $index = 0, string $transport = null): ?RawMessage
+ public static function getMailerMessage(int $index = 0, ?string $transport = null): ?RawMessage
{
return self::getMailerMessages($transport)[$index] ?? null;
}
diff --git a/src/Symfony/Bundle/FrameworkBundle/Test/NotificationAssertionsTrait.php b/src/Symfony/Bundle/FrameworkBundle/Test/NotificationAssertionsTrait.php
index 30298ef04c54f..ed1968ea3ce8d 100644
--- a/src/Symfony/Bundle/FrameworkBundle/Test/NotificationAssertionsTrait.php
+++ b/src/Symfony/Bundle/FrameworkBundle/Test/NotificationAssertionsTrait.php
@@ -22,14 +22,14 @@
*/
trait NotificationAssertionsTrait
{
- public static function assertNotificationCount(int $count, string $transportName = null, string $message = ''): void
+ public static function assertNotificationCount(int $count, ?string $transportName = null, string $message = ''): void
{
self::assertThat(self::getNotificationEvents(), new NotifierConstraint\NotificationCount($count, $transportName), $message);
}
- public static function assertQueuedNotificationCount(int $count, string $transportName = null, string $message = ''): void
+ public static function assertQueuedNotificationCount(int $count, ?string $transportName = null, string $message = ''): void
{
- self::assertThat(self::getMessageMailerEvents(), new NotifierConstraint\NotificationCount($count, $transportName, true), $message);
+ self::assertThat(self::getNotificationEvents(), new NotifierConstraint\NotificationCount($count, $transportName, true), $message);
}
public static function assertNotificationIsQueued(MessageEvent $event, string $message = ''): void
@@ -65,12 +65,12 @@ public static function assertNotificationTransportIsNotEqual(MessageInterface $n
/**
* @return MessageEvent[]
*/
- public static function getNotifierEvents(string $transportName = null): array
+ public static function getNotifierEvents(?string $transportName = null): array
{
return self::getNotificationEvents()->getEvents($transportName);
}
- public static function getNotifierEvent(int $index = 0, string $transportName = null): ?MessageEvent
+ public static function getNotifierEvent(int $index = 0, ?string $transportName = null): ?MessageEvent
{
return self::getNotifierEvents($transportName)[$index] ?? null;
}
@@ -78,12 +78,12 @@ public static function getNotifierEvent(int $index = 0, string $transportName =
/**
* @return MessageInterface[]
*/
- public static function getNotifierMessages(string $transportName = null): array
+ public static function getNotifierMessages(?string $transportName = null): array
{
return self::getNotificationEvents()->getMessages($transportName);
}
- public static function getNotifierMessage(int $index = 0, string $transportName = null): ?MessageInterface
+ public static function getNotifierMessage(int $index = 0, ?string $transportName = null): ?MessageInterface
{
return self::getNotifierMessages($transportName)[$index] ?? null;
}
diff --git a/src/Symfony/Bundle/FrameworkBundle/Test/TestBrowserToken.php b/src/Symfony/Bundle/FrameworkBundle/Test/TestBrowserToken.php
index 8bf365eb06380..25d71d084a25b 100644
--- a/src/Symfony/Bundle/FrameworkBundle/Test/TestBrowserToken.php
+++ b/src/Symfony/Bundle/FrameworkBundle/Test/TestBrowserToken.php
@@ -23,7 +23,7 @@ class TestBrowserToken extends AbstractToken
{
private string $firewallName;
- public function __construct(array $roles = [], UserInterface $user = null, string $firewallName = 'main')
+ public function __construct(array $roles = [], ?UserInterface $user = null, string $firewallName = 'main')
{
parent::__construct($roles);
diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/CacheWarmer/ConfigBuilderCacheWarmerTest.php b/src/Symfony/Bundle/FrameworkBundle/Tests/CacheWarmer/ConfigBuilderCacheWarmerTest.php
new file mode 100644
index 0000000000000..1336caed35c55
--- /dev/null
+++ b/src/Symfony/Bundle/FrameworkBundle/Tests/CacheWarmer/ConfigBuilderCacheWarmerTest.php
@@ -0,0 +1,82 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Bundle\FrameworkBundle\Tests\CacheWarmer;
+
+use Symfony\Bundle\FrameworkBundle\CacheWarmer\ConfigBuilderCacheWarmer;
+use Symfony\Bundle\FrameworkBundle\FrameworkBundle;
+use Symfony\Bundle\FrameworkBundle\Tests\TestCase;
+use Symfony\Component\Config\Loader\LoaderInterface;
+use Symfony\Component\DependencyInjection\ContainerBuilder;
+use Symfony\Component\Filesystem\Filesystem;
+use Symfony\Component\HttpKernel\Kernel;
+
+class ConfigBuilderCacheWarmerTest extends TestCase
+{
+ private $varDir;
+
+ protected function setUp(): void
+ {
+ $this->varDir = sys_get_temp_dir().'/'.uniqid();
+ $fs = new Filesystem();
+ $fs->mkdir($this->varDir);
+ }
+
+ protected function tearDown(): void
+ {
+ $fs = new Filesystem();
+ $fs->remove($this->varDir);
+ unset($this->varDir);
+ }
+
+ public function testBuildDirIsUsedAsConfigBuilderOutputDir()
+ {
+ $kernel = new class($this->varDir) extends Kernel {
+ private $varDir;
+
+ public function __construct(string $varDir)
+ {
+ parent::__construct('test', false);
+
+ $this->varDir = $varDir;
+ }
+
+ public function registerBundles(): iterable
+ {
+ yield new FrameworkBundle();
+ }
+
+ public function getBuildDir(): string
+ {
+ return $this->varDir.'/build';
+ }
+
+ public function getCacheDir(): string
+ {
+ return $this->varDir.'/cache';
+ }
+
+ public function registerContainerConfiguration(LoaderInterface $loader): void
+ {
+ $loader->load(static function (ContainerBuilder $container) {
+ $container->loadFromExtension('framework', ['http_method_override' => false]);
+ });
+ }
+ };
+ $kernel->boot();
+
+ $warmer = new ConfigBuilderCacheWarmer($kernel);
+ $warmer->warmUp($kernel->getCacheDir());
+
+ self::assertDirectoryExists($kernel->getBuildDir().'/Symfony');
+ self::assertDirectoryDoesNotExist($kernel->getCacheDir().'/Symfony');
+ }
+}
diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/CacheWarmer/SerializerCacheWarmerTest.php b/src/Symfony/Bundle/FrameworkBundle/Tests/CacheWarmer/SerializerCacheWarmerTest.php
index 85dbd88104f57..5feb0c8ec1bd7 100644
--- a/src/Symfony/Bundle/FrameworkBundle/Tests/CacheWarmer/SerializerCacheWarmerTest.php
+++ b/src/Symfony/Bundle/FrameworkBundle/Tests/CacheWarmer/SerializerCacheWarmerTest.php
@@ -40,7 +40,7 @@ public function testWarmUp(array $loaders)
$this->assertTrue($arrayPool->getItem('Symfony_Bundle_FrameworkBundle_Tests_Fixtures_Serialization_Author')->isHit());
}
- public static function loaderProvider()
+ public static function loaderProvider(): array
{
return [
[
diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/Command/CachePoolClearCommandTest.php b/src/Symfony/Bundle/FrameworkBundle/Tests/Command/CachePoolClearCommandTest.php
index 12ae2bd39236e..62f66b614e45d 100644
--- a/src/Symfony/Bundle/FrameworkBundle/Tests/Command/CachePoolClearCommandTest.php
+++ b/src/Symfony/Bundle/FrameworkBundle/Tests/Command/CachePoolClearCommandTest.php
@@ -44,7 +44,7 @@ public function testComplete(array $input, array $expectedSuggestions)
$this->assertSame($expectedSuggestions, $suggestions);
}
- public static function provideCompletionSuggestions()
+ public static function provideCompletionSuggestions(): iterable
{
yield 'pool_name' => [
['f'],
diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/Command/CachePoolDeleteCommandTest.php b/src/Symfony/Bundle/FrameworkBundle/Tests/Command/CachePoolDeleteCommandTest.php
index b910489abb839..a5c741cda488c 100644
--- a/src/Symfony/Bundle/FrameworkBundle/Tests/Command/CachePoolDeleteCommandTest.php
+++ b/src/Symfony/Bundle/FrameworkBundle/Tests/Command/CachePoolDeleteCommandTest.php
@@ -98,7 +98,7 @@ public function testComplete(array $input, array $expectedSuggestions)
$this->assertSame($expectedSuggestions, $suggestions);
}
- public static function provideCompletionSuggestions()
+ public static function provideCompletionSuggestions(): iterable
{
yield 'pool_name' => [
['f'],
diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/Command/EventDispatcherDebugCommandTest.php b/src/Symfony/Bundle/FrameworkBundle/Tests/Command/EventDispatcherDebugCommandTest.php
index 331d8d44a52f8..359196e11dd28 100644
--- a/src/Symfony/Bundle/FrameworkBundle/Tests/Command/EventDispatcherDebugCommandTest.php
+++ b/src/Symfony/Bundle/FrameworkBundle/Tests/Command/EventDispatcherDebugCommandTest.php
@@ -32,7 +32,7 @@ public function testComplete(array $input, array $expectedSuggestions)
$this->assertSame($expectedSuggestions, $suggestions);
}
- public static function provideCompletionSuggestions()
+ public static function provideCompletionSuggestions(): iterable
{
yield 'event' => [[''], [MessageEvent::class, 'console.command']];
yield 'event for other dispatcher' => [['--dispatcher', 'other_event_dispatcher', ''], ['other_event', 'App\OtherEvent']];
diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/Command/SecretsListCommandTest.php b/src/Symfony/Bundle/FrameworkBundle/Tests/Command/SecretsListCommandTest.php
new file mode 100644
index 0000000000000..12d3ab2e8ac28
--- /dev/null
+++ b/src/Symfony/Bundle/FrameworkBundle/Tests/Command/SecretsListCommandTest.php
@@ -0,0 +1,57 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Bundle\FrameworkBundle\Tests\Command;
+
+use PHPUnit\Framework\TestCase;
+use Symfony\Bundle\FrameworkBundle\Command\SecretsListCommand;
+use Symfony\Bundle\FrameworkBundle\Secrets\AbstractVault;
+use Symfony\Bundle\FrameworkBundle\Secrets\DotenvVault;
+use Symfony\Component\Console\Tester\CommandTester;
+
+class SecretsListCommandTest extends TestCase
+{
+ /**
+ * @backupGlobals enabled
+ */
+ public function testExecute()
+ {
+ $vault = $this->createMock(AbstractVault::class);
+ $vault->method('list')->willReturn(['A' => 'a', 'B' => 'b', 'C' => null, 'D' => null, 'E' => null]);
+
+ $_ENV = ['A' => '', 'B' => 'A', 'C' => '', 'D' => false, 'E' => null];
+ $localVault = new DotenvVault('/not/a/path');
+
+ $command = new SecretsListCommand($vault, $localVault);
+ $tester = new CommandTester($command);
+ $this->assertSame(0, $tester->execute([]));
+
+ $expectedOutput = <<)%%" to reference a secret in a config file.
+
+ // To reveal the secrets run %s secrets:list --reveal
+
+ -------- -------- -------------
+ Secret Value Local Value
+ -------- -------- -------------
+ A "a"
+ B "b" ******
+ C ******
+ D ****** ******
+ E ******
+ -------- -------- -------------
+
+ // Local values override secret values.
+ // Use secrets:set --local to define them.
+ EOTXT;
+ $this->assertStringMatchesFormat($expectedOutput, trim(preg_replace('/ ++$/m', '', $tester->getDisplay(true)), "\n"));
+ }
+}
diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/Command/SecretsRemoveCommandTest.php b/src/Symfony/Bundle/FrameworkBundle/Tests/Command/SecretsRemoveCommandTest.php
index 88c247ec61ebc..2c12b6128d9f5 100644
--- a/src/Symfony/Bundle/FrameworkBundle/Tests/Command/SecretsRemoveCommandTest.php
+++ b/src/Symfony/Bundle/FrameworkBundle/Tests/Command/SecretsRemoveCommandTest.php
@@ -37,7 +37,7 @@ public function testComplete(bool $withLocalVault, array $input, array $expected
$this->assertSame($expectedSuggestions, $suggestions);
}
- public static function provideCompletionSuggestions()
+ public static function provideCompletionSuggestions(): iterable
{
yield 'name' => [true, [''], ['SECRET', 'OTHER_SECRET']];
yield '--local name (with local vault)' => [true, ['--local', ''], ['SECRET']];
diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/Command/SecretsSetCommandTest.php b/src/Symfony/Bundle/FrameworkBundle/Tests/Command/SecretsSetCommandTest.php
index 8e8e968c8f710..678fb417c53cf 100644
--- a/src/Symfony/Bundle/FrameworkBundle/Tests/Command/SecretsSetCommandTest.php
+++ b/src/Symfony/Bundle/FrameworkBundle/Tests/Command/SecretsSetCommandTest.php
@@ -32,7 +32,7 @@ public function testComplete(array $input, array $expectedSuggestions)
$this->assertSame($expectedSuggestions, $suggestions);
}
- public static function provideCompletionSuggestions()
+ public static function provideCompletionSuggestions(): iterable
{
yield 'name' => [[''], ['SECRET', 'OTHER_SECRET']];
yield '--local name (with local vault)' => [['--local', ''], ['SECRET', 'OTHER_SECRET']];
diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/Command/TranslationDebugCommandTest.php b/src/Symfony/Bundle/FrameworkBundle/Tests/Command/TranslationDebugCommandTest.php
index 846abd44500e0..57535aea50e35 100644
--- a/src/Symfony/Bundle/FrameworkBundle/Tests/Command/TranslationDebugCommandTest.php
+++ b/src/Symfony/Bundle/FrameworkBundle/Tests/Command/TranslationDebugCommandTest.php
@@ -158,12 +158,12 @@ protected function tearDown(): void
$this->fs->remove($this->translationDir);
}
- private function createCommandTester(array $extractedMessages = [], array $loadedMessages = [], KernelInterface $kernel = null, array $transPaths = [], array $codePaths = []): CommandTester
+ private function createCommandTester(array $extractedMessages = [], array $loadedMessages = [], ?KernelInterface $kernel = null, array $transPaths = [], array $codePaths = []): CommandTester
{
return new CommandTester($this->createCommand($extractedMessages, $loadedMessages, $kernel, $transPaths, $codePaths));
}
- private function createCommand(array $extractedMessages = [], array $loadedMessages = [], KernelInterface $kernel = null, array $transPaths = [], array $codePaths = [], ExtractorInterface $extractor = null, array $bundles = [], array $enabledLocales = []): TranslationDebugCommand
+ private function createCommand(array $extractedMessages = [], array $loadedMessages = [], ?KernelInterface $kernel = null, array $transPaths = [], array $codePaths = [], ?ExtractorInterface $extractor = null, array $bundles = [], array $enabledLocales = []): TranslationDebugCommand
{
$translator = $this->createMock(Translator::class);
$translator
@@ -269,7 +269,7 @@ function ($path, $catalogue) use ($extractedMessagesWithDomains) {
$this->assertSame($expectedSuggestions, $suggestions);
}
- public static function provideCompletionSuggestions()
+ public static function provideCompletionSuggestions(): iterable
{
yield 'locale' => [
[''],
diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/Command/TranslationUpdateCommandCompletionTest.php b/src/Symfony/Bundle/FrameworkBundle/Tests/Command/TranslationUpdateCommandCompletionTest.php
index 91999d288266e..0b8ee7648eab6 100644
--- a/src/Symfony/Bundle/FrameworkBundle/Tests/Command/TranslationUpdateCommandCompletionTest.php
+++ b/src/Symfony/Bundle/FrameworkBundle/Tests/Command/TranslationUpdateCommandCompletionTest.php
@@ -42,7 +42,7 @@ public function testComplete(array $input, array $expectedSuggestions)
$this->assertSame($expectedSuggestions, $suggestions);
}
- public static function provideCompletionSuggestions()
+ public static function provideCompletionSuggestions(): iterable
{
$bundle = new ExtensionPresentBundle();
@@ -67,7 +67,7 @@ protected function tearDown(): void
$this->fs->remove($this->translationDir);
}
- private function createCommandCompletionTester($extractedMessages = [], $loadedMessages = [], KernelInterface $kernel = null, array $transPaths = [], array $codePaths = []): CommandCompletionTester
+ private function createCommandCompletionTester($extractedMessages = [], $loadedMessages = [], ?KernelInterface $kernel = null, array $transPaths = [], array $codePaths = []): CommandCompletionTester
{
$translator = $this->createMock(Translator::class);
$translator
diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/Command/TranslationUpdateCommandTest.php b/src/Symfony/Bundle/FrameworkBundle/Tests/Command/TranslationUpdateCommandTest.php
index f883fac0c57ce..8b2ad0891ce28 100644
--- a/src/Symfony/Bundle/FrameworkBundle/Tests/Command/TranslationUpdateCommandTest.php
+++ b/src/Symfony/Bundle/FrameworkBundle/Tests/Command/TranslationUpdateCommandTest.php
@@ -193,7 +193,7 @@ protected function tearDown(): void
$this->fs->remove($this->translationDir);
}
- private function createCommandTester($extractedMessages = [], $loadedMessages = [], KernelInterface $kernel = null, array $transPaths = [], array $codePaths = []): CommandTester
+ private function createCommandTester($extractedMessages = [], $loadedMessages = [], ?KernelInterface $kernel = null, array $transPaths = [], array $codePaths = []): CommandTester
{
$translator = $this->createMock(Translator::class);
$translator
diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/Console/Descriptor/ObjectsProvider.php b/src/Symfony/Bundle/FrameworkBundle/Tests/Console/Descriptor/ObjectsProvider.php
index daafc6011d3d0..cc9cfad683a72 100644
--- a/src/Symfony/Bundle/FrameworkBundle/Tests/Console/Descriptor/ObjectsProvider.php
+++ b/src/Symfony/Bundle/FrameworkBundle/Tests/Console/Descriptor/ObjectsProvider.php
@@ -169,6 +169,7 @@ public static function getContainerDefinitions()
->addTag('tag1', ['attr1' => 'val1', 'attr2' => 'val2'])
->addTag('tag1', ['attr3' => 'val3'])
->addTag('tag2')
+ ->addTag('tag3', ['array_attr' => ['foo', 'bar', [[[['ccc']]]]]])
->addMethodCall('setMailer', [new Reference('mailer')])
->setFactory([new Reference('factory.service'), 'get']),
'.definition_3' => $definition3
diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/Controller/AbstractControllerTest.php b/src/Symfony/Bundle/FrameworkBundle/Tests/Controller/AbstractControllerTest.php
index efa9c7becab59..aa3e67919ecc8 100644
--- a/src/Symfony/Bundle/FrameworkBundle/Tests/Controller/AbstractControllerTest.php
+++ b/src/Symfony/Bundle/FrameworkBundle/Tests/Controller/AbstractControllerTest.php
@@ -386,7 +386,7 @@ public function testdenyAccessUnlessGrantedSetsAttributesAsArray($attribute, $ex
}
}
- public static function provideDenyAccessUnlessGrantedSetsAttributesAsArray()
+ public static function provideDenyAccessUnlessGrantedSetsAttributesAsArray(): array
{
$obj = new \stdClass();
$obj->foo = 'bar';
diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/Controller/ControllerResolverTest.php b/src/Symfony/Bundle/FrameworkBundle/Tests/Controller/ControllerResolverTest.php
index 2c042917acc85..b993ae7e7d504 100644
--- a/src/Symfony/Bundle/FrameworkBundle/Tests/Controller/ControllerResolverTest.php
+++ b/src/Symfony/Bundle/FrameworkBundle/Tests/Controller/ControllerResolverTest.php
@@ -148,7 +148,7 @@ class_exists(AbstractControllerTest::class);
$this->assertSame($controllerContainer, $controller->getContainer());
}
- protected function createControllerResolver(LoggerInterface $logger = null, Psr11ContainerInterface $container = null)
+ protected function createControllerResolver(?LoggerInterface $logger = null, ?Psr11ContainerInterface $container = null)
{
if (!$container) {
$container = $this->createMockContainer();
diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/Controller/RedirectControllerTest.php b/src/Symfony/Bundle/FrameworkBundle/Tests/Controller/RedirectControllerTest.php
index de72396df6ad5..b2da9ef58c5c1 100644
--- a/src/Symfony/Bundle/FrameworkBundle/Tests/Controller/RedirectControllerTest.php
+++ b/src/Symfony/Bundle/FrameworkBundle/Tests/Controller/RedirectControllerTest.php
@@ -103,7 +103,7 @@ public function testRoute($permanent, $keepRequestMethod, $keepQueryParams, $ign
$this->assertEquals($expectedCode, $returnResponse->getStatusCode());
}
- public static function provider()
+ public static function provider(): array
{
return [
[true, false, false, false, 301, ['additional-parameter' => 'value']],
@@ -210,7 +210,7 @@ public function testUrlRedirectDefaultPorts()
$this->assertRedirectUrl($returnValue, $expectedUrl);
}
- public static function urlRedirectProvider()
+ public static function urlRedirectProvider(): array
{
return [
// Standard ports
@@ -262,7 +262,7 @@ public function testUrlRedirect($scheme, $httpPort, $httpsPort, $requestScheme,
$this->assertRedirectUrl($returnValue, $expectedUrl);
}
- public static function pathQueryParamsProvider()
+ public static function pathQueryParamsProvider(): array
{
return [
['http://www.example.com/base/redirect-path', '/redirect-path', ''],
diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/Controller/TemplateControllerTest.php b/src/Symfony/Bundle/FrameworkBundle/Tests/Controller/TemplateControllerTest.php
index f558333f36a40..c0f5da11f6a3d 100644
--- a/src/Symfony/Bundle/FrameworkBundle/Tests/Controller/TemplateControllerTest.php
+++ b/src/Symfony/Bundle/FrameworkBundle/Tests/Controller/TemplateControllerTest.php
@@ -32,13 +32,23 @@ public function testTwig()
$this->assertEquals('bar', $controller('mytemplate')->getContent());
}
- public function testNoTwig()
+ public function testNoTwigTemplateActionMethod()
{
+ $controller = new TemplateController();
+
$this->expectException(\LogicException::class);
$this->expectExceptionMessage('You cannot use the TemplateController if the Twig Bundle is not available. Try running "composer require symfony/twig-bundle".');
- $controller = new TemplateController();
$controller->templateAction('mytemplate')->getContent();
+ }
+
+ public function testNoTwigInvokeMethod()
+ {
+ $controller = new TemplateController();
+
+ $this->expectException(\LogicException::class);
+ $this->expectExceptionMessage('You cannot use the TemplateController if the Twig Bundle is not available.');
+
$controller('mytemplate')->getContent();
}
diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Compiler/DataCollectorTranslatorPassTest.php b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Compiler/DataCollectorTranslatorPassTest.php
index 8601f8c81ad2c..a1aefd63920f3 100644
--- a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Compiler/DataCollectorTranslatorPassTest.php
+++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Compiler/DataCollectorTranslatorPassTest.php
@@ -111,7 +111,7 @@ public static function getNotImplementingTranslatorBagInterfaceTranslatorClassNa
class TranslatorWithTranslatorBag implements TranslatorInterface
{
- public function trans(string $id, array $parameters = [], string $domain = null, string $locale = null): string
+ public function trans(string $id, array $parameters = [], ?string $domain = null, ?string $locale = null): string
{
}
diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Compiler/ProfilerPassTest.php b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Compiler/ProfilerPassTest.php
index eef047dfa8c29..f33bbbf8f2c16 100644
--- a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Compiler/ProfilerPassTest.php
+++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Compiler/ProfilerPassTest.php
@@ -65,7 +65,7 @@ public function testValidCollector()
public static function provideValidCollectorWithTemplateUsingAutoconfigure(): \Generator
{
yield [new class() implements TemplateAwareDataCollectorInterface {
- public function collect(Request $request, Response $response, \Throwable $exception = null): void
+ public function collect(Request $request, Response $response, ?\Throwable $exception = null): void
{
}
@@ -85,7 +85,7 @@ public static function getTemplate(): string
}];
yield [new class() extends AbstractDataCollector {
- public function collect(Request $request, Response $response, \Throwable $exception = null): void
+ public function collect(Request $request, Response $response, ?\Throwable $exception = null): void
{
}
diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/ConfigurationTest.php b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/ConfigurationTest.php
index e11042d66e941..3f5b1332f9c3d 100644
--- a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/ConfigurationTest.php
+++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/ConfigurationTest.php
@@ -95,6 +95,30 @@ public function testAssetsCanBeEnabled()
$this->assertEquals($defaultConfig, $config['assets']);
}
+ public function testAssetMapperCanBeEnabled()
+ {
+ $processor = new Processor();
+ $configuration = new Configuration(true);
+ $config = $processor->processConfiguration($configuration, [['http_method_override' => false, 'asset_mapper' => null]]);
+
+ $defaultConfig = [
+ 'enabled' => true,
+ 'paths' => [],
+ 'excluded_patterns' => [],
+ 'server' => true,
+ 'public_prefix' => '/assets/',
+ 'missing_import_mode' => 'warn',
+ 'extensions' => [],
+ 'importmap_path' => '%kernel.project_dir%/importmap.php',
+ 'importmap_polyfill' => null,
+ 'vendor_dir' => '%kernel.project_dir%/assets/vendor',
+ 'provider' => 'jsdelivr.esm',
+ 'importmap_script_attributes' => [],
+ ];
+
+ $this->assertEquals($defaultConfig, $config['asset_mapper']);
+ }
+
/**
* @dataProvider provideValidAssetsPackageNameConfigurationTests
*/
@@ -116,7 +140,7 @@ public function testValidAssetsPackageNameConfiguration($packageName)
$this->assertArrayHasKey($packageName, $config['assets']['packages']);
}
- public static function provideValidAssetsPackageNameConfigurationTests()
+ public static function provideValidAssetsPackageNameConfigurationTests(): array
{
return [
['foobar'],
@@ -143,7 +167,7 @@ public function testInvalidAssetsConfiguration(array $assetConfig, $expectedMess
]);
}
- public static function provideInvalidAssetConfigurationTests()
+ public static function provideInvalidAssetConfigurationTests(): iterable
{
// helper to turn config into embedded package config
$createPackageConfig = fn (array $packageConfig) => [
@@ -195,7 +219,7 @@ public function testValidLockConfiguration($lockConfig, $processedConfig)
$this->assertEquals($processedConfig, $config['lock']);
}
- public static function provideValidLockConfigurationTests()
+ public static function provideValidLockConfigurationTests(): iterable
{
yield [null, ['enabled' => true, 'resources' => ['default' => [class_exists(SemaphoreStore::class) && SemaphoreStore::isSupported() ? 'semaphore' : 'flock']]]];
@@ -589,6 +613,20 @@ protected static function getBundleDefaultConfig()
'json_manifest_path' => null,
'strict_mode' => false,
],
+ 'asset_mapper' => [
+ 'enabled' => !class_exists(FullStack::class),
+ 'paths' => [],
+ 'excluded_patterns' => [],
+ 'server' => true,
+ 'public_prefix' => '/assets/',
+ 'missing_import_mode' => 'warn',
+ 'extensions' => [],
+ 'importmap_path' => '%kernel.project_dir%/importmap.php',
+ 'importmap_polyfill' => null,
+ 'vendor_dir' => '%kernel.project_dir%/assets/vendor',
+ 'provider' => 'jsdelivr.esm',
+ 'importmap_script_attributes' => [],
+ ],
'cache' => [
'pools' => [],
'app' => 'cache.adapter.filesystem',
diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/legacy_translator_enabled_locales.php b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/legacy_translator_enabled_locales.php
deleted file mode 100644
index 46acfce8c144d..0000000000000
--- a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/legacy_translator_enabled_locales.php
+++ /dev/null
@@ -1,19 +0,0 @@
-loadFromExtension('framework', [
- 'http_method_override' => false,
- 'secret' => 's3cr3t',
- 'default_locale' => 'fr',
- 'router' => [
- 'resource' => '%kernel.project_dir%/config/routing.xml',
- 'type' => 'xml',
- 'utf8' => true,
- ],
- 'translator' => [
- 'enabled' => true,
- 'fallback' => 'fr',
- 'paths' => ['%kernel.project_dir%/Fixtures/translations'],
- 'cache_dir' => '%kernel.cache_dir%/translations',
- 'enabled_locales' => ['fr', 'en'],
- ],
-]);
diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/serializer_legacy_cache.php b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/serializer_legacy_cache.php
deleted file mode 100644
index 6695d9f7988ba..0000000000000
--- a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/serializer_legacy_cache.php
+++ /dev/null
@@ -1,9 +0,0 @@
-loadFromExtension('framework', [
- 'http_method_override' => false,
- 'serializer' => [
- 'enabled' => true,
- 'cache' => 'foo',
- ],
-]);
diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/webhook.php b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/webhook.php
new file mode 100644
index 0000000000000..5a50a738b4747
--- /dev/null
+++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/webhook.php
@@ -0,0 +1,8 @@
+loadFromExtension('framework', [
+ 'http_method_override' => false,
+ 'webhook' => ['enabled' => true],
+ 'http_client' => ['enabled' => true],
+ 'serializer' => ['enabled' => true],
+]);
diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/webhook_without_serializer.php b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/webhook_without_serializer.php
new file mode 100644
index 0000000000000..cd6f3ec903a24
--- /dev/null
+++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/webhook_without_serializer.php
@@ -0,0 +1,8 @@
+loadFromExtension('framework', [
+ 'http_method_override' => false,
+ 'webhook' => ['enabled' => true],
+ 'http_client' => ['enabled' => true],
+ 'serializer' => ['enabled' => false],
+]);
diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/asset_mapper.xml b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/asset_mapper.xml
new file mode 100644
index 0000000000000..3b6f149c85d2d
--- /dev/null
+++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/asset_mapper.xml
@@ -0,0 +1,27 @@
+
+
+
+
+
+
+ assets/
+ assets2/
+ */assets/build/*
+ application/zip
+ reload
+
+
+
diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/legacy_translator_enabled_locales.xml b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/legacy_translator_enabled_locales.xml
deleted file mode 100644
index 91139d9d0af3f..0000000000000
--- a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/legacy_translator_enabled_locales.xml
+++ /dev/null
@@ -1,17 +0,0 @@
-
-
-
-
-
-
-
- %kernel.project_dir%/Fixtures/translations
- fr
- en
-
-
-
diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/serializer_legacy_cache.xml b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/webhook.xml
similarity index 74%
rename from src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/serializer_legacy_cache.xml
rename to src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/webhook.xml
index 9296670bb1657..aaf6952708672 100644
--- a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/serializer_legacy_cache.xml
+++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/webhook.xml
@@ -1,4 +1,5 @@
-
+
+
-
+
+
+
diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/webhook_without_serializer.xml b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/webhook_without_serializer.xml
new file mode 100644
index 0000000000000..76e72b4144bb0
--- /dev/null
+++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/webhook_without_serializer.xml
@@ -0,0 +1,14 @@
+
+
+
+
+
+
+
+
+
+
diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/workflows.xml b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/workflows.xml
index 067206ff11921..e9c28666098e2 100644
--- a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/workflows.xml
+++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/workflows.xml
@@ -10,7 +10,6 @@
draft
- Symfony\Bundle\FrameworkBundle\Tests\DependencyInjection\FrameworkExtensionTestCase
diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/serializer_legacy_cache.yml b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/webhook.yml
similarity index 52%
rename from src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/serializer_legacy_cache.yml
rename to src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/webhook.yml
index 5fd44373fcdda..7c13a0fc2aa4f 100644
--- a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/serializer_legacy_cache.yml
+++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/webhook.yml
@@ -1,5 +1,8 @@
framework:
http_method_override: false
+ webhook:
+ enabled: true
+ http_client:
+ enabled: true
serializer:
enabled: true
- cache: foo
diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/webhook_without_serializer.yml b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/webhook_without_serializer.yml
new file mode 100644
index 0000000000000..e61c199420451
--- /dev/null
+++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/webhook_without_serializer.yml
@@ -0,0 +1,8 @@
+framework:
+ http_method_override: false
+ webhook:
+ enabled: true
+ http_client:
+ enabled: true
+ serializer:
+ enabled: false
diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/FrameworkExtensionTestCase.php b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/FrameworkExtensionTestCase.php
index fe3b773186218..946c6a8003571 100644
--- a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/FrameworkExtensionTestCase.php
+++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/FrameworkExtensionTestCase.php
@@ -82,6 +82,8 @@
use Symfony\Component\Validator\DependencyInjection\AddConstraintValidatorsPass;
use Symfony\Component\Validator\Validation;
use Symfony\Component\Validator\Validator\ValidatorInterface;
+use Symfony\Component\Webhook\Client\RequestParser;
+use Symfony\Component\Webhook\Controller\WebhookController;
use Symfony\Component\Workflow;
use Symfony\Component\Workflow\Exception\InvalidDefinitionException;
use Symfony\Component\Workflow\Metadata\InMemoryMetadataStore;
@@ -546,7 +548,7 @@ public function testEnabledPhpErrorsConfig()
$container = $this->createContainerFromFile('php_errors_enabled');
$definition = $container->getDefinition('debug.error_handler_configurator');
- $this->assertEquals(new Reference('monolog.logger.php', ContainerInterface::NULL_ON_INVALID_REFERENCE), $definition->getArgument(0));
+ $this->assertEquals(new Reference('logger', ContainerInterface::NULL_ON_INVALID_REFERENCE), $definition->getArgument(0));
$this->assertNull($definition->getArgument(1));
$this->assertSame(-1, $container->getParameter('debug.error_handler.throw_at'));
}
@@ -566,7 +568,7 @@ public function testPhpErrorsWithLogLevel()
$container = $this->createContainerFromFile('php_errors_log_level');
$definition = $container->getDefinition('debug.error_handler_configurator');
- $this->assertEquals(new Reference('monolog.logger.php', ContainerInterface::NULL_ON_INVALID_REFERENCE), $definition->getArgument(0));
+ $this->assertEquals(new Reference('logger', ContainerInterface::NULL_ON_INVALID_REFERENCE), $definition->getArgument(0));
$this->assertSame(8, $definition->getArgument(1));
}
@@ -575,7 +577,7 @@ public function testPhpErrorsWithLogLevels()
$container = $this->createContainerFromFile('php_errors_log_levels');
$definition = $container->getDefinition('debug.error_handler_configurator');
- $this->assertEquals(new Reference('monolog.logger.php', ContainerInterface::NULL_ON_INVALID_REFERENCE), $definition->getArgument(0));
+ $this->assertEquals(new Reference('logger', ContainerInterface::NULL_ON_INVALID_REFERENCE), $definition->getArgument(0));
$this->assertSame([
\E_NOTICE => \Psr\Log\LogLevel::ERROR,
\E_WARNING => \Psr\Log\LogLevel::ERROR,
@@ -1570,6 +1572,12 @@ public function testSerializerCacheActivated()
public function testSerializerCacheUsedWithoutAnnotationsAndMappingFiles()
{
$container = $this->createContainerFromFile('serializer_mapping_without_annotations', ['kernel.debug' => true, 'kernel.container_class' => __CLASS__]);
+ $this->assertFalse($container->hasDefinition('serializer.mapping.cache_class_metadata_factory'));
+ }
+
+ public function testSerializerCacheUsedWithoutAnnotationsAndMappingFilesNoDebug()
+ {
+ $container = $this->createContainerFromFile('serializer_mapping_without_annotations', ['kernel.debug' => false, 'kernel.container_class' => __CLASS__]);
$this->assertTrue($container->hasDefinition('serializer.mapping.cache_class_metadata_factory'));
}
@@ -2276,6 +2284,38 @@ public function testNotifierWithSpecificMessageBus()
$this->assertEquals(new Reference('app.another_bus'), $container->getDefinition('notifier.channel.sms')->getArgument(1));
}
+ public function testWebhook()
+ {
+ if (!class_exists(WebhookController::class)) {
+ $this->markTestSkipped('Webhook not available.');
+ }
+
+ $container = $this->createContainerFromFile('webhook');
+
+ $this->assertTrue($container->hasAlias(RequestParser::class));
+ $this->assertSame('webhook.request_parser', (string) $container->getAlias(RequestParser::class));
+ $this->assertSame(RequestParser::class, $container->getDefinition('webhook.request_parser')->getClass());
+
+ $this->assertFalse($container->getDefinition('webhook.transport')->hasErrors());
+ $this->assertFalse($container->getDefinition('webhook.body_configurator.json')->hasErrors());
+ }
+
+ public function testWebhookWithoutSerializer()
+ {
+ if (!class_exists(WebhookController::class)) {
+ $this->markTestSkipped('Webhook not available.');
+ }
+
+ $container = $this->createContainerFromFile('webhook_without_serializer');
+
+ $this->assertFalse($container->getDefinition('webhook.transport')->hasErrors());
+ $this->assertTrue($container->getDefinition('webhook.body_configurator.json')->hasErrors());
+ $this->assertSame(
+ ['You cannot use the "webhook transport" service since the Serializer component is not enabled. Try setting "framework.serializer.enabled" to true.'],
+ $container->getDefinition('webhook.body_configurator.json')->getErrors()
+ );
+ }
+
protected function createContainer(array $data = [])
{
return new ContainerBuilder(new EnvPlaceholderParameterBag(array_merge([
@@ -2294,7 +2334,7 @@ protected function createContainer(array $data = [])
], $data)));
}
- protected function createContainerFromFile($file, $data = [], $resetCompilerPasses = true, $compile = true, FrameworkExtension $extension = null)
+ protected function createContainerFromFile($file, $data = [], $resetCompilerPasses = true, $compile = true, ?FrameworkExtension $extension = null)
{
$cacheKey = md5(static::class.$file.serialize($data));
if ($compile && isset(self::$containerCache[$cacheKey])) {
diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/PhpFrameworkExtensionTest.php b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/PhpFrameworkExtensionTest.php
index 5daeaa14ec28e..1574377c15896 100644
--- a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/PhpFrameworkExtensionTest.php
+++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/PhpFrameworkExtensionTest.php
@@ -11,6 +11,7 @@
namespace Symfony\Bundle\FrameworkBundle\Tests\DependencyInjection;
+use Symfony\Component\Config\Definition\Exception\InvalidConfigurationException;
use Symfony\Component\Config\FileLocator;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Exception\LogicException;
@@ -58,6 +59,36 @@ public function testAssetPackageCannotHavePathAndUrl()
});
}
+ public function testWorkflowValidationPlacesIsArray()
+ {
+ $this->expectException(InvalidConfigurationException::class);
+ $this->expectExceptionMessage('The "places" option must be an array in workflow configuration.');
+ $this->createContainerFromClosure(function ($container) {
+ $container->loadFromExtension('framework', [
+ 'workflows' => [
+ 'article' => [
+ 'places' => null,
+ ],
+ ],
+ ]);
+ });
+ }
+
+ public function testWorkflowValidationTransitonsIsArray()
+ {
+ $this->expectException(InvalidConfigurationException::class);
+ $this->expectExceptionMessage('The "transitions" option must be an array in workflow configuration.');
+ $this->createContainerFromClosure(function ($container) {
+ $container->loadFromExtension('framework', [
+ 'workflows' => [
+ 'article' => [
+ 'transitions' => null,
+ ],
+ ],
+ ]);
+ });
+ }
+
public function testWorkflowValidationStateMachine()
{
$this->expectException(InvalidDefinitionException::class);
@@ -88,6 +119,63 @@ public function testWorkflowValidationStateMachine()
});
}
+ public function testWorkflowDefaultMarkingStoreDefinition()
+ {
+ $container = $this->createContainerFromClosure(function ($container) {
+ $container->loadFromExtension('framework', [
+ 'http_method_override' => false,
+ 'workflows' => [
+ 'workflow_a' => [
+ 'type' => 'state_machine',
+ 'marking_store' => [
+ 'type' => 'method',
+ 'property' => 'status',
+ ],
+ 'supports' => [
+ __CLASS__,
+ ],
+ 'places' => [
+ 'a',
+ 'b',
+ ],
+ 'transitions' => [
+ 'a_to_b' => [
+ 'from' => ['a'],
+ 'to' => ['b'],
+ ],
+ ],
+ ],
+ 'workflow_b' => [
+ 'type' => 'state_machine',
+ 'supports' => [
+ __CLASS__,
+ ],
+ 'places' => [
+ 'a',
+ 'b',
+ ],
+ 'transitions' => [
+ 'a_to_b' => [
+ 'from' => ['a'],
+ 'to' => ['b'],
+ ],
+ ],
+ ],
+ ],
+ ]);
+ });
+
+ $workflowA = $container->getDefinition('state_machine.workflow_a');
+ $argumentsA = $workflowA->getArguments();
+ $this->assertArrayHasKey('index_1', $argumentsA, 'workflow_a has a marking_store argument');
+ $this->assertNotNull($argumentsA['index_1'], 'workflow_a marking_store argument is not null');
+
+ $workflowB = $container->getDefinition('state_machine.workflow_b');
+ $argumentsB = $workflowB->getArguments();
+ $this->assertArrayHasKey('index_1', $argumentsB, 'workflow_b has a marking_store argument');
+ $this->assertNull($argumentsB['index_1'], 'workflow_b marking_store argument is null');
+ }
+
public function testRateLimiterWithLockFactory()
{
try {
diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/XmlFrameworkExtensionTest.php b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/XmlFrameworkExtensionTest.php
index 4a2ff788bf5c6..36d3f5e379d3e 100644
--- a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/XmlFrameworkExtensionTest.php
+++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/XmlFrameworkExtensionTest.php
@@ -14,7 +14,6 @@
use Symfony\Component\Config\FileLocator;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Loader\XmlFileLoader;
-use Symfony\Component\RateLimiter\Policy\SlidingWindowLimiter;
class XmlFrameworkExtensionTest extends FrameworkExtensionTestCase
{
@@ -74,4 +73,24 @@ public function testRateLimiter()
$this->assertTrue($container->hasDefinition('limiter.sliding_window'));
}
+
+ public function testAssetMapper()
+ {
+ $container = $this->createContainerFromFile('asset_mapper');
+
+ $definition = $container->getDefinition('asset_mapper.public_assets_path_resolver');
+ $this->assertSame('/assets_path/', $definition->getArgument(1));
+
+ $definition = $container->getDefinition('asset_mapper.dev_server_subscriber');
+ $this->assertSame(['zip' => 'application/zip'], $definition->getArgument(2));
+
+ $definition = $container->getDefinition('asset_mapper.importmap.renderer');
+ $this->assertSame(['data-turbo-track' => 'reload'], $definition->getArgument(3));
+
+ $definition = $container->getDefinition('asset_mapper.repository');
+ $this->assertSame(['assets/' => '', 'assets2/' => 'my_namespace'], $definition->getArgument(0));
+
+ $definition = $container->getDefinition('asset_mapper.compiler.css_asset_url_compiler');
+ $this->assertSame('strict', $definition->getArgument(0));
+ }
}
diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/ContainerExcluded.php b/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/ContainerExcluded.php
new file mode 100644
index 0000000000000..2508b74276bc0
--- /dev/null
+++ b/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/ContainerExcluded.php
@@ -0,0 +1,7 @@
+val3
+
+ ["foo","bar",[[[["ccc"]]]]]
+ .alias_2
diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/builder_1_services.json b/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/builder_1_services.json
index 9bb716e442e17..ac6d122ce4539 100644
--- a/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/builder_1_services.json
+++ b/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/builder_1_services.json
@@ -33,6 +33,24 @@
{
"name": "tag2",
"parameters": []
+ },
+ {
+ "name": "tag3",
+ "parameters": {
+ "array_attr": [
+ "foo",
+ "bar",
+ [
+ [
+ [
+ [
+ "ccc"
+ ]
+ ]
+ ]
+ ]
+ ]
+ }
}
],
"usages": []
diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/builder_1_services.md b/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/builder_1_services.md
index 3825ed8ebbba4..6dfab327d037a 100644
--- a/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/builder_1_services.md
+++ b/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/builder_1_services.md
@@ -25,6 +25,8 @@ Definitions
- Tag: `tag1`
- Attr3: val3
- Tag: `tag2`
+- Tag: `tag3`
+ - Array_attr: ["foo","bar",[[[["ccc"]]]]]
- Usages: none
### .definition_3
diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/builder_1_services.xml b/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/builder_1_services.xml
index d3cf16a0f4c5a..84499f0845657 100644
--- a/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/builder_1_services.xml
+++ b/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/builder_1_services.xml
@@ -15,6 +15,9 @@
val3
+
+ ["foo","bar",[[[["ccc"]]]]]
+
diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/builder_1_tag1.json b/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/builder_1_tag1.json
index 66eb0af836225..5e60f26d170b7 100644
--- a/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/builder_1_tag1.json
+++ b/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/builder_1_tag1.json
@@ -33,6 +33,24 @@
{
"name": "tag2",
"parameters": []
+ },
+ {
+ "name": "tag3",
+ "parameters": {
+ "array_attr": [
+ "foo",
+ "bar",
+ [
+ [
+ [
+ [
+ "ccc"
+ ]
+ ]
+ ]
+ ]
+ ]
+ }
}
],
"usages": []
diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/builder_1_tag1.md b/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/builder_1_tag1.md
index a76b77df04e55..aeae0d9f294ce 100644
--- a/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/builder_1_tag1.md
+++ b/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/builder_1_tag1.md
@@ -25,4 +25,6 @@ Definitions
- Tag: `tag1`
- Attr3: val3
- Tag: `tag2`
+- Tag: `tag3`
+ - Array_attr: ["foo","bar",[[[["ccc"]]]]]
- Usages: none
diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/builder_1_tag1.xml b/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/builder_1_tag1.xml
index b2929b01ac403..5413d7e5ea326 100644
--- a/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/builder_1_tag1.xml
+++ b/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/builder_1_tag1.xml
@@ -14,6 +14,9 @@
val3
+
+ ["foo","bar",[[[["ccc"]]]]]
+
diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/builder_1_tags.json b/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/builder_1_tags.json
index e0679f2cac58d..518f694ea3451 100644
--- a/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/builder_1_tags.json
+++ b/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/builder_1_tags.json
@@ -38,5 +38,25 @@
],
"usages": []
}
+ ],
+ "tag3": [
+ {
+ "class": "Full\\Qualified\\Class2",
+ "public": false,
+ "synthetic": true,
+ "lazy": false,
+ "shared": true,
+ "abstract": false,
+ "autowire": false,
+ "autoconfigure": false,
+ "deprecated": false,
+ "file": "\/path\/to\/file",
+ "factory_service": "factory.service",
+ "factory_method": "get",
+ "calls": [
+ "setMailer"
+ ],
+ "usages": []
+ }
]
}
diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/builder_1_tags.md b/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/builder_1_tags.md
index f9558d326e7b3..80da2ddafd560 100644
--- a/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/builder_1_tags.md
+++ b/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/builder_1_tags.md
@@ -41,3 +41,24 @@ tag2
- Factory Method: `get`
- Call: `setMailer`
- Usages: none
+
+
+tag3
+----
+
+### .definition_2
+
+- Class: `Full\Qualified\Class2`
+- Public: no
+- Synthetic: yes
+- Lazy: no
+- Shared: yes
+- Abstract: no
+- Autowired: no
+- Autoconfigured: no
+- Deprecated: no
+- File: `/path/to/file`
+- Factory Service: `factory.service`
+- Factory Method: `get`
+- Call: `setMailer`
+- Usages: none
diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/builder_1_tags.txt b/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/builder_1_tags.txt
index b10e4661f6701..5be3bb0792754 100644
--- a/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/builder_1_tags.txt
+++ b/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/builder_1_tags.txt
@@ -12,3 +12,8 @@
* .definition_2
+[33m"tag3" tag[39m
+[33m----------[39m
+
+ * .definition_2
+
diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/builder_1_tags.xml b/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/builder_1_tags.xml
index 75a9714f5d8a6..1c68779f0ea71 100644
--- a/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/builder_1_tags.xml
+++ b/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/builder_1_tags.xml
@@ -16,4 +16,12 @@
+
+
+
+
+
+
+
+
diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/definition_2.json b/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/definition_2.json
index 622904da2ef86..a661428c9cb08 100644
--- a/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/definition_2.json
+++ b/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/definition_2.json
@@ -31,6 +31,24 @@
{
"name": "tag2",
"parameters": []
+ },
+ {
+ "name": "tag3",
+ "parameters": {
+ "array_attr": [
+ "foo",
+ "bar",
+ [
+ [
+ [
+ [
+ "ccc"
+ ]
+ ]
+ ]
+ ]
+ ]
+ }
}
],
"usages": []
diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/definition_2.md b/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/definition_2.md
index 376cbdb52348b..486f35fb77a27 100644
--- a/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/definition_2.md
+++ b/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/definition_2.md
@@ -17,4 +17,6 @@
- Tag: `tag1`
- Attr3: val3
- Tag: `tag2`
+- Tag: `tag3`
+ - Array_attr: ["foo","bar",[[[["ccc"]]]]]
- Usages: none
diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/definition_2.txt b/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/definition_2.txt
index 2b8d3dde599e0..6fdb6d980942e 100644
--- a/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/definition_2.txt
+++ b/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/definition_2.txt
@@ -1,22 +1,23 @@
- ----------------- ---------------------------------
- [32m Option [39m [32m Value [39m
- ----------------- ---------------------------------
- Service ID -
- Class Full\Qualified\Class2
- Tags tag1 ([32mattr1[39m: val1, [32mattr2[39m: val2)
- tag1 ([32mattr3[39m: val3)
- tag2
- Calls setMailer
- Public no
- Synthetic yes
- Lazy no
- Shared yes
- Abstract no
- Autowired no
- Autoconfigured no
- Required File /path/to/file
- Factory Service factory.service
- Factory Method get
- Usages none
- ----------------- ---------------------------------
+ ----------------- ------------------------------------------------
+ [32m Option [39m [32m Value [39m
+ ----------------- ------------------------------------------------
+ Service ID -
+ Class Full\Qualified\Class2
+ Tags tag1 ([32mattr1[39m: val1, [32mattr2[39m: val2)
+ tag1 ([32mattr3[39m: val3)
+ tag2
+ tag3 ([32marray_attr[39m: ["foo","bar",[[[["ccc"]]]]])
+ Calls setMailer
+ Public no
+ Synthetic yes
+ Lazy no
+ Shared yes
+ Abstract no
+ Autowired no
+ Autoconfigured no
+ Required File /path/to/file
+ Factory Service factory.service
+ Factory Method get
+ Usages none
+ ----------------- ------------------------------------------------
diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/definition_2.xml b/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/definition_2.xml
index ab072f3e3adf5..4dd3ca0a0b619 100644
--- a/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/definition_2.xml
+++ b/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/definition_2.xml
@@ -13,5 +13,8 @@
val3
+
+ ["foo","bar",[[[["ccc"]]]]]
+
diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/definition_arguments_2.json b/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/definition_arguments_2.json
index 20ef01a34b7a5..eeeb6f44a448b 100644
--- a/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/definition_arguments_2.json
+++ b/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/definition_arguments_2.json
@@ -32,6 +32,24 @@
{
"name": "tag2",
"parameters": []
+ },
+ {
+ "name": "tag3",
+ "parameters": {
+ "array_attr": [
+ "foo",
+ "bar",
+ [
+ [
+ [
+ [
+ "ccc"
+ ]
+ ]
+ ]
+ ]
+ ]
+ }
}
],
"usages": []
diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/definition_arguments_2.md b/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/definition_arguments_2.md
index f5bf50e61764c..5b427bff5a26f 100644
--- a/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/definition_arguments_2.md
+++ b/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/definition_arguments_2.md
@@ -18,4 +18,6 @@
- Tag: `tag1`
- Attr3: val3
- Tag: `tag2`
+- Tag: `tag3`
+ - Array_attr: ["foo","bar",[[[["ccc"]]]]]
- Usages: none
diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/definition_arguments_2.txt b/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/definition_arguments_2.txt
index 2b8d3dde599e0..43ca2cffa0ae3 100644
--- a/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/definition_arguments_2.txt
+++ b/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/definition_arguments_2.txt
@@ -1,22 +1,23 @@
- ----------------- ---------------------------------
- [32m Option [39m [32m Value [39m
- ----------------- ---------------------------------
- Service ID -
- Class Full\Qualified\Class2
- Tags tag1 ([32mattr1[39m: val1, [32mattr2[39m: val2)
- tag1 ([32mattr3[39m: val3)
- tag2
- Calls setMailer
- Public no
- Synthetic yes
- Lazy no
- Shared yes
- Abstract no
- Autowired no
- Autoconfigured no
- Required File /path/to/file
- Factory Service factory.service
- Factory Method get
- Usages none
- ----------------- ---------------------------------
+ ----------------- ------------------------------------------------
+ [32m Option [39m [32m Value [39m
+ ----------------- ------------------------------------------------
+ Service ID -
+ Class Full\Qualified\Class2
+ Tags tag1 ([32mattr1[39m: val1, [32mattr2[39m: val2)
+ tag1 ([32mattr3[39m: val3)
+ tag2
+ tag3 ([32marray_attr[39m: ["foo","bar",[[[["ccc"]]]]])
+ Calls setMailer
+ Public no
+ Synthetic yes
+ Lazy no
+ Shared yes
+ Abstract no
+ Autowired no
+ Autoconfigured no
+ Required File /path/to/file
+ Factory Service factory.service
+ Factory Method get
+ Usages none
+ ----------------- ------------------------------------------------
diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/definition_arguments_2.xml b/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/definition_arguments_2.xml
index ab072f3e3adf5..4dd3ca0a0b619 100644
--- a/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/definition_arguments_2.xml
+++ b/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/definition_arguments_2.xml
@@ -13,5 +13,8 @@
val3
+
+ ["foo","bar",[[[["ccc"]]]]]
+
diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/TestBundle/FooBundle/Controller/DefaultController.php b/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Serializer/CircularReferenceHandler.php
similarity index 61%
rename from src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/TestBundle/FooBundle/Controller/DefaultController.php
rename to src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Serializer/CircularReferenceHandler.php
index ddda38cb1c14e..b4e402a042a4f 100644
--- a/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/TestBundle/FooBundle/Controller/DefaultController.php
+++ b/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Serializer/CircularReferenceHandler.php
@@ -9,13 +9,11 @@
* file that was distributed with this source code.
*/
-namespace TestBundle\FooBundle\Controller;
+namespace Symfony\Bundle\FrameworkBundle\Tests\Fixtures\Serializer;
-/**
- * DefaultController.
- *
- * @author Fabien Potencier
- */
-class DefaultController
+class CircularReferenceHandler
{
+ public function __invoke()
+ {
+ }
}
diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/TestBundle/FooBundle/Controller/Sub/DefaultController.php b/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Serializer/MaxDepthHandler.php
similarity index 61%
rename from src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/TestBundle/FooBundle/Controller/Sub/DefaultController.php
rename to src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Serializer/MaxDepthHandler.php
index 3c889e7309970..f76fb3db82985 100644
--- a/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/TestBundle/FooBundle/Controller/Sub/DefaultController.php
+++ b/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Serializer/MaxDepthHandler.php
@@ -9,13 +9,11 @@
* file that was distributed with this source code.
*/
-namespace TestBundle\FooBundle\Controller\Sub;
+namespace Symfony\Bundle\FrameworkBundle\Tests\Fixtures\Serializer;
-/**
- * DefaultController.
- *
- * @author Fabien Potencier
- */
-class DefaultController
+class MaxDepthHandler
{
+ public function __invoke()
+ {
+ }
}
diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/Bundle/TestBundle/AutowiringTypes/AutowiredServices.php b/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/Bundle/TestBundle/AutowiringTypes/AutowiredServices.php
index 4743460e6ee5b..2dc1fac4bf83b 100644
--- a/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/Bundle/TestBundle/AutowiringTypes/AutowiredServices.php
+++ b/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/Bundle/TestBundle/AutowiringTypes/AutowiredServices.php
@@ -21,7 +21,7 @@ class AutowiredServices
private $dispatcher;
private $cachePool;
- public function __construct(Reader $annotationReader = null, EventDispatcherInterface $dispatcher, CacheItemPoolInterface $cachePool)
+ public function __construct(?Reader $annotationReader, EventDispatcherInterface $dispatcher, CacheItemPoolInterface $cachePool)
{
$this->annotationReader = $annotationReader;
$this->dispatcher = $dispatcher;
diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/Bundle/TestBundle/Controller/AnnotatedController.php b/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/Bundle/TestBundle/Controller/AnnotatedController.php
index 2bee3d0b833e1..c3bbbaf245e67 100644
--- a/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/Bundle/TestBundle/Controller/AnnotatedController.php
+++ b/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/Bundle/TestBundle/Controller/AnnotatedController.php
@@ -18,7 +18,7 @@
class AnnotatedController
{
#[Route('/null_request', name: 'null_request')]
- public function requestDefaultNullAction(Request $request = null): Response
+ public function requestDefaultNullAction(?Request $request = null): Response
{
return new Response($request ? $request::class : null);
}
diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/Bundle/TestBundle/TestServiceContainer/PrivateService.php b/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/Bundle/TestBundle/TestServiceContainer/PrivateService.php
index 6a244cb40ce54..51168b7ea6c24 100644
--- a/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/Bundle/TestBundle/TestServiceContainer/PrivateService.php
+++ b/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/Bundle/TestBundle/TestServiceContainer/PrivateService.php
@@ -13,4 +13,5 @@
class PrivateService
{
+ public $inner;
}
diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/CachePoolClearCommandTest.php b/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/CachePoolClearCommandTest.php
index 76ac645d2b6f6..291e9dbc129bb 100644
--- a/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/CachePoolClearCommandTest.php
+++ b/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/CachePoolClearCommandTest.php
@@ -132,7 +132,7 @@ public function testClearFailed()
$this->assertStringContainsString('[WARNING] Cache pool "cache.public_pool" could not be cleared.', $tester->getDisplay());
}
- private function createCommandTester(array $poolNames = null)
+ private function createCommandTester(?array $poolNames = null)
{
$application = new Application(static::$kernel);
$application->add(new CachePoolClearCommand(static::getContainer()->get('cache.global_clearer'), $poolNames));
diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/ConfigDebugCommandTest.php b/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/ConfigDebugCommandTest.php
index 307b34a395299..c9bfba234b08e 100644
--- a/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/ConfigDebugCommandTest.php
+++ b/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/ConfigDebugCommandTest.php
@@ -24,39 +24,89 @@
*/
class ConfigDebugCommandTest extends AbstractWebTestCase
{
- private $application;
+ /**
+ * @testWith [true]
+ * [false]
+ */
+ public function testShowList(bool $debug)
+ {
+ $tester = $this->createCommandTester($debug);
+ $ret = $tester->execute([]);
+
+ $this->assertSame(0, $ret, 'Returns 0 in case of success');
+ $this->assertStringContainsString('Available registered bundles with their extension alias if available', $tester->getDisplay());
+ $this->assertStringContainsString(' DefaultConfigTestBundle default_config_test', $tester->getDisplay());
+ $this->assertStringContainsString(' ExtensionWithoutConfigTestBundle extension_without_config_test', $tester->getDisplay());
+ $this->assertStringContainsString(' FrameworkBundle framework', $tester->getDisplay());
+ $this->assertStringContainsString(' TestBundle test', $tester->getDisplay());
+ $this->assertStringContainsString('Available registered non-bundle extension aliases', $tester->getDisplay());
+ $this->assertStringContainsString(' foo', $tester->getDisplay());
+ $this->assertStringContainsString(' test_dump', $tester->getDisplay());
+ }
- protected function setUp(): void
+ /**
+ * @testWith [true]
+ * [false]
+ */
+ public function testDumpKernelExtension(bool $debug)
{
- $kernel = static::createKernel(['test_case' => 'ConfigDump', 'root_config' => 'config.yml']);
- $this->application = new Application($kernel);
- $this->application->doRun(new ArrayInput([]), new NullOutput());
+ $tester = $this->createCommandTester($debug);
+ $ret = $tester->execute(['name' => 'foo']);
+
+ $this->assertSame(0, $ret, 'Returns 0 in case of success');
+ $this->assertStringContainsString('foo:', $tester->getDisplay());
+ $this->assertStringContainsString(' foo: bar', $tester->getDisplay());
}
- public function testDumpBundleName()
+ /**
+ * @testWith [true]
+ * [false]
+ */
+ public function testDumpBundleName(bool $debug)
{
- $tester = $this->createCommandTester();
+ $tester = $this->createCommandTester($debug);
$ret = $tester->execute(['name' => 'TestBundle']);
$this->assertSame(0, $ret, 'Returns 0 in case of success');
$this->assertStringContainsString('custom: foo', $tester->getDisplay());
}
- public function testDumpBundleOption()
+ /**
+ * @testWith [true]
+ * [false]
+ */
+ public function testDumpBundleOption(bool $debug)
{
- $tester = $this->createCommandTester();
+ $tester = $this->createCommandTester($debug);
$ret = $tester->execute(['name' => 'TestBundle', 'path' => 'custom']);
$this->assertSame(0, $ret, 'Returns 0 in case of success');
$this->assertStringContainsString('foo', $tester->getDisplay());
}
- public function testDumpWithUnsupportedFormat()
+ /**
+ * @testWith [true]
+ * [false]
+ */
+ public function testDumpWithoutTitleIsValidJson(bool $debug)
+ {
+ $tester = $this->createCommandTester($debug);
+ $ret = $tester->execute(['name' => 'TestBundle', '--format' => 'json']);
+
+ $this->assertSame(0, $ret, 'Returns 0 in case of success');
+ $this->assertJson($tester->getDisplay());
+ }
+
+ /**
+ * @testWith [true]
+ * [false]
+ */
+ public function testDumpWithUnsupportedFormat(bool $debug)
{
- $tester = $this->createCommandTester();
+ $tester = $this->createCommandTester($debug);
$this->expectException(InvalidArgumentException::class);
- $this->expectExceptionMessage('Supported formats are "yaml", "json"');
+ $this->expectExceptionMessage('Supported formats are "txt", "yaml", "json"');
$tester->execute([
'name' => 'test',
@@ -64,9 +114,13 @@ public function testDumpWithUnsupportedFormat()
]);
}
- public function testParametersValuesAreResolved()
+ /**
+ * @testWith [true]
+ * [false]
+ */
+ public function testParametersValuesAreResolved(bool $debug)
{
- $tester = $this->createCommandTester();
+ $tester = $this->createCommandTester($debug);
$ret = $tester->execute(['name' => 'framework']);
$this->assertSame(0, $ret, 'Returns 0 in case of success');
@@ -74,89 +128,121 @@ public function testParametersValuesAreResolved()
$this->assertStringContainsString('secret: test', $tester->getDisplay());
}
- public function testParametersValuesAreFullyResolved()
+ /**
+ * @testWith [true]
+ * [false]
+ */
+ public function testParametersValuesAreFullyResolved(bool $debug)
{
- $tester = $this->createCommandTester();
+ $tester = $this->createCommandTester($debug);
$ret = $tester->execute(['name' => 'framework', '--resolve-env' => true]);
$this->assertSame(0, $ret, 'Returns 0 in case of success');
$this->assertStringContainsString('locale: en', $tester->getDisplay());
$this->assertStringContainsString('secret: test', $tester->getDisplay());
$this->assertStringContainsString('cookie_httponly: true', $tester->getDisplay());
- $this->assertStringContainsString('ide: '.($_ENV['SYMFONY_IDE'] ?? $_SERVER['SYMFONY_IDE'] ?? 'null'), $tester->getDisplay());
+ $this->assertStringContainsString('ide: '.$debug ? ($_ENV['SYMFONY_IDE'] ?? $_SERVER['SYMFONY_IDE'] ?? 'null') : 'null', $tester->getDisplay());
}
- public function testDefaultParameterValueIsResolvedIfConfigIsExisting()
+ /**
+ * @testWith [true]
+ * [false]
+ */
+ public function testDefaultParameterValueIsResolvedIfConfigIsExisting(bool $debug)
{
- $tester = $this->createCommandTester();
+ $tester = $this->createCommandTester($debug);
$ret = $tester->execute(['name' => 'framework']);
$this->assertSame(0, $ret, 'Returns 0 in case of success');
- $kernelCacheDir = $this->application->getKernel()->getContainer()->getParameter('kernel.cache_dir');
+ $kernelCacheDir = self::$kernel->getContainer()->getParameter('kernel.cache_dir');
$this->assertStringContainsString(sprintf("dsn: 'file:%s/profiler'", $kernelCacheDir), $tester->getDisplay());
}
- public function testDumpExtensionConfigWithoutBundle()
+ /**
+ * @testWith [true]
+ * [false]
+ */
+ public function testDumpExtensionConfigWithoutBundle(bool $debug)
{
- $tester = $this->createCommandTester();
+ $tester = $this->createCommandTester($debug);
$ret = $tester->execute(['name' => 'test_dump']);
$this->assertSame(0, $ret, 'Returns 0 in case of success');
$this->assertStringContainsString('enabled: true', $tester->getDisplay());
}
- public function testDumpUndefinedBundleOption()
+ /**
+ * @testWith [true]
+ * [false]
+ */
+ public function testDumpUndefinedBundleOption(bool $debug)
{
- $tester = $this->createCommandTester();
+ $tester = $this->createCommandTester($debug);
$tester->execute(['name' => 'TestBundle', 'path' => 'foo']);
$this->assertStringContainsString('Unable to find configuration for "test.foo"', $tester->getDisplay());
}
- public function testDumpWithPrefixedEnv()
+ /**
+ * @testWith [true]
+ * [false]
+ */
+ public function testDumpWithPrefixedEnv(bool $debug)
{
- $tester = $this->createCommandTester();
+ $tester = $this->createCommandTester($debug);
$tester->execute(['name' => 'FrameworkBundle']);
$this->assertStringContainsString("cookie_httponly: '%env(bool:COOKIE_HTTPONLY)%'", $tester->getDisplay());
}
- public function testDumpFallsBackToDefaultConfigAndResolvesParameterValue()
+ /**
+ * @testWith [true]
+ * [false]
+ */
+ public function testDumpFallsBackToDefaultConfigAndResolvesParameterValue(bool $debug)
{
- $tester = $this->createCommandTester();
+ $tester = $this->createCommandTester($debug);
$ret = $tester->execute(['name' => 'DefaultConfigTestBundle']);
$this->assertSame(0, $ret, 'Returns 0 in case of success');
$this->assertStringContainsString('foo: bar', $tester->getDisplay());
}
- public function testDumpFallsBackToDefaultConfigAndResolvesEnvPlaceholder()
+ /**
+ * @testWith [true]
+ * [false]
+ */
+ public function testDumpFallsBackToDefaultConfigAndResolvesEnvPlaceholder(bool $debug)
{
- $tester = $this->createCommandTester();
+ $tester = $this->createCommandTester($debug);
$ret = $tester->execute(['name' => 'DefaultConfigTestBundle']);
$this->assertSame(0, $ret, 'Returns 0 in case of success');
$this->assertStringContainsString("baz: '%env(BAZ)%'", $tester->getDisplay());
}
- public function testDumpThrowsExceptionWhenDefaultConfigFallbackIsImpossible()
+ /**
+ * @testWith [true]
+ * [false]
+ */
+ public function testDumpThrowsExceptionWhenDefaultConfigFallbackIsImpossible(bool $debug)
{
$this->expectException(\LogicException::class);
$this->expectExceptionMessage('The extension with alias "extension_without_config_test" does not have configuration.');
- $tester = $this->createCommandTester();
+ $tester = $this->createCommandTester($debug);
$tester->execute(['name' => 'ExtensionWithoutConfigTestBundle']);
}
/**
* @dataProvider provideCompletionSuggestions
*/
- public function testComplete(array $input, array $expectedSuggestions)
+ public function testComplete(bool $debug, array $input, array $expectedSuggestions)
{
- $this->application->add(new ConfigDebugCommand());
-
- $tester = new CommandCompletionTester($this->application->get('debug:config'));
+ $application = $this->createApplication($debug);
+ $application->add(new ConfigDebugCommand());
+ $tester = new CommandCompletionTester($application->get('debug:config'));
$suggestions = $tester->complete($input);
foreach ($expectedSuggestions as $expectedSuggestion) {
@@ -166,19 +252,31 @@ public function testComplete(array $input, array $expectedSuggestions)
public static function provideCompletionSuggestions(): \Generator
{
- yield 'name' => [[''], ['default_config_test', 'extension_without_config_test', 'framework', 'test']];
+ $name = ['default_config_test', 'extension_without_config_test', 'framework', 'test', 'foo', 'test_dump'];
+ yield 'name, no debug' => [false, [''], $name];
+ yield 'name, debug' => [true, [''], $name];
- yield 'name (started CamelCase)' => [['Fra'], ['DefaultConfigTestBundle', 'ExtensionWithoutConfigTestBundle', 'FrameworkBundle', 'TestBundle']];
+ $nameWithPath = ['secret', 'router.resource', 'router.utf8', 'router.enabled', 'validation.enabled', 'default_locale'];
+ yield 'name with existing path, no debug' => [false, ['framework', ''], $nameWithPath];
+ yield 'name with existing path, debug' => [true, ['framework', ''], $nameWithPath];
- yield 'name with existing path' => [['framework', ''], ['secret', 'router.resource', 'router.utf8', 'router.enabled', 'validation.enabled', 'default_locale']];
-
- yield 'option --format' => [['--format', ''], ['yaml', 'json']];
+ yield 'option --format, no debug' => [false, ['--format', ''], ['yaml', 'json']];
+ yield 'option --format, debug' => [true, ['--format', ''], ['yaml', 'json']];
}
- private function createCommandTester(): CommandTester
+ private function createCommandTester(bool $debug): CommandTester
{
- $command = $this->application->find('debug:config');
+ $command = $this->createApplication($debug)->find('debug:config');
return new CommandTester($command);
}
+
+ private function createApplication(bool $debug): Application
+ {
+ $kernel = static::bootKernel(['debug' => $debug, 'test_case' => 'ConfigDump', 'root_config' => 'config.yml']);
+ $application = new Application($kernel);
+ $application->doRun(new ArrayInput([]), new NullOutput());
+
+ return $application;
+ }
}
diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/ConfigDumpReferenceCommandTest.php b/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/ConfigDumpReferenceCommandTest.php
index e944960aea4e7..8f5930faac2eb 100644
--- a/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/ConfigDumpReferenceCommandTest.php
+++ b/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/ConfigDumpReferenceCommandTest.php
@@ -23,26 +23,47 @@
*/
class ConfigDumpReferenceCommandTest extends AbstractWebTestCase
{
- private $application;
-
- protected function setUp(): void
+ /**
+ * @testWith [true]
+ * [false]
+ */
+ public function testShowList(bool $debug)
{
- $kernel = static::createKernel(['test_case' => 'ConfigDump', 'root_config' => 'config.yml']);
- $this->application = new Application($kernel);
- $this->application->doRun(new ArrayInput([]), new NullOutput());
+ $tester = $this->createCommandTester($debug);
+ $ret = $tester->execute([]);
+
+ $this->assertSame(0, $ret, 'Returns 0 in case of success');
+ $this->assertStringContainsString('Available registered bundles with their extension alias if available', $tester->getDisplay());
+ $this->assertStringContainsString(' DefaultConfigTestBundle default_config_test', $tester->getDisplay());
+ $this->assertStringContainsString(' ExtensionWithoutConfigTestBundle extension_without_config_test', $tester->getDisplay());
+ $this->assertStringContainsString(' FrameworkBundle framework', $tester->getDisplay());
+ $this->assertStringContainsString(' TestBundle test', $tester->getDisplay());
+ $this->assertStringContainsString('Available registered non-bundle extension aliases', $tester->getDisplay());
+ $this->assertStringContainsString(' foo', $tester->getDisplay());
+ $this->assertStringContainsString(' test_dump', $tester->getDisplay());
}
- public function testDumpKernelExtension()
+ /**
+ * @testWith [true]
+ * [false]
+ */
+ public function testDumpKernelExtension(bool $debug)
{
- $tester = $this->createCommandTester();
+ $tester = $this->createCommandTester($debug);
$ret = $tester->execute(['name' => 'foo']);
+
+ $this->assertSame(0, $ret, 'Returns 0 in case of success');
$this->assertStringContainsString('foo:', $tester->getDisplay());
$this->assertStringContainsString(' bar', $tester->getDisplay());
}
- public function testDumpBundleName()
+ /**
+ * @testWith [true]
+ * [false]
+ */
+ public function testDumpBundleName(bool $debug)
{
- $tester = $this->createCommandTester();
+ $tester = $this->createCommandTester($debug);
$ret = $tester->execute(['name' => 'TestBundle']);
$this->assertSame(0, $ret, 'Returns 0 in case of success');
@@ -50,18 +71,26 @@ public function testDumpBundleName()
$this->assertStringContainsString(' custom:', $tester->getDisplay());
}
- public function testDumpExtensionConfigWithoutBundle()
+ /**
+ * @testWith [true]
+ * [false]
+ */
+ public function testDumpExtensionConfigWithoutBundle(bool $debug)
{
- $tester = $this->createCommandTester();
+ $tester = $this->createCommandTester($debug);
$ret = $tester->execute(['name' => 'test_dump']);
$this->assertSame(0, $ret, 'Returns 0 in case of success');
$this->assertStringContainsString('enabled: true', $tester->getDisplay());
}
- public function testDumpAtPath()
+ /**
+ * @testWith [true]
+ * [false]
+ */
+ public function testDumpAtPath(bool $debug)
{
- $tester = $this->createCommandTester();
+ $tester = $this->createCommandTester($debug);
$ret = $tester->execute([
'name' => 'test',
'path' => 'array',
@@ -79,9 +108,13 @@ public function testDumpAtPath()
, $tester->getDisplay(true));
}
- public function testDumpAtPathXml()
+ /**
+ * @testWith [true]
+ * [false]
+ */
+ public function testDumpAtPathXml(bool $debug)
{
- $tester = $this->createCommandTester();
+ $tester = $this->createCommandTester($debug);
$ret = $tester->execute([
'name' => 'test',
'path' => 'array',
@@ -95,24 +128,40 @@ public function testDumpAtPathXml()
/**
* @dataProvider provideCompletionSuggestions
*/
- public function testComplete(array $input, array $expectedSuggestions)
+ public function testComplete(bool $debug, array $input, array $expectedSuggestions)
{
- $this->application->add(new ConfigDumpReferenceCommand());
- $tester = new CommandCompletionTester($this->application->get('config:dump-reference'));
- $suggestions = $tester->complete($input, 2);
+ $application = $this->createApplication($debug);
+
+ $application->add(new ConfigDumpReferenceCommand());
+ $tester = new CommandCompletionTester($application->get('config:dump-reference'));
+ $suggestions = $tester->complete($input);
$this->assertSame($expectedSuggestions, $suggestions);
}
public static function provideCompletionSuggestions(): iterable
{
- yield 'name' => [[''], ['DefaultConfigTestBundle', 'default_config_test', 'ExtensionWithoutConfigTestBundle', 'extension_without_config_test', 'FrameworkBundle', 'framework', 'TestBundle', 'test']];
- yield 'option --format' => [['--format', ''], ['yaml', 'xml']];
+ $name = ['foo', 'default_config_test', 'extension_without_config_test', 'framework', 'test', 'test_dump', 'DefaultConfigTestBundle', 'ExtensionWithoutConfigTestBundle', 'FrameworkBundle', 'TestBundle'];
+ yield 'name, no debug' => [false, [''], $name];
+ yield 'name, debug' => [true, [''], $name];
+
+ $optionFormat = ['yaml', 'xml'];
+ yield 'option --format, no debug' => [false, ['--format', ''], $optionFormat];
+ yield 'option --format, debug' => [true, ['--format', ''], $optionFormat];
}
- private function createCommandTester(): CommandTester
+ private function createCommandTester(bool $debug): CommandTester
{
- $command = $this->application->find('config:dump-reference');
+ $command = $this->createApplication($debug)->find('config:dump-reference');
return new CommandTester($command);
}
+
+ private function createApplication(bool $debug): Application
+ {
+ $kernel = static::createKernel(['debug' => $debug, 'test_case' => 'ConfigDump', 'root_config' => 'config.yml']);
+ $application = new Application($kernel);
+ $application->doRun(new ArrayInput([]), new NullOutput());
+
+ return $application;
+ }
}
diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/ContainerDebugCommandTest.php b/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/ContainerDebugCommandTest.php
index b3624cc5c9e74..efbc1f54acb08 100644
--- a/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/ContainerDebugCommandTest.php
+++ b/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/ContainerDebugCommandTest.php
@@ -13,6 +13,7 @@
use Symfony\Bundle\FrameworkBundle\Console\Application;
use Symfony\Bundle\FrameworkBundle\Tests\Fixtures\BackslashClass;
+use Symfony\Bundle\FrameworkBundle\Tests\Fixtures\ContainerExcluded;
use Symfony\Component\Console\Tester\ApplicationTester;
use Symfony\Component\Console\Tester\CommandCompletionTester;
use Symfony\Component\HttpKernel\HttpKernelInterface;
@@ -99,6 +100,19 @@ public function testDeprecatedServiceAndAlias()
$this->assertStringContainsString('[WARNING] The "deprecated_alias" alias is deprecated since foo/bar 1.9 and will be removed in 2.0', $tester->getDisplay());
}
+ public function testExcludedService()
+ {
+ static::bootKernel(['test_case' => 'ContainerDebug', 'root_config' => 'config.yml']);
+
+ $application = new Application(static::$kernel);
+ $application->setAutoExit(false);
+
+ $tester = new ApplicationTester($application);
+
+ $tester->run(['command' => 'debug:container']);
+ $this->assertStringNotContainsString(ContainerExcluded::class, $tester->getDisplay());
+ }
+
/**
* @dataProvider provideIgnoreBackslashWhenFindingService
*/
@@ -255,7 +269,7 @@ public function testGetDeprecationNoFile()
$this->assertStringContainsString('[WARNING] The deprecation file does not exist', $tester->getDisplay());
}
- public static function provideIgnoreBackslashWhenFindingService()
+ public static function provideIgnoreBackslashWhenFindingService(): array
{
return [
[BackslashClass::class],
@@ -283,7 +297,7 @@ public function testComplete(array $input, array $expectedSuggestions, array $no
}
}
- public static function provideCompletionSuggestions()
+ public static function provideCompletionSuggestions(): iterable
{
$serviceId = 'console.command.container_debug';
$hiddenServiceId = '.console.command.container_debug.lazy';
diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/KernelTestCaseTest.php b/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/KernelTestCaseTest.php
deleted file mode 100644
index aa12467829ed1..0000000000000
--- a/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/KernelTestCaseTest.php
+++ /dev/null
@@ -1,61 +0,0 @@
-
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Bundle\FrameworkBundle\Tests\Functional;
-
-use Symfony\Bundle\FrameworkBundle\Test\TestContainer;
-use Symfony\Bundle\FrameworkBundle\Tests\Functional\Bundle\TestBundle\TestServiceContainer\NonPublicService;
-use Symfony\Bundle\FrameworkBundle\Tests\Functional\Bundle\TestBundle\TestServiceContainer\PrivateService;
-use Symfony\Bundle\FrameworkBundle\Tests\Functional\Bundle\TestBundle\TestServiceContainer\PublicService;
-use Symfony\Bundle\FrameworkBundle\Tests\Functional\Bundle\TestBundle\TestServiceContainer\UnusedPrivateService;
-use Symfony\Component\DependencyInjection\ContainerInterface;
-use Symfony\Component\DependencyInjection\Exception\InvalidArgumentException;
-
-class KernelTestCaseTest extends AbstractWebTestCase
-{
- public function testThatPrivateServicesAreUnavailableIfTestConfigIsDisabled()
- {
- static::bootKernel(['test_case' => 'TestServiceContainer', 'root_config' => 'test_disabled.yml', 'environment' => 'test_disabled']);
-
- $this->expectException(\LogicException::class);
- static::getContainer();
- }
-
- public function testThatPrivateServicesAreAvailableIfTestConfigIsEnabled()
- {
- static::bootKernel(['test_case' => 'TestServiceContainer']);
-
- $container = static::getContainer();
- $this->assertInstanceOf(ContainerInterface::class, $container);
- $this->assertInstanceOf(TestContainer::class, $container);
- $this->assertTrue($container->has(PublicService::class));
- $this->assertTrue($container->has(NonPublicService::class));
- $this->assertTrue($container->has(PrivateService::class));
- $this->assertTrue($container->has('private_service'));
- $this->assertFalse($container->has(UnusedPrivateService::class));
- }
-
- public function testThatPrivateServicesCanBeSetIfTestConfigIsEnabled()
- {
- static::bootKernel(['test_case' => 'TestServiceContainer']);
-
- $container = static::getContainer();
-
- $service = new \stdClass();
-
- $container->set('private_service', $service);
- $this->assertSame($service, $container->get('private_service'));
-
- $this->expectException(InvalidArgumentException::class);
- $this->expectExceptionMessage('The "private_service" service is already initialized, you cannot replace it.');
- $container->set('private_service', new \stdClass());
- }
-}
diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/RouterDebugCommandTest.php b/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/RouterDebugCommandTest.php
index 9865e7edea6fe..a428801aee2ff 100644
--- a/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/RouterDebugCommandTest.php
+++ b/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/RouterDebugCommandTest.php
@@ -96,7 +96,7 @@ public function testComplete(array $input, array $expectedSuggestions)
$this->assertSame($expectedSuggestions, $tester->complete($input));
}
- public static function provideCompletionSuggestions()
+ public static function provideCompletionSuggestions(): iterable
{
yield 'option --format' => [
['--format', ''],
diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/TestServiceContainerTest.php b/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/TestServiceContainerTest.php
index 76a373c0c05a9..fe7093081509f 100644
--- a/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/TestServiceContainerTest.php
+++ b/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/TestServiceContainerTest.php
@@ -16,6 +16,7 @@
use Symfony\Bundle\FrameworkBundle\Tests\Functional\Bundle\TestBundle\TestServiceContainer\PrivateService;
use Symfony\Bundle\FrameworkBundle\Tests\Functional\Bundle\TestBundle\TestServiceContainer\PublicService;
use Symfony\Bundle\FrameworkBundle\Tests\Functional\Bundle\TestBundle\TestServiceContainer\UnusedPrivateService;
+use Symfony\Component\DependencyInjection\Exception\InvalidArgumentException;
class TestServiceContainerTest extends AbstractWebTestCase
{
@@ -40,6 +41,33 @@ public function testThatPrivateServicesAreAvailableIfTestConfigIsEnabled()
$this->assertFalse(static::getContainer()->has(UnusedPrivateService::class));
}
+ public function testThatPrivateServicesCanBeSetIfTestConfigIsEnabled()
+ {
+ static::bootKernel(['test_case' => 'TestServiceContainer']);
+
+ $container = static::getContainer();
+
+ $service = new \stdClass();
+
+ $container->set('private_service', $service);
+ $this->assertSame($service, $container->get('private_service'));
+
+ $this->expectException(InvalidArgumentException::class);
+ $this->expectExceptionMessage('The "private_service" service is already initialized, you cannot replace it.');
+ $container->set('private_service', new \stdClass());
+ }
+
+ public function testSetDecoratedService()
+ {
+ static::bootKernel(['test_case' => 'TestServiceContainer']);
+
+ $container = static::getContainer();
+
+ $service = new PrivateService();
+ $container->set('decorated', $service);
+ $this->assertSame($service, $container->get('decorated')->inner);
+ }
+
/**
* @doesNotPerformAssertions
*/
diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/app/ContainerDebug/config.yml b/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/app/ContainerDebug/config.yml
index cc1a01bb8f0b5..15ddaca64356f 100644
--- a/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/app/ContainerDebug/config.yml
+++ b/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/app/ContainerDebug/config.yml
@@ -33,3 +33,5 @@ services:
- '%env(REAL)%'
- '%env(int:key:2:json:JSON)%'
- '%env(float:key:2:json:JSON)%'
+ Symfony\Bundle\FrameworkBundle\Tests\Fixtures\ContainerExcluded:
+ tags: ['container.excluded']
diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/app/Serializer/config.yml b/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/app/Serializer/config.yml
index e51b738580255..81cbbe52c89f4 100644
--- a/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/app/Serializer/config.yml
+++ b/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/app/Serializer/config.yml
@@ -5,6 +5,8 @@ framework:
http_method_override: false
serializer:
enabled: true
+ circular_reference_handler: Symfony\Bundle\FrameworkBundle\Tests\Fixtures\Serializer\CircularReferenceHandler
+ max_depth_handler: Symfony\Bundle\FrameworkBundle\Tests\Fixtures\Serializer\MaxDepthHandler
default_context:
enable_max_depth: true
fake_context_option: foo
@@ -58,3 +60,7 @@ services:
serializer.encoder.csv.alias:
alias: serializer.encoder.csv
public: true
+
+ Symfony\Bundle\FrameworkBundle\Tests\Fixtures\Serializer\CircularReferenceHandler: ~
+
+ Symfony\Bundle\FrameworkBundle\Tests\Fixtures\Serializer\MaxDepthHandler: ~
diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/app/TestServiceContainer/services.yml b/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/app/TestServiceContainer/services.yml
index 523cca58d0b63..46cb7be6a8f6f 100644
--- a/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/app/TestServiceContainer/services.yml
+++ b/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/app/TestServiceContainer/services.yml
@@ -8,8 +8,18 @@ services:
private_service: '@Symfony\Bundle\FrameworkBundle\Tests\Functional\Bundle\TestBundle\TestServiceContainer\PrivateService'
+ decorated:
+ class: Symfony\Bundle\FrameworkBundle\Tests\Functional\Bundle\TestBundle\TestServiceContainer\PrivateService
+
Symfony\Bundle\FrameworkBundle\Tests\Functional\Bundle\TestBundle\TestServiceContainer\PublicService:
public: true
arguments:
- '@Symfony\Bundle\FrameworkBundle\Tests\Functional\Bundle\TestBundle\TestServiceContainer\NonPublicService'
- '@Symfony\Bundle\FrameworkBundle\Tests\Functional\Bundle\TestBundle\TestServiceContainer\PrivateService'
+ - '@decorated'
+
+ decorator:
+ class: Symfony\Bundle\FrameworkBundle\Tests\Functional\Bundle\TestBundle\TestServiceContainer\PrivateService
+ decorates: decorated
+ properties:
+ inner: '@.inner'
diff --git a/src/Symfony/Bundle/FrameworkBundle/Translation/Translator.php b/src/Symfony/Bundle/FrameworkBundle/Translation/Translator.php
index dac3b6394fce8..b310f5a0f7393 100644
--- a/src/Symfony/Bundle/FrameworkBundle/Translation/Translator.php
+++ b/src/Symfony/Bundle/FrameworkBundle/Translation/Translator.php
@@ -121,7 +121,7 @@ public function warmUp(string $cacheDir): array
/**
* @return void
*/
- public function addResource(string $format, mixed $resource, string $locale, string $domain = null)
+ public function addResource(string $format, mixed $resource, string $locale, ?string $domain = null)
{
if ($this->resourceFiles) {
$this->addResourceFiles();
diff --git a/src/Symfony/Bundle/FrameworkBundle/composer.json b/src/Symfony/Bundle/FrameworkBundle/composer.json
index e17a3a4c5cda9..0924ebbbff720 100644
--- a/src/Symfony/Bundle/FrameworkBundle/composer.json
+++ b/src/Symfony/Bundle/FrameworkBundle/composer.json
@@ -21,7 +21,7 @@
"ext-xml": "*",
"symfony/cache": "^5.4|^6.0",
"symfony/config": "^6.1",
- "symfony/dependency-injection": "^6.2.8",
+ "symfony/dependency-injection": "^6.3.1",
"symfony/deprecation-contracts": "^2.5|^3",
"symfony/error-handler": "^6.1",
"symfony/event-dispatcher": "^5.4|^6.0",
@@ -36,6 +36,7 @@
"doctrine/annotations": "^1.13.1|^2",
"doctrine/persistence": "^1.3|^2|^3",
"symfony/asset": "^5.4|^6.0",
+ "symfony/asset-mapper": "^6.3",
"symfony/browser-kit": "^5.4|^6.0",
"symfony/console": "^5.4.9|^6.0.9",
"symfony/clock": "^6.2",
@@ -76,10 +77,9 @@
"doctrine/persistence": "<1.3",
"phpdocumentor/reflection-docblock": "<3.2.2",
"phpdocumentor/type-resolver": "<1.4.0",
- "phpunit/phpunit": "<5.4.3",
"symfony/asset": "<5.4",
"symfony/clock": "<6.3",
- "symfony/console": "<5.4",
+ "symfony/console": "<5.4|>=7.0",
"symfony/dotenv": "<5.4",
"symfony/dom-crawler": "<6.3",
"symfony/http-client": "<6.3",
diff --git a/src/Symfony/Bundle/SecurityBundle/DataCollector/SecurityDataCollector.php b/src/Symfony/Bundle/SecurityBundle/DataCollector/SecurityDataCollector.php
index 14b95bff007b1..fc9fd7a29f0d9 100644
--- a/src/Symfony/Bundle/SecurityBundle/DataCollector/SecurityDataCollector.php
+++ b/src/Symfony/Bundle/SecurityBundle/DataCollector/SecurityDataCollector.php
@@ -44,7 +44,7 @@ class SecurityDataCollector extends DataCollector implements LateDataCollectorIn
private ?TraceableFirewallListener $firewall;
private bool $hasVarDumper;
- public function __construct(TokenStorageInterface $tokenStorage = null, RoleHierarchyInterface $roleHierarchy = null, LogoutUrlGenerator $logoutUrlGenerator = null, AccessDecisionManagerInterface $accessDecisionManager = null, FirewallMapInterface $firewallMap = null, TraceableFirewallListener $firewall = null)
+ public function __construct(?TokenStorageInterface $tokenStorage = null, ?RoleHierarchyInterface $roleHierarchy = null, ?LogoutUrlGenerator $logoutUrlGenerator = null, ?AccessDecisionManagerInterface $accessDecisionManager = null, ?FirewallMapInterface $firewallMap = null, ?TraceableFirewallListener $firewall = null)
{
$this->tokenStorage = $tokenStorage;
$this->roleHierarchy = $roleHierarchy;
@@ -55,7 +55,7 @@ public function __construct(TokenStorageInterface $tokenStorage = null, RoleHier
$this->hasVarDumper = class_exists(ClassStub::class);
}
- public function collect(Request $request, Response $response, \Throwable $exception = null): void
+ public function collect(Request $request, Response $response, ?\Throwable $exception = null): void
{
if (null === $this->tokenStorage) {
$this->data = [
diff --git a/src/Symfony/Bundle/SecurityBundle/Debug/TraceableFirewallListener.php b/src/Symfony/Bundle/SecurityBundle/Debug/TraceableFirewallListener.php
index bb5fe03096466..b2394e44d7cce 100644
--- a/src/Symfony/Bundle/SecurityBundle/Debug/TraceableFirewallListener.php
+++ b/src/Symfony/Bundle/SecurityBundle/Debug/TraceableFirewallListener.php
@@ -17,13 +17,14 @@
use Symfony\Component\HttpKernel\Event\RequestEvent;
use Symfony\Component\Security\Http\Authenticator\Debug\TraceableAuthenticatorManagerListener;
use Symfony\Component\Security\Http\Firewall\FirewallListenerInterface;
+use Symfony\Contracts\Service\ResetInterface;
/**
* Firewall collecting called security listeners and authenticators.
*
* @author Robin Chalas
*/
-final class TraceableFirewallListener extends FirewallListener
+final class TraceableFirewallListener extends FirewallListener implements ResetInterface
{
private array $wrappedListeners = [];
private array $authenticatorsInfo = [];
@@ -41,6 +42,12 @@ public function getAuthenticatorsInfo(): array
return $this->authenticatorsInfo;
}
+ public function reset(): void
+ {
+ $this->wrappedListeners = [];
+ $this->authenticatorsInfo = [];
+ }
+
protected function callListeners(RequestEvent $event, iterable $listeners): void
{
$wrappedListeners = [];
diff --git a/src/Symfony/Bundle/SecurityBundle/DependencyInjection/Compiler/AddSecurityVotersPass.php b/src/Symfony/Bundle/SecurityBundle/DependencyInjection/Compiler/AddSecurityVotersPass.php
index ccf474087af5d..8a2bad79a140c 100644
--- a/src/Symfony/Bundle/SecurityBundle/DependencyInjection/Compiler/AddSecurityVotersPass.php
+++ b/src/Symfony/Bundle/SecurityBundle/DependencyInjection/Compiler/AddSecurityVotersPass.php
@@ -56,7 +56,7 @@ public function process(ContainerBuilder $container)
}
if ($debug) {
- $voterServices[] = new Reference($debugVoterServiceId = 'debug.security.voter.'.$voterServiceId);
+ $voterServices[] = new Reference($debugVoterServiceId = '.debug.security.voter.'.$voterServiceId);
$container
->register($debugVoterServiceId, TraceableVoter::class)
diff --git a/src/Symfony/Bundle/SecurityBundle/DependencyInjection/Security/AccessToken/OidcTokenHandlerFactory.php b/src/Symfony/Bundle/SecurityBundle/DependencyInjection/Security/AccessToken/OidcTokenHandlerFactory.php
index 6f19f3845cb15..cc51398069cdf 100644
--- a/src/Symfony/Bundle/SecurityBundle/DependencyInjection/Security/AccessToken/OidcTokenHandlerFactory.php
+++ b/src/Symfony/Bundle/SecurityBundle/DependencyInjection/Security/AccessToken/OidcTokenHandlerFactory.php
@@ -13,10 +13,10 @@
use Jose\Component\Core\Algorithm;
use Jose\Component\Core\JWK;
-use Symfony\Bundle\SecurityBundle\DependencyInjection\Security\Factory\SignatureAlgorithmFactory;
use Symfony\Component\Config\Definition\Builder\NodeBuilder;
use Symfony\Component\DependencyInjection\ChildDefinition;
use Symfony\Component\DependencyInjection\ContainerBuilder;
+use Symfony\Component\DependencyInjection\Exception\LogicException;
use Symfony\Component\DependencyInjection\Reference;
/**
@@ -28,26 +28,29 @@ class OidcTokenHandlerFactory implements TokenHandlerFactoryInterface
{
public function create(ContainerBuilder $container, string $id, array|string $config): void
{
- $tokenHandlerDefinition = $container->setDefinition($id, new ChildDefinition('security.access_token_handler.oidc'));
- $tokenHandlerDefinition->replaceArgument(3, $config['claim']);
- $tokenHandlerDefinition->replaceArgument(4, $config['audience']);
+ $tokenHandlerDefinition = $container->setDefinition($id, (new ChildDefinition('security.access_token_handler.oidc'))
+ ->replaceArgument(2, $config['audience'])
+ ->replaceArgument(3, $config['issuers'])
+ ->replaceArgument(4, $config['claim'])
+ );
- // Create the signature algorithm and the JWK
if (!ContainerBuilder::willBeAvailable('web-token/jwt-core', Algorithm::class, ['symfony/security-bundle'])) {
- $container->register('security.access_token_handler.oidc.signature', 'stdClass')
- ->addError('You cannot use the "oidc" token handler since "web-token/jwt-core" is not installed. Try running "web-token/jwt-core".');
- $container->register('security.access_token_handler.oidc.jwk', 'stdClass')
- ->addError('You cannot use the "oidc" token handler since "web-token/jwt-core" is not installed. Try running "web-token/jwt-core".');
+ throw new LogicException('You cannot use the "oidc" token handler since "web-token/jwt-core" is not installed. Try running "composer require web-token/jwt-core".');
+ }
+
+ // @see Symfony\Bundle\SecurityBundle\DependencyInjection\Security\Factory\SignatureAlgorithmFactory
+ // for supported algorithms
+ if (\in_array($config['algorithm'], ['ES256', 'ES384', 'ES512'], true)) {
+ $tokenHandlerDefinition->replaceArgument(0, new Reference('security.access_token_handler.oidc.signature.'.$config['algorithm']));
} else {
- $container->register('security.access_token_handler.oidc.signature', Algorithm::class)
- ->setFactory([SignatureAlgorithmFactory::class, 'create'])
- ->setArguments([$config['signature']['algorithm']]);
- $container->register('security.access_token_handler.oidc.jwk', JWK::class)
- ->setFactory([JWK::class, 'createFromJson'])
- ->setArguments([$config['signature']['key']]);
+ $tokenHandlerDefinition->replaceArgument(0, (new ChildDefinition('security.access_token_handler.oidc.signature'))
+ ->replaceArgument(0, $config['algorithm'])
+ );
}
- $tokenHandlerDefinition->replaceArgument(0, new Reference('security.access_token_handler.oidc.signature'));
- $tokenHandlerDefinition->replaceArgument(1, new Reference('security.access_token_handler.oidc.jwk'));
+
+ $tokenHandlerDefinition->replaceArgument(1, (new ChildDefinition('security.access_token_handler.oidc.jwk'))
+ ->replaceArgument(0, $config['key'])
+ );
}
public function getKey(): string
@@ -67,20 +70,20 @@ public function addConfiguration(NodeBuilder $node): void
->end()
->scalarNode('audience')
->info('Audience set in the token, for validation purpose.')
- ->defaultNull()
+ ->isRequired()
+ ->end()
+ ->arrayNode('issuers')
+ ->info('Issuers allowed to generate the token, for validation purpose.')
+ ->isRequired()
+ ->prototype('scalar')->end()
+ ->end()
+ ->scalarNode('algorithm')
+ ->info('Algorithm used to sign the token.')
+ ->isRequired()
->end()
- ->arrayNode('signature')
+ ->scalarNode('key')
+ ->info('JSON-encoded JWK used to sign the token (must contain a "kty" key).')
->isRequired()
- ->children()
- ->scalarNode('algorithm')
- ->info('Algorithm used to sign the token.')
- ->isRequired()
- ->end()
- ->scalarNode('key')
- ->info('JSON-encoded JWK used to sign the token (must contain a "kty" key).')
- ->isRequired()
- ->end()
- ->end()
->end()
->end()
->end()
diff --git a/src/Symfony/Bundle/SecurityBundle/DependencyInjection/Security/AccessToken/OidcUserInfoTokenHandlerFactory.php b/src/Symfony/Bundle/SecurityBundle/DependencyInjection/Security/AccessToken/OidcUserInfoTokenHandlerFactory.php
index 08b1019f2c210..88e6372f138f8 100644
--- a/src/Symfony/Bundle/SecurityBundle/DependencyInjection/Security/AccessToken/OidcUserInfoTokenHandlerFactory.php
+++ b/src/Symfony/Bundle/SecurityBundle/DependencyInjection/Security/AccessToken/OidcUserInfoTokenHandlerFactory.php
@@ -14,8 +14,9 @@
use Symfony\Component\Config\Definition\Builder\NodeBuilder;
use Symfony\Component\DependencyInjection\ChildDefinition;
use Symfony\Component\DependencyInjection\ContainerBuilder;
+use Symfony\Component\DependencyInjection\Exception\LogicException;
use Symfony\Component\DependencyInjection\Reference;
-use Symfony\Component\HttpClient\HttpClient;
+use Symfony\Contracts\HttpClient\HttpClientInterface;
/**
* Configures a token handler for an OIDC server.
@@ -26,24 +27,18 @@ class OidcUserInfoTokenHandlerFactory implements TokenHandlerFactoryInterface
{
public function create(ContainerBuilder $container, string $id, array|string $config): void
{
- $tokenHandlerDefinition = $container->setDefinition($id, new ChildDefinition('security.access_token_handler.oidc_user_info'));
- $tokenHandlerDefinition->replaceArgument(2, $config['claim']);
+ $clientDefinition = (new ChildDefinition('security.access_token_handler.oidc_user_info.http_client'))
+ ->replaceArgument(0, ['base_uri' => $config['base_uri']]);
- // Create the client service
- if (!isset($config['client']['id'])) {
- $clientDefinitionId = 'http_client.security.access_token_handler.oidc_user_info';
- if (!ContainerBuilder::willBeAvailable('symfony/http-client', HttpClient::class, ['symfony/security-bundle'])) {
- $container->register($clientDefinitionId, 'stdClass')
- ->addError('You cannot use the "oidc_user_info" token handler since the HttpClient component is not installed. Try running "composer require symfony/http-client".');
- } else {
- $container->register($clientDefinitionId, HttpClient::class)
- ->setFactory([HttpClient::class, 'create'])
- ->setArguments([$config['client']])
- ->addTag('http_client.client');
- }
+ if (isset($config['client'])) {
+ $clientDefinition->setFactory([new Reference($config['client']), 'withOptions']);
+ } elseif (!ContainerBuilder::willBeAvailable('symfony/http-client', HttpClientInterface::class, ['symfony/security-bundle'])) {
+ throw new LogicException('You cannot use the "oidc_user_info" token handler since the HttpClient component is not installed. Try running "composer require symfony/http-client".');
}
- $tokenHandlerDefinition->replaceArgument(0, new Reference($config['client']['id'] ?? $clientDefinitionId));
+ $container->setDefinition($id, new ChildDefinition('security.access_token_handler.oidc_user_info'))
+ ->replaceArgument(0, $clientDefinition)
+ ->replaceArgument(2, $config['claim']);
}
public function getKey(): string
@@ -56,19 +51,23 @@ public function addConfiguration(NodeBuilder $node): void
$node
->arrayNode($this->getKey())
->fixXmlConfig($this->getKey())
+ ->beforeNormalization()
+ ->ifString()
+ ->then(static fn ($v) => ['claim' => 'sub', 'base_uri' => $v])
+ ->end()
->children()
+ ->scalarNode('base_uri')
+ ->info('Base URI of the userinfo endpoint on the OIDC server.')
+ ->isRequired()
+ ->cannotBeEmpty()
+ ->end()
->scalarNode('claim')
- ->info('Claim which contains the user identifier (e.g.: sub, email..).')
+ ->info('Claim which contains the user identifier (e.g. sub, email, etc.).')
->defaultValue('sub')
+ ->cannotBeEmpty()
->end()
- ->arrayNode('client')
- ->info('HttpClient to call the OIDC server.')
- ->isRequired()
- ->beforeNormalization()
- ->ifString()
- ->then(static function ($v): array { return ['id' => $v]; })
- ->end()
- ->prototype('scalar')->end()
+ ->scalarNode('client')
+ ->info('HttpClient service id to use to call the OIDC server.')
->end()
->end()
->end()
diff --git a/src/Symfony/Bundle/SecurityBundle/DependencyInjection/Security/Factory/AbstractFactory.php b/src/Symfony/Bundle/SecurityBundle/DependencyInjection/Security/Factory/AbstractFactory.php
index 24eb1377c51c2..f82b46217e5a4 100644
--- a/src/Symfony/Bundle/SecurityBundle/DependencyInjection/Security/Factory/AbstractFactory.php
+++ b/src/Symfony/Bundle/SecurityBundle/DependencyInjection/Security/Factory/AbstractFactory.php
@@ -16,9 +16,6 @@
use Symfony\Component\DependencyInjection\ContainerBuilder;
/**
- * AbstractFactory is the base class for all classes inheriting from
- * AbstractAuthenticationListener.
- *
* @author Fabien Potencier
* @author Lukas Kahwe Smith
* @author Johannes M. Schmitt
diff --git a/src/Symfony/Bundle/SecurityBundle/DependencyInjection/Security/Factory/LoginThrottlingFactory.php b/src/Symfony/Bundle/SecurityBundle/DependencyInjection/Security/Factory/LoginThrottlingFactory.php
index 4092f3e837f4c..b62720bfd80d8 100644
--- a/src/Symfony/Bundle/SecurityBundle/DependencyInjection/Security/Factory/LoginThrottlingFactory.php
+++ b/src/Symfony/Bundle/SecurityBundle/DependencyInjection/Security/Factory/LoginThrottlingFactory.php
@@ -76,6 +76,7 @@ public function createAuthenticator(ContainerBuilder $container, string $firewal
$container->register($config['limiter'] = 'security.login_throttling.'.$firewallName.'.limiter', DefaultLoginRateLimiter::class)
->addArgument(new Reference('limiter.'.$globalId))
->addArgument(new Reference('limiter.'.$localId))
+ ->addArgument('%kernel.secret%')
;
}
@@ -98,9 +99,6 @@ private function registerRateLimiter(ContainerBuilder $container, string $name,
if (!interface_exists(LockInterface::class)) {
throw new LogicException(sprintf('Rate limiter "%s" requires the Lock component to be installed. Try running "composer require symfony/lock".', $name));
}
- if (!$container->hasDefinition('lock.factory.abstract')) {
- throw new LogicException(sprintf('Rate limiter "%s" requires the Lock component to be configured.', $name));
- }
$limiter->replaceArgument(2, new Reference($limiterConfig['lock_factory']));
}
diff --git a/src/Symfony/Bundle/SecurityBundle/DependencyInjection/Security/Factory/RememberMeFactory.php b/src/Symfony/Bundle/SecurityBundle/DependencyInjection/Security/Factory/RememberMeFactory.php
index ca9f0ae1787bd..95b59c3e5c248 100644
--- a/src/Symfony/Bundle/SecurityBundle/DependencyInjection/Security/Factory/RememberMeFactory.php
+++ b/src/Symfony/Bundle/SecurityBundle/DependencyInjection/Security/Factory/RememberMeFactory.php
@@ -110,15 +110,6 @@ public function createAuthenticator(ContainerBuilder $container, string $firewal
->replaceArgument(3, $config['name'] ?? $this->options['name'])
;
- foreach ($container->findTaggedServiceIds('security.remember_me_aware') as $serviceId => $attributes) {
- // register ContextListener
- if (str_starts_with($serviceId, 'security.context_listener')) {
- continue;
- }
-
- throw new \LogicException(sprintf('Symfony Authenticator Security dropped support for the "security.remember_me_aware" tag, service "%s" will no longer work as expected.', $serviceId));
- }
-
return $authenticatorId;
}
diff --git a/src/Symfony/Bundle/SecurityBundle/DependencyInjection/Security/Factory/SignatureAlgorithmFactory.php b/src/Symfony/Bundle/SecurityBundle/DependencyInjection/Security/Factory/SignatureAlgorithmFactory.php
index f9f876deff2bf..e6dc8b3010d68 100644
--- a/src/Symfony/Bundle/SecurityBundle/DependencyInjection/Security/Factory/SignatureAlgorithmFactory.php
+++ b/src/Symfony/Bundle/SecurityBundle/DependencyInjection/Security/Factory/SignatureAlgorithmFactory.php
@@ -11,7 +11,7 @@
namespace Symfony\Bundle\SecurityBundle\DependencyInjection\Security\Factory;
-use Jose\Component\Core\Algorithm as SignatureAlgorithm;
+use Jose\Component\Core\Algorithm as AlgorithmInterface;
use Jose\Component\Signature\Algorithm;
use Symfony\Component\Security\Core\Exception\InvalidArgumentException;
use Symfony\Component\Security\Http\AccessToken\Oidc\OidcTokenHandler;
@@ -19,33 +19,27 @@
/**
* Creates a signature algorithm for {@see OidcTokenHandler}.
*
+ * @internal
+ *
* @experimental
*/
final class SignatureAlgorithmFactory
{
- public static function create(string $algorithm): SignatureAlgorithm
+ public static function create(string $algorithm): AlgorithmInterface
{
switch ($algorithm) {
case 'ES256':
- if (!class_exists(Algorithm\ES256::class)) {
- throw new \LogicException('You cannot use the "ES256" signature algorithm since "web-token/jwt-signature-algorithm-ecdsa" is not installed. Try running "composer require web-token/jwt-signature-algorithm-ecdsa".');
- }
-
- return new Algorithm\ES256();
case 'ES384':
- if (!class_exists(Algorithm\ES384::class)) {
- throw new \LogicException('You cannot use the "ES384" signature algorithm since "web-token/jwt-signature-algorithm-ecdsa" is not installed. Try running "composer require web-token/jwt-signature-algorithm-ecdsa".');
- }
-
- return new Algorithm\ES384();
case 'ES512':
- if (!class_exists(Algorithm\ES512::class)) {
- throw new \LogicException('You cannot use the "ES512" signature algorithm since "web-token/jwt-signature-algorithm-ecdsa" is not installed. Try running "composer require web-token/jwt-signature-algorithm-ecdsa".');
+ if (!class_exists(Algorithm::class.'\\'.$algorithm)) {
+ throw new \LogicException(sprintf('You cannot use the "%s" signature algorithm since "web-token/jwt-signature-algorithm-ecdsa" is not installed. Try running "composer require web-token/jwt-signature-algorithm-ecdsa".', $algorithm));
}
- return new Algorithm\ES512();
- default:
- throw new InvalidArgumentException(sprintf('Unsupported signature algorithm "%s". Only ES* algorithms are supported. If you want to use another algorithm, create your TokenHandler as a service.', $algorithm));
+ $algorithm = Algorithm::class.'\\'.$algorithm;
+
+ return new $algorithm();
}
+
+ throw new InvalidArgumentException(sprintf('Unsupported signature algorithm "%s". Only ES* algorithms are supported. If you want to use another algorithm, create your TokenHandler as a service.', $algorithm));
}
}
diff --git a/src/Symfony/Bundle/SecurityBundle/DependencyInjection/SecurityExtension.php b/src/Symfony/Bundle/SecurityBundle/DependencyInjection/SecurityExtension.php
index 37978b285f3d7..bd26da4cd5490 100644
--- a/src/Symfony/Bundle/SecurityBundle/DependencyInjection/SecurityExtension.php
+++ b/src/Symfony/Bundle/SecurityBundle/DependencyInjection/SecurityExtension.php
@@ -428,11 +428,10 @@ private function createFirewall(ContainerBuilder $container, string $id, array $
$listeners[] = new Reference('security.channel_listener');
$contextKey = null;
- $contextListenerId = null;
// Context serializer listener
if (false === $firewall['stateless']) {
$contextKey = $firewall['context'] ?? $id;
- $listeners[] = new Reference($contextListenerId = $this->createContextListener($container, $contextKey, $firewallEventDispatcherId));
+ $listeners[] = new Reference($this->createContextListener($container, $contextKey, $firewallEventDispatcherId));
$sessionStrategyId = 'security.authentication.session_strategy';
$container
@@ -507,7 +506,7 @@ private function createFirewall(ContainerBuilder $container, string $id, array $
// Authentication listeners
$firewallAuthenticationProviders = [];
- [$authListeners, $defaultEntryPoint] = $this->createAuthenticationListeners($container, $id, $firewall, $firewallAuthenticationProviders, $defaultProvider, $providerIds, $configuredEntryPoint, $contextListenerId);
+ [$authListeners, $defaultEntryPoint] = $this->createAuthenticationListeners($container, $id, $firewall, $firewallAuthenticationProviders, $defaultProvider, $providerIds, $configuredEntryPoint);
// $configuredEntryPoint is resolved into a service ID and stored in $defaultEntryPoint
$configuredEntryPoint = $defaultEntryPoint;
@@ -537,6 +536,7 @@ private function createFirewall(ContainerBuilder $container, string $id, array $
->register('debug.security.firewall.authenticator.'.$id, TraceableAuthenticatorManagerListener::class)
->setDecoratedService('security.firewall.authenticator.'.$id)
->setArguments([new Reference('debug.security.firewall.authenticator.'.$id.'.inner')])
+ ->addTag('kernel.reset', ['method' => 'reset'])
;
}
@@ -611,7 +611,7 @@ private function createContextListener(ContainerBuilder $container, string $cont
return $this->contextListeners[$contextKey] = $listenerId;
}
- private function createAuthenticationListeners(ContainerBuilder $container, string $id, array $firewall, array &$authenticationProviders, ?string $defaultProvider, array $providerIds, ?string $defaultEntryPoint, string $contextListenerId = null): array
+ private function createAuthenticationListeners(ContainerBuilder $container, string $id, array $firewall, array &$authenticationProviders, ?string $defaultProvider, array $providerIds, ?string $defaultEntryPoint): array
{
$listeners = [];
$entryPoints = [];
@@ -620,7 +620,7 @@ private function createAuthenticationListeners(ContainerBuilder $container, stri
$key = str_replace('-', '_', $factory->getKey());
if (isset($firewall[$key])) {
- $userProvider = $this->getUserProvider($container, $id, $firewall, $key, $defaultProvider, $providerIds, $contextListenerId);
+ $userProvider = $this->getUserProvider($container, $id, $firewall, $key, $defaultProvider, $providerIds);
if (!$factory instanceof AuthenticatorFactoryInterface) {
throw new InvalidConfigurationException(sprintf('Authenticator factory "%s" ("%s") must implement "%s".', get_debug_type($factory), $key, AuthenticatorFactoryInterface::class));
@@ -656,7 +656,7 @@ private function createAuthenticationListeners(ContainerBuilder $container, stri
return [$listeners, $defaultEntryPoint];
}
- private function getUserProvider(ContainerBuilder $container, string $id, array $firewall, string $factoryKey, ?string $defaultProvider, array $providerIds, ?string $contextListenerId): ?string
+ private function getUserProvider(ContainerBuilder $container, string $id, array $firewall, string $factoryKey, ?string $defaultProvider, array $providerIds): ?string
{
if (isset($firewall[$factoryKey]['provider'])) {
if (!isset($providerIds[$normalizedName = str_replace('-', '_', $firewall[$factoryKey]['provider'])])) {
@@ -666,10 +666,6 @@ private function getUserProvider(ContainerBuilder $container, string $id, array
return $providerIds[$normalizedName];
}
- if ('remember_me' === $factoryKey && $contextListenerId) {
- $container->getDefinition($contextListenerId)->addTag('security.remember_me_aware', ['id' => $id, 'provider' => 'none']);
- }
-
if ($defaultProvider) {
return $defaultProvider;
}
@@ -726,7 +722,10 @@ private function createHasher(array $config): Reference|array
{
// a custom hasher service
if (isset($config['id'])) {
- return new Reference($config['id']);
+ return $config['migrate_from'] ?? false ? [
+ 'instance' => new Reference($config['id']),
+ 'migrate_from' => $config['migrate_from'],
+ ] : new Reference($config['id']);
}
if ($config['migrate_from'] ?? false) {
@@ -938,7 +937,7 @@ private function createExpression(ContainerBuilder $container, string $expressio
return $this->expressions[$id] = new Reference($id);
}
- private function createRequestMatcher(ContainerBuilder $container, string $path = null, string $host = null, int $port = null, array $methods = [], array $ips = null, array $attributes = []): Reference
+ private function createRequestMatcher(ContainerBuilder $container, ?string $path = null, ?string $host = null, ?int $port = null, array $methods = [], ?array $ips = null, array $attributes = []): Reference
{
if ($methods) {
$methods = array_map('strtoupper', $methods);
diff --git a/src/Symfony/Bundle/SecurityBundle/LoginLink/FirewallAwareLoginLinkHandler.php b/src/Symfony/Bundle/SecurityBundle/LoginLink/FirewallAwareLoginLinkHandler.php
index ff2ea2ddc9305..2bcbcade0c5f0 100644
--- a/src/Symfony/Bundle/SecurityBundle/LoginLink/FirewallAwareLoginLinkHandler.php
+++ b/src/Symfony/Bundle/SecurityBundle/LoginLink/FirewallAwareLoginLinkHandler.php
@@ -38,7 +38,7 @@ public function __construct(FirewallMap $firewallMap, ContainerInterface $loginL
$this->requestStack = $requestStack;
}
- public function createLoginLink(UserInterface $user, Request $request = null, int $lifetime = null): LoginLinkDetails
+ public function createLoginLink(UserInterface $user, ?Request $request = null, ?int $lifetime = null): LoginLinkDetails
{
return $this->getForFirewall()->createLoginLink($user, $request, $lifetime);
}
diff --git a/src/Symfony/Bundle/SecurityBundle/Resources/config/schema/security-1.0.xsd b/src/Symfony/Bundle/SecurityBundle/Resources/config/schema/security-1.0.xsd
index f0835052a6848..0a698476ef409 100644
--- a/src/Symfony/Bundle/SecurityBundle/Resources/config/schema/security-1.0.xsd
+++ b/src/Symfony/Bundle/SecurityBundle/Resources/config/schema/security-1.0.xsd
@@ -140,10 +140,12 @@
+
+
@@ -177,6 +179,7 @@
+
@@ -305,6 +308,51 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/Symfony/Bundle/SecurityBundle/Resources/config/security_authenticator_access_token.php b/src/Symfony/Bundle/SecurityBundle/Resources/config/security_authenticator_access_token.php
index fafe477d5bd23..66716b23ad892 100644
--- a/src/Symfony/Bundle/SecurityBundle/Resources/config/security_authenticator_access_token.php
+++ b/src/Symfony/Bundle/SecurityBundle/Resources/config/security_authenticator_access_token.php
@@ -11,6 +11,12 @@
namespace Symfony\Component\DependencyInjection\Loader\Configurator;
+use Jose\Component\Core\Algorithm;
+use Jose\Component\Core\JWK;
+use Jose\Component\Signature\Algorithm\ES256;
+use Jose\Component\Signature\Algorithm\ES384;
+use Jose\Component\Signature\Algorithm\ES512;
+use Symfony\Bundle\SecurityBundle\DependencyInjection\Security\Factory\SignatureAlgorithmFactory;
use Symfony\Component\Security\Http\AccessToken\ChainAccessTokenExtractor;
use Symfony\Component\Security\Http\AccessToken\FormEncodedBodyExtractor;
use Symfony\Component\Security\Http\AccessToken\HeaderAccessTokenExtractor;
@@ -18,6 +24,7 @@
use Symfony\Component\Security\Http\AccessToken\Oidc\OidcUserInfoTokenHandler;
use Symfony\Component\Security\Http\AccessToken\QueryAccessTokenExtractor;
use Symfony\Component\Security\Http\Authenticator\AccessTokenAuthenticator;
+use Symfony\Contracts\HttpClient\HttpClientInterface;
return static function (ContainerConfigurator $container) {
$container->services()
@@ -35,7 +42,6 @@
null,
null,
])
- ->call('setTranslator', [service('translator')->ignoreOnInvalid()])
->set('security.authenticator.access_token.chain_extractor', ChainAccessTokenExtractor::class)
->abstract()
@@ -44,22 +50,55 @@
])
// OIDC
+ ->set('security.access_token_handler.oidc_user_info.http_client', HttpClientInterface::class)
+ ->abstract()
+ ->factory([service('http_client'), 'withOptions'])
+ ->args([abstract_arg('http client options')])
+
->set('security.access_token_handler.oidc_user_info', OidcUserInfoTokenHandler::class)
->abstract()
->args([
abstract_arg('http client'),
service('logger')->nullOnInvalid(),
- 'sub',
+ abstract_arg('claim'),
])
->set('security.access_token_handler.oidc', OidcTokenHandler::class)
->abstract()
->args([
abstract_arg('signature algorithm'),
- abstract_arg('jwk'),
- service('logger')->nullOnInvalid(),
+ abstract_arg('signature key'),
+ abstract_arg('audience'),
+ abstract_arg('issuers'),
'sub',
- null,
+ service('logger')->nullOnInvalid(),
+ service('clock'),
+ ])
+
+ ->set('security.access_token_handler.oidc.jwk', JWK::class)
+ ->abstract()
+ ->factory([JWK::class, 'createFromJson'])
+ ->args([
+ abstract_arg('signature key'),
])
+
+ ->set('security.access_token_handler.oidc.signature', Algorithm::class)
+ ->abstract()
+ ->factory([SignatureAlgorithmFactory::class, 'create'])
+ ->args([
+ abstract_arg('signature algorithm'),
+ ])
+
+ ->set('security.access_token_handler.oidc.signature.ES256', ES256::class)
+ ->parent('security.access_token_handler.oidc.signature')
+ ->args(['index_0' => 'ES256'])
+
+ ->set('security.access_token_handler.oidc.signature.ES384', ES384::class)
+ ->parent('security.access_token_handler.oidc.signature')
+ ->args(['index_0' => 'ES384'])
+
+ ->set('security.access_token_handler.oidc.signature.ES512', ES512::class)
+ ->parent('security.access_token_handler.oidc.signature')
+ ->args(['index_0' => 'ES512'])
;
};
diff --git a/src/Symfony/Bundle/SecurityBundle/Resources/config/security_debug.php b/src/Symfony/Bundle/SecurityBundle/Resources/config/security_debug.php
index dc668b15e9ded..c98e3a6984672 100644
--- a/src/Symfony/Bundle/SecurityBundle/Resources/config/security_debug.php
+++ b/src/Symfony/Bundle/SecurityBundle/Resources/config/security_debug.php
@@ -36,6 +36,7 @@
service('security.logout_url_generator'),
])
->tag('kernel.event_subscriber')
+ ->tag('kernel.reset', ['method' => 'reset'])
->alias('security.firewall', 'debug.security.firewall')
;
};
diff --git a/src/Symfony/Bundle/SecurityBundle/Security.php b/src/Symfony/Bundle/SecurityBundle/Security.php
index d5cd800e020a8..a1ad99c8e2b09 100644
--- a/src/Symfony/Bundle/SecurityBundle/Security.php
+++ b/src/Symfony/Bundle/SecurityBundle/Security.php
@@ -59,9 +59,13 @@ public function getFirewallConfig(Request $request): ?FirewallConfig
*
* @return Response|null The authenticator success response if any
*/
- public function login(UserInterface $user, string $authenticatorName = null, string $firewallName = null): ?Response
+ public function login(UserInterface $user, ?string $authenticatorName = null, ?string $firewallName = null): ?Response
{
$request = $this->container->get('request_stack')->getCurrentRequest();
+ if (null === $request) {
+ throw new LogicException('Unable to login without a request context.');
+ }
+
$firewallName ??= $this->getFirewallConfig($request)?->getName();
if (!$firewallName) {
@@ -86,6 +90,11 @@ public function login(UserInterface $user, string $authenticatorName = null, str
*/
public function logout(bool $validateCsrfToken = true): ?Response
{
+ $request = $this->container->get('request_stack')->getMainRequest();
+ if (null === $request) {
+ throw new LogicException('Unable to logout without a request context.');
+ }
+
/** @var TokenStorageInterface $tokenStorage */
$tokenStorage = $this->container->get('security.token_storage');
@@ -93,8 +102,6 @@ public function logout(bool $validateCsrfToken = true): ?Response
throw new LogicException('Unable to logout as there is no logged-in user.');
}
- $request = $this->container->get('request_stack')->getMainRequest();
-
if (!$firewallConfig = $this->container->get('security.firewall.map')->getFirewallConfig($request)) {
throw new LogicException('Unable to logout as the request is not behind a firewall.');
}
diff --git a/src/Symfony/Bundle/SecurityBundle/Security/FirewallContext.php b/src/Symfony/Bundle/SecurityBundle/Security/FirewallContext.php
index 5077c6768d95e..a9bd4ccda2e07 100644
--- a/src/Symfony/Bundle/SecurityBundle/Security/FirewallContext.php
+++ b/src/Symfony/Bundle/SecurityBundle/Security/FirewallContext.php
@@ -30,7 +30,7 @@ class FirewallContext
/**
* @param iterable $listeners
*/
- public function __construct(iterable $listeners, ExceptionListener $exceptionListener = null, LogoutListener $logoutListener = null, FirewallConfig $config = null)
+ public function __construct(iterable $listeners, ?ExceptionListener $exceptionListener = null, ?LogoutListener $logoutListener = null, ?FirewallConfig $config = null)
{
$this->listeners = $listeners;
$this->exceptionListener = $exceptionListener;
diff --git a/src/Symfony/Bundle/SecurityBundle/Tests/DataCollector/SecurityDataCollectorTest.php b/src/Symfony/Bundle/SecurityBundle/Tests/DataCollector/SecurityDataCollectorTest.php
index 9d2b056385de3..65bc90cd8487e 100644
--- a/src/Symfony/Bundle/SecurityBundle/Tests/DataCollector/SecurityDataCollectorTest.php
+++ b/src/Symfony/Bundle/SecurityBundle/Tests/DataCollector/SecurityDataCollectorTest.php
@@ -227,7 +227,7 @@ public function testCollectCollectsDecisionLogWhenStrategyIsAffirmative()
$voter2 = new DummyVoter();
$decoratedVoter1 = new TraceableVoter($voter1, new class() implements EventDispatcherInterface {
- public function dispatch(object $event, string $eventName = null): object
+ public function dispatch(object $event, ?string $eventName = null): object
{
return new \stdClass();
}
@@ -302,7 +302,7 @@ public function testCollectCollectsDecisionLogWhenStrategyIsUnanimous()
$voter2 = new DummyVoter();
$decoratedVoter1 = new TraceableVoter($voter1, new class() implements EventDispatcherInterface {
- public function dispatch(object $event, string $eventName = null): object
+ public function dispatch(object $event, ?string $eventName = null): object
{
return new \stdClass();
}
@@ -397,7 +397,7 @@ public function dispatch(object $event, string $eventName = null): object
$this->assertSame($dataCollector->getVoterStrategy(), $strategy, 'Wrong value returned by getVoterStrategy');
}
- public static function provideRoles()
+ public static function provideRoles(): array
{
return [
// Basic roles
diff --git a/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/Compiler/AddSecurityVotersPassTest.php b/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/Compiler/AddSecurityVotersPassTest.php
index 62e1c9cfcf721..b4c2009584f5e 100644
--- a/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/Compiler/AddSecurityVotersPassTest.php
+++ b/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/Compiler/AddSecurityVotersPassTest.php
@@ -91,11 +91,11 @@ public function testThatVotersAreTraceableInDebugMode()
$compilerPass = new AddSecurityVotersPass();
$compilerPass->process($container);
- $def1 = $container->getDefinition('debug.security.voter.voter1');
+ $def1 = $container->getDefinition('.debug.security.voter.voter1');
$this->assertNull($def1->getDecoratedService(), 'voter1: should not be decorated');
$this->assertEquals(new Reference('voter1'), $def1->getArgument(0), 'voter1: wrong argument');
- $def2 = $container->getDefinition('debug.security.voter.voter2');
+ $def2 = $container->getDefinition('.debug.security.voter.voter2');
$this->assertNull($def2->getDecoratedService(), 'voter2: should not be decorated');
$this->assertEquals(new Reference('voter2'), $def2->getArgument(0), 'voter2: wrong argument');
diff --git a/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/Compiler/RegisterEntryPointsPassTest.php b/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/Compiler/RegisterEntryPointsPassTest.php
index b10b8a810bc7a..d2fb348676bc7 100644
--- a/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/Compiler/RegisterEntryPointsPassTest.php
+++ b/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/Compiler/RegisterEntryPointsPassTest.php
@@ -93,7 +93,7 @@ public function onAuthenticationFailure(Request $request, AuthenticationExceptio
], JsonResponse::HTTP_FORBIDDEN);
}
- public function start(Request $request, AuthenticationException $authException = null): Response
+ public function start(Request $request, ?AuthenticationException $authException = null): Response
{
}
}
diff --git a/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/CompleteConfigurationTestCase.php b/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/CompleteConfigurationTestCase.php
index 44193e4ec0a58..f88bbf086511f 100644
--- a/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/CompleteConfigurationTestCase.php
+++ b/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/CompleteConfigurationTestCase.php
@@ -242,7 +242,7 @@ public function testFirewalls()
],
], $listeners);
- $this->assertFalse($container->hasAlias(UserCheckerInterface::class, 'No user checker alias is registered when custom user checker services are registered'));
+ $this->assertFalse($container->hasAlias(UserCheckerInterface::class), 'No user checker alias is registered when custom user checker services are registered');
}
public function testFirewallRequestMatchers()
diff --git a/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/Fixtures/php/legacy_remember_me_options.php b/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/Fixtures/php/legacy_remember_me_options.php
deleted file mode 100644
index cfbef609a18db..0000000000000
--- a/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/Fixtures/php/legacy_remember_me_options.php
+++ /dev/null
@@ -1,18 +0,0 @@
-loadFromExtension('security', [
- 'providers' => [
- 'default' => ['id' => 'foo'],
- ],
-
- 'firewalls' => [
- 'main' => [
- 'form_login' => true,
- 'remember_me' => [
- 'secret' => 'TheSecret',
- 'catch_exceptions' => false,
- 'token_provider' => 'token_provider_id',
- ],
- ],
- ],
-]);
diff --git a/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/Fixtures/php/logout_delete_cookies.php b/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/Fixtures/php/logout_delete_cookies.php
deleted file mode 100644
index 8ffe12e3eb929..0000000000000
--- a/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/Fixtures/php/logout_delete_cookies.php
+++ /dev/null
@@ -1,21 +0,0 @@
-loadFromExtension('security', [
- 'providers' => [
- 'default' => ['id' => 'foo'],
- ],
-
- 'firewalls' => [
- 'main' => [
- 'provider' => 'default',
- 'form_login' => true,
- 'logout' => [
- 'delete_cookies' => [
- 'cookie1-name' => true,
- 'cookie2_name' => true,
- 'cookie3-long_name' => ['path' => '/'],
- ],
- ],
- ],
- ],
-]);
diff --git a/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/Fixtures/xml/legacy_remember_me_options.xml b/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/Fixtures/xml/legacy_remember_me_options.xml
deleted file mode 100644
index 767397ada3515..0000000000000
--- a/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/Fixtures/xml/legacy_remember_me_options.xml
+++ /dev/null
@@ -1,21 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/Fixtures/xml/logout_delete_cookies.xml b/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/Fixtures/xml/logout_delete_cookies.xml
deleted file mode 100644
index e66043c359a15..0000000000000
--- a/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/Fixtures/xml/logout_delete_cookies.xml
+++ /dev/null
@@ -1,23 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/Fixtures/yml/legacy_remember_me_options.yml b/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/Fixtures/yml/legacy_remember_me_options.yml
deleted file mode 100644
index a521c8c6a803d..0000000000000
--- a/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/Fixtures/yml/legacy_remember_me_options.yml
+++ /dev/null
@@ -1,12 +0,0 @@
-security:
- providers:
- default:
- id: foo
-
- firewalls:
- main:
- form_login: true
- remember_me:
- secret: TheSecret
- catch_exceptions: false
- token_provider: token_provider_id
diff --git a/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/Fixtures/yml/logout_delete_cookies.yml b/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/Fixtures/yml/logout_delete_cookies.yml
deleted file mode 100644
index 09bea8c13ab37..0000000000000
--- a/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/Fixtures/yml/logout_delete_cookies.yml
+++ /dev/null
@@ -1,15 +0,0 @@
-security:
- providers:
- default:
- id: foo
-
- firewalls:
- main:
- provider: default
- form_login: true
- logout:
- delete_cookies:
- cookie1-name: ~
- cookie2_name: ~
- cookie3-long_name:
- path: '/'
diff --git a/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/Security/Factory/AccessTokenFactoryTest.php b/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/Security/Factory/AccessTokenFactoryTest.php
index a9da80fbb40ba..e733c7efc644b 100644
--- a/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/Security/Factory/AccessTokenFactoryTest.php
+++ b/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/Security/Factory/AccessTokenFactoryTest.php
@@ -18,7 +18,11 @@
use Symfony\Bundle\SecurityBundle\DependencyInjection\Security\Factory\AccessTokenFactory;
use Symfony\Component\Config\Definition\Builder\ArrayNodeDefinition;
use Symfony\Component\Config\Definition\Exception\InvalidConfigurationException;
+use Symfony\Component\DependencyInjection\ChildDefinition;
use Symfony\Component\DependencyInjection\ContainerBuilder;
+use Symfony\Component\DependencyInjection\Exception\LogicException;
+use Symfony\Component\DependencyInjection\Reference;
+use Symfony\Contracts\HttpClient\HttpClientInterface;
class AccessTokenFactoryTest extends TestCase
{
@@ -76,7 +80,12 @@ public function testOidcUserInfoTokenHandlerConfigurationWithExistingClient()
{
$container = new ContainerBuilder();
$config = [
- 'token_handler' => ['oidc_user_info' => ['client' => 'oidc.client']],
+ 'token_handler' => [
+ 'oidc_user_info' => [
+ 'base_uri' => 'https://www.example.com/realms/demo/protocol/openid-connect/userinfo',
+ 'client' => 'oidc.client',
+ ],
+ ],
];
$factory = new AccessTokenFactory($this->createTokenHandlerFactories());
@@ -86,14 +95,24 @@ public function testOidcUserInfoTokenHandlerConfigurationWithExistingClient()
$this->assertTrue($container->hasDefinition('security.authenticator.access_token.firewall1'));
$this->assertTrue($container->hasDefinition('security.access_token_handler.firewall1'));
- $this->assertFalse($container->hasDefinition('http_client.security.access_token_handler.oidc_user_info'));
+
+ $expected = [
+ 'index_0' => (new ChildDefinition('security.access_token_handler.oidc_user_info.http_client'))
+ ->setFactory([new Reference('oidc.client'), 'withOptions'])
+ ->replaceArgument(0, ['base_uri' => 'https://www.example.com/realms/demo/protocol/openid-connect/userinfo']),
+ 'index_2' => 'sub',
+ ];
+ $this->assertEquals($expected, $container->getDefinition('security.access_token_handler.firewall1')->getArguments());
}
- public function testOidcUserInfoTokenHandlerConfigurationWithClientCreation()
+ /**
+ * @dataProvider getOidcUserInfoConfiguration
+ */
+ public function testOidcUserInfoTokenHandlerConfigurationWithBaseUri(array|string $configuration)
{
$container = new ContainerBuilder();
$config = [
- 'token_handler' => ['oidc_user_info' => ['client' => ['base_uri' => 'https://www.example.com/realms/demo/protocol/openid-connect/userinfo']]],
+ 'token_handler' => ['oidc_user_info' => $configuration],
];
$factory = new AccessTokenFactory($this->createTokenHandlerFactories());
@@ -103,7 +122,25 @@ public function testOidcUserInfoTokenHandlerConfigurationWithClientCreation()
$this->assertTrue($container->hasDefinition('security.authenticator.access_token.firewall1'));
$this->assertTrue($container->hasDefinition('security.access_token_handler.firewall1'));
- $this->assertTrue($container->hasDefinition('http_client.security.access_token_handler.oidc_user_info'));
+
+ $expected = [
+ 'index_0' => (new ChildDefinition('security.access_token_handler.oidc_user_info.http_client'))
+ ->replaceArgument(0, ['base_uri' => 'https://www.example.com/realms/demo/protocol/openid-connect/userinfo']),
+ 'index_2' => 'sub',
+ ];
+
+ if (!interface_exists(HttpClientInterface::class)) {
+ $this->expectException(LogicException::class);
+ $this->expectExceptionMessage('You cannot use the "oidc_user_info" token handler since the HttpClient component is not installed. Try running "composer require symfony/http-client".');
+ }
+
+ $this->assertEquals($expected, $container->getDefinition('security.access_token_handler.firewall1')->getArguments());
+ }
+
+ public static function getOidcUserInfoConfiguration(): iterable
+ {
+ yield [['base_uri' => 'https://www.example.com/realms/demo/protocol/openid-connect/userinfo']];
+ yield ['https://www.example.com/realms/demo/protocol/openid-connect/userinfo'];
}
public function testMultipleTokenHandlersSet()
@@ -114,7 +151,7 @@ public function testMultipleTokenHandlersSet()
$config = [
'token_handler' => [
'id' => 'in_memory_token_handler_service_id',
- 'oidc_user_info' => ['client' => 'oidc.client'],
+ 'oidc_user_info' => 'https://www.example.com/realms/demo/protocol/openid-connect/userinfo',
],
];
diff --git a/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/SecurityExtensionTest.php b/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/SecurityExtensionTest.php
index 4c8c16e6a3245..ccc22f79be2f9 100644
--- a/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/SecurityExtensionTest.php
+++ b/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/SecurityExtensionTest.php
@@ -566,7 +566,7 @@ public function testSecretRememberMeHasher()
$this->assertSame('very', $handler->getArgument(2));
}
- public function sessionConfigurationProvider()
+ public static function sessionConfigurationProvider(): array
{
return [
[
@@ -670,10 +670,27 @@ public function testValidAccessControlWithEmptyRow()
$this->assertTrue(true, 'extension throws an InvalidConfigurationException if there is one more more empty access control items');
}
+ public static function provideEntryPointFirewalls(): iterable
+ {
+ // only one entry point available
+ yield [['http_basic' => true], 'security.authenticator.http_basic.main'];
+ // explicitly configured by authenticator key
+ yield [['form_login' => true, 'http_basic' => true, 'entry_point' => 'form_login'], 'security.authenticator.form_login.main'];
+ // explicitly configured another service
+ yield [['form_login' => true, 'entry_point' => EntryPointStub::class], EntryPointStub::class];
+ // no entry point required
+ yield [['json_login' => true], null];
+
+ // only one guard authenticator entry point available
+ yield [[
+ 'guard' => ['authenticators' => [AppCustomAuthenticator::class]],
+ ], 'security.authenticator.guard.main.0'];
+ }
+
/**
* @dataProvider provideEntryPointRequiredData
*/
- public function testEntryPointRequired(array $firewall, $messageRegex)
+ public function testEntryPointRequired(array $firewall, string $messageRegex)
{
$this->expectException(InvalidConfigurationException::class);
$this->expectExceptionMessageMatches($messageRegex);
@@ -692,7 +709,7 @@ public function testEntryPointRequired(array $firewall, $messageRegex)
$container->compile();
}
- public static function provideEntryPointRequiredData()
+ public static function provideEntryPointRequiredData(): iterable
{
// more than one entry point available and not explicitly set
yield [
@@ -723,7 +740,7 @@ public function testConfigureCustomAuthenticator(array $firewall, array $expecte
$this->assertEquals($expectedAuthenticators, array_map('strval', $container->getDefinition('security.authenticator.manager.main')->getArgument(0)));
}
- public static function provideConfigureCustomAuthenticatorData()
+ public static function provideConfigureCustomAuthenticatorData(): iterable
{
yield [
['custom_authenticator' => TestAuthenticator::class],
@@ -800,7 +817,7 @@ public function testUserCheckerWithAuthenticatorManager(array $config, string $e
$this->assertEquals($expectedUserCheckerClass, $container->findDefinition($userCheckerId)->getClass());
}
- public static function provideUserCheckerConfig()
+ public static function provideUserCheckerConfig(): iterable
{
yield [[], InMemoryUserChecker::class];
yield [['user_checker' => TestUserChecker::class], TestUserChecker::class];
@@ -887,6 +904,32 @@ public function testNothingDoneWithEmptyConfiguration()
$this->assertFalse($container->has('security.authorization_checker'));
}
+ public function testCustomHasherWithMigrateFrom()
+ {
+ $container = $this->getRawContainer();
+
+ $container->loadFromExtension('security', [
+ 'password_hashers' => [
+ 'legacy' => 'md5',
+ 'App\User' => [
+ 'id' => 'App\Security\CustomHasher',
+ 'migrate_from' => 'legacy',
+ ],
+ ],
+ 'firewalls' => ['main' => ['http_basic' => true]],
+ ]);
+
+ $container->compile();
+
+ $hashersMap = $container->getDefinition('security.password_hasher_factory')->getArgument(0);
+
+ $this->assertArrayHasKey('App\User', $hashersMap);
+ $this->assertEquals($hashersMap['App\User'], [
+ 'instance' => new Reference('App\Security\CustomHasher'),
+ 'migrate_from' => ['legacy'],
+ ]);
+ }
+
protected function getRawContainer()
{
$container = new ContainerBuilder();
diff --git a/src/Symfony/Bundle/SecurityBundle/Tests/Functional/AccessTokenTest.php b/src/Symfony/Bundle/SecurityBundle/Tests/Functional/AccessTokenTest.php
index 8ca49ccc1430c..6cc2b1f0fb150 100644
--- a/src/Symfony/Bundle/SecurityBundle/Tests/Functional/AccessTokenTest.php
+++ b/src/Symfony/Bundle/SecurityBundle/Tests/Functional/AccessTokenTest.php
@@ -333,6 +333,18 @@ public function testSelfContainedTokens()
$this->assertSame(['message' => 'Welcome @dunglas!'], json_decode($response->getContent(), true));
}
+ public function testCustomUserLoader()
+ {
+ $client = $this->createClient(['test_case' => 'AccessToken', 'root_config' => 'config_custom_user_loader.yml']);
+ $client->catchExceptions(false);
+ $client->request('GET', '/foo', [], [], ['HTTP_AUTHORIZATION' => 'Bearer SELF_CONTAINED_ACCESS_TOKEN']);
+ $response = $client->getResponse();
+
+ $this->assertInstanceOf(Response::class, $response);
+ $this->assertSame(200, $response->getStatusCode());
+ $this->assertSame(['message' => 'Welcome @dunglas!'], json_decode($response->getContent(), true));
+ }
+
/**
* @requires extension openssl
*/
@@ -343,7 +355,7 @@ public function testOidcSuccess()
'iat' => $time,
'nbf' => $time,
'exp' => $time + 3600,
- 'iss' => 'https://www.example.com/',
+ 'iss' => 'https://www.example.com',
'aud' => 'Symfony OIDC',
'sub' => 'e21bf182-1538-406e-8ccb-e25a17aba39f',
'username' => 'dunglas',
diff --git a/src/Symfony/Bundle/SecurityBundle/Tests/Functional/AuthenticatorTest.php b/src/Symfony/Bundle/SecurityBundle/Tests/Functional/AuthenticatorTest.php
index ca99dbf3eadab..d162f99131399 100644
--- a/src/Symfony/Bundle/SecurityBundle/Tests/Functional/AuthenticatorTest.php
+++ b/src/Symfony/Bundle/SecurityBundle/Tests/Functional/AuthenticatorTest.php
@@ -60,7 +60,7 @@ public function testWithoutUserProvider($email)
$this->assertJsonStringEqualsJsonString('{"email":"'.$email.'"}', $client->getResponse()->getContent());
}
- public static function provideEmails()
+ public static function provideEmails(): iterable
{
yield ['jane@example.org', true];
yield ['john@example.org', false];
@@ -84,7 +84,7 @@ public function testLoginUsersWithMultipleFirewalls(string $username, string $fi
$this->assertEquals('Welcome '.$username.'!', $client->getResponse()->getContent());
}
- public static function provideEmailsWithFirewalls()
+ public static function provideEmailsWithFirewalls(): iterable
{
yield ['jane@example.org', 'main'];
yield ['john@example.org', 'custom'];
diff --git a/src/Symfony/Bundle/SecurityBundle/Tests/Functional/Bundle/FirewallEntryPointBundle/Security/EntryPointStub.php b/src/Symfony/Bundle/SecurityBundle/Tests/Functional/Bundle/FirewallEntryPointBundle/Security/EntryPointStub.php
index 56552b99c7983..16a757260cf27 100644
--- a/src/Symfony/Bundle/SecurityBundle/Tests/Functional/Bundle/FirewallEntryPointBundle/Security/EntryPointStub.php
+++ b/src/Symfony/Bundle/SecurityBundle/Tests/Functional/Bundle/FirewallEntryPointBundle/Security/EntryPointStub.php
@@ -20,7 +20,7 @@ class EntryPointStub implements AuthenticationEntryPointInterface
{
public const RESPONSE_TEXT = '2be8e651259189d841a19eecdf37e771e2431741';
- public function start(Request $request, AuthenticationException $authException = null): Response
+ public function start(Request $request, ?AuthenticationException $authException = null): Response
{
return new Response(self::RESPONSE_TEXT);
}
diff --git a/src/Symfony/Bundle/SecurityBundle/Tests/Functional/Bundle/FormLoginBundle/Controller/LoginController.php b/src/Symfony/Bundle/SecurityBundle/Tests/Functional/Bundle/FormLoginBundle/Controller/LoginController.php
index 09b0ff09ba8d1..11f33cb076627 100644
--- a/src/Symfony/Bundle/SecurityBundle/Tests/Functional/Bundle/FormLoginBundle/Controller/LoginController.php
+++ b/src/Symfony/Bundle/SecurityBundle/Tests/Functional/Bundle/FormLoginBundle/Controller/LoginController.php
@@ -29,7 +29,7 @@ public function __construct(ContainerInterface $container)
$this->container = $container;
}
- public function loginAction(Request $request, UserInterface $user = null)
+ public function loginAction(Request $request, ?UserInterface $user = null)
{
// get the login error if there is one
if ($request->attributes->has(SecurityRequestAttributes::AUTHENTICATION_ERROR)) {
diff --git a/src/Symfony/Bundle/SecurityBundle/Tests/Functional/CsrfFormLoginTest.php b/src/Symfony/Bundle/SecurityBundle/Tests/Functional/CsrfFormLoginTest.php
index 25aa013131648..f8768d9502a24 100644
--- a/src/Symfony/Bundle/SecurityBundle/Tests/Functional/CsrfFormLoginTest.php
+++ b/src/Symfony/Bundle/SecurityBundle/Tests/Functional/CsrfFormLoginTest.php
@@ -122,7 +122,7 @@ public function testFormLoginRedirectsToProtectedResourceAfterLogin($options)
$this->assertStringContainsString('You\'re browsing to path "/protected-resource".', $text);
}
- public static function provideClientOptions()
+ public static function provideClientOptions(): iterable
{
yield [['test_case' => 'CsrfFormLogin', 'root_config' => 'config.yml']];
yield [['test_case' => 'CsrfFormLogin', 'root_config' => 'routes_as_path.yml']];
diff --git a/src/Symfony/Bundle/SecurityBundle/Tests/Functional/FormLoginTest.php b/src/Symfony/Bundle/SecurityBundle/Tests/Functional/FormLoginTest.php
index 583c0dd2336b0..f6957f45a87b4 100644
--- a/src/Symfony/Bundle/SecurityBundle/Tests/Functional/FormLoginTest.php
+++ b/src/Symfony/Bundle/SecurityBundle/Tests/Functional/FormLoginTest.php
@@ -147,7 +147,7 @@ public function testLoginThrottling()
}
}
- public static function provideClientOptions()
+ public static function provideClientOptions(): iterable
{
yield [['test_case' => 'StandardFormLogin', 'root_config' => 'base_config.yml']];
yield [['test_case' => 'StandardFormLogin', 'root_config' => 'routes_as_path.yml']];
diff --git a/src/Symfony/Bundle/SecurityBundle/Tests/Functional/RememberMeTest.php b/src/Symfony/Bundle/SecurityBundle/Tests/Functional/RememberMeTest.php
index 2fff3a9eddc7a..036069f070f6b 100644
--- a/src/Symfony/Bundle/SecurityBundle/Tests/Functional/RememberMeTest.php
+++ b/src/Symfony/Bundle/SecurityBundle/Tests/Functional/RememberMeTest.php
@@ -93,7 +93,7 @@ public function testSessionLessRememberMeLogout()
$this->assertNull($cookieJar->get('REMEMBERME'));
}
- public static function provideConfigs()
+ public static function provideConfigs(): iterable
{
yield [['root_config' => 'config_session.yml']];
yield [['root_config' => 'config_persistent.yml']];
diff --git a/src/Symfony/Bundle/SecurityBundle/Tests/Functional/SecurityRoutingIntegrationTest.php b/src/Symfony/Bundle/SecurityBundle/Tests/Functional/SecurityRoutingIntegrationTest.php
index 362801253f305..517253fdff94e 100644
--- a/src/Symfony/Bundle/SecurityBundle/Tests/Functional/SecurityRoutingIntegrationTest.php
+++ b/src/Symfony/Bundle/SecurityBundle/Tests/Functional/SecurityRoutingIntegrationTest.php
@@ -125,8 +125,7 @@ public function testInvalidIpsInAccessControl()
$this->expectException(\LogicException::class);
$this->expectExceptionMessage('The given value "256.357.458.559" in the "security.access_control" config option is not a valid IP address.');
- $client = $this->createClient(['test_case' => 'StandardFormLogin', 'root_config' => 'invalid_ip_access_control.yml']);
- $client->request('GET', '/unprotected_resource');
+ $this->createClient(['test_case' => 'StandardFormLogin', 'root_config' => 'invalid_ip_access_control.yml']);
}
public function testPublicHomepage()
@@ -151,7 +150,19 @@ private function assertRestricted($client, $path)
$this->assertEquals(302, $client->getResponse()->getStatusCode());
}
- public static function provideConfigs()
+ public static function provideClientOptions(): iterable
+ {
+ yield [['test_case' => 'StandardFormLogin', 'root_config' => 'base_config.yml', 'enable_authenticator_manager' => true]];
+ yield [['test_case' => 'StandardFormLogin', 'root_config' => 'routes_as_path.yml', 'enable_authenticator_manager' => true]];
+ }
+
+ public static function provideLegacyClientOptions()
+ {
+ yield [['test_case' => 'StandardFormLogin', 'root_config' => 'base_config.yml', 'enable_authenticator_manager' => true]];
+ yield [['test_case' => 'StandardFormLogin', 'root_config' => 'routes_as_path.yml', 'enable_authenticator_manager' => true]];
+ }
+
+ public static function provideConfigs(): iterable
{
yield [['test_case' => 'StandardFormLogin', 'root_config' => 'base_config.yml']];
yield [['test_case' => 'StandardFormLogin', 'root_config' => 'routes_as_path.yml']];
diff --git a/src/Symfony/Bundle/SecurityBundle/Tests/Functional/SecurityTest.php b/src/Symfony/Bundle/SecurityBundle/Tests/Functional/SecurityTest.php
index f2d6733fcf350..15cc79f6b9808 100644
--- a/src/Symfony/Bundle/SecurityBundle/Tests/Functional/SecurityTest.php
+++ b/src/Symfony/Bundle/SecurityBundle/Tests/Functional/SecurityTest.php
@@ -76,7 +76,7 @@ public function testUserWillBeMarkedAsChangedIfRolesHasChanged(UserInterface $us
$this->assertEquals(302, $client->getResponse()->getStatusCode());
}
- public static function userWillBeMarkedAsChangedIfRolesHasChangedProvider()
+ public static function userWillBeMarkedAsChangedIfRolesHasChangedProvider(): array
{
return [
[
diff --git a/src/Symfony/Bundle/SecurityBundle/Tests/Functional/app/AbstractTokenCompareRoles/legacy_config.yml b/src/Symfony/Bundle/SecurityBundle/Tests/Functional/app/AbstractTokenCompareRoles/legacy_config.yml
deleted file mode 100644
index 54bfaf89cb6c7..0000000000000
--- a/src/Symfony/Bundle/SecurityBundle/Tests/Functional/app/AbstractTokenCompareRoles/legacy_config.yml
+++ /dev/null
@@ -1,30 +0,0 @@
-imports:
- - { resource: ./../config/framework.yml }
-
-services:
- _defaults: { public: true }
-
- security.user.provider.array:
- class: Symfony\Bundle\SecurityBundle\Tests\Functional\Bundle\SecuredPageBundle\Security\Core\User\ArrayUserProvider
-
-security:
- password_hashers:
- \Symfony\Component\Security\Core\User\UserInterface: plaintext
-
- providers:
- array:
- id: security.user.provider.array
-
- firewalls:
- default:
- form_login:
- check_path: login
- remember_me: true
- require_previous_session: false
- logout: ~
- stateless: false
-
- access_control:
- - { path: ^/admin$, roles: ROLE_ADMIN }
- - { path: ^/login$, roles: IS_AUTHENTICATED_ANONYMOUSLY }
- - { path: .*, roles: IS_AUTHENTICATED_FULLY }
diff --git a/src/Symfony/Bundle/SecurityBundle/Tests/Functional/app/AccessToken/config_custom_user_loader.yml b/src/Symfony/Bundle/SecurityBundle/Tests/Functional/app/AccessToken/config_custom_user_loader.yml
new file mode 100644
index 0000000000000..2027656b4d83c
--- /dev/null
+++ b/src/Symfony/Bundle/SecurityBundle/Tests/Functional/app/AccessToken/config_custom_user_loader.yml
@@ -0,0 +1,32 @@
+imports:
+ - { resource: ./../config/framework.yml }
+
+framework:
+ http_method_override: false
+ serializer: ~
+
+security:
+ password_hashers:
+ Symfony\Component\Security\Core\User\InMemoryUser: plaintext
+
+ providers:
+ in_memory:
+ memory:
+ users:
+ dunglas: { password: foo, roles: [ROLE_MISSING] }
+
+ firewalls:
+ main:
+ pattern: ^/
+ stateless: true
+ access_token:
+ token_handler: access_token.access_token_handler
+ token_extractors: 'header'
+ realm: 'My API'
+
+ access_control:
+ - { path: ^/foo, roles: ROLE_USER }
+
+services:
+ access_token.access_token_handler:
+ class: Symfony\Bundle\SecurityBundle\Tests\Functional\Bundle\AccessTokenBundle\Security\Handler\AccessTokenHandler
diff --git a/src/Symfony/Bundle/SecurityBundle/Tests/Functional/app/AccessToken/config_oidc.yml b/src/Symfony/Bundle/SecurityBundle/Tests/Functional/app/AccessToken/config_oidc.yml
index 45802961a1a61..dd770e4520e41 100644
--- a/src/Symfony/Bundle/SecurityBundle/Tests/Functional/app/AccessToken/config_oidc.yml
+++ b/src/Symfony/Bundle/SecurityBundle/Tests/Functional/app/AccessToken/config_oidc.yml
@@ -23,10 +23,10 @@ security:
oidc:
claim: 'username'
audience: 'Symfony OIDC'
- signature:
- algorithm: 'ES256'
- # tip: use https://mkjwk.org/ to generate a JWK
- key: '{"kty":"EC","d":"iA_TV2zvftni_9aFAQwFO_9aypfJFCSpcCyevDvz220","crv":"P-256","x":"0QEAsI1wGI-dmYatdUZoWSRWggLEpyzopuhwk-YUnA4","y":"KYl-qyZ26HobuYwlQh-r0iHX61thfP82qqEku7i0woo"}'
+ issuers: [ 'https://www.example.com' ]
+ algorithm: 'ES256'
+ # tip: use https://mkjwk.org/ to generate a JWK
+ key: '{"kty":"EC","d":"iA_TV2zvftni_9aFAQwFO_9aypfJFCSpcCyevDvz220","crv":"P-256","x":"0QEAsI1wGI-dmYatdUZoWSRWggLEpyzopuhwk-YUnA4","y":"KYl-qyZ26HobuYwlQh-r0iHX61thfP82qqEku7i0woo"}'
token_extractors: 'header'
realm: 'My API'
diff --git a/src/Symfony/Bundle/SecurityBundle/Tests/Functional/app/AutowiringTypes/legacy_config.yml b/src/Symfony/Bundle/SecurityBundle/Tests/Functional/app/AutowiringTypes/legacy_config.yml
deleted file mode 100644
index 2045118e1b9f1..0000000000000
--- a/src/Symfony/Bundle/SecurityBundle/Tests/Functional/app/AutowiringTypes/legacy_config.yml
+++ /dev/null
@@ -1,15 +0,0 @@
-imports:
- - { resource: ../config/framework.yml }
-
-services:
- _defaults: { public: true }
- test.autowiring_types.autowired_services:
- class: Symfony\Bundle\SecurityBundle\Tests\Functional\Bundle\AutowiringBundle\AutowiredServices
- autowire: true
-security:
- providers:
- dummy:
- memory: ~
- firewalls:
- dummy:
- security: false
diff --git a/src/Symfony/Bundle/SecurityBundle/Tests/Functional/app/JsonLogin/legacy_config.yml b/src/Symfony/Bundle/SecurityBundle/Tests/Functional/app/JsonLogin/legacy_config.yml
deleted file mode 100644
index 022263a978e6d..0000000000000
--- a/src/Symfony/Bundle/SecurityBundle/Tests/Functional/app/JsonLogin/legacy_config.yml
+++ /dev/null
@@ -1,27 +0,0 @@
-imports:
- - { resource: ./../config/framework.yml }
-
-framework:
- http_method_override: false
- serializer: ~
-
-security:
- password_hashers:
- Symfony\Component\Security\Core\User\InMemoryUser: plaintext
-
- providers:
- in_memory:
- memory:
- users:
- dunglas: { password: foo, roles: [ROLE_USER] }
-
- firewalls:
- main:
- pattern: ^/
- json_login:
- check_path: /chk
- username_path: user.login
- password_path: user.password
-
- access_control:
- - { path: ^/foo, roles: ROLE_USER }
diff --git a/src/Symfony/Bundle/SecurityBundle/Tests/Functional/app/JsonLogin/legacy_custom_handlers.yml b/src/Symfony/Bundle/SecurityBundle/Tests/Functional/app/JsonLogin/legacy_custom_handlers.yml
deleted file mode 100644
index f1f1a93ab0c0b..0000000000000
--- a/src/Symfony/Bundle/SecurityBundle/Tests/Functional/app/JsonLogin/legacy_custom_handlers.yml
+++ /dev/null
@@ -1,31 +0,0 @@
-imports:
- - { resource: ./../config/framework.yml }
-
-security:
- password_hashers:
- Symfony\Component\Security\Core\User\InMemoryUser: plaintext
-
- providers:
- in_memory:
- memory:
- users:
- dunglas: { password: foo, roles: [ROLE_USER] }
-
- firewalls:
- main:
- pattern: ^/
- json_login:
- check_path: /chk
- username_path: user.login
- password_path: user.password
- success_handler: json_login.success_handler
- failure_handler: json_login.failure_handler
-
- access_control:
- - { path: ^/foo, roles: ROLE_USER }
-
-services:
- json_login.success_handler:
- class: Symfony\Bundle\SecurityBundle\Tests\Functional\Bundle\JsonLoginBundle\Security\Http\JsonAuthenticationSuccessHandler
- json_login.failure_handler:
- class: Symfony\Bundle\SecurityBundle\Tests\Functional\Bundle\JsonLoginBundle\Security\Http\JsonAuthenticationFailureHandler
diff --git a/src/Symfony/Bundle/SecurityBundle/Tests/Functional/app/SecurityHelper/legacy_config.yml b/src/Symfony/Bundle/SecurityBundle/Tests/Functional/app/SecurityHelper/legacy_config.yml
deleted file mode 100644
index 01aa24889faf0..0000000000000
--- a/src/Symfony/Bundle/SecurityBundle/Tests/Functional/app/SecurityHelper/legacy_config.yml
+++ /dev/null
@@ -1,22 +0,0 @@
-imports:
- - { resource: ./../config/framework.yml }
-
-services:
- # alias the service so we can access it in the tests
- functional_test.security.helper:
- alias: security.helper
- public: true
-
- functional.test.security.token_storage:
- alias: security.token_storage
- public: true
-
-security:
- providers:
- in_memory:
- memory:
- users: []
-
- firewalls:
- default:
- anonymous: ~
diff --git a/src/Symfony/Bundle/SecurityBundle/Tests/SecurityTest.php b/src/Symfony/Bundle/SecurityBundle/Tests/SecurityTest.php
index 95b0006f5f896..045dfc70a7c5e 100644
--- a/src/Symfony/Bundle/SecurityBundle/Tests/SecurityTest.php
+++ b/src/Symfony/Bundle/SecurityBundle/Tests/SecurityTest.php
@@ -252,6 +252,28 @@ public function testLoginWithoutAuthenticatorThrows()
$security->login($user);
}
+ public function testLoginWithoutRequestContext()
+ {
+ $requestStack = new RequestStack();
+ $user = $this->createMock(UserInterface::class);
+
+ $container = $this->createMock(ContainerInterface::class);
+ $container
+ ->expects($this->atLeastOnce())
+ ->method('get')
+ ->willReturnMap([
+ ['request_stack', $requestStack],
+ ])
+ ;
+
+ $security = new Security($container, ['main' => null]);
+
+ $this->expectException(\LogicException::class);
+ $this->expectExceptionMessage('Unable to login without a request context.');
+
+ $security->login($user);
+ }
+
public function testLogout()
{
$request = new Request();
@@ -458,6 +480,27 @@ public function testLogoutWithValidCsrf()
$this->assertEquals('a custom response', $response->getContent());
}
+ public function testLogoutWithoutRequestContext()
+ {
+ $requestStack = new RequestStack();
+
+ $container = $this->createMock(ContainerInterface::class);
+ $container
+ ->expects($this->atLeastOnce())
+ ->method('get')
+ ->willReturnMap([
+ ['request_stack', $requestStack],
+ ])
+ ;
+
+ $security = new Security($container, ['main' => null]);
+
+ $this->expectException(\LogicException::class);
+ $this->expectExceptionMessage('Unable to logout without a request context.');
+
+ $security->logout();
+ }
+
private function createContainer(string $serviceId, object $serviceObject): ContainerInterface
{
return new ServiceLocator([$serviceId => fn () => $serviceObject]);
diff --git a/src/Symfony/Bundle/SecurityBundle/composer.json b/src/Symfony/Bundle/SecurityBundle/composer.json
index 8fb916cd27114..deedf660b975c 100644
--- a/src/Symfony/Bundle/SecurityBundle/composer.json
+++ b/src/Symfony/Bundle/SecurityBundle/composer.json
@@ -19,15 +19,18 @@
"php": ">=8.1",
"composer-runtime-api": ">=2.1",
"ext-xml": "*",
+ "symfony/clock": "^6.3",
"symfony/config": "^6.1",
"symfony/dependency-injection": "^6.2",
+ "symfony/deprecation-contracts": "^2.5|^3",
"symfony/event-dispatcher": "^5.4|^6.0",
"symfony/http-kernel": "^6.2",
"symfony/http-foundation": "^6.2",
"symfony/password-hasher": "^5.4|^6.0",
"symfony/security-core": "^6.2",
"symfony/security-csrf": "^5.4|^6.0",
- "symfony/security-http": "^6.3"
+ "symfony/security-http": "^6.3.6",
+ "symfony/service-contracts": "^2.5|^3"
},
"require-dev": {
"doctrine/annotations": "^1.10.4|^2",
@@ -38,7 +41,8 @@
"symfony/dom-crawler": "^5.4|^6.0",
"symfony/expression-language": "^5.4|^6.0",
"symfony/form": "^5.4|^6.0",
- "symfony/framework-bundle": "^5.4|^6.0",
+ "symfony/framework-bundle": "^6.3",
+ "symfony/http-client": "^5.4|^6.0",
"symfony/ldap": "^5.4|^6.0",
"symfony/process": "^5.4|^6.0",
"symfony/rate-limiter": "^5.4|^6.0",
@@ -59,7 +63,8 @@
"conflict": {
"symfony/browser-kit": "<5.4",
"symfony/console": "<5.4",
- "symfony/framework-bundle": "<5.4",
+ "symfony/framework-bundle": "<6.3",
+ "symfony/http-client": "<5.4",
"symfony/ldap": "<5.4",
"symfony/twig-bundle": "<5.4"
},
diff --git a/src/Symfony/Bundle/TwigBundle/DependencyInjection/Compiler/ExtensionPass.php b/src/Symfony/Bundle/TwigBundle/DependencyInjection/Compiler/ExtensionPass.php
index 5c3cff66fc411..63dd68e91b90d 100644
--- a/src/Symfony/Bundle/TwigBundle/DependencyInjection/Compiler/ExtensionPass.php
+++ b/src/Symfony/Bundle/TwigBundle/DependencyInjection/Compiler/ExtensionPass.php
@@ -46,6 +46,12 @@ public function process(ContainerBuilder $container)
$container->removeDefinition('twig.extension.yaml');
}
+ if (!$container->has('asset_mapper')) {
+ // edge case where AssetMapper is installed, but not enabled
+ $container->removeDefinition('twig.extension.importmap');
+ $container->removeDefinition('twig.runtime.importmap');
+ }
+
$viewDir = \dirname((new \ReflectionClass(\Symfony\Bridge\Twig\Extension\FormExtension::class))->getFileName(), 2).'/Resources/views';
$templateIterator = $container->getDefinition('twig.template_iterator');
$templatePaths = $templateIterator->getArgument(1);
diff --git a/src/Symfony/Bundle/TwigBundle/DependencyInjection/Configuration.php b/src/Symfony/Bundle/TwigBundle/DependencyInjection/Configuration.php
index 4712b18a6ac1b..114e693b5c326 100644
--- a/src/Symfony/Bundle/TwigBundle/DependencyInjection/Configuration.php
+++ b/src/Symfony/Bundle/TwigBundle/DependencyInjection/Configuration.php
@@ -157,7 +157,7 @@ private function addTwigOptions(ArrayNodeDefinition $rootNode): void
->normalizeKeys(false)
->useAttributeAsKey('paths')
->beforeNormalization()
- ->always()
+ ->ifArray()
->then(function ($paths) {
$normalized = [];
foreach ($paths as $path => $namespace) {
diff --git a/src/Symfony/Bundle/TwigBundle/DependencyInjection/TwigExtension.php b/src/Symfony/Bundle/TwigBundle/DependencyInjection/TwigExtension.php
index 101dbf699a5a4..f257f60298bb6 100644
--- a/src/Symfony/Bundle/TwigBundle/DependencyInjection/TwigExtension.php
+++ b/src/Symfony/Bundle/TwigBundle/DependencyInjection/TwigExtension.php
@@ -11,6 +11,7 @@
namespace Symfony\Bundle\TwigBundle\DependencyInjection;
+use Symfony\Component\AssetMapper\AssetMapper;
use Symfony\Component\Config\FileLocator;
use Symfony\Component\Config\Resource\FileExistenceResource;
use Symfony\Component\Console\Application;
@@ -86,6 +87,10 @@ public function load(array $configs, ContainerBuilder $container)
}
}
+ if ($container::willBeAvailable('symfony/asset-mapper', AssetMapper::class, ['symfony/twig-bundle'])) {
+ $loader->load('importmap.php');
+ }
+
$container->setParameter('twig.form.resources', $config['form_themes']);
$container->setParameter('twig.default_path', $config['default_path']);
$defaultTwigPath = $container->getParameterBag()->resolveValue($config['default_path']);
diff --git a/src/Symfony/Bundle/TwigBundle/Resources/config/importmap.php b/src/Symfony/Bundle/TwigBundle/Resources/config/importmap.php
new file mode 100644
index 0000000000000..c28021959e0f1
--- /dev/null
+++ b/src/Symfony/Bundle/TwigBundle/Resources/config/importmap.php
@@ -0,0 +1,27 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\DependencyInjection\Loader\Configurator;
+
+use Symfony\Bridge\Twig\Extension\ImportMapExtension;
+use Symfony\Bridge\Twig\Extension\ImportMapRuntime;
+
+return static function (ContainerConfigurator $container) {
+ $container->services()
+
+ ->set('twig.runtime.importmap', ImportMapRuntime::class)
+ ->args([service('asset_mapper.importmap.renderer')])
+ ->tag('twig.runtime')
+
+ ->set('twig.extension.importmap', ImportMapExtension::class)
+ ->tag('twig.extension')
+ ;
+};
diff --git a/src/Symfony/Bundle/TwigBundle/TemplateIterator.php b/src/Symfony/Bundle/TwigBundle/TemplateIterator.php
index 7242cfb0c5d44..bd42f1ac07e8d 100644
--- a/src/Symfony/Bundle/TwigBundle/TemplateIterator.php
+++ b/src/Symfony/Bundle/TwigBundle/TemplateIterator.php
@@ -36,7 +36,7 @@ class TemplateIterator implements \IteratorAggregate
* @param string|null $defaultPath The directory where global templates can be stored
* @param string[] $namePatterns Pattern of file names
*/
- public function __construct(KernelInterface $kernel, array $paths = [], string $defaultPath = null, array $namePatterns = [])
+ public function __construct(KernelInterface $kernel, array $paths = [], ?string $defaultPath = null, array $namePatterns = [])
{
$this->kernel = $kernel;
$this->paths = $paths;
@@ -78,7 +78,7 @@ public function getIterator(): \Traversable
*
* @return string[]
*/
- private function findTemplatesInDirectory(string $dir, string $namespace = null, array $excludeDirs = []): array
+ private function findTemplatesInDirectory(string $dir, ?string $namespace = null, array $excludeDirs = []): array
{
if (!is_dir($dir)) {
return [];
diff --git a/src/Symfony/Bundle/TwigBundle/Tests/DependencyInjection/ConfigurationTest.php b/src/Symfony/Bundle/TwigBundle/Tests/DependencyInjection/ConfigurationTest.php
index 41627c48041e3..6ed43087579ce 100644
--- a/src/Symfony/Bundle/TwigBundle/Tests/DependencyInjection/ConfigurationTest.php
+++ b/src/Symfony/Bundle/TwigBundle/Tests/DependencyInjection/ConfigurationTest.php
@@ -52,4 +52,16 @@ public function testArrayKeysInGlobalsAreNotNormalized()
$this->assertSame(['global' => ['value' => ['some-key' => 'some-value']]], $config['globals']);
}
+
+ public function testNullPathsAreConvertedToIterable()
+ {
+ $input = [
+ 'paths' => null,
+ ];
+
+ $processor = new Processor();
+ $config = $processor->processConfiguration(new Configuration(), [$input]);
+
+ $this->assertSame([], $config['paths']);
+ }
}
diff --git a/src/Symfony/Bundle/TwigBundle/Tests/DependencyInjection/TwigExtensionTest.php b/src/Symfony/Bundle/TwigBundle/Tests/DependencyInjection/TwigExtensionTest.php
index e1fcb3af33a92..d4eaae53fe6f2 100644
--- a/src/Symfony/Bundle/TwigBundle/Tests/DependencyInjection/TwigExtensionTest.php
+++ b/src/Symfony/Bundle/TwigBundle/Tests/DependencyInjection/TwigExtensionTest.php
@@ -237,7 +237,7 @@ public function testStopwatchExtensionAvailability($debug, $stopwatchEnabled, $e
$this->assertSame($expected, $stopwatchIsAvailable->getValue($tokenParsers[0]));
}
- public static function stopwatchExtensionAvailabilityProvider()
+ public static function stopwatchExtensionAvailabilityProvider(): array
{
return [
'debug-and-stopwatch-enabled' => [true, true, true],
diff --git a/src/Symfony/Bundle/TwigBundle/composer.json b/src/Symfony/Bundle/TwigBundle/composer.json
index e7297860ff44b..af4b61e9c2cbf 100644
--- a/src/Symfony/Bundle/TwigBundle/composer.json
+++ b/src/Symfony/Bundle/TwigBundle/composer.json
@@ -20,7 +20,7 @@
"composer-runtime-api": ">=2.1",
"symfony/config": "^6.1",
"symfony/dependency-injection": "^6.1",
- "symfony/twig-bridge": "^6.2",
+ "symfony/twig-bridge": "^6.3",
"symfony/http-foundation": "^5.4|^6.0",
"symfony/http-kernel": "^6.2",
"twig/twig": "^2.13|^3.0.4"
diff --git a/src/Symfony/Bundle/WebProfilerBundle/Controller/ExceptionPanelController.php b/src/Symfony/Bundle/WebProfilerBundle/Controller/ExceptionPanelController.php
index 4941208c88bc2..0eb122314c070 100644
--- a/src/Symfony/Bundle/WebProfilerBundle/Controller/ExceptionPanelController.php
+++ b/src/Symfony/Bundle/WebProfilerBundle/Controller/ExceptionPanelController.php
@@ -28,7 +28,7 @@ class ExceptionPanelController
private $errorRenderer;
private $profiler;
- public function __construct(HtmlErrorRenderer $errorRenderer, Profiler $profiler = null)
+ public function __construct(HtmlErrorRenderer $errorRenderer, ?Profiler $profiler = null)
{
$this->errorRenderer = $errorRenderer;
$this->profiler = $profiler;
diff --git a/src/Symfony/Bundle/WebProfilerBundle/Controller/ProfilerController.php b/src/Symfony/Bundle/WebProfilerBundle/Controller/ProfilerController.php
index b9a861df38dd2..e0aaa3158f990 100644
--- a/src/Symfony/Bundle/WebProfilerBundle/Controller/ProfilerController.php
+++ b/src/Symfony/Bundle/WebProfilerBundle/Controller/ProfilerController.php
@@ -40,7 +40,7 @@ class ProfilerController
private $cspHandler;
private $baseDir;
- public function __construct(UrlGeneratorInterface $generator, Profiler $profiler = null, Environment $twig, array $templates, ContentSecurityPolicyHandler $cspHandler = null, string $baseDir = null)
+ public function __construct(UrlGeneratorInterface $generator, ?Profiler $profiler, Environment $twig, array $templates, ?ContentSecurityPolicyHandler $cspHandler = null, ?string $baseDir = null)
{
$this->generator = $generator;
$this->profiler = $profiler;
@@ -122,13 +122,15 @@ public function panelAction(Request $request, string $token): Response
*
* @throws NotFoundHttpException
*/
- public function toolbarAction(Request $request, string $token = null): Response
+ public function toolbarAction(Request $request, ?string $token = null): Response
{
if (null === $this->profiler) {
throw new NotFoundHttpException('The profiler must be enabled.');
}
- if ($request->hasSession() && ($session = $request->getSession())->isStarted() && $session->getFlashBag() instanceof AutoExpireFlashBag) {
+ if (!$request->attributes->getBoolean('_stateless') && $request->hasSession()
+ && ($session = $request->getSession())->isStarted() && $session->getFlashBag() instanceof AutoExpireFlashBag
+ ) {
// keep current flashes for one more request if using AutoExpireFlashBag
$session->getFlashBag()->setAll($session->getFlashBag()->peekAll());
}
@@ -172,7 +174,11 @@ public function searchBarAction(Request $request): Response
$this->cspHandler?->disableCsp();
- $session = $request->hasSession() ? $request->getSession() : null;
+
+ $session = null;
+ if ($request->attributes->getBoolean('_stateless') && $request->hasSession()) {
+ $session = $request->getSession();
+ }
return new Response(
$this->twig->render('@WebProfiler/Profiler/search.html.twig', [
@@ -247,7 +253,7 @@ public function searchAction(Request $request): Response
$limit = $request->query->get('limit');
$token = $request->query->get('token');
- if ($request->hasSession()) {
+ if (!$request->attributes->getBoolean('_stateless') && $request->hasSession()) {
$session = $request->getSession();
$session->set('_profiler_search_ip', $ip);
diff --git a/src/Symfony/Bundle/WebProfilerBundle/Controller/RouterController.php b/src/Symfony/Bundle/WebProfilerBundle/Controller/RouterController.php
index 50560e0b3ffa1..0de07db823f97 100644
--- a/src/Symfony/Bundle/WebProfilerBundle/Controller/RouterController.php
+++ b/src/Symfony/Bundle/WebProfilerBundle/Controller/RouterController.php
@@ -40,7 +40,7 @@ class RouterController
*/
private $expressionLanguageProviders = [];
- public function __construct(Profiler $profiler = null, Environment $twig, UrlMatcherInterface $matcher = null, RouteCollection $routes = null, iterable $expressionLanguageProviders = [])
+ public function __construct(?Profiler $profiler, Environment $twig, ?UrlMatcherInterface $matcher = null, ?RouteCollection $routes = null, iterable $expressionLanguageProviders = [])
{
$this->profiler = $profiler;
$this->twig = $twig;
diff --git a/src/Symfony/Bundle/WebProfilerBundle/EventListener/WebDebugToolbarListener.php b/src/Symfony/Bundle/WebProfilerBundle/EventListener/WebDebugToolbarListener.php
index c29a389902113..c2b350ff05d68 100644
--- a/src/Symfony/Bundle/WebProfilerBundle/EventListener/WebDebugToolbarListener.php
+++ b/src/Symfony/Bundle/WebProfilerBundle/EventListener/WebDebugToolbarListener.php
@@ -48,7 +48,7 @@ class WebDebugToolbarListener implements EventSubscriberInterface
private ?ContentSecurityPolicyHandler $cspHandler;
private ?DumpDataCollector $dumpDataCollector;
- public function __construct(Environment $twig, bool $interceptRedirects = false, int $mode = self::ENABLED, UrlGeneratorInterface $urlGenerator = null, string $excludedAjaxPaths = '^/bundles|^/_wdt', ContentSecurityPolicyHandler $cspHandler = null, DumpDataCollector $dumpDataCollector = null)
+ public function __construct(Environment $twig, bool $interceptRedirects = false, int $mode = self::ENABLED, ?UrlGeneratorInterface $urlGenerator = null, string $excludedAjaxPaths = '^/bundles|^/_wdt', ?ContentSecurityPolicyHandler $cspHandler = null, ?DumpDataCollector $dumpDataCollector = null)
{
$this->twig = $twig;
$this->urlGenerator = $urlGenerator;
@@ -121,7 +121,7 @@ public function onKernelResponse(ResponseEvent $event): void
if (self::DISABLED === $this->mode
|| !$response->headers->has('X-Debug-Token')
|| $response->isRedirection()
- || ($response->headers->has('Content-Type') && !str_contains($response->headers->get('Content-Type'), 'html'))
+ || ($response->headers->has('Content-Type') && !str_contains($response->headers->get('Content-Type') ?? '', 'html'))
|| 'html' !== $request->getRequestFormat()
|| false !== stripos($response->headers->get('Content-Disposition', ''), 'attachment;')
) {
diff --git a/src/Symfony/Bundle/WebProfilerBundle/Resources/views/Collector/http_client.html.twig b/src/Symfony/Bundle/WebProfilerBundle/Resources/views/Collector/http_client.html.twig
index 2cdd22b2d0f1a..f3ee1393f9ff3 100644
--- a/src/Symfony/Bundle/WebProfilerBundle/Resources/views/Collector/http_client.html.twig
+++ b/src/Symfony/Bundle/WebProfilerBundle/Resources/views/Collector/http_client.html.twig
@@ -127,7 +127,7 @@
Profile
{% endif %}
- {% if trace.curlCommand is not null %}
+ {% if trace.curlCommand is defined and trace.curlCommand %}
The redirect was intercepted by the Symfony Web Debug toolbar to help debugging.
diff --git a/src/Symfony/Bundle/WebProfilerBundle/Tests/Controller/ProfilerControllerTest.php b/src/Symfony/Bundle/WebProfilerBundle/Tests/Controller/ProfilerControllerTest.php
index 86fd36e137d71..aa9546b4c7091 100644
--- a/src/Symfony/Bundle/WebProfilerBundle/Tests/Controller/ProfilerControllerTest.php
+++ b/src/Symfony/Bundle/WebProfilerBundle/Tests/Controller/ProfilerControllerTest.php
@@ -340,7 +340,7 @@ public function testPhpinfoActionWithProfilerDisabled()
$twig = $this->createMock(Environment::class);
$controller = new ProfilerController($urlGenerator, null, $twig, []);
- $controller->phpinfoAction(Request::create('/_profiler/phpinfo'));
+ $controller->phpinfoAction();
}
public function testPhpinfoAction()
@@ -353,7 +353,7 @@ public function testPhpinfoAction()
$this->assertStringContainsString('PHP License', $client->getResponse()->getContent());
}
- public static function provideCspVariants()
+ public static function provideCspVariants(): array
{
return [
[true],
diff --git a/src/Symfony/Bundle/WebProfilerBundle/Tests/Csp/ContentSecurityPolicyHandlerTest.php b/src/Symfony/Bundle/WebProfilerBundle/Tests/Csp/ContentSecurityPolicyHandlerTest.php
index 7d5c0761b1dcc..bce62829467b9 100644
--- a/src/Symfony/Bundle/WebProfilerBundle/Tests/Csp/ContentSecurityPolicyHandlerTest.php
+++ b/src/Symfony/Bundle/WebProfilerBundle/Tests/Csp/ContentSecurityPolicyHandlerTest.php
@@ -46,7 +46,7 @@ public function testOnKernelResponse($nonce, $expectedNonce, Request $request, R
}
}
- public static function provideRequestAndResponses()
+ public static function provideRequestAndResponses(): array
{
$nonce = bin2hex(random_bytes(16));
@@ -73,7 +73,7 @@ public static function provideRequestAndResponses()
];
}
- public static function provideRequestAndResponsesForOnKernelResponse()
+ public static function provideRequestAndResponsesForOnKernelResponse(): array
{
$nonce = bin2hex(random_bytes(16));
diff --git a/src/Symfony/Bundle/WebProfilerBundle/Tests/EventListener/WebDebugToolbarListenerTest.php b/src/Symfony/Bundle/WebProfilerBundle/Tests/EventListener/WebDebugToolbarListenerTest.php
index 3744e47c7fd6c..33bf1a32d27f8 100644
--- a/src/Symfony/Bundle/WebProfilerBundle/Tests/EventListener/WebDebugToolbarListenerTest.php
+++ b/src/Symfony/Bundle/WebProfilerBundle/Tests/EventListener/WebDebugToolbarListenerTest.php
@@ -148,7 +148,7 @@ public function testToolbarIsNotInjectedOnRedirection($statusCode)
$this->assertEquals('