diff --git a/CHANGELOG.md b/CHANGELOG.md
index ce62c9cdf..76b3cb947 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,6 +1,14 @@
CHANGELOG
=========
+7.4
+---
+
+ * Add `ControllerHelper`; the helpers from AbstractController as a standalone service
+ * Allow using their name without added suffix when using `#[Target]` for custom services
+ * Deprecate `Symfony\Bundle\FrameworkBundle\Console\Application::add()` in favor of `Symfony\Bundle\FrameworkBundle\Console\Application::addCommand()`
+ * Add `assertEmailAddressNotContains()` to the `MailerAssertionsTrait`
+
7.3
---
@@ -698,7 +706,7 @@ CHANGELOG
* added Client::enableProfiler()
* a new parameter has been added to the DIC: `router.request_context.base_url`
You can customize it for your functional tests or for generating URLs with
- the right base URL when your are in the CLI context.
+ the right base URL when you are in the CLI context.
* added support for default templates per render tag
2.1.0
diff --git a/Command/AboutCommand.php b/Command/AboutCommand.php
index 0c6899328..8b4604970 100644
--- a/Command/AboutCommand.php
+++ b/Command/AboutCommand.php
@@ -36,11 +36,11 @@ protected function configure(): void
{
$this
->setHelp(<<<'EOT'
-The %command.name% command displays information about the current Symfony project.
+ The %command.name% command displays information about the current Symfony project.
-The PHP section displays important configuration that could affect your application. The values might
-be different between web and CLI.
-EOT
+ The PHP section displays important configuration that could affect your application. The values might
+ be different between web and CLI.
+ EOT
)
;
}
diff --git a/Command/AssetsInstallCommand.php b/Command/AssetsInstallCommand.php
index 5dc8c828e..099204cae 100644
--- a/Command/AssetsInstallCommand.php
+++ b/Command/AssetsInstallCommand.php
@@ -23,7 +23,6 @@
use Symfony\Component\Filesystem\Exception\IOException;
use Symfony\Component\Filesystem\Filesystem;
use Symfony\Component\Finder\Finder;
-use Symfony\Component\HttpKernel\Bundle\BundleInterface;
use Symfony\Component\HttpKernel\KernelInterface;
/**
@@ -58,24 +57,24 @@ protected function configure(): void
->addOption('relative', null, InputOption::VALUE_NONE, 'Make relative symlinks')
->addOption('no-cleanup', null, InputOption::VALUE_NONE, 'Do not remove the assets of the bundles that no longer exist')
->setHelp(<<<'EOT'
-The %command.name% command installs bundle assets into a given
-directory (e.g. the public directory).
+ The %command.name% command installs bundle assets into a given
+ directory (e.g. the public directory).
- php %command.full_name% public
+ php %command.full_name% public
-A "bundles" directory will be created inside the target directory and the
-"Resources/public" directory of each bundle will be copied into it.
+ A "bundles" directory will be created inside the target directory and the
+ "Resources/public" directory of each bundle will be copied into it.
-To create a symlink to each bundle instead of copying its assets, use the
---symlink option (will fall back to hard copies when symbolic links aren't possible:
+ To create a symlink to each bundle instead of copying its assets, use the
+ --symlink option (will fall back to hard copies when symbolic links aren't possible:
- php %command.full_name% public --symlink
+ php %command.full_name% public --symlink
-To make symlink relative, add the --relative option:
+ To make symlink relative, add the --relative option:
- php %command.full_name% public --symlink --relative
+ php %command.full_name% public --symlink --relative
-EOT
+ EOT
)
;
}
@@ -119,7 +118,6 @@ protected function execute(InputInterface $input, OutputInterface $output): int
$copyUsed = false;
$exitCode = 0;
$validAssetDirs = [];
- /** @var BundleInterface $bundle */
foreach ($kernel->getBundles() as $bundle) {
if (!is_dir($originDir = $bundle->getPath().'/Resources/public') && !is_dir($originDir = $bundle->getPath().'/public')) {
continue;
@@ -239,7 +237,7 @@ private function symlink(string $originDir, string $targetDir, bool $relative =
*/
private function hardCopy(string $originDir, string $targetDir): string
{
- $this->filesystem->mkdir($targetDir, 0777);
+ $this->filesystem->mkdir($targetDir, 0o777);
// We use a custom iterator to ignore VCS files
$this->filesystem->mirror($originDir, $targetDir, Finder::create()->ignoreDotFiles(false)->in($originDir));
diff --git a/Command/BuildDebugContainerTrait.php b/Command/BuildDebugContainerTrait.php
index 2f625e9e3..011510095 100644
--- a/Command/BuildDebugContainerTrait.php
+++ b/Command/BuildDebugContainerTrait.php
@@ -39,7 +39,9 @@ protected function getContainerBuilder(KernelInterface $kernel): ContainerBuilde
return $this->container;
}
- if (!$kernel->isDebug() || !$kernel->getContainer()->getParameter('debug.container.dump') || !(new ConfigCache($kernel->getContainer()->getParameter('debug.container.dump'), true))->isFresh()) {
+ $file = $kernel->isDebug() ? $kernel->getContainer()->getParameter('debug.container.dump') : false;
+
+ if (!$file || !(new ConfigCache($file, true))->isFresh()) {
$buildContainer = \Closure::bind(function () {
$this->initializeBundles();
@@ -57,13 +59,17 @@ protected function getContainerBuilder(KernelInterface $kernel): ContainerBuilde
return $containerBuilder;
}, $kernel, $kernel::class);
$container = $buildContainer();
- (new XmlFileLoader($container, new FileLocator()))->load($kernel->getContainer()->getParameter('debug.container.dump'));
- $locatorPass = new ServiceLocatorTagPass();
- $locatorPass->process($container);
- $container->getCompilerPassConfig()->setBeforeOptimizationPasses([]);
- $container->getCompilerPassConfig()->setOptimizationPasses([]);
- $container->getCompilerPassConfig()->setBeforeRemovingPasses([]);
+ if (str_ends_with($file, '.xml') && is_file(substr_replace($file, '.ser', -4))) {
+ $dumpedContainer = unserialize(file_get_contents(substr_replace($file, '.ser', -4)));
+ $container->setDefinitions($dumpedContainer->getDefinitions());
+ $container->setAliases($dumpedContainer->getAliases());
+ $container->__construct($dumpedContainer->getParameterBag());
+ } else {
+ (new XmlFileLoader($container, new FileLocator()))->load($file);
+ $locatorPass = new ServiceLocatorTagPass();
+ $locatorPass->process($container);
+ }
}
return $this->container = $container;
diff --git a/Command/CacheClearCommand.php b/Command/CacheClearCommand.php
index 0e48ead59..3f3960ef8 100644
--- a/Command/CacheClearCommand.php
+++ b/Command/CacheClearCommand.php
@@ -56,12 +56,12 @@ protected function configure(): void
new InputOption('no-optional-warmers', '', InputOption::VALUE_NONE, 'Skip optional cache warmers (faster)'),
])
->setHelp(<<<'EOF'
-The %command.name% command clears and warms up the application cache for a given environment
-and debug mode:
+ The %command.name% command clears and warms up the application cache for a given environment
+ and debug mode:
- php %command.full_name% --env=dev
- php %command.full_name% --env=prod --no-debug
-EOF
+ php %command.full_name% --env=dev
+ php %command.full_name% --env=prod --no-debug
+ EOF
)
;
}
@@ -213,7 +213,7 @@ private function isNfs(string $dir): bool
if ('/' === \DIRECTORY_SEPARATOR && @is_readable('/proc/mounts') && $files = @file('/proc/mounts')) {
foreach ($files as $mount) {
$mount = \array_slice(explode(' ', $mount), 1, -3);
- if (!\in_array(array_pop($mount), ['vboxsf', 'nfs'])) {
+ if (!\in_array(array_pop($mount), ['vboxsf', 'nfs'], true)) {
continue;
}
$mounts[] = implode(' ', $mount).'/';
diff --git a/Command/CachePoolClearCommand.php b/Command/CachePoolClearCommand.php
index 5d840e597..d4bca0d8f 100644
--- a/Command/CachePoolClearCommand.php
+++ b/Command/CachePoolClearCommand.php
@@ -51,10 +51,10 @@ protected function configure(): void
->addOption('all', null, InputOption::VALUE_NONE, 'Clear all cache pools')
->addOption('exclude', null, InputOption::VALUE_IS_ARRAY | InputOption::VALUE_REQUIRED, 'A list of cache pools or cache pool clearers to exclude')
->setHelp(<<<'EOF'
-The %command.name% command clears the given cache pools or cache pool clearers.
+ The %command.name% command clears the given cache pools or cache pool clearers.
- %command.full_name% [...]
-EOF
+ %command.full_name% [...]
+ EOF
)
;
}
diff --git a/Command/CachePoolDeleteCommand.php b/Command/CachePoolDeleteCommand.php
index 8fb1d1aaa..c3c23a391 100644
--- a/Command/CachePoolDeleteCommand.php
+++ b/Command/CachePoolDeleteCommand.php
@@ -47,10 +47,10 @@ protected function configure(): void
new InputArgument('key', InputArgument::REQUIRED, 'The cache key to delete from the pool'),
])
->setHelp(<<<'EOF'
-The %command.name% deletes an item from a given cache pool.
+ The %command.name% deletes an item from a given cache pool.
- %command.full_name%
-EOF
+ %command.full_name%
+ EOF
)
;
}
diff --git a/Command/CachePoolListCommand.php b/Command/CachePoolListCommand.php
index 6b8e71eb0..6aedfb0c0 100644
--- a/Command/CachePoolListCommand.php
+++ b/Command/CachePoolListCommand.php
@@ -38,8 +38,8 @@ protected function configure(): void
{
$this
->setHelp(<<<'EOF'
-The %command.name% command lists all available cache pools.
-EOF
+ The %command.name% command lists all available cache pools.
+ EOF
)
;
}
diff --git a/Command/CachePoolPruneCommand.php b/Command/CachePoolPruneCommand.php
index 745a001cc..5036da8ef 100644
--- a/Command/CachePoolPruneCommand.php
+++ b/Command/CachePoolPruneCommand.php
@@ -39,10 +39,10 @@ protected function configure(): void
{
$this
->setHelp(<<<'EOF'
-The %command.name% command deletes all expired items from all pruneable pools.
+ The %command.name% command deletes all expired items from all pruneable pools.
- %command.full_name%
-EOF
+ %command.full_name%
+ EOF
)
;
}
diff --git a/Command/CacheWarmupCommand.php b/Command/CacheWarmupCommand.php
index b096b0801..8ade22560 100644
--- a/Command/CacheWarmupCommand.php
+++ b/Command/CacheWarmupCommand.php
@@ -44,11 +44,11 @@ protected function configure(): void
new InputOption('no-optional-warmers', '', InputOption::VALUE_NONE, 'Skip optional cache warmers (faster)'),
])
->setHelp(<<<'EOF'
-The %command.name% command warms up the cache.
+ The %command.name% command warms up the cache.
-Before running this command, the cache must be empty.
+ Before running this command, the cache must be empty.
-EOF
+ EOF
)
;
}
diff --git a/Command/ConfigDebugCommand.php b/Command/ConfigDebugCommand.php
index 8d5f85cee..50c8dddf5 100644
--- a/Command/ConfigDebugCommand.php
+++ b/Command/ConfigDebugCommand.php
@@ -49,23 +49,23 @@ protected function configure(): void
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
-extension/bundle.
+ The %command.name% command dumps the current configuration for an
+ extension/bundle.
-Either the extension alias or bundle name can be used:
+ Either the extension alias or bundle name can be used:
- php %command.full_name% framework
- php %command.full_name% FrameworkBundle
+ php %command.full_name% framework
+ php %command.full_name% FrameworkBundle
-The --format option specifies the format of the command output:
+ The --format option specifies the format of the command output:
- php %command.full_name% framework --format=json
+ php %command.full_name% framework --format=json
-For dumping a specific option, add its path as second argument:
+ For dumping a specific option, add its path as second argument:
- php %command.full_name% framework serializer.enabled
+ php %command.full_name% framework serializer.enabled
-EOF
+ EOF
)
;
}
diff --git a/Command/ConfigDumpReferenceCommand.php b/Command/ConfigDumpReferenceCommand.php
index 3cb744d74..3a6d1252d 100644
--- a/Command/ConfigDumpReferenceCommand.php
+++ b/Command/ConfigDumpReferenceCommand.php
@@ -47,23 +47,23 @@ protected function configure(): void
new InputOption('format', null, InputOption::VALUE_REQUIRED, \sprintf('The output format ("%s")', implode('", "', $this->getAvailableFormatOptions())), 'yaml'),
])
->setHelp(<<%command.name% command dumps the default configuration for an
-extension/bundle.
+ The %command.name% command dumps the default configuration for an
+ extension/bundle.
-Either the extension alias or bundle name can be used:
+ Either the extension alias or bundle name can be used:
- php %command.full_name% framework
- php %command.full_name% FrameworkBundle
+ php %command.full_name% framework
+ php %command.full_name% FrameworkBundle
-The --format option specifies the format of the command output:
+ The --format option specifies the format of the command output:
- php %command.full_name% FrameworkBundle --format=json
+ php %command.full_name% FrameworkBundle --format=json
-For dumping a specific option, add its path as second argument (only available for the yaml format):
+ For dumping a specific option, add its path as second argument (only available for the yaml format):
- php %command.full_name% framework http_client.default_options
+ php %command.full_name% framework http_client.default_options
-EOF
+ EOF
)
;
}
diff --git a/Command/ContainerDebugCommand.php b/Command/ContainerDebugCommand.php
index 17c71bdca..f0f7d5a1b 100644
--- a/Command/ContainerDebugCommand.php
+++ b/Command/ContainerDebugCommand.php
@@ -57,59 +57,59 @@ protected function configure(): void
new InputOption('deprecations', null, InputOption::VALUE_NONE, 'Display deprecations generated when compiling and warming up the container'),
])
->setHelp(<<<'EOF'
-The %command.name% command displays all configured public services:
+ The %command.name% command displays all configured public services:
- php %command.full_name%
+ php %command.full_name%
-To see deprecations generated during container compilation and cache warmup, use the --deprecations option:
+ To see deprecations generated during container compilation and cache warmup, use the --deprecations option:
- php %command.full_name% --deprecations
+ php %command.full_name% --deprecations
-To get specific information about a service, specify its name:
+ To get specific information about a service, specify its name:
- php %command.full_name% validator
+ php %command.full_name% validator
-To get specific information about a service including all its arguments, use the --show-arguments flag:
+ To get specific information about a service including all its arguments, use the --show-arguments flag:
- php %command.full_name% validator --show-arguments
+ php %command.full_name% validator --show-arguments
-To see available types that can be used for autowiring, use the --types flag:
+ To see available types that can be used for autowiring, use the --types flag:
- php %command.full_name% --types
+ php %command.full_name% --types
-To see environment variables used by the container, use the --env-vars flag:
+ To see environment variables used by the container, use the --env-vars flag:
- php %command.full_name% --env-vars
+ php %command.full_name% --env-vars
-Display a specific environment variable by specifying its name with the --env-var option:
+ Display a specific environment variable by specifying its name with the --env-var option:
- php %command.full_name% --env-var=APP_ENV
+ php %command.full_name% --env-var=APP_ENV
-Use the --tags option to display tagged public services grouped by tag:
+ Use the --tags option to display tagged public services grouped by tag:
- php %command.full_name% --tags
+ php %command.full_name% --tags
-Find all services with a specific tag by specifying the tag name with the --tag option:
+ Find all services with a specific tag by specifying the tag name with the --tag option:
- php %command.full_name% --tag=form.type
+ php %command.full_name% --tag=form.type
-Use the --parameters option to display all parameters:
+ Use the --parameters option to display all parameters:
- php %command.full_name% --parameters
+ php %command.full_name% --parameters
-Display a specific parameter by specifying its name with the --parameter option:
+ Display a specific parameter by specifying its name with the --parameter option:
- php %command.full_name% --parameter=kernel.debug
+ php %command.full_name% --parameter=kernel.debug
-By default, internal services are hidden. You can display them
-using the --show-hidden flag:
+ By default, internal services are hidden. You can display them
+ using the --show-hidden flag:
- php %command.full_name% --show-hidden
+ php %command.full_name% --show-hidden
-The --format option specifies the format of the command output:
+ The --format option specifies the format of the command output:
- php %command.full_name% --format=json
-EOF
+ php %command.full_name% --format=json
+ EOF
)
;
}
diff --git a/Command/ContainerLintCommand.php b/Command/ContainerLintCommand.php
index d71fd6810..2fc0be7c5 100644
--- a/Command/ContainerLintCommand.php
+++ b/Command/ContainerLintCommand.php
@@ -25,7 +25,6 @@
use Symfony\Component\DependencyInjection\Compiler\PassConfig;
use Symfony\Component\DependencyInjection\Compiler\ResolveFactoryClassPass;
use Symfony\Component\DependencyInjection\Compiler\ResolveParameterPlaceHoldersPass;
-use Symfony\Component\DependencyInjection\Container;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Exception\InvalidArgumentException;
use Symfony\Component\DependencyInjection\Loader\XmlFileLoader;
@@ -82,9 +81,10 @@ private function getContainerBuilder(bool $resolveEnvVars): ContainerBuilder
}
$kernel = $this->getApplication()->getKernel();
- $kernelContainer = $kernel->getContainer();
+ $container = $kernel->getContainer();
+ $file = $kernel->isDebug() ? $container->getParameter('debug.container.dump') : false;
- if (!$kernel->isDebug() || !$kernelContainer->getParameter('debug.container.dump') || !(new ConfigCache($kernelContainer->getParameter('debug.container.dump'), true))->isFresh()) {
+ if (!$file || !(new ConfigCache($file, true))->isFresh()) {
if (!$kernel instanceof Kernel) {
throw new RuntimeException(\sprintf('This command does not support the application kernel: "%s" does not extend "%s".', get_debug_type($kernel), Kernel::class));
}
@@ -96,15 +96,20 @@ private function getContainerBuilder(bool $resolveEnvVars): ContainerBuilder
}, $kernel, $kernel::class);
$container = $buildContainer();
} 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));
+ if (str_ends_with($file, '.xml') && is_file(substr_replace($file, '.ser', -4))) {
+ $container = unserialize(file_get_contents(substr_replace($file, '.ser', -4)));
+ } else {
+ (new XmlFileLoader($container = new ContainerBuilder(new EnvPlaceholderParameterBag()), new FileLocator()))->load($file);
}
- (new XmlFileLoader($container = new ContainerBuilder($parameterBag = new EnvPlaceholderParameterBag()), new FileLocator()))->load($kernelContainer->getParameter('debug.container.dump'));
+ if (!$container instanceof ContainerBuilder) {
+ throw new RuntimeException(\sprintf('This command does not support the application container: "%s" is not a "%s".', get_debug_type($container), ContainerBuilder::class));
+ }
if ($resolveEnvVars) {
$container->getCompilerPassConfig()->setOptimizationPasses([new ResolveParameterPlaceHoldersPass(), new ResolveFactoryClassPass()]);
} else {
+ $parameterBag = $container->getParameterBag();
$refl = new \ReflectionProperty($parameterBag, 'resolved');
$refl->setValue($parameterBag, true);
diff --git a/Command/DebugAutowiringCommand.php b/Command/DebugAutowiringCommand.php
index e159c5a39..5c1869c6a 100644
--- a/Command/DebugAutowiringCommand.php
+++ b/Command/DebugAutowiringCommand.php
@@ -20,7 +20,6 @@
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Style\SymfonyStyle;
-use Symfony\Component\DependencyInjection\Attribute\Target;
use Symfony\Component\ErrorHandler\ErrorRenderer\FileLinkFormatter;
/**
@@ -48,16 +47,16 @@ protected function configure(): void
new InputOption('all', null, InputOption::VALUE_NONE, 'Show also services that are not aliased'),
])
->setHelp(<<<'EOF'
-The %command.name% command displays the classes and interfaces that
-you can use as type-hints for autowiring:
+ The %command.name% command displays the classes and interfaces that
+ you can use as type-hints for autowiring:
- php %command.full_name%
+ php %command.full_name%
-You can also pass a search term to filter the list:
+ You can also pass a search term to filter the list:
- php %command.full_name% log
+ php %command.full_name% log
-EOF
+ EOF
)
;
}
@@ -137,7 +136,7 @@ protected function execute(InputInterface $input, OutputInterface $output): int
}
$target = substr($id, \strlen($previousId) + 3);
- if ($previousId.' $'.(new Target($target))->getParsedName() === $serviceId) {
+ if ($container->findDefinition($id) === $container->findDefinition($serviceId)) {
$serviceLine .= ' - target:>'.$target.'>';
break;
}
@@ -185,7 +184,7 @@ private function getFileLink(string $class): string
return '';
}
- return (string) $this->fileLinkFormatter->format($r->getFileName(), $r->getStartLine());
+ return $r->getFileName() ? ($this->fileLinkFormatter->format($r->getFileName(), $r->getStartLine()) ?: '') : '';
}
public function complete(CompletionInput $input, CompletionSuggestions $suggestions): void
diff --git a/Command/EventDispatcherDebugCommand.php b/Command/EventDispatcherDebugCommand.php
index 3c51cb1b7..43766ed92 100644
--- a/Command/EventDispatcherDebugCommand.php
+++ b/Command/EventDispatcherDebugCommand.php
@@ -53,18 +53,18 @@ protected function configure(): void
new InputOption('raw', null, InputOption::VALUE_NONE, 'To output raw description'),
])
->setHelp(<<<'EOF'
-The %command.name% command displays all configured listeners:
+ The %command.name% command displays all configured listeners:
- php %command.full_name%
+ php %command.full_name%
-To get specific listeners for an event, specify its name:
+ To get specific listeners for an event, specify its name:
- php %command.full_name% kernel.request
+ php %command.full_name% kernel.request
-The --format option specifies the format of the command output:
+ The --format option specifies the format of the command output:
- php %command.full_name% --format=json
-EOF
+ php %command.full_name% --format=json
+ EOF
)
;
}
diff --git a/Command/RouterDebugCommand.php b/Command/RouterDebugCommand.php
index e54377115..3daf865b3 100644
--- a/Command/RouterDebugCommand.php
+++ b/Command/RouterDebugCommand.php
@@ -58,14 +58,14 @@ protected function configure(): void
new InputOption('method', null, InputOption::VALUE_REQUIRED, 'Filter by HTTP method', '', ['GET', 'POST', 'PUT', 'DELETE', 'PATCH']),
])
->setHelp(<<<'EOF'
-The %command.name% displays the configured routes:
+ The %command.name% displays the configured routes:
- php %command.full_name%
+ php %command.full_name%
-The --format option specifies the format of the command output:
+ The --format option specifies the format of the command output:
- php %command.full_name% --format=json
-EOF
+ php %command.full_name% --format=json
+ EOF
)
;
}
diff --git a/Command/RouterMatchCommand.php b/Command/RouterMatchCommand.php
index 3f0ea3cb5..dee448517 100644
--- a/Command/RouterMatchCommand.php
+++ b/Command/RouterMatchCommand.php
@@ -53,15 +53,15 @@ protected function configure(): void
new InputOption('host', null, InputOption::VALUE_REQUIRED, 'Set the URI host'),
])
->setHelp(<<<'EOF'
-The %command.name% shows which routes match a given request and which don't and for what reason:
+ The %command.name% shows which routes match a given request and which don't and for what reason:
- php %command.full_name% /foo
+ php %command.full_name% /foo
-or
+ or
- php %command.full_name% /foo --method POST --scheme https --host symfony.com --verbose
+ php %command.full_name% /foo --method POST --scheme https --host symfony.com --verbose
-EOF
+ EOF
)
;
}
diff --git a/Command/SecretsDecryptToLocalCommand.php b/Command/SecretsDecryptToLocalCommand.php
index 4e392b677..3dee29450 100644
--- a/Command/SecretsDecryptToLocalCommand.php
+++ b/Command/SecretsDecryptToLocalCommand.php
@@ -40,14 +40,14 @@ protected function configure(): void
$this
->addOption('force', 'f', InputOption::VALUE_NONE, 'Force overriding of secrets that already exist in the local vault')
->setHelp(<<<'EOF'
-The %command.name% command decrypts all secrets and copies them in the local vault.
+ The %command.name% command decrypts all secrets and copies them in the local vault.
- %command.full_name%
+ %command.full_name%
-When the --force option is provided, secrets that already exist in the local vault are overridden.
+ When the --force option is provided, secrets that already exist in the local vault are overridden.
- %command.full_name% --force
-EOF
+ %command.full_name% --force
+ EOF
)
;
}
diff --git a/Command/SecretsEncryptFromLocalCommand.php b/Command/SecretsEncryptFromLocalCommand.php
index 9740098e5..248f10966 100644
--- a/Command/SecretsEncryptFromLocalCommand.php
+++ b/Command/SecretsEncryptFromLocalCommand.php
@@ -38,10 +38,10 @@ protected function configure(): void
{
$this
->setHelp(<<<'EOF'
-The %command.name% command encrypts all locally overridden secrets to the vault.
+ The %command.name% command encrypts all locally overridden secrets to the vault.
- %command.full_name%
-EOF
+ %command.full_name%
+ EOF
)
;
}
diff --git a/Command/SecretsGenerateKeysCommand.php b/Command/SecretsGenerateKeysCommand.php
index f721c786e..e0d5d9c52 100644
--- a/Command/SecretsGenerateKeysCommand.php
+++ b/Command/SecretsGenerateKeysCommand.php
@@ -43,16 +43,16 @@ protected function configure(): void
->addOption('local', 'l', InputOption::VALUE_NONE, 'Update the local vault.')
->addOption('rotate', 'r', InputOption::VALUE_NONE, 'Re-encrypt existing secrets with the newly generated keys.')
->setHelp(<<<'EOF'
-The %command.name% command generates a new encryption key.
+ The %command.name% command generates a new encryption key.
- %command.full_name%
+ %command.full_name%
-If encryption keys already exist, the command must be called with
-the --rotate option in order to override those keys and re-encrypt
-existing secrets.
+ If encryption keys already exist, the command must be called with
+ the --rotate option in order to override those keys and re-encrypt
+ existing secrets.
- %command.full_name% --rotate
-EOF
+ %command.full_name% --rotate
+ EOF
)
;
}
diff --git a/Command/SecretsListCommand.php b/Command/SecretsListCommand.php
index 920b3b1fc..9057f58d1 100644
--- a/Command/SecretsListCommand.php
+++ b/Command/SecretsListCommand.php
@@ -43,14 +43,14 @@ protected function configure(): void
$this
->addOption('reveal', 'r', InputOption::VALUE_NONE, 'Display decrypted values alongside names')
->setHelp(<<<'EOF'
-The %command.name% command list all stored secrets.
+ The %command.name% command list all stored secrets.
- %command.full_name%
+ %command.full_name%
-When the option --reveal is provided, the decrypted secrets are also displayed.
+ When the option --reveal is provided, the decrypted secrets are also displayed.
- %command.full_name% --reveal
-EOF
+ %command.full_name% --reveal
+ EOF
)
;
}
diff --git a/Command/SecretsRemoveCommand.php b/Command/SecretsRemoveCommand.php
index 59bbe8211..2c3bbb18e 100644
--- a/Command/SecretsRemoveCommand.php
+++ b/Command/SecretsRemoveCommand.php
@@ -45,10 +45,10 @@ protected function configure(): void
->addArgument('name', InputArgument::REQUIRED, 'The name of the secret')
->addOption('local', 'l', InputOption::VALUE_NONE, 'Update the local vault.')
->setHelp(<<<'EOF'
-The %command.name% command removes a secret from the vault.
+ The %command.name% command removes a secret from the vault.
- %command.full_name%
-EOF
+ %command.full_name%
+ EOF
)
;
}
diff --git a/Command/SecretsRevealCommand.php b/Command/SecretsRevealCommand.php
index c2110ee76..8a678e14d 100644
--- a/Command/SecretsRevealCommand.php
+++ b/Command/SecretsRevealCommand.php
@@ -38,10 +38,10 @@ protected function configure(): void
$this
->addArgument('name', InputArgument::REQUIRED, 'The name of the secret to reveal', null, fn () => array_keys($this->vault->list()))
->setHelp(<<<'EOF'
-The %command.name% command reveals a stored secret.
+ The %command.name% command reveals a stored secret.
- %command.full_name%
-EOF
+ %command.full_name%
+ EOF
)
;
}
diff --git a/Command/SecretsSetCommand.php b/Command/SecretsSetCommand.php
index f7e8eeaa6..c9eabb25a 100644
--- a/Command/SecretsSetCommand.php
+++ b/Command/SecretsSetCommand.php
@@ -48,24 +48,24 @@ protected function configure(): void
->addOption('local', 'l', InputOption::VALUE_NONE, 'Update the local vault.')
->addOption('random', 'r', InputOption::VALUE_OPTIONAL, 'Generate a random value.', false)
->setHelp(<<<'EOF'
-The %command.name% command stores a secret in the vault.
+ The %command.name% command stores a secret in the vault.
- %command.full_name%
+ %command.full_name%
-To reference secrets in services.yaml or any other config
-files, use "%env()%".
+ To reference secrets in services.yaml or any other config
+ files, use "%env()%".
-By default, the secret value should be entered interactively.
-Alternatively, provide a file where to read the secret from:
+ By default, the secret value should be entered interactively.
+ Alternatively, provide a file where to read the secret from:
- php %command.full_name% filename
+ php %command.full_name% filename
-Use "-" as a file name to read from STDIN:
+ Use "-" as a file name to read from STDIN:
- cat filename | php %command.full_name% -
+ cat filename | php %command.full_name% -
-Use --local to override secrets for local needs.
-EOF
+ Use --local to override secrets for local needs.
+ EOF
)
;
}
diff --git a/Command/TranslationDebugCommand.php b/Command/TranslationDebugCommand.php
index a320130d5..b186646a3 100644
--- a/Command/TranslationDebugCommand.php
+++ b/Command/TranslationDebugCommand.php
@@ -75,35 +75,35 @@ protected function configure(): void
new InputOption('all', null, InputOption::VALUE_NONE, 'Load messages from all registered bundles'),
])
->setHelp(<<<'EOF'
-The %command.name% command helps finding unused or missing translation
-messages and comparing them with the fallback ones by inspecting the
-templates and translation files of a given bundle or the default translations directory.
+ The %command.name% command helps finding unused or missing translation
+ messages and comparing them with the fallback ones by inspecting the
+ templates and translation files of a given bundle or the default translations directory.
-You can display information about bundle translations in a specific locale:
+ You can display information about bundle translations in a specific locale:
- php %command.full_name% en AcmeDemoBundle
+ php %command.full_name% en AcmeDemoBundle
-You can also specify a translation domain for the search:
+ You can also specify a translation domain for the search:
- php %command.full_name% --domain=messages en AcmeDemoBundle
+ php %command.full_name% --domain=messages en AcmeDemoBundle
-You can only display missing messages:
+ You can only display missing messages:
- php %command.full_name% --only-missing en AcmeDemoBundle
+ php %command.full_name% --only-missing en AcmeDemoBundle
-You can only display unused messages:
+ You can only display unused messages:
- php %command.full_name% --only-unused en AcmeDemoBundle
+ php %command.full_name% --only-unused en AcmeDemoBundle
-You can display information about application translations in a specific locale:
+ You can display information about application translations in a specific locale:
- php %command.full_name% en
+ php %command.full_name% en
-You can display information about translations in all registered bundles in a specific locale:
+ You can display information about translations in all registered bundles in a specific locale:
- php %command.full_name% --all en
+ php %command.full_name% --all en
-EOF
+ EOF
)
;
}
diff --git a/Command/TranslationExtractCommand.php b/Command/TranslationExtractCommand.php
index c8e61b61a..0cd780734 100644
--- a/Command/TranslationExtractCommand.php
+++ b/Command/TranslationExtractCommand.php
@@ -83,34 +83,34 @@ protected function configure(): void
new InputOption('as-tree', null, InputOption::VALUE_REQUIRED, 'Dump the messages as a tree-like structure: The given value defines the level where to switch to inline YAML'),
])
->setHelp(<<<'EOF'
-The %command.name% command extracts translation strings from templates
-of a given bundle or the default translations directory. It can display them or merge
-the new ones into the translation files.
+ The %command.name% command extracts translation strings from templates
+ of a given bundle or the default translations directory. It can display them or merge
+ the new ones into the translation files.
-When new translation strings are found it can automatically add a prefix to the translation
-message. However, if the --no-fill option is used, the --prefix
-option has no effect, since the translation values are left empty.
+ When new translation strings are found it can automatically add a prefix to the translation
+ message. However, if the --no-fill option is used, the --prefix
+ option has no effect, since the translation values are left empty.
-Example running against a Bundle (AcmeBundle)
+ Example running against a Bundle (AcmeBundle)
- php %command.full_name% --dump-messages en AcmeBundle
- php %command.full_name% --force --prefix="new_" fr AcmeBundle
+ php %command.full_name% --dump-messages en AcmeBundle
+ php %command.full_name% --force --prefix="new_" fr AcmeBundle
-Example running against default messages directory
+ Example running against default messages directory
- php %command.full_name% --dump-messages en
- php %command.full_name% --force --prefix="new_" fr
+ php %command.full_name% --dump-messages en
+ php %command.full_name% --force --prefix="new_" fr
-You can sort the output with the --sort> flag:
+ You can sort the output with the --sort> flag:
- php %command.full_name% --dump-messages --sort=asc en AcmeBundle
- php %command.full_name% --force --sort=desc fr
+ php %command.full_name% --dump-messages --sort=asc en AcmeBundle
+ php %command.full_name% --force --sort=desc fr
-You can dump a tree-like structure using the yaml format with --as-tree> flag:
+ You can dump a tree-like structure using the yaml format with --as-tree> flag:
- php %command.full_name% --force --format=yaml --as-tree=3 en AcmeBundle
+ php %command.full_name% --force --format=yaml --as-tree=3 en AcmeBundle
-EOF
+ EOF
)
;
}
diff --git a/Command/WorkflowDumpCommand.php b/Command/WorkflowDumpCommand.php
index 201fb8be8..06570e9ea 100644
--- a/Command/WorkflowDumpCommand.php
+++ b/Command/WorkflowDumpCommand.php
@@ -59,13 +59,13 @@ protected function configure(): void
new InputOption('dump-format', null, InputOption::VALUE_REQUIRED, 'The dump format ['.implode('|', self::DUMP_FORMAT_OPTIONS).']', 'dot'),
])
->setHelp(<<<'EOF'
-The %command.name% command dumps the graphical representation of a
-workflow in different formats
+ The %command.name% command dumps the graphical representation of a
+ workflow in different formats
-DOT: %command.full_name% | dot -Tpng > workflow.png
-PUML: %command.full_name% --dump-format=puml | java -jar plantuml.jar -p > workflow.png
-MERMAID: %command.full_name% --dump-format=mermaid | mmdc -o workflow.svg
-EOF
+ DOT: %command.full_name% | dot -Tpng > workflow.png
+ PUML: %command.full_name% --dump-format=puml | java -jar plantuml.jar -p > workflow.png
+ MERMAID: %command.full_name% --dump-format=mermaid | mmdc -o workflow.svg
+ EOF
)
;
}
diff --git a/Command/XliffLintCommand.php b/Command/XliffLintCommand.php
index 5b094f165..9bbe39db1 100644
--- a/Command/XliffLintCommand.php
+++ b/Command/XliffLintCommand.php
@@ -47,11 +47,11 @@ protected function configure(): void
$this->setHelp($this->getHelp().<<<'EOF'
-Or find all files in a bundle:
+ Or find all files in a bundle:
- php %command.full_name% @AcmeDemoBundle
+ php %command.full_name% @AcmeDemoBundle
-EOF
+ EOF
);
}
}
diff --git a/Command/YamlLintCommand.php b/Command/YamlLintCommand.php
index 141390812..5948add7c 100644
--- a/Command/YamlLintCommand.php
+++ b/Command/YamlLintCommand.php
@@ -46,11 +46,11 @@ protected function configure(): void
$this->setHelp($this->getHelp().<<<'EOF'
-Or find all files in a bundle:
+ Or find all files in a bundle:
- php %command.full_name% @AcmeDemoBundle
+ php %command.full_name% @AcmeDemoBundle
-EOF
+ EOF
);
}
}
diff --git a/Console/Application.php b/Console/Application.php
index 274e7b06d..8eb3808a5 100644
--- a/Console/Application.php
+++ b/Console/Application.php
@@ -159,11 +159,29 @@ public function getLongVersion(): string
return parent::getLongVersion().\sprintf(' (env: %s>, debug: %s>)', $this->kernel->getEnvironment(), $this->kernel->isDebug() ? 'true' : 'false');
}
+ /**
+ * @deprecated since Symfony 7.4, use Application::addCommand() instead
+ */
public function add(Command $command): ?Command
+ {
+ trigger_deprecation('symfony/framework-bundle', '7.4', 'The "%s()" method is deprecated and will be removed in Symfony 8.0, use "%s::addCommand()" instead.', __METHOD__, self::class);
+
+ return $this->addCommand($command);
+ }
+
+ public function addCommand(callable|Command $command): ?Command
{
$this->registerCommands();
- return parent::add($command);
+ if (!method_exists(BaseApplication::class, 'addCommand')) {
+ if (!$command instanceof Command) {
+ throw new \LogicException('Using callables as commands requires symfony/console 7.4 or higher.');
+ }
+
+ return parent::add($command);
+ }
+
+ return parent::addCommand($command);
}
protected function registerCommands(): void
@@ -197,7 +215,7 @@ protected function registerCommands(): void
foreach ($container->getParameter('console.command.ids') as $id) {
if (!isset($lazyCommandIds[$id])) {
try {
- $this->add($container->get($id));
+ $this->addCommand($container->get($id));
} catch (\Throwable $e) {
$this->registrationErrors[] = $e;
}
diff --git a/Console/Descriptor/TextDescriptor.php b/Console/Descriptor/TextDescriptor.php
index 12b345411..a5b31b186 100644
--- a/Console/Descriptor/TextDescriptor.php
+++ b/Console/Descriptor/TextDescriptor.php
@@ -576,6 +576,9 @@ private function formatRouterConfig(array $config): string
return trim($configAsString);
}
+ /**
+ * @param (callable():ContainerBuilder)|null $getContainer
+ */
private function formatControllerLink(mixed $controller, string $anchorText, ?callable $getContainer = null): string
{
if (null === $this->fileLinkFormatter) {
diff --git a/Console/Descriptor/XmlDescriptor.php b/Console/Descriptor/XmlDescriptor.php
index 8daa61d2a..6a25ae3a3 100644
--- a/Console/Descriptor/XmlDescriptor.php
+++ b/Console/Descriptor/XmlDescriptor.php
@@ -288,6 +288,9 @@ private function getContainerServiceDocument(object $service, string $id, ?Conta
return $dom;
}
+ /**
+ * @param (callable(string):bool)|null $filter
+ */
private function getContainerServicesDocument(ContainerBuilder $container, ?string $tag = null, bool $showHidden = false, ?callable $filter = null): \DOMDocument
{
$dom = new \DOMDocument('1.0', 'UTF-8');
diff --git a/Controller/AbstractController.php b/Controller/AbstractController.php
index de7395d5a..c44028f8c 100644
--- a/Controller/AbstractController.php
+++ b/Controller/AbstractController.php
@@ -67,18 +67,6 @@ public function setContainer(ContainerInterface $container): ?ContainerInterface
return $previous;
}
- /**
- * Gets a container parameter by its name.
- */
- protected function getParameter(string $name): array|bool|string|int|float|\UnitEnum|null
- {
- if (!$this->container->has('parameter_bag')) {
- throw new ServiceNotFoundException('parameter_bag.', null, null, [], \sprintf('The "%s::getParameter()" method is missing a parameter bag to work properly. Did you forget to register your controller as a service subscriber? This can be fixed either by using autoconfiguration or by manually wiring a "parameter_bag" in the service locator passed to the controller.', static::class));
- }
-
- return $this->container->get('parameter_bag')->get($name);
- }
-
public static function getSubscribedServices(): array
{
return [
@@ -96,6 +84,18 @@ public static function getSubscribedServices(): array
];
}
+ /**
+ * Gets a container parameter by its name.
+ */
+ protected function getParameter(string $name): array|bool|string|int|float|\UnitEnum|null
+ {
+ if (!$this->container->has('parameter_bag')) {
+ throw new ServiceNotFoundException('parameter_bag.', null, null, [], \sprintf('The "%s::getParameter()" method is missing a parameter bag to work properly. Did you forget to register your controller as a service subscriber? This can be fixed either by using autoconfiguration or by manually wiring a "parameter_bag" in the service locator passed to the controller.', static::class));
+ }
+
+ return $this->container->get('parameter_bag')->get($name);
+ }
+
/**
* Generates a URL from the given parameters.
*
diff --git a/Controller/ControllerHelper.php b/Controller/ControllerHelper.php
new file mode 100644
index 000000000..4fc56b6a9
--- /dev/null
+++ b/Controller/ControllerHelper.php
@@ -0,0 +1,473 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Bundle\FrameworkBundle\Controller;
+
+use Psr\Container\ContainerInterface;
+use Psr\Link\EvolvableLinkInterface;
+use Psr\Link\LinkInterface;
+use Symfony\Component\DependencyInjection\Exception\ServiceNotFoundException;
+use Symfony\Component\DependencyInjection\ParameterBag\ContainerBagInterface;
+use Symfony\Component\Form\Extension\Core\Type\FormType;
+use Symfony\Component\Form\FormBuilderInterface;
+use Symfony\Component\Form\FormFactoryInterface;
+use Symfony\Component\Form\FormInterface;
+use Symfony\Component\HttpFoundation\BinaryFileResponse;
+use Symfony\Component\HttpFoundation\Exception\SessionNotFoundException;
+use Symfony\Component\HttpFoundation\JsonResponse;
+use Symfony\Component\HttpFoundation\RedirectResponse;
+use Symfony\Component\HttpFoundation\Request;
+use Symfony\Component\HttpFoundation\RequestStack;
+use Symfony\Component\HttpFoundation\Response;
+use Symfony\Component\HttpFoundation\ResponseHeaderBag;
+use Symfony\Component\HttpFoundation\Session\FlashBagAwareSessionInterface;
+use Symfony\Component\HttpFoundation\StreamedResponse;
+use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
+use Symfony\Component\HttpKernel\HttpKernelInterface;
+use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
+use Symfony\Component\Routing\RouterInterface;
+use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface;
+use Symfony\Component\Security\Core\Authorization\AccessDecision;
+use Symfony\Component\Security\Core\Authorization\AuthorizationCheckerInterface;
+use Symfony\Component\Security\Core\Exception\AccessDeniedException;
+use Symfony\Component\Security\Core\User\UserInterface;
+use Symfony\Component\Security\Csrf\CsrfToken;
+use Symfony\Component\Security\Csrf\CsrfTokenManagerInterface;
+use Symfony\Component\Serializer\SerializerInterface;
+use Symfony\Component\WebLink\EventListener\AddLinkHeaderListener;
+use Symfony\Component\WebLink\GenericLinkProvider;
+use Symfony\Component\WebLink\HttpHeaderSerializer;
+use Symfony\Contracts\Service\ServiceSubscriberInterface;
+use Twig\Environment;
+
+/**
+ * Provides the helpers from AbstractControler as a standalone service.
+ *
+ * Best used together with #[AutowireMethodOf] to remove any coupling.
+ */
+class ControllerHelper implements ServiceSubscriberInterface
+{
+ public function __construct(
+ private ContainerInterface $container,
+ ) {
+ }
+
+ public static function getSubscribedServices(): array
+ {
+ return [
+ 'router' => '?'.RouterInterface::class,
+ 'request_stack' => '?'.RequestStack::class,
+ 'http_kernel' => '?'.HttpKernelInterface::class,
+ 'serializer' => '?'.SerializerInterface::class,
+ 'security.authorization_checker' => '?'.AuthorizationCheckerInterface::class,
+ 'twig' => '?'.Environment::class,
+ 'form.factory' => '?'.FormFactoryInterface::class,
+ 'security.token_storage' => '?'.TokenStorageInterface::class,
+ 'security.csrf.token_manager' => '?'.CsrfTokenManagerInterface::class,
+ 'parameter_bag' => '?'.ContainerBagInterface::class,
+ 'web_link.http_header_serializer' => '?'.HttpHeaderSerializer::class,
+ ];
+ }
+
+ /**
+ * Gets a container parameter by its name.
+ */
+ public function getParameter(string $name): array|bool|string|int|float|\UnitEnum|null
+ {
+ if (!$this->container->has('parameter_bag')) {
+ throw new ServiceNotFoundException('parameter_bag.', null, null, [], \sprintf('The "%s::getParameter()" method is missing a parameter bag to work properly. Did you forget to register your controller as a service subscriber? This can be fixed either by using autoconfiguration or by manually wiring a "parameter_bag" in the service locator passed to the controller.', static::class));
+ }
+
+ return $this->container->get('parameter_bag')->get($name);
+ }
+
+ /**
+ * Generates a URL from the given parameters.
+ *
+ * @see UrlGeneratorInterface
+ */
+ public function generateUrl(string $route, array $parameters = [], int $referenceType = UrlGeneratorInterface::ABSOLUTE_PATH): string
+ {
+ return $this->container->get('router')->generate($route, $parameters, $referenceType);
+ }
+
+ /**
+ * Forwards the request to another controller.
+ *
+ * @param string $controller The controller name (a string like "App\Controller\PostController::index" or "App\Controller\PostController" if it is invokable)
+ */
+ public function forward(string $controller, array $path = [], array $query = []): Response
+ {
+ $request = $this->container->get('request_stack')->getCurrentRequest();
+ $path['_controller'] = $controller;
+ $subRequest = $request->duplicate($query, null, $path);
+
+ return $this->container->get('http_kernel')->handle($subRequest, HttpKernelInterface::SUB_REQUEST);
+ }
+
+ /**
+ * Returns a RedirectResponse to the given URL.
+ *
+ * @param int $status The HTTP status code (302 "Found" by default)
+ */
+ public function redirect(string $url, int $status = 302): RedirectResponse
+ {
+ return new RedirectResponse($url, $status);
+ }
+
+ /**
+ * Returns a RedirectResponse to the given route with the given parameters.
+ *
+ * @param int $status The HTTP status code (302 "Found" by default)
+ */
+ public function redirectToRoute(string $route, array $parameters = [], int $status = 302): RedirectResponse
+ {
+ return $this->redirect($this->generateUrl($route, $parameters), $status);
+ }
+
+ /**
+ * Returns a JsonResponse that uses the serializer component if enabled, or json_encode.
+ *
+ * @param int $status The HTTP status code (200 "OK" by default)
+ */
+ public function json(mixed $data, int $status = 200, array $headers = [], array $context = []): JsonResponse
+ {
+ if ($this->container->has('serializer')) {
+ $json = $this->container->get('serializer')->serialize($data, 'json', array_merge([
+ 'json_encode_options' => JsonResponse::DEFAULT_ENCODING_OPTIONS,
+ ], $context));
+
+ return new JsonResponse($json, $status, $headers, true);
+ }
+
+ return new JsonResponse($data, $status, $headers);
+ }
+
+ /**
+ * Returns a BinaryFileResponse object with original or customized file name and disposition header.
+ */
+ public 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());
+
+ return $response;
+ }
+
+ /**
+ * Adds a flash message to the current session for type.
+ *
+ * @throws \LogicException
+ */
+ public function addFlash(string $type, mixed $message): void
+ {
+ try {
+ $session = $this->container->get('request_stack')->getSession();
+ } catch (SessionNotFoundException $e) {
+ throw new \LogicException('You cannot use the addFlash method if sessions are disabled. Enable them in "config/packages/framework.yaml".', 0, $e);
+ }
+
+ if (!$session instanceof FlashBagAwareSessionInterface) {
+ throw new \LogicException(\sprintf('You cannot use the addFlash method because class "%s" doesn\'t implement "%s".', get_debug_type($session), FlashBagAwareSessionInterface::class));
+ }
+
+ $session->getFlashBag()->add($type, $message);
+ }
+
+ /**
+ * Checks if the attribute is granted against the current authentication token and optionally supplied subject.
+ *
+ * @throws \LogicException
+ */
+ public function isGranted(mixed $attribute, mixed $subject = null): bool
+ {
+ if (!$this->container->has('security.authorization_checker')) {
+ throw new \LogicException('The SecurityBundle is not registered in your application. Try running "composer require symfony/security-bundle".');
+ }
+
+ return $this->container->get('security.authorization_checker')->isGranted($attribute, $subject);
+ }
+
+ /**
+ * Checks if the attribute is granted against the current authentication token and optionally supplied subject.
+ */
+ public function getAccessDecision(mixed $attribute, mixed $subject = null): AccessDecision
+ {
+ if (!$this->container->has('security.authorization_checker')) {
+ throw new \LogicException('The SecurityBundle is not registered in your application. Try running "composer require symfony/security-bundle".');
+ }
+
+ $accessDecision = new AccessDecision();
+ $accessDecision->isGranted = $this->container->get('security.authorization_checker')->isGranted($attribute, $subject, $accessDecision);
+
+ return $accessDecision;
+ }
+
+ /**
+ * Throws an exception unless the attribute is granted against the current authentication token and optionally
+ * supplied subject.
+ *
+ * @throws AccessDeniedException
+ */
+ public function denyAccessUnlessGranted(mixed $attribute, mixed $subject = null, string $message = 'Access Denied.'): void
+ {
+ if (class_exists(AccessDecision::class)) {
+ $accessDecision = $this->getAccessDecision($attribute, $subject);
+ $isGranted = $accessDecision->isGranted;
+ } else {
+ $accessDecision = null;
+ $isGranted = $this->isGranted($attribute, $subject);
+ }
+
+ if (!$isGranted) {
+ $e = $this->createAccessDeniedException(3 > \func_num_args() && $accessDecision ? $accessDecision->getMessage() : $message);
+ $e->setAttributes([$attribute]);
+ $e->setSubject($subject);
+
+ if ($accessDecision) {
+ $e->setAccessDecision($accessDecision);
+ }
+
+ throw $e;
+ }
+ }
+
+ /**
+ * Returns a rendered view.
+ *
+ * Forms found in parameters are auto-cast to form views.
+ */
+ public function renderView(string $view, array $parameters = []): string
+ {
+ return $this->doRenderView($view, null, $parameters, __FUNCTION__);
+ }
+
+ /**
+ * Returns a rendered block from a view.
+ *
+ * Forms found in parameters are auto-cast to form views.
+ */
+ public function renderBlockView(string $view, string $block, array $parameters = []): string
+ {
+ return $this->doRenderView($view, $block, $parameters, __FUNCTION__);
+ }
+
+ /**
+ * Renders a view.
+ *
+ * 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.
+ */
+ public function render(string $view, array $parameters = [], ?Response $response = null): Response
+ {
+ return $this->doRender($view, null, $parameters, $response, __FUNCTION__);
+ }
+
+ /**
+ * Renders a block in a view.
+ *
+ * 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.
+ */
+ public function renderBlock(string $view, string $block, array $parameters = [], ?Response $response = null): Response
+ {
+ return $this->doRender($view, $block, $parameters, $response, __FUNCTION__);
+ }
+
+ /**
+ * Streams a view.
+ */
+ public 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".');
+ }
+
+ $twig = $this->container->get('twig');
+
+ $callback = function () use ($twig, $view, $parameters) {
+ $twig->display($view, $parameters);
+ };
+
+ if (null === $response) {
+ return new StreamedResponse($callback);
+ }
+
+ $response->setCallback($callback);
+
+ return $response;
+ }
+
+ /**
+ * Returns a NotFoundHttpException.
+ *
+ * This will result in a 404 response code. Usage example:
+ *
+ * throw $this->createNotFoundException('Page not found!');
+ */
+ public function createNotFoundException(string $message = 'Not Found', ?\Throwable $previous = null): NotFoundHttpException
+ {
+ return new NotFoundHttpException($message, $previous);
+ }
+
+ /**
+ * Returns an AccessDeniedException.
+ *
+ * This will result in a 403 response code. Usage example:
+ *
+ * throw $this->createAccessDeniedException('Unable to access this page!');
+ *
+ * @throws \LogicException If the Security component is not available
+ */
+ public 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".');
+ }
+
+ return new AccessDeniedException($message, $previous);
+ }
+
+ /**
+ * Creates and returns a Form instance from the type of the form.
+ */
+ public function createForm(string $type, mixed $data = null, array $options = []): FormInterface
+ {
+ return $this->container->get('form.factory')->create($type, $data, $options);
+ }
+
+ /**
+ * Creates and returns a form builder instance.
+ */
+ public function createFormBuilder(mixed $data = null, array $options = []): FormBuilderInterface
+ {
+ return $this->container->get('form.factory')->createBuilder(FormType::class, $data, $options);
+ }
+
+ /**
+ * Get a user from the Security Token Storage.
+ *
+ * @throws \LogicException If SecurityBundle is not available
+ *
+ * @see TokenInterface::getUser()
+ */
+ public function getUser(): ?UserInterface
+ {
+ if (!$this->container->has('security.token_storage')) {
+ throw new \LogicException('The SecurityBundle is not registered in your application. Try running "composer require symfony/security-bundle".');
+ }
+
+ if (null === $token = $this->container->get('security.token_storage')->getToken()) {
+ return null;
+ }
+
+ return $token->getUser();
+ }
+
+ /**
+ * Checks the validity of a CSRF token.
+ *
+ * @param string $id The id used when generating the token
+ * @param string|null $token The actual token sent with the request that should be validated
+ */
+ public function isCsrfTokenValid(string $id, #[\SensitiveParameter] ?string $token): bool
+ {
+ if (!$this->container->has('security.csrf.token_manager')) {
+ throw new \LogicException('CSRF protection is not enabled in your application. Enable it with the "csrf_protection" key in "config/packages/framework.yaml".');
+ }
+
+ return $this->container->get('security.csrf.token_manager')->isTokenValid(new CsrfToken($id, $token));
+ }
+
+ /**
+ * Adds a Link HTTP header to the current response.
+ *
+ * @see https://tools.ietf.org/html/rfc5988
+ */
+ public function addLink(Request $request, LinkInterface $link): void
+ {
+ if (!class_exists(AddLinkHeaderListener::class)) {
+ throw new \LogicException('You cannot use the "addLink" method if the WebLink component is not available. Try running "composer require symfony/web-link".');
+ }
+
+ if (null === $linkProvider = $request->attributes->get('_links')) {
+ $request->attributes->set('_links', new GenericLinkProvider([$link]));
+
+ return;
+ }
+
+ $request->attributes->set('_links', $linkProvider->withLink($link));
+ }
+
+ /**
+ * @param LinkInterface[] $links
+ */
+ public 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".');
+ }
+
+ $response ??= new Response();
+
+ $populatedLinks = [];
+ foreach ($links as $link) {
+ if ($link instanceof EvolvableLinkInterface && !$link->getRels()) {
+ $link = $link->withRel('preload');
+ }
+
+ $populatedLinks[] = $link;
+ }
+
+ $response->headers->set('Link', $this->container->get('web_link.http_header_serializer')->serialize($populatedLinks), false);
+ $response->sendHeaders(103);
+
+ return $response;
+ }
+
+ private function doRenderView(string $view, ?string $block, array $parameters, string $method): string
+ {
+ if (!$this->container->has('twig')) {
+ throw new \LogicException(\sprintf('You cannot use the "%s" method if the Twig Bundle is not available. Try running "composer require symfony/twig-bundle".', $method));
+ }
+
+ foreach ($parameters as $k => $v) {
+ if ($v instanceof FormInterface) {
+ $parameters[$k] = $v->createView();
+ }
+ }
+
+ if (null !== $block) {
+ return $this->container->get('twig')->load($view)->renderBlock($block, $parameters);
+ }
+
+ return $this->container->get('twig')->render($view, $parameters);
+ }
+
+ private function doRender(string $view, ?string $block, array $parameters, ?Response $response, string $method): Response
+ {
+ $content = $this->doRenderView($view, $block, $parameters, $method);
+ $response ??= new Response();
+
+ if (200 === $response->getStatusCode()) {
+ foreach ($parameters as $v) {
+ if ($v instanceof FormInterface && $v->isSubmitted() && !$v->isValid()) {
+ $response->setStatusCode(422);
+ break;
+ }
+ }
+ }
+
+ $response->setContent($content);
+
+ return $response;
+ }
+}
diff --git a/DependencyInjection/Compiler/ContainerBuilderDebugDumpPass.php b/DependencyInjection/Compiler/ContainerBuilderDebugDumpPass.php
index e4023e623..456305bc9 100644
--- a/DependencyInjection/Compiler/ContainerBuilderDebugDumpPass.php
+++ b/DependencyInjection/Compiler/ContainerBuilderDebugDumpPass.php
@@ -13,8 +13,11 @@
use Symfony\Component\Config\ConfigCache;
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
+use Symfony\Component\DependencyInjection\Compiler\ResolveEnvPlaceholdersPass;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Dumper\XmlDumper;
+use Symfony\Component\DependencyInjection\ParameterBag\EnvPlaceholderParameterBag;
+use Symfony\Component\Filesystem\Filesystem;
/**
* Dumps the ContainerBuilder to a cache file so that it can be used by
@@ -31,9 +34,52 @@ public function process(ContainerBuilder $container): void
return;
}
- $cache = new ConfigCache($container->getParameter('debug.container.dump'), true);
- if (!$cache->isFresh()) {
- $cache->write((new XmlDumper($container))->dump(), $container->getResources());
+ $file = $container->getParameter('debug.container.dump');
+ $cache = new ConfigCache($file, true);
+ if ($cache->isFresh()) {
+ return;
+ }
+ $cache->write((new XmlDumper($container))->dump(), $container->getResources());
+
+ if (!str_ends_with($file, '.xml')) {
+ return;
+ }
+
+ $file = substr_replace($file, '.ser', -4);
+
+ try {
+ $dump = new ContainerBuilder(clone $container->getParameterBag());
+ $dump->setDefinitions(unserialize(serialize($container->getDefinitions())));
+ $dump->setAliases($container->getAliases());
+
+ if (($bag = $container->getParameterBag()) instanceof EnvPlaceholderParameterBag) {
+ (new ResolveEnvPlaceholdersPass(null))->process($dump);
+ $dump->__construct(new EnvPlaceholderParameterBag($container->resolveEnvPlaceholders($this->escapeParameters($bag->all()))));
+ }
+
+ $fs = new Filesystem();
+ $fs->dumpFile($file, serialize($dump));
+ $fs->chmod($file, 0o666, umask());
+ } catch (\Throwable $e) {
+ $container->getCompiler()->log($this, $e->getMessage());
+ // ignore serialization and file-system errors
+ if (file_exists($file)) {
+ @unlink($file);
+ }
}
}
+
+ private function escapeParameters(array $parameters): array
+ {
+ $params = [];
+ foreach ($parameters as $k => $v) {
+ $params[$k] = match (true) {
+ \is_array($v) => $this->escapeParameters($v),
+ \is_string($v) => str_replace('%', '%%', $v),
+ default => $v,
+ };
+ }
+
+ return $params;
+ }
}
diff --git a/DependencyInjection/Configuration.php b/DependencyInjection/Configuration.php
index d66a5c6ff..0181b18a1 100644
--- a/DependencyInjection/Configuration.php
+++ b/DependencyInjection/Configuration.php
@@ -2562,7 +2562,7 @@ private function addRateLimiterSection(ArrayNodeDefinition $rootNode, callable $
->end()
->end()
->validate()
- ->ifTrue(static fn ($v) => !\in_array($v['policy'], ['no_limit', 'compound']) && !isset($v['limit']))
+ ->ifTrue(static fn ($v) => !\in_array($v['policy'], ['no_limit', 'compound'], true) && !isset($v['limit']))
->thenInvalid('A limit must be provided when using a policy different than "compound" or "no_limit".')
->end()
->end()
diff --git a/DependencyInjection/FrameworkExtension.php b/DependencyInjection/FrameworkExtension.php
index a85642ec2..e21b8b838 100644
--- a/DependencyInjection/FrameworkExtension.php
+++ b/DependencyInjection/FrameworkExtension.php
@@ -33,6 +33,7 @@
use Symfony\Bundle\FrameworkBundle\Routing\RouteLoaderInterface;
use Symfony\Bundle\FullStack;
use Symfony\Bundle\MercureBundle\MercureBundle;
+use Symfony\Component\Asset\Package;
use Symfony\Component\Asset\PackageInterface;
use Symfony\Component\AssetMapper\AssetMapper;
use Symfony\Component\AssetMapper\Compiler\AssetCompilerInterface;
@@ -61,7 +62,6 @@
use Symfony\Component\DependencyInjection\Alias;
use Symfony\Component\DependencyInjection\Argument\IteratorArgument;
use Symfony\Component\DependencyInjection\Argument\ServiceLocatorArgument;
-use Symfony\Component\DependencyInjection\Attribute\Target;
use Symfony\Component\DependencyInjection\ChildDefinition;
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
use Symfony\Component\DependencyInjection\Compiler\ServiceLocatorTagPass;
@@ -134,6 +134,8 @@
use Symfony\Component\Messenger\MessageBusInterface;
use Symfony\Component\Messenger\Middleware\DeduplicateMiddleware;
use Symfony\Component\Messenger\Middleware\RouterContextMiddleware;
+use Symfony\Component\Messenger\Transport\AmqpExt\AmqpTransportFactory;
+use Symfony\Component\Messenger\Transport\RedisExt\RedisTransportFactory;
use Symfony\Component\Messenger\Transport\Serialization\SerializerInterface;
use Symfony\Component\Messenger\Transport\TransportFactoryInterface as MessengerTransportFactoryInterface;
use Symfony\Component\Messenger\Transport\TransportInterface;
@@ -177,6 +179,7 @@
use Symfony\Component\Scheduler\Messenger\Serializer\Normalizer\SchedulerTriggerNormalizer;
use Symfony\Component\Security\Core\AuthenticationEvents;
use Symfony\Component\Security\Core\Exception\AuthenticationException;
+use Symfony\Component\Security\Csrf\CsrfToken;
use Symfony\Component\Security\Csrf\CsrfTokenManagerInterface;
use Symfony\Component\Semaphore\PersistingStoreInterface as SemaphoreStoreInterface;
use Symfony\Component\Semaphore\Semaphore;
@@ -217,6 +220,7 @@
use Symfony\Component\Validator\ObjectInitializerInterface;
use Symfony\Component\Validator\Validation;
use Symfony\Component\Webhook\Controller\WebhookController;
+use Symfony\Component\WebLink\HttpHeaderParser;
use Symfony\Component\WebLink\HttpHeaderSerializer;
use Symfony\Component\Workflow;
use Symfony\Component\Workflow\WorkflowInterface;
@@ -389,7 +393,7 @@ public function load(array $configs, ContainerBuilder $container): void
}
if ($this->readConfigEnabled('assets', $container, $config['assets'])) {
- if (!class_exists(\Symfony\Component\Asset\Package::class)) {
+ if (!class_exists(Package::class)) {
throw new LogicException('Asset support cannot be enabled as the Asset component is not installed. Try running "composer require symfony/asset".');
}
@@ -502,6 +506,11 @@ public function load(array $configs, ContainerBuilder $container): void
}
$loader->load('web_link.php');
+
+ // Require symfony/web-link 7.4
+ if (!class_exists(HttpHeaderParser::class)) {
+ $container->removeDefinition('web_link.http_header_parser');
+ }
}
if ($this->readConfigEnabled('uid', $container, $config['uid'])) {
@@ -589,9 +598,9 @@ public function load(array $configs, ContainerBuilder $container): void
$container->removeDefinition('cache.messenger.restart_workers_signal');
if ($container->hasDefinition('messenger.transport.amqp.factory') && !class_exists(MessengerBridge\Amqp\Transport\AmqpTransportFactory::class)) {
- if (class_exists(\Symfony\Component\Messenger\Transport\AmqpExt\AmqpTransportFactory::class)) {
+ if (class_exists(AmqpTransportFactory::class)) {
$container->getDefinition('messenger.transport.amqp.factory')
- ->setClass(\Symfony\Component\Messenger\Transport\AmqpExt\AmqpTransportFactory::class)
+ ->setClass(AmqpTransportFactory::class)
->addTag('messenger.transport_factory');
} else {
$container->removeDefinition('messenger.transport.amqp.factory');
@@ -599,9 +608,9 @@ public function load(array $configs, ContainerBuilder $container): void
}
if ($container->hasDefinition('messenger.transport.redis.factory') && !class_exists(MessengerBridge\Redis\Transport\RedisTransportFactory::class)) {
- if (class_exists(\Symfony\Component\Messenger\Transport\RedisExt\RedisTransportFactory::class)) {
+ if (class_exists(RedisTransportFactory::class)) {
$container->getDefinition('messenger.transport.redis.factory')
- ->setClass(\Symfony\Component\Messenger\Transport\RedisExt\RedisTransportFactory::class)
+ ->setClass(RedisTransportFactory::class)
->addTag('messenger.transport_factory');
} else {
$container->removeDefinition('messenger.transport.redis.factory');
@@ -1184,8 +1193,7 @@ private function registerWorkflowConfiguration(array $config, ContainerBuilder $
// Store to container
$container->setDefinition($workflowId, $workflowDefinition);
$container->setDefinition($definitionDefinitionId, $definitionDefinition);
- $container->registerAliasForArgument($workflowId, WorkflowInterface::class, $name.'.'.$type);
- $container->registerAliasForArgument($workflowId, WorkflowInterface::class, $name);
+ $container->registerAliasForArgument($workflowId, WorkflowInterface::class, $name.'.'.$type, $name);
// Add workflow to Registry
if ($workflow['supports']) {
@@ -1420,7 +1428,7 @@ private function registerAssetsConfiguration(array $config, ContainerBuilder $co
$packageDefinition = $this->createPackageDefinition($package['base_path'], $package['base_urls'], $version)
->addTag('assets.package', ['package' => $name]);
$container->setDefinition('assets._package_'.$name, $packageDefinition);
- $container->registerAliasForArgument('assets._package_'.$name, PackageInterface::class, $name.'.package');
+ $container->registerAliasForArgument('assets._package_'.$name, PackageInterface::class, $name.'.package', $name);
}
}
@@ -1967,7 +1975,7 @@ private function registerSecurityCsrfConfiguration(array $config, ContainerBuild
return;
}
- if (!class_exists(\Symfony\Component\Security\Csrf\CsrfToken::class)) {
+ if (!class_exists(CsrfToken::class)) {
throw new LogicException('CSRF support cannot be enabled as the Security CSRF component is not installed. Try running "composer require symfony/security-csrf".');
}
if (!$config['stateless_token_ids'] && !$this->isInitializedConfigEnabled('session')) {
@@ -2049,7 +2057,7 @@ private function registerSerializerConfiguration(array $config, ContainerBuilder
}
$fileRecorder = function ($extension, $path) use (&$serializerLoaders) {
- $definition = new Definition(\in_array($extension, ['yaml', 'yml']) ? YamlFileLoader::class : XmlFileLoader::class, [$path]);
+ $definition = new Definition(\in_array($extension, ['yaml', 'yml'], true) ? YamlFileLoader::class : XmlFileLoader::class, [$path]);
$serializerLoaders[] = $definition;
};
@@ -2241,7 +2249,7 @@ private function registerLockConfiguration(array $config, ContainerBuilder $cont
$container->setAlias('lock.factory', new Alias('lock.'.$resourceName.'.factory', false));
$container->setAlias(LockFactory::class, new Alias('lock.factory', false));
} else {
- $container->registerAliasForArgument('lock.'.$resourceName.'.factory', LockFactory::class, $resourceName.'.lock.factory');
+ $container->registerAliasForArgument('lock.'.$resourceName.'.factory', LockFactory::class, $resourceName.'.lock.factory', $resourceName);
}
}
}
@@ -2276,7 +2284,7 @@ private function registerSemaphoreConfiguration(array $config, ContainerBuilder
$container->setAlias('semaphore.factory', new Alias('semaphore.'.$resourceName.'.factory', false));
$container->setAlias(SemaphoreFactory::class, new Alias('semaphore.factory', false));
} else {
- $container->registerAliasForArgument('semaphore.'.$resourceName.'.factory', SemaphoreFactory::class, $resourceName.'.semaphore.factory');
+ $container->registerAliasForArgument('semaphore.'.$resourceName.'.factory', SemaphoreFactory::class, $resourceName.'.semaphore.factory', $resourceName);
}
}
}
@@ -2879,6 +2887,7 @@ private function registerMailerConfiguration(array $config, ContainerBuilder $co
MailerBridge\Mailomat\Transport\MailomatTransportFactory::class => 'mailer.transport_factory.mailomat',
MailerBridge\MailPace\Transport\MailPaceTransportFactory::class => 'mailer.transport_factory.mailpace',
MailerBridge\Mailchimp\Transport\MandrillTransportFactory::class => 'mailer.transport_factory.mailchimp',
+ MailerBridge\MicrosoftGraph\Transport\MicrosoftGraphTransportFactory::class => 'mailer.transport_factory.microsoftgraph',
MailerBridge\Postal\Transport\PostalTransportFactory::class => 'mailer.transport_factory.postal',
MailerBridge\Postmark\Transport\PostmarkTransportFactory::class => 'mailer.transport_factory.postmark',
MailerBridge\Mailtrap\Transport\MailtrapTransportFactory::class => 'mailer.transport_factory.mailtrap',
@@ -2931,7 +2940,7 @@ private function registerMailerConfiguration(array $config, ContainerBuilder $co
$headers = new Definition(Headers::class);
foreach ($config['headers'] as $name => $data) {
$value = $data['value'];
- if (\in_array(strtolower($name), ['from', 'to', 'cc', 'bcc', 'reply-to'])) {
+ if (\in_array(strtolower($name), ['from', 'to', 'cc', 'bcc', 'reply-to'], true)) {
$value = (array) $value;
}
$headers->addMethodCall('addHeader', [$name, $value]);
@@ -3301,13 +3310,11 @@ private function registerRateLimiterConfiguration(array $config, ContainerBuilde
$factoryAlias = $container->registerAliasForArgument($limiterId, RateLimiterFactory::class, $name.'.limiter');
if (interface_exists(RateLimiterFactoryInterface::class)) {
- $container->registerAliasForArgument($limiterId, RateLimiterFactoryInterface::class, $name.'.limiter');
- $factoryAlias->setDeprecated('symfony/framework-bundle', '7.3', \sprintf('The "%%alias_id%%" autowiring alias is deprecated and will be removed in 8.0, use "%s $%s" instead.', RateLimiterFactoryInterface::class, (new Target($name.'.limiter'))->getParsedName()));
- $internalAliasId = \sprintf('.%s $%s.limiter', RateLimiterFactory::class, $name);
+ $container->registerAliasForArgument($limiterId, RateLimiterFactoryInterface::class, $name.'.limiter', $name);
- if ($container->hasAlias($internalAliasId)) {
- $container->getAlias($internalAliasId)->setDeprecated('symfony/framework-bundle', '7.3', \sprintf('The "%%alias_id%%" autowiring alias is deprecated and will be removed in 8.0, use "%s $%s" instead.', RateLimiterFactoryInterface::class, (new Target($name.'.limiter'))->getParsedName()));
- }
+ $factoryAlias->setDeprecated('symfony/framework-bundle', '7.3', 'The "%alias_id%" autowiring alias is deprecated and will be removed in 8.0, use "RateLimiterFactoryInterface" instead.');
+ $container->getAlias(\sprintf('.%s $%s.limiter', RateLimiterFactory::class, $name))
+ ->setDeprecated('symfony/framework-bundle', '7.3', 'The "%alias_id%" autowiring alias is deprecated and will be removed in 8.0, use "RateLimiterFactoryInterface" instead.');
}
}
@@ -3332,7 +3339,7 @@ private function registerRateLimiterConfiguration(array $config, ContainerBuilde
)))
;
- $container->registerAliasForArgument($limiterId, RateLimiterFactoryInterface::class, $name.'.limiter');
+ $container->registerAliasForArgument($limiterId, RateLimiterFactoryInterface::class, $name.'.limiter', $name);
}
}
diff --git a/FrameworkBundle.php b/FrameworkBundle.php
index 300fe22fb..34e8b3ae7 100644
--- a/FrameworkBundle.php
+++ b/FrameworkBundle.php
@@ -103,8 +103,7 @@ public function boot(): void
$_ENV['DOCTRINE_DEPRECATIONS'] = $_SERVER['DOCTRINE_DEPRECATIONS'] ??= 'trigger';
if (class_exists(SymfonyRuntime::class)) {
- $handler = set_error_handler('var_dump');
- restore_error_handler();
+ $handler = get_error_handler();
} else {
$handler = [ErrorHandler::register(null, false)];
}
diff --git a/KernelBrowser.php b/KernelBrowser.php
index add2508ff..d5b4262a4 100644
--- a/KernelBrowser.php
+++ b/KernelBrowser.php
@@ -205,25 +205,25 @@ protected function getScript(object $request): string
$profilerCode = '';
if ($this->profiler) {
$profilerCode = <<<'EOF'
-$container = $kernel->getContainer();
-$container = $container->has('test.service_container') ? $container->get('test.service_container') : $container;
-$container->get('profiler')->enable();
-EOF;
+ $container = $kernel->getContainer();
+ $container = $container->has('test.service_container') ? $container->get('test.service_container') : $container;
+ $container->get('profiler')->enable();
+ EOF;
}
$code = <<boot();
-$profilerCode
+ \$kernel = unserialize($kernel);
+ \$kernel->boot();
+ $profilerCode
-\$request = unserialize($request);
-EOF;
+ \$request = unserialize($request);
+ EOF;
return $code.$this->getHandleScript();
}
diff --git a/Resources/config/console.php b/Resources/config/console.php
index 7ef10bb52..fda2f75d7 100644
--- a/Resources/config/console.php
+++ b/Resources/config/console.php
@@ -45,6 +45,7 @@
use Symfony\Component\Console\Messenger\RunCommandMessageHandler;
use Symfony\Component\Dotenv\Command\DebugCommand as DotenvDebugCommand;
use Symfony\Component\ErrorHandler\Command\ErrorDumpCommand;
+use Symfony\Component\Form\Command\DebugCommand;
use Symfony\Component\Messenger\Command\ConsumeMessagesCommand;
use Symfony\Component\Messenger\Command\DebugCommand as MessengerDebugCommand;
use Symfony\Component\Messenger\Command\FailedMessagesRemoveCommand;
@@ -327,7 +328,7 @@
])
->tag('console.command')
- ->set('console.command.form_debug', \Symfony\Component\Form\Command\DebugCommand::class)
+ ->set('console.command.form_debug', DebugCommand::class)
->args([
service('form.registry'),
[], // All form types namespaces are stored here by FormPass
diff --git a/Resources/config/mailer_transports.php b/Resources/config/mailer_transports.php
index 2c79b4d55..e88e95166 100644
--- a/Resources/config/mailer_transports.php
+++ b/Resources/config/mailer_transports.php
@@ -24,6 +24,7 @@
use Symfony\Component\Mailer\Bridge\Mailomat\Transport\MailomatTransportFactory;
use Symfony\Component\Mailer\Bridge\MailPace\Transport\MailPaceTransportFactory;
use Symfony\Component\Mailer\Bridge\Mailtrap\Transport\MailtrapTransportFactory;
+use Symfony\Component\Mailer\Bridge\MicrosoftGraph\Transport\MicrosoftGraphTransportFactory;
use Symfony\Component\Mailer\Bridge\Postal\Transport\PostalTransportFactory;
use Symfony\Component\Mailer\Bridge\Postmark\Transport\PostmarkTransportFactory;
use Symfony\Component\Mailer\Bridge\Resend\Transport\ResendTransportFactory;
@@ -60,6 +61,7 @@
'mailjet' => MailjetTransportFactory::class,
'mailomat' => MailomatTransportFactory::class,
'mailpace' => MailPaceTransportFactory::class,
+ 'microsoftgraph' => MicrosoftGraphTransportFactory::class,
'native' => NativeTransportFactory::class,
'null' => NullTransportFactory::class,
'postal' => PostalTransportFactory::class,
diff --git a/Resources/config/profiling.php b/Resources/config/profiling.php
index a81c53a63..ba734bee2 100644
--- a/Resources/config/profiling.php
+++ b/Resources/config/profiling.php
@@ -39,6 +39,7 @@
param('profiler_listener.only_main_requests'),
])
->tag('kernel.event_subscriber')
+ ->tag('kernel.reset', ['method' => '?reset'])
->set('console_profiler_listener', ConsoleProfilerListener::class)
->args([
diff --git a/Resources/config/web.php b/Resources/config/web.php
index a4e975dac..29e128715 100644
--- a/Resources/config/web.php
+++ b/Resources/config/web.php
@@ -12,6 +12,7 @@
namespace Symfony\Component\DependencyInjection\Loader\Configurator;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
+use Symfony\Bundle\FrameworkBundle\Controller\ControllerHelper;
use Symfony\Bundle\FrameworkBundle\Controller\ControllerResolver;
use Symfony\Bundle\FrameworkBundle\Controller\TemplateController;
use Symfony\Component\HttpKernel\Controller\ArgumentResolver;
@@ -145,6 +146,12 @@
->set('controller.cache_attribute_listener', CacheAttributeListener::class)
->tag('kernel.event_subscriber')
+ ->tag('kernel.reset', ['method' => '?reset'])
+
+ ->set('controller.helper', ControllerHelper::class)
+ ->tag('container.service_subscriber')
+
+ ->alias(ControllerHelper::class, 'controller.helper')
;
};
diff --git a/Resources/config/web_link.php b/Resources/config/web_link.php
index 64345cc99..df55d1947 100644
--- a/Resources/config/web_link.php
+++ b/Resources/config/web_link.php
@@ -12,6 +12,7 @@
namespace Symfony\Component\DependencyInjection\Loader\Configurator;
use Symfony\Component\WebLink\EventListener\AddLinkHeaderListener;
+use Symfony\Component\WebLink\HttpHeaderParser;
use Symfony\Component\WebLink\HttpHeaderSerializer;
return static function (ContainerConfigurator $container) {
@@ -20,6 +21,9 @@
->set('web_link.http_header_serializer', HttpHeaderSerializer::class)
->alias(HttpHeaderSerializer::class, 'web_link.http_header_serializer')
+ ->set('web_link.http_header_parser', HttpHeaderParser::class)
+ ->alias(HttpHeaderParser::class, 'web_link.http_header_parser')
+
->set('web_link.add_link_header_listener', AddLinkHeaderListener::class)
->args([
service('web_link.http_header_serializer'),
diff --git a/Routing/Router.php b/Routing/Router.php
index 9efa07fae..f9e41273c 100644
--- a/Routing/Router.php
+++ b/Routing/Router.php
@@ -36,6 +36,9 @@
class Router extends BaseRouter implements WarmableInterface, ServiceSubscriberInterface
{
private array $collectedParameters = [];
+ /**
+ * @var \Closure(string):mixed
+ */
private \Closure $paramFetcher;
/**
diff --git a/Secrets/SodiumVault.php b/Secrets/SodiumVault.php
index 2a8e5dcc8..5abdfdc70 100644
--- a/Secrets/SodiumVault.php
+++ b/Secrets/SodiumVault.php
@@ -228,7 +228,7 @@ private function export(string $filename, string $data): void
private function createSecretsDir(): void
{
- if ($this->secretsDir && !is_dir($this->secretsDir) && !@mkdir($this->secretsDir, 0777, true) && !is_dir($this->secretsDir)) {
+ if ($this->secretsDir && !is_dir($this->secretsDir) && !@mkdir($this->secretsDir, 0o777, true) && !is_dir($this->secretsDir)) {
throw new \RuntimeException(\sprintf('Unable to create the secrets directory (%s).', $this->secretsDir));
}
diff --git a/Test/BrowserKitAssertionsTrait.php b/Test/BrowserKitAssertionsTrait.php
index 1b7437b77..6086e75ec 100644
--- a/Test/BrowserKitAssertionsTrait.php
+++ b/Test/BrowserKitAssertionsTrait.php
@@ -16,6 +16,7 @@
use PHPUnit\Framework\Constraint\LogicalNot;
use PHPUnit\Framework\ExpectationFailedException;
use Symfony\Component\BrowserKit\AbstractBrowser;
+use Symfony\Component\BrowserKit\History;
use Symfony\Component\BrowserKit\Test\Constraint as BrowserKitConstraint;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
@@ -28,24 +29,31 @@
*/
trait BrowserKitAssertionsTrait
{
- public static function assertResponseIsSuccessful(string $message = '', bool $verbose = true): void
+ private static bool $defaultVerboseMode = true;
+
+ public static function setBrowserKitAssertionsAsVerbose(bool $verbose): void
{
- self::assertThatForResponse(new ResponseConstraint\ResponseIsSuccessful($verbose), $message);
+ self::$defaultVerboseMode = $verbose;
}
- public static function assertResponseStatusCodeSame(int $expectedCode, string $message = '', bool $verbose = true): void
+ public static function assertResponseIsSuccessful(string $message = '', ?bool $verbose = null): void
{
- self::assertThatForResponse(new ResponseConstraint\ResponseStatusCodeSame($expectedCode, $verbose), $message);
+ self::assertThatForResponse(new ResponseConstraint\ResponseIsSuccessful($verbose ?? self::$defaultVerboseMode), $message);
}
- public static function assertResponseFormatSame(?string $expectedFormat, string $message = ''): void
+ public static function assertResponseStatusCodeSame(int $expectedCode, string $message = '', ?bool $verbose = null): void
{
- self::assertThatForResponse(new ResponseConstraint\ResponseFormatSame(self::getRequest(), $expectedFormat), $message);
+ self::assertThatForResponse(new ResponseConstraint\ResponseStatusCodeSame($expectedCode, $verbose ?? self::$defaultVerboseMode), $message);
}
- public static function assertResponseRedirects(?string $expectedLocation = null, ?int $expectedCode = null, string $message = '', bool $verbose = true): void
+ public static function assertResponseFormatSame(?string $expectedFormat, string $message = '', ?bool $verbose = null): void
{
- $constraint = new ResponseConstraint\ResponseIsRedirected($verbose);
+ self::assertThatForResponse(new ResponseConstraint\ResponseFormatSame(self::getRequest(), $expectedFormat, $verbose ?? self::$defaultVerboseMode), $message);
+ }
+
+ public static function assertResponseRedirects(?string $expectedLocation = null, ?int $expectedCode = null, string $message = '', ?bool $verbose = null): void
+ {
+ $constraint = new ResponseConstraint\ResponseIsRedirected($verbose ?? self::$defaultVerboseMode);
if ($expectedLocation) {
if (class_exists(ResponseConstraint\ResponseHeaderLocationSame::class)) {
$locationConstraint = new ResponseConstraint\ResponseHeaderLocationSame(self::getRequest(), $expectedLocation);
@@ -100,9 +108,9 @@ public static function assertResponseCookieValueSame(string $name, string $expec
), $message);
}
- public static function assertResponseIsUnprocessable(string $message = '', bool $verbose = true): void
+ public static function assertResponseIsUnprocessable(string $message = '', ?bool $verbose = null): void
{
- self::assertThatForResponse(new ResponseConstraint\ResponseIsUnprocessable($verbose), $message);
+ self::assertThatForResponse(new ResponseConstraint\ResponseIsUnprocessable($verbose ?? self::$defaultVerboseMode), $message);
}
public static function assertBrowserHasCookie(string $name, string $path = '/', ?string $domain = null, string $message = ''): void
@@ -115,6 +123,38 @@ public static function assertBrowserNotHasCookie(string $name, string $path = '/
self::assertThatForClient(new LogicalNot(new BrowserKitConstraint\BrowserHasCookie($name, $path, $domain)), $message);
}
+ public static function assertBrowserHistoryIsOnFirstPage(string $message = ''): void
+ {
+ if (!method_exists(History::class, 'isFirstPage')) {
+ throw new \LogicException('The `assertBrowserHistoryIsOnFirstPage` method requires symfony/browser-kit >= 7.4.');
+ }
+ self::assertThatForClient(new BrowserKitConstraint\BrowserHistoryIsOnFirstPage(), $message);
+ }
+
+ public static function assertBrowserHistoryIsNotOnFirstPage(string $message = ''): void
+ {
+ if (!method_exists(History::class, 'isFirstPage')) {
+ throw new \LogicException('The `assertBrowserHistoryIsNotOnFirstPage` method requires symfony/browser-kit >= 7.4.');
+ }
+ self::assertThatForClient(new LogicalNot(new BrowserKitConstraint\BrowserHistoryIsOnFirstPage()), $message);
+ }
+
+ public static function assertBrowserHistoryIsOnLastPage(string $message = ''): void
+ {
+ if (!method_exists(History::class, 'isLastPage')) {
+ throw new \LogicException('The `assertBrowserHistoryIsOnLastPage` method requires symfony/browser-kit >= 7.4.');
+ }
+ self::assertThatForClient(new BrowserKitConstraint\BrowserHistoryIsOnLastPage(), $message);
+ }
+
+ public static function assertBrowserHistoryIsNotOnLastPage(string $message = ''): void
+ {
+ if (!method_exists(History::class, 'isLastPage')) {
+ throw new \LogicException('The `assertBrowserHistoryIsNotOnLastPage` method requires symfony/browser-kit >= 7.4.');
+ }
+ self::assertThatForClient(new LogicalNot(new BrowserKitConstraint\BrowserHistoryIsOnLastPage()), $message);
+ }
+
public static function assertBrowserCookieValueSame(string $name, string $expectedValue, bool $raw = false, string $path = '/', ?string $domain = null, string $message = ''): void
{
self::assertThatForClient(LogicalAnd::fromConstraints(
diff --git a/Test/MailerAssertionsTrait.php b/Test/MailerAssertionsTrait.php
index 2308c3e2f..07f4c99f5 100644
--- a/Test/MailerAssertionsTrait.php
+++ b/Test/MailerAssertionsTrait.php
@@ -90,6 +90,11 @@ public static function assertEmailAddressContains(RawMessage $email, string $hea
self::assertThat($email, new MimeConstraint\EmailAddressContains($headerName, $expectedValue), $message);
}
+ public static function assertEmailAddressNotContains(RawMessage $email, string $headerName, string $expectedValue, string $message = ''): void
+ {
+ self::assertThat($email, new LogicalNot(new MimeConstraint\EmailAddressContains($headerName, $expectedValue)), $message);
+ }
+
public static function assertEmailSubjectContains(RawMessage $email, string $expectedValue, string $message = ''): void
{
self::assertThat($email, new MimeConstraint\EmailSubjectContains($expectedValue), $message);
diff --git a/Tests/CacheWarmer/SerializerCacheWarmerTest.php b/Tests/CacheWarmer/SerializerCacheWarmerTest.php
index f17aad0e3..5c19d2a3f 100644
--- a/Tests/CacheWarmer/SerializerCacheWarmerTest.php
+++ b/Tests/CacheWarmer/SerializerCacheWarmerTest.php
@@ -11,6 +11,7 @@
namespace Symfony\Bundle\FrameworkBundle\Tests\CacheWarmer;
+use PHPUnit\Framework\Attributes\DataProvider;
use Symfony\Bundle\FrameworkBundle\CacheWarmer\SerializerCacheWarmer;
use Symfony\Bundle\FrameworkBundle\Tests\TestCase;
use Symfony\Component\Cache\Adapter\NullAdapter;
@@ -38,9 +39,7 @@ private function getArrayPool(string $file): PhpArrayAdapter
return $this->arrayPool = new PhpArrayAdapter($file, new NullAdapter());
}
- /**
- * @dataProvider loaderProvider
- */
+ #[DataProvider('loaderProvider')]
public function testWarmUp(array $loaders)
{
$file = sys_get_temp_dir().'/cache-serializer.php';
@@ -57,9 +56,7 @@ public function testWarmUp(array $loaders)
$this->assertTrue($arrayPool->getItem('Symfony_Bundle_FrameworkBundle_Tests_Fixtures_Serialization_Author')->isHit());
}
- /**
- * @dataProvider loaderProvider
- */
+ #[DataProvider('loaderProvider')]
public function testWarmUpAbsoluteFilePath(array $loaders)
{
$file = sys_get_temp_dir().'/0/cache-serializer.php';
@@ -79,9 +76,7 @@ public function testWarmUpAbsoluteFilePath(array $loaders)
$this->assertTrue($arrayPool->getItem('Symfony_Bundle_FrameworkBundle_Tests_Fixtures_Serialization_Author')->isHit());
}
- /**
- * @dataProvider loaderProvider
- */
+ #[DataProvider('loaderProvider')]
public function testWarmUpWithoutBuildDir(array $loaders)
{
$file = sys_get_temp_dir().'/cache-serializer.php';
diff --git a/Tests/Command/AboutCommand/AboutCommandTest.php b/Tests/Command/AboutCommand/AboutCommandTest.php
index bcf3c7fe0..044d816e0 100644
--- a/Tests/Command/AboutCommand/AboutCommandTest.php
+++ b/Tests/Command/AboutCommand/AboutCommandTest.php
@@ -34,7 +34,7 @@ public function testAboutWithReadableFiles()
$this->fs->mkdir($kernel->getProjectDir());
$this->fs->dumpFile($kernel->getCacheDir().'/readable_file', 'The file content.');
- $this->fs->chmod($kernel->getCacheDir().'/readable_file', 0777);
+ $this->fs->chmod($kernel->getCacheDir().'/readable_file', 0o777);
$tester = $this->createCommandTester($kernel);
$ret = $tester->execute([]);
@@ -43,7 +43,7 @@ public function testAboutWithReadableFiles()
$this->assertStringContainsString('Cache directory', $tester->getDisplay());
$this->assertStringContainsString('Log directory', $tester->getDisplay());
- $this->fs->chmod($kernel->getCacheDir().'/readable_file', 0777);
+ $this->fs->chmod($kernel->getCacheDir().'/readable_file', 0o777);
try {
$this->fs->remove($kernel->getProjectDir());
@@ -62,7 +62,7 @@ public function testAboutWithUnreadableFiles()
}
$this->fs->dumpFile($kernel->getCacheDir().'/unreadable_file', 'The file content.');
- $this->fs->chmod($kernel->getCacheDir().'/unreadable_file', 0222);
+ $this->fs->chmod($kernel->getCacheDir().'/unreadable_file', 0o222);
$tester = $this->createCommandTester($kernel);
$ret = $tester->execute([]);
@@ -71,7 +71,7 @@ public function testAboutWithUnreadableFiles()
$this->assertStringContainsString('Cache directory', $tester->getDisplay());
$this->assertStringContainsString('Log directory', $tester->getDisplay());
- $this->fs->chmod($kernel->getCacheDir().'/unreadable_file', 0777);
+ $this->fs->chmod($kernel->getCacheDir().'/unreadable_file', 0o777);
try {
$this->fs->remove($kernel->getProjectDir());
@@ -82,7 +82,7 @@ public function testAboutWithUnreadableFiles()
private function createCommandTester(TestAppKernel $kernel): CommandTester
{
$application = new Application($kernel);
- $application->add(new AboutCommand());
+ $application->addCommand(new AboutCommand());
return new CommandTester($application->find('about'));
}
diff --git a/Tests/Command/CachePoolClearCommandTest.php b/Tests/Command/CachePoolClearCommandTest.php
index 3a927f217..dcf788134 100644
--- a/Tests/Command/CachePoolClearCommandTest.php
+++ b/Tests/Command/CachePoolClearCommandTest.php
@@ -11,6 +11,7 @@
namespace Symfony\Bundle\FrameworkBundle\Tests\Command;
+use PHPUnit\Framework\Attributes\DataProvider;
use PHPUnit\Framework\MockObject\MockObject;
use Psr\Cache\CacheItemPoolInterface;
use Symfony\Bundle\FrameworkBundle\Command\CachePoolClearCommand;
@@ -30,13 +31,11 @@ protected function setUp(): void
$this->cachePool = $this->createMock(CacheItemPoolInterface::class);
}
- /**
- * @dataProvider provideCompletionSuggestions
- */
+ #[DataProvider('provideCompletionSuggestions')]
public function testComplete(array $input, array $expectedSuggestions)
{
$application = new Application($this->getKernel());
- $application->add(new CachePoolClearCommand(new Psr6CacheClearer(['foo' => $this->cachePool]), ['foo']));
+ $application->addCommand(new CachePoolClearCommand(new Psr6CacheClearer(['foo' => $this->cachePool]), ['foo']));
$tester = new CommandCompletionTester($application->get('cache:pool:clear'));
$suggestions = $tester->complete($input);
diff --git a/Tests/Command/CachePoolDeleteCommandTest.php b/Tests/Command/CachePoolDeleteCommandTest.php
index 3db39e121..afd3ecdd7 100644
--- a/Tests/Command/CachePoolDeleteCommandTest.php
+++ b/Tests/Command/CachePoolDeleteCommandTest.php
@@ -11,6 +11,7 @@
namespace Symfony\Bundle\FrameworkBundle\Tests\Command;
+use PHPUnit\Framework\Attributes\DataProvider;
use PHPUnit\Framework\MockObject\MockObject;
use Psr\Cache\CacheItemPoolInterface;
use Symfony\Bundle\FrameworkBundle\Command\CachePoolDeleteCommand;
@@ -84,13 +85,11 @@ public function testCommandDeleteFailed()
$tester->execute(['pool' => 'foo', 'key' => 'bar']);
}
- /**
- * @dataProvider provideCompletionSuggestions
- */
+ #[DataProvider('provideCompletionSuggestions')]
public function testComplete(array $input, array $expectedSuggestions)
{
$application = new Application($this->getKernel());
- $application->add(new CachePoolDeleteCommand(new Psr6CacheClearer(['foo' => $this->cachePool]), ['foo']));
+ $application->addCommand(new CachePoolDeleteCommand(new Psr6CacheClearer(['foo' => $this->cachePool]), ['foo']));
$tester = new CommandCompletionTester($application->get('cache:pool:delete'));
$suggestions = $tester->complete($input);
@@ -125,7 +124,7 @@ private function getKernel(): MockObject&KernelInterface
private function getCommandTester(KernelInterface $kernel): CommandTester
{
$application = new Application($kernel);
- $application->add(new CachePoolDeleteCommand(new Psr6CacheClearer(['foo' => $this->cachePool])));
+ $application->addCommand(new CachePoolDeleteCommand(new Psr6CacheClearer(['foo' => $this->cachePool])));
return new CommandTester($application->find('cache:pool:delete'));
}
diff --git a/Tests/Command/CachePruneCommandTest.php b/Tests/Command/CachePruneCommandTest.php
index a2d0ad7fe..18a3622f2 100644
--- a/Tests/Command/CachePruneCommandTest.php
+++ b/Tests/Command/CachePruneCommandTest.php
@@ -77,7 +77,7 @@ private function getPruneableInterfaceMock(): MockObject&PruneableInterface
private function getCommandTester(KernelInterface $kernel, RewindableGenerator $generator): CommandTester
{
$application = new Application($kernel);
- $application->add(new CachePoolPruneCommand($generator));
+ $application->addCommand(new CachePoolPruneCommand($generator));
return new CommandTester($application->find('cache:pool:prune'));
}
diff --git a/Tests/Command/EventDispatcherDebugCommandTest.php b/Tests/Command/EventDispatcherDebugCommandTest.php
index 359196e11..7dc1e0dc6 100644
--- a/Tests/Command/EventDispatcherDebugCommandTest.php
+++ b/Tests/Command/EventDispatcherDebugCommandTest.php
@@ -11,6 +11,7 @@
namespace Symfony\Bundle\FrameworkBundle\Tests\Command;
+use PHPUnit\Framework\Attributes\DataProvider;
use PHPUnit\Framework\TestCase;
use Symfony\Bundle\FrameworkBundle\Command\EventDispatcherDebugCommand;
use Symfony\Component\Console\Tester\CommandCompletionTester;
@@ -20,9 +21,7 @@
class EventDispatcherDebugCommandTest extends TestCase
{
- /**
- * @dataProvider provideCompletionSuggestions
- */
+ #[DataProvider('provideCompletionSuggestions')]
public function testComplete(array $input, array $expectedSuggestions)
{
$tester = $this->createCommandCompletionTester();
diff --git a/Tests/Command/RouterMatchCommandTest.php b/Tests/Command/RouterMatchCommandTest.php
index b6b6771f9..97b1859be 100644
--- a/Tests/Command/RouterMatchCommandTest.php
+++ b/Tests/Command/RouterMatchCommandTest.php
@@ -46,8 +46,8 @@ public function testWithNotMatchPath()
private function createCommandTester(): CommandTester
{
$application = new Application($this->getKernel());
- $application->add(new RouterMatchCommand($this->getRouter()));
- $application->add(new RouterDebugCommand($this->getRouter()));
+ $application->addCommand(new RouterMatchCommand($this->getRouter()));
+ $application->addCommand(new RouterDebugCommand($this->getRouter()));
return new CommandTester($application->find('router:match'));
}
diff --git a/Tests/Command/SecretsDecryptToLocalCommandTest.php b/Tests/Command/SecretsDecryptToLocalCommandTest.php
index 8a1c05d69..fb5a66194 100644
--- a/Tests/Command/SecretsDecryptToLocalCommandTest.php
+++ b/Tests/Command/SecretsDecryptToLocalCommandTest.php
@@ -11,15 +11,14 @@
namespace Symfony\Bundle\FrameworkBundle\Tests\Command;
+use PHPUnit\Framework\Attributes\RequiresPhpExtension;
use PHPUnit\Framework\TestCase;
use Symfony\Bundle\FrameworkBundle\Command\SecretsDecryptToLocalCommand;
use Symfony\Bundle\FrameworkBundle\Secrets\SodiumVault;
use Symfony\Component\Console\Tester\CommandTester;
use Symfony\Component\Filesystem\Filesystem;
-/**
- * @requires extension sodium
- */
+#[RequiresPhpExtension('sodium')]
class SecretsDecryptToLocalCommandTest extends TestCase
{
private string $mainDir;
diff --git a/Tests/Command/SecretsEncryptFromLocalCommandTest.php b/Tests/Command/SecretsEncryptFromLocalCommandTest.php
index 68926c175..6e458913a 100644
--- a/Tests/Command/SecretsEncryptFromLocalCommandTest.php
+++ b/Tests/Command/SecretsEncryptFromLocalCommandTest.php
@@ -11,6 +11,7 @@
namespace Symfony\Bundle\FrameworkBundle\Tests\Command;
+use PHPUnit\Framework\Attributes\RequiresPhpExtension;
use PHPUnit\Framework\TestCase;
use Symfony\Bundle\FrameworkBundle\Command\SecretsEncryptFromLocalCommand;
use Symfony\Bundle\FrameworkBundle\Secrets\AbstractVault;
@@ -18,9 +19,7 @@
use Symfony\Component\Console\Tester\CommandTester;
use Symfony\Component\Filesystem\Filesystem;
-/**
- * @requires extension sodium
- */
+#[RequiresPhpExtension('sodium')]
class SecretsEncryptFromLocalCommandTest extends TestCase
{
private string $vaultDir;
diff --git a/Tests/Command/SecretsGenerateKeysCommandTest.php b/Tests/Command/SecretsGenerateKeysCommandTest.php
index 9574782bf..2940fcfc3 100644
--- a/Tests/Command/SecretsGenerateKeysCommandTest.php
+++ b/Tests/Command/SecretsGenerateKeysCommandTest.php
@@ -11,6 +11,7 @@
namespace Symfony\Bundle\FrameworkBundle\Tests\Command;
+use PHPUnit\Framework\Attributes\RequiresPhpExtension;
use PHPUnit\Framework\TestCase;
use Symfony\Bundle\FrameworkBundle\Command\SecretsGenerateKeysCommand;
use Symfony\Bundle\FrameworkBundle\Secrets\AbstractVault;
@@ -18,9 +19,7 @@
use Symfony\Component\Console\Tester\CommandTester;
use Symfony\Component\Filesystem\Filesystem;
-/**
- * @requires extension sodium
- */
+#[RequiresPhpExtension('sodium')]
class SecretsGenerateKeysCommandTest extends TestCase
{
private string $secretsDir;
diff --git a/Tests/Command/SecretsListCommandTest.php b/Tests/Command/SecretsListCommandTest.php
index 12d3ab2e8..de09d8941 100644
--- a/Tests/Command/SecretsListCommandTest.php
+++ b/Tests/Command/SecretsListCommandTest.php
@@ -11,6 +11,7 @@
namespace Symfony\Bundle\FrameworkBundle\Tests\Command;
+use PHPUnit\Framework\Attributes\BackupGlobals;
use PHPUnit\Framework\TestCase;
use Symfony\Bundle\FrameworkBundle\Command\SecretsListCommand;
use Symfony\Bundle\FrameworkBundle\Secrets\AbstractVault;
@@ -19,9 +20,7 @@
class SecretsListCommandTest extends TestCase
{
- /**
- * @backupGlobals enabled
- */
+ #[BackupGlobals(true)]
public function testExecute()
{
$vault = $this->createMock(AbstractVault::class);
diff --git a/Tests/Command/SecretsRemoveCommandTest.php b/Tests/Command/SecretsRemoveCommandTest.php
index 2c12b6128..d09fa3c01 100644
--- a/Tests/Command/SecretsRemoveCommandTest.php
+++ b/Tests/Command/SecretsRemoveCommandTest.php
@@ -11,6 +11,7 @@
namespace Symfony\Bundle\FrameworkBundle\Tests\Command;
+use PHPUnit\Framework\Attributes\DataProvider;
use PHPUnit\Framework\TestCase;
use Symfony\Bundle\FrameworkBundle\Command\SecretsRemoveCommand;
use Symfony\Bundle\FrameworkBundle\Secrets\AbstractVault;
@@ -18,9 +19,7 @@
class SecretsRemoveCommandTest extends TestCase
{
- /**
- * @dataProvider provideCompletionSuggestions
- */
+ #[DataProvider('provideCompletionSuggestions')]
public function testComplete(bool $withLocalVault, array $input, array $expectedSuggestions)
{
$vault = $this->createMock(AbstractVault::class);
diff --git a/Tests/Command/SecretsRevealCommandTest.php b/Tests/Command/SecretsRevealCommandTest.php
index d77d303d5..37065d1c0 100644
--- a/Tests/Command/SecretsRevealCommandTest.php
+++ b/Tests/Command/SecretsRevealCommandTest.php
@@ -11,6 +11,7 @@
namespace Symfony\Bundle\FrameworkBundle\Tests\Command;
+use PHPUnit\Framework\Attributes\BackupGlobals;
use PHPUnit\Framework\TestCase;
use Symfony\Bundle\FrameworkBundle\Command\SecretsRevealCommand;
use Symfony\Bundle\FrameworkBundle\Secrets\AbstractVault;
@@ -59,9 +60,7 @@ public function testFailedDecrypt()
$this->assertStringContainsString('The secret "secretKey" could not be decrypted.', trim($tester->getDisplay(true)));
}
- /**
- * @backupGlobals enabled
- */
+ #[BackupGlobals(true)]
public function testLocalVaultOverride()
{
$vault = $this->createMock(AbstractVault::class);
@@ -78,9 +77,7 @@ public function testLocalVaultOverride()
$this->assertEquals('newSecretValue', trim($tester->getDisplay(true)));
}
- /**
- * @backupGlobals enabled
- */
+ #[BackupGlobals(true)]
public function testOnlyLocalVaultContainsName()
{
$vault = $this->createMock(AbstractVault::class);
diff --git a/Tests/Command/SecretsSetCommandTest.php b/Tests/Command/SecretsSetCommandTest.php
index 678fb417c..57db9c529 100644
--- a/Tests/Command/SecretsSetCommandTest.php
+++ b/Tests/Command/SecretsSetCommandTest.php
@@ -11,6 +11,7 @@
namespace Symfony\Bundle\FrameworkBundle\Tests\Command;
+use PHPUnit\Framework\Attributes\DataProvider;
use PHPUnit\Framework\TestCase;
use Symfony\Bundle\FrameworkBundle\Command\SecretsSetCommand;
use Symfony\Bundle\FrameworkBundle\Secrets\AbstractVault;
@@ -18,9 +19,7 @@
class SecretsSetCommandTest extends TestCase
{
- /**
- * @dataProvider provideCompletionSuggestions
- */
+ #[DataProvider('provideCompletionSuggestions')]
public function testComplete(array $input, array $expectedSuggestions)
{
$vault = $this->createMock(AbstractVault::class);
diff --git a/Tests/Command/TranslationDebugCommandTest.php b/Tests/Command/TranslationDebugCommandTest.php
index c6c91a857..e0e49fd2e 100644
--- a/Tests/Command/TranslationDebugCommandTest.php
+++ b/Tests/Command/TranslationDebugCommandTest.php
@@ -11,6 +11,7 @@
namespace Symfony\Bundle\FrameworkBundle\Tests\Command;
+use PHPUnit\Framework\Attributes\DataProvider;
use PHPUnit\Framework\TestCase;
use Symfony\Bundle\FrameworkBundle\Command\TranslationDebugCommand;
use Symfony\Bundle\FrameworkBundle\Console\Application;
@@ -223,7 +224,7 @@ function ($path, $catalogue) use ($loadedMessages) {
$command = new TranslationDebugCommand($translator, $loader, $extractor, $this->translationDir.'/translations', $this->translationDir.'/templates', $transPaths, $codePaths, $enabledLocales);
$application = new Application($kernel);
- $application->add($command);
+ $application->addCommand($command);
return $application->find('debug:translation');
}
@@ -240,9 +241,7 @@ private function getBundle($path)
return $bundle;
}
- /**
- * @dataProvider provideCompletionSuggestions
- */
+ #[DataProvider('provideCompletionSuggestions')]
public function testComplete(array $input, array $expectedSuggestions)
{
$extractedMessagesWithDomains = [
diff --git a/Tests/Command/TranslationExtractCommandCompletionTest.php b/Tests/Command/TranslationExtractCommandCompletionTest.php
index 6d2f22d96..49874fe7c 100644
--- a/Tests/Command/TranslationExtractCommandCompletionTest.php
+++ b/Tests/Command/TranslationExtractCommandCompletionTest.php
@@ -11,6 +11,7 @@
namespace Symfony\Bundle\FrameworkBundle\Tests\Command;
+use PHPUnit\Framework\Attributes\DataProvider;
use PHPUnit\Framework\TestCase;
use Symfony\Bundle\FrameworkBundle\Command\TranslationExtractCommand;
use Symfony\Bundle\FrameworkBundle\Console\Application;
@@ -30,9 +31,7 @@ class TranslationExtractCommandCompletionTest extends TestCase
private Filesystem $fs;
private string $translationDir;
- /**
- * @dataProvider provideCompletionSuggestions
- */
+ #[DataProvider('provideCompletionSuggestions')]
public function testComplete(array $input, array $expectedSuggestions)
{
$tester = $this->createCommandCompletionTester(['messages' => ['foo' => 'foo']]);
@@ -132,7 +131,7 @@ function ($path, $catalogue) use ($loadedMessages) {
$command = new TranslationExtractCommand($writer, $loader, $extractor, 'en', $this->translationDir.'/translations', $this->translationDir.'/templates', $transPaths, $codePaths, ['en', 'fr']);
$application = new Application($kernel);
- $application->add($command);
+ $application->addCommand($command);
return new CommandCompletionTester($application->find('translation:extract'));
}
diff --git a/Tests/Command/TranslationExtractCommandTest.php b/Tests/Command/TranslationExtractCommandTest.php
index c5e78de12..276af4476 100644
--- a/Tests/Command/TranslationExtractCommandTest.php
+++ b/Tests/Command/TranslationExtractCommandTest.php
@@ -11,6 +11,7 @@
namespace Symfony\Bundle\FrameworkBundle\Tests\Command;
+use PHPUnit\Framework\Attributes\DataProvider;
use PHPUnit\Framework\TestCase;
use Symfony\Bundle\FrameworkBundle\Command\TranslationExtractCommand;
use Symfony\Bundle\FrameworkBundle\Console\Application;
@@ -154,12 +155,12 @@ public function testFilterDuplicateTransPaths()
if (preg_match('/\.[a-z]+$/', $transPath)) {
if (!realpath(\dirname($transPath))) {
- mkdir(\dirname($transPath), 0777, true);
+ mkdir(\dirname($transPath), 0o777, true);
}
touch($transPath);
} else {
- mkdir($transPath, 0777, true);
+ mkdir($transPath, 0o777, true);
}
}
@@ -177,9 +178,7 @@ public function testFilterDuplicateTransPaths()
$this->assertEquals($expectedPaths, $filteredTransPaths);
}
- /**
- * @dataProvider removeNoFillProvider
- */
+ #[DataProvider('removeNoFillProvider')]
public function testRemoveNoFillTranslationsMethod($noFillCounter, $messages)
{
// Preparing mock
@@ -304,7 +303,7 @@ function (MessageCatalogue $catalogue) use ($writerMessages) {
$command = new TranslationExtractCommand($writer, $loader, $extractor, 'en', $this->translationDir.'/translations', $this->translationDir.'/templates', $transPaths, $codePaths);
$application = new Application($kernel);
- $application->add($command);
+ $application->addCommand($command);
return new CommandTester($application->find('translation:extract'));
}
diff --git a/Tests/Command/WorkflowDumpCommandTest.php b/Tests/Command/WorkflowDumpCommandTest.php
index 284e97623..d7d17a923 100644
--- a/Tests/Command/WorkflowDumpCommandTest.php
+++ b/Tests/Command/WorkflowDumpCommandTest.php
@@ -11,6 +11,7 @@
namespace Symfony\Bundle\FrameworkBundle\Tests\Command;
+use PHPUnit\Framework\Attributes\DataProvider;
use PHPUnit\Framework\TestCase;
use Symfony\Bundle\FrameworkBundle\Command\WorkflowDumpCommand;
use Symfony\Component\Console\Application;
@@ -19,13 +20,16 @@
class WorkflowDumpCommandTest extends TestCase
{
- /**
- * @dataProvider provideCompletionSuggestions
- */
+ #[DataProvider('provideCompletionSuggestions')]
public function testComplete(array $input, array $expectedSuggestions)
{
$application = new Application();
- $application->add(new WorkflowDumpCommand(new ServiceLocator([])));
+ $command = new WorkflowDumpCommand(new ServiceLocator([]));
+ if (method_exists($application, 'addCommand')) {
+ $application->addCommand($command);
+ } else {
+ $application->add($command);
+ }
$tester = new CommandCompletionTester($application->find('workflow:dump'));
$suggestions = $tester->complete($input, 2);
diff --git a/Tests/Command/XliffLintCommandTest.php b/Tests/Command/XliffLintCommandTest.php
index d5495ada9..f10834c5b 100644
--- a/Tests/Command/XliffLintCommandTest.php
+++ b/Tests/Command/XliffLintCommandTest.php
@@ -35,10 +35,10 @@ public function testGetHelp()
{
$command = new XliffLintCommand();
$expected = <<php %command.full_name% @AcmeDemoBundle
-EOF;
+ php %command.full_name% @AcmeDemoBundle
+ EOF;
$this->assertStringContainsString($expected, $command->getHelp());
}
@@ -59,7 +59,12 @@ private function createCommandTester($application = null): CommandTester
{
if (!$application) {
$application = new BaseApplication();
- $application->add(new XliffLintCommand());
+ $command = new XliffLintCommand();
+ if (method_exists($application, 'addCommand')) {
+ $application->addCommand($command);
+ } else {
+ $application->add($command);
+ }
}
$command = $application->find('lint:xliff');
diff --git a/Tests/Command/YamlLintCommandTest.php b/Tests/Command/YamlLintCommandTest.php
index ec2093119..28c55a5ba 100644
--- a/Tests/Command/YamlLintCommandTest.php
+++ b/Tests/Command/YamlLintCommandTest.php
@@ -73,10 +73,10 @@ public function testGetHelp()
{
$command = new YamlLintCommand();
$expected = <<php %command.full_name% @AcmeDemoBundle
-EOF;
+ php %command.full_name% @AcmeDemoBundle
+ EOF;
$this->assertStringContainsString($expected, $command->getHelp());
}
@@ -107,7 +107,12 @@ private function createCommandTester($application = null): CommandTester
{
if (!$application) {
$application = new BaseApplication();
- $application->add(new YamlLintCommand());
+ $command = new YamlLintCommand();
+ if (method_exists($application, 'addCommand')) {
+ $application->addCommand($command);
+ } else {
+ $application->add($command);
+ }
}
$command = $application->find('lint:yaml');
diff --git a/Tests/Console/ApplicationTest.php b/Tests/Console/ApplicationTest.php
index 0b92a813c..7f712107c 100644
--- a/Tests/Console/ApplicationTest.php
+++ b/Tests/Console/ApplicationTest.php
@@ -119,7 +119,7 @@ public function testBundleCommandCanOverriddeAPreExistingCommandWithTheSameName(
$application = new Application($kernel);
$newCommand = new Command('example');
- $application->add($newCommand);
+ $application->addCommand($newCommand);
$this->assertSame($newCommand, $application->get('example'));
}
diff --git a/Tests/Console/Descriptor/AbstractDescriptorTestCase.php b/Tests/Console/Descriptor/AbstractDescriptorTestCase.php
index eb18fbcc7..a6cbd3085 100644
--- a/Tests/Console/Descriptor/AbstractDescriptorTestCase.php
+++ b/Tests/Console/Descriptor/AbstractDescriptorTestCase.php
@@ -11,6 +11,9 @@
namespace Symfony\Bundle\FrameworkBundle\Tests\Console\Descriptor;
+use PHPUnit\Framework\Attributes\DataProvider;
+use PHPUnit\Framework\Attributes\Group;
+use PHPUnit\Framework\Attributes\IgnoreDeprecations;
use PHPUnit\Framework\TestCase;
use Symfony\Bundle\FrameworkBundle\Tests\Fixtures\FooUnitEnum;
use Symfony\Component\Console\Input\ArrayInput;
@@ -39,8 +42,8 @@ protected function tearDown(): void
putenv($this->colSize ? 'COLUMNS='.$this->colSize : 'COLUMNS');
}
- /** @dataProvider getDescribeRouteCollectionTestData */
- public function testDescribeRouteCollection(RouteCollection $routes, $expectedDescription)
+ #[DataProvider('getDescribeRouteCollectionTestData')]
+ public function testDescribeRouteCollection(RouteCollection $routes, $expectedDescription, $file)
{
$this->assertDescription($expectedDescription, $routes);
}
@@ -50,8 +53,8 @@ public static function getDescribeRouteCollectionTestData(): array
return static::getDescriptionTestData(ObjectsProvider::getRouteCollections());
}
- /** @dataProvider getDescribeRouteCollectionWithHttpMethodFilterTestData */
- public function testDescribeRouteCollectionWithHttpMethodFilter(string $httpMethod, RouteCollection $routes, $expectedDescription)
+ #[DataProvider('getDescribeRouteCollectionWithHttpMethodFilterTestData')]
+ public function testDescribeRouteCollectionWithHttpMethodFilter(string $httpMethod, RouteCollection $routes, $expectedDescription, $file)
{
$this->assertDescription($expectedDescription, $routes, ['method' => $httpMethod]);
}
@@ -65,8 +68,8 @@ public static function getDescribeRouteCollectionWithHttpMethodFilterTestData():
}
}
- /** @dataProvider getDescribeRouteTestData */
- public function testDescribeRoute(Route $route, $expectedDescription)
+ #[DataProvider('getDescribeRouteTestData')]
+ public function testDescribeRoute(Route $route, $expectedDescription, $file)
{
$this->assertDescription($expectedDescription, $route);
}
@@ -76,8 +79,8 @@ public static function getDescribeRouteTestData(): array
return static::getDescriptionTestData(ObjectsProvider::getRoutes());
}
- /** @dataProvider getDescribeContainerParametersTestData */
- public function testDescribeContainerParameters(ParameterBag $parameters, $expectedDescription)
+ #[DataProvider('getDescribeContainerParametersTestData')]
+ public function testDescribeContainerParameters(ParameterBag $parameters, $expectedDescription, $file)
{
$this->assertDescription($expectedDescription, $parameters);
}
@@ -87,8 +90,8 @@ public static function getDescribeContainerParametersTestData(): array
return static::getDescriptionTestData(ObjectsProvider::getContainerParameters());
}
- /** @dataProvider getDescribeContainerBuilderTestData */
- public function testDescribeContainerBuilder(ContainerBuilder $builder, $expectedDescription, array $options)
+ #[DataProvider('getDescribeContainerBuilderTestData')]
+ public function testDescribeContainerBuilder(ContainerBuilder $builder, $expectedDescription, array $options, $file)
{
$this->assertDescription($expectedDescription, $builder, $options);
}
@@ -98,10 +101,8 @@ public static function getDescribeContainerBuilderTestData(): array
return static::getContainerBuilderDescriptionTestData(ObjectsProvider::getContainerBuilders());
}
- /**
- * @dataProvider getDescribeContainerExistingClassDefinitionTestData
- */
- public function testDescribeContainerExistingClassDefinition(Definition $definition, $expectedDescription)
+ #[DataProvider('getDescribeContainerExistingClassDefinitionTestData')]
+ public function testDescribeContainerExistingClassDefinition(Definition $definition, $expectedDescription, $file)
{
$this->assertDescription($expectedDescription, $definition);
}
@@ -111,8 +112,8 @@ public static function getDescribeContainerExistingClassDefinitionTestData(): ar
return static::getDescriptionTestData(ObjectsProvider::getContainerDefinitionsWithExistingClasses());
}
- /** @dataProvider getDescribeContainerDefinitionTestData */
- public function testDescribeContainerDefinition(Definition $definition, $expectedDescription)
+ #[DataProvider('getDescribeContainerDefinitionTestData')]
+ public function testDescribeContainerDefinition(Definition $definition, $expectedDescription, $file)
{
$this->assertDescription($expectedDescription, $definition);
}
@@ -122,8 +123,8 @@ public static function getDescribeContainerDefinitionTestData(): array
return static::getDescriptionTestData(ObjectsProvider::getContainerDefinitions());
}
- /** @dataProvider getDescribeContainerDefinitionWithArgumentsShownTestData */
- public function testDescribeContainerDefinitionWithArgumentsShown(Definition $definition, $expectedDescription)
+ #[DataProvider('getDescribeContainerDefinitionWithArgumentsShownTestData')]
+ public function testDescribeContainerDefinitionWithArgumentsShown(Definition $definition, $expectedDescription, $file)
{
$this->assertDescription($expectedDescription, $definition, []);
}
@@ -142,8 +143,8 @@ public static function getDescribeContainerDefinitionWithArgumentsShownTestData(
return static::getDescriptionTestData($definitionsWithArgs);
}
- /** @dataProvider getDescribeContainerAliasTestData */
- public function testDescribeContainerAlias(Alias $alias, $expectedDescription)
+ #[DataProvider('getDescribeContainerAliasTestData')]
+ public function testDescribeContainerAlias(Alias $alias, $expectedDescription, $file)
{
$this->assertDescription($expectedDescription, $alias);
}
@@ -153,8 +154,8 @@ public static function getDescribeContainerAliasTestData(): array
return static::getDescriptionTestData(ObjectsProvider::getContainerAliases());
}
- /** @dataProvider getDescribeContainerDefinitionWhichIsAnAliasTestData */
- public function testDescribeContainerDefinitionWhichIsAnAlias(Alias $alias, $expectedDescription, ContainerBuilder $builder, $options = [])
+ #[DataProvider('getDescribeContainerDefinitionWhichIsAnAliasTestData')]
+ public function testDescribeContainerDefinitionWhichIsAnAlias(Alias $alias, $expectedDescription, ContainerBuilder $builder, $options = [], $file = null)
{
$this->assertDescription($expectedDescription, $builder, $options);
}
@@ -185,13 +186,12 @@ public static function getDescribeContainerDefinitionWhichIsAnAliasTestData(): a
}
/**
- * The legacy group must be kept as deprecations will always be raised.
- *
- * @group legacy
- *
- * @dataProvider getDescribeContainerParameterTestData
+ * The #[IgnoreDeprecation] attribute must be kept as deprecations will always be raised.
*/
- public function testDescribeContainerParameter($parameter, $expectedDescription, array $options)
+ #[IgnoreDeprecations]
+ #[Group('legacy')]
+ #[DataProvider('getDescribeContainerParameterTestData')]
+ public function testDescribeContainerParameter($parameter, $expectedDescription, array $options, $file)
{
$this->assertDescription($expectedDescription, $parameter, $options);
}
@@ -213,8 +213,8 @@ public static function getDescribeContainerParameterTestData(): array
return $data;
}
- /** @dataProvider getDescribeEventDispatcherTestData */
- public function testDescribeEventDispatcher(EventDispatcher $eventDispatcher, $expectedDescription, array $options)
+ #[DataProvider('getDescribeEventDispatcherTestData')]
+ public function testDescribeEventDispatcher(EventDispatcher $eventDispatcher, $expectedDescription, array $options, $file)
{
$this->assertDescription($expectedDescription, $eventDispatcher, $options);
}
@@ -224,8 +224,8 @@ public static function getDescribeEventDispatcherTestData(): array
return static::getEventDispatcherDescriptionTestData(ObjectsProvider::getEventDispatchers());
}
- /** @dataProvider getDescribeCallableTestData */
- public function testDescribeCallable($callable, $expectedDescription)
+ #[DataProvider('getDescribeCallableTestData')]
+ public function testDescribeCallable($callable, $expectedDescription, $file)
{
$this->assertDescription($expectedDescription, $callable);
}
@@ -235,12 +235,10 @@ public static function getDescribeCallableTestData(): array
return static::getDescriptionTestData(ObjectsProvider::getCallables());
}
- /**
- * @group legacy
- *
- * @dataProvider getDescribeDeprecatedCallableTestData
- */
- public function testDescribeDeprecatedCallable($callable, $expectedDescription)
+ #[IgnoreDeprecations]
+ #[Group('legacy')]
+ #[DataProvider('getDescribeDeprecatedCallableTestData')]
+ public function testDescribeDeprecatedCallable($callable, $expectedDescription, $file)
{
$this->assertDescription($expectedDescription, $callable);
}
@@ -250,7 +248,7 @@ public static function getDescribeDeprecatedCallableTestData(): array
return static::getDescriptionTestData(ObjectsProvider::getDeprecatedCallables());
}
- /** @dataProvider getClassDescriptionTestData */
+ #[DataProvider('getClassDescriptionTestData')]
public function testGetClassDescription($object, $expectedDescription)
{
$this->assertEquals($expectedDescription, $this->getDescriptor()->getClassDescription($object));
@@ -266,10 +264,8 @@ public static function getClassDescriptionTestData(): array
];
}
- /**
- * @dataProvider getDeprecationsTestData
- */
- public function testGetDeprecations(ContainerBuilder $builder, $expectedDescription)
+ #[DataProvider('getDeprecationsTestData')]
+ public function testGetDeprecations(ContainerBuilder $builder, $expectedDescription, $file)
{
$this->assertDescription($expectedDescription, $builder, ['deprecations' => true]);
}
@@ -357,7 +353,7 @@ private static function getEventDispatcherDescriptionTestData(array $objects): a
return $data;
}
- /** @dataProvider getDescribeContainerBuilderWithPriorityTagsTestData */
+ #[DataProvider('getDescribeContainerBuilderWithPriorityTagsTestData')]
public function testDescribeContainerBuilderWithPriorityTags(ContainerBuilder $builder, $expectedDescription, array $options)
{
$this->assertDescription($expectedDescription, $builder, $options);
diff --git a/Tests/Console/Descriptor/TextDescriptorTest.php b/Tests/Console/Descriptor/TextDescriptorTest.php
index 34e16f5e4..101ac68a0 100644
--- a/Tests/Console/Descriptor/TextDescriptorTest.php
+++ b/Tests/Console/Descriptor/TextDescriptorTest.php
@@ -11,6 +11,7 @@
namespace Symfony\Bundle\FrameworkBundle\Tests\Console\Descriptor;
+use PHPUnit\Framework\Attributes\DataProvider;
use Symfony\Bundle\FrameworkBundle\Console\Descriptor\TextDescriptor;
use Symfony\Component\ErrorHandler\ErrorRenderer\FileLinkFormatter;
use Symfony\Component\Routing\Route;
@@ -45,11 +46,11 @@ public static function getDescribeRouteWithControllerLinkTestData()
return $getDescribeData;
}
- /** @dataProvider getDescribeRouteWithControllerLinkTestData */
- public function testDescribeRouteWithControllerLink(Route $route, $expectedDescription)
+ #[DataProvider('getDescribeRouteWithControllerLinkTestData')]
+ public function testDescribeRouteWithControllerLink(Route $route, $expectedDescription, $file)
{
static::$fileLinkFormatter = new FileLinkFormatter('myeditor://open?file=%f&line=%l');
- parent::testDescribeRoute($route, str_replace('[:file:]', __FILE__, $expectedDescription));
+ parent::testDescribeRoute($route, str_replace('[:file:]', __FILE__, $expectedDescription), $file);
}
}
diff --git a/Tests/Controller/AbstractControllerTest.php b/Tests/Controller/AbstractControllerTest.php
index 2024cb8f7..f778aa4be 100644
--- a/Tests/Controller/AbstractControllerTest.php
+++ b/Tests/Controller/AbstractControllerTest.php
@@ -11,6 +11,8 @@
namespace Symfony\Bundle\FrameworkBundle\Tests\Controller;
+use PHPUnit\Framework\Attributes\DataProvider;
+use PHPUnit\Framework\Attributes\RunInSeparateProcess;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Bundle\FrameworkBundle\Tests\TestCase;
use Symfony\Component\DependencyInjection\Container;
@@ -101,7 +103,7 @@ public function testMissingParameterBag()
$controller->setContainer($container);
$this->expectException(ServiceNotFoundException::class);
- $this->expectExceptionMessage('TestAbstractController::getParameter()" method is missing a parameter bag');
+ $this->expectExceptionMessage('::getParameter()" method is missing a parameter bag');
$controller->getParameter('foo');
}
@@ -389,9 +391,7 @@ public function testdenyAccessUnlessGranted()
}
}
- /**
- * @dataProvider provideDenyAccessUnlessGrantedSetsAttributesAsArray
- */
+ #[DataProvider('provideDenyAccessUnlessGrantedSetsAttributesAsArray')]
public function testdenyAccessUnlessGrantedSetsAttributesAsArray($attribute, $exceptionAttributes)
{
$authorizationChecker = $this->createMock(AuthorizationCheckerInterface::class);
@@ -526,9 +526,7 @@ public function testRedirectToRoute()
$this->assertSame(302, $response->getStatusCode());
}
- /**
- * @runInSeparateProcess
- */
+ #[RunInSeparateProcess]
public function testAddFlash()
{
$flashBag = new FlashBag();
diff --git a/Tests/Controller/ControllerHelperTest.php b/Tests/Controller/ControllerHelperTest.php
new file mode 100644
index 000000000..cb35c4757
--- /dev/null
+++ b/Tests/Controller/ControllerHelperTest.php
@@ -0,0 +1,64 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Bundle\FrameworkBundle\Tests\Controller;
+
+use Psr\Container\ContainerInterface;
+use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
+use Symfony\Bundle\FrameworkBundle\Controller\ControllerHelper;
+
+class ControllerHelperTest extends AbstractControllerTest
+{
+ protected function createController()
+ {
+ return new class extends ControllerHelper {
+ public function __construct()
+ {
+ }
+
+ public function setContainer(ContainerInterface $container)
+ {
+ parent::__construct($container);
+ }
+ };
+ }
+
+ public function testSync()
+ {
+ $r = new \ReflectionClass(ControllerHelper::class);
+ $m = $r->getMethod('getSubscribedServices');
+ $helperSrc = file($r->getFileName());
+ $helperSrc = implode('', \array_slice($helperSrc, $m->getStartLine() - 1, $r->getEndLine() - $m->getStartLine()));
+
+ $r = new \ReflectionClass(AbstractController::class);
+ $m = $r->getMethod('getSubscribedServices');
+ $abstractSrc = file($r->getFileName());
+ $code = [
+ implode('', \array_slice($abstractSrc, $m->getStartLine() - 1, $m->getEndLine() - $m->getStartLine() + 1)),
+ ];
+
+ foreach ($r->getMethods(\ReflectionMethod::IS_PROTECTED) as $m) {
+ if ($m->getDocComment()) {
+ $code[] = ' '.$m->getDocComment();
+ }
+ $code[] = substr_replace(implode('', \array_slice($abstractSrc, $m->getStartLine() - 1, $m->getEndLine() - $m->getStartLine() + 1)), 'public', 4, 9);
+ }
+ foreach ($r->getMethods(\ReflectionMethod::IS_PRIVATE) as $m) {
+ if ($m->getDocComment()) {
+ $code[] = ' '.$m->getDocComment();
+ }
+ $code[] = implode('', \array_slice($abstractSrc, $m->getStartLine() - 1, $m->getEndLine() - $m->getStartLine() + 1));
+ }
+ $code = implode("\n", $code);
+
+ $this->assertSame($code, $helperSrc, 'Methods from AbstractController are not properly synced in ControllerHelper');
+ }
+}
diff --git a/Tests/Controller/RedirectControllerTest.php b/Tests/Controller/RedirectControllerTest.php
index 161424e0e..55f3b33c3 100644
--- a/Tests/Controller/RedirectControllerTest.php
+++ b/Tests/Controller/RedirectControllerTest.php
@@ -11,6 +11,7 @@
namespace Symfony\Bundle\FrameworkBundle\Tests\Controller;
+use PHPUnit\Framework\Attributes\DataProvider;
use Symfony\Bundle\FrameworkBundle\Controller\RedirectController;
use Symfony\Bundle\FrameworkBundle\Tests\TestCase;
use Symfony\Component\HttpFoundation\ParameterBag;
@@ -60,9 +61,7 @@ public function testEmptyRoute()
}
}
- /**
- * @dataProvider provider
- */
+ #[DataProvider('provider')]
public function testRoute($permanent, $keepRequestMethod, $keepQueryParams, $ignoreAttributes, $expectedCode, $expectedAttributes)
{
$request = new Request();
@@ -255,9 +254,7 @@ public static function urlRedirectProvider(): array
];
}
- /**
- * @dataProvider urlRedirectProvider
- */
+ #[DataProvider('urlRedirectProvider')]
public function testUrlRedirect($scheme, $httpPort, $httpsPort, $requestScheme, $requestPort, $expectedPort)
{
$host = 'www.example.com';
@@ -287,9 +284,7 @@ public static function pathQueryParamsProvider(): array
];
}
- /**
- * @dataProvider pathQueryParamsProvider
- */
+ #[DataProvider('pathQueryParamsProvider')]
public function testPathQueryParams($expectedUrl, $path, $queryString)
{
$scheme = 'http';
diff --git a/Tests/DependencyInjection/Compiler/ProfilerPassTest.php b/Tests/DependencyInjection/Compiler/ProfilerPassTest.php
index 5a2215009..12dfc085d 100644
--- a/Tests/DependencyInjection/Compiler/ProfilerPassTest.php
+++ b/Tests/DependencyInjection/Compiler/ProfilerPassTest.php
@@ -11,6 +11,7 @@
namespace Symfony\Bundle\FrameworkBundle\Tests\DependencyInjection\Compiler;
+use PHPUnit\Framework\Attributes\DataProvider;
use PHPUnit\Framework\TestCase;
use Symfony\Bundle\FrameworkBundle\DataCollector\AbstractDataCollector;
use Symfony\Bundle\FrameworkBundle\DataCollector\TemplateAwareDataCollectorInterface;
@@ -98,9 +99,7 @@ public static function getTemplate(): string
}];
}
- /**
- * @dataProvider provideValidCollectorWithTemplateUsingAutoconfigure
- */
+ #[DataProvider('provideValidCollectorWithTemplateUsingAutoconfigure')]
public function testValidCollectorWithTemplateUsingAutoconfigure(TemplateAwareDataCollectorInterface $dataCollector)
{
$container = new ContainerBuilder();
diff --git a/Tests/DependencyInjection/Compiler/TestServiceContainerRefPassesTest.php b/Tests/DependencyInjection/Compiler/TestServiceContainerRefPassesTest.php
index fc69d5bd1..3a6824e4f 100644
--- a/Tests/DependencyInjection/Compiler/TestServiceContainerRefPassesTest.php
+++ b/Tests/DependencyInjection/Compiler/TestServiceContainerRefPassesTest.php
@@ -33,44 +33,44 @@ public function testProcess()
$container->addCompilerPass(new TestServiceContainerWeakRefPass(), PassConfig::TYPE_BEFORE_REMOVING, -32);
$container->addCompilerPass(new TestServiceContainerRealRefPass(), PassConfig::TYPE_AFTER_REMOVING);
- $container->register('Test\public_service')
+ $container->register('test.public_service', 'stdClass')
->setPublic(true)
- ->addArgument(new Reference('Test\private_used_shared_service'))
- ->addArgument(new Reference('Test\private_used_non_shared_service'))
- ->addArgument(new Reference('Test\soon_private_service'))
+ ->addArgument(new Reference('test.private_used_shared_service'))
+ ->addArgument(new Reference('test.private_used_non_shared_service'))
+ ->addArgument(new Reference('test.soon_private_service'))
;
- $container->register('Test\soon_private_service')
+ $container->register('test.soon_private_service', 'stdClass')
->setPublic(true)
->addTag('container.private', ['package' => 'foo/bar', 'version' => '1.42'])
;
- $container->register('Test\soon_private_service_decorated')
+ $container->register('test.soon_private_service_decorated', 'stdClass')
->setPublic(true)
->addTag('container.private', ['package' => 'foo/bar', 'version' => '1.42'])
;
- $container->register('Test\soon_private_service_decorator')
- ->setDecoratedService('Test\soon_private_service_decorated')
- ->setArguments(['Test\soon_private_service_decorator.inner']);
+ $container->register('test.soon_private_service_decorator', 'stdClass')
+ ->setDecoratedService('test.soon_private_service_decorated')
+ ->setArguments(['test.soon_private_service_decorator.inner']);
- $container->register('Test\private_used_shared_service');
- $container->register('Test\private_unused_shared_service');
- $container->register('Test\private_used_non_shared_service')->setShared(false);
- $container->register('Test\private_unused_non_shared_service')->setShared(false);
+ $container->register('test.private_used_shared_service', 'stdClass');
+ $container->register('test.private_unused_shared_service', 'stdClass');
+ $container->register('test.private_used_non_shared_service', 'stdClass')->setShared(false);
+ $container->register('test.private_unused_non_shared_service', 'stdClass')->setShared(false);
$container->compile();
$expected = [
- 'Test\private_used_shared_service' => new ServiceClosureArgument(new Reference('Test\private_used_shared_service')),
- 'Test\private_used_non_shared_service' => new ServiceClosureArgument(new Reference('Test\private_used_non_shared_service')),
- 'Test\soon_private_service' => new ServiceClosureArgument(new Reference('.container.private.Test\soon_private_service')),
- 'Test\soon_private_service_decorator' => new ServiceClosureArgument(new Reference('.container.private.Test\soon_private_service_decorated')),
- 'Test\soon_private_service_decorated' => new ServiceClosureArgument(new Reference('.container.private.Test\soon_private_service_decorated')),
+ 'test.private_used_shared_service' => new ServiceClosureArgument(new Reference('test.private_used_shared_service')),
+ 'test.private_used_non_shared_service' => new ServiceClosureArgument(new Reference('test.private_used_non_shared_service')),
+ 'test.soon_private_service' => new ServiceClosureArgument(new Reference('.container.private.test.soon_private_service')),
+ 'test.soon_private_service_decorator' => new ServiceClosureArgument(new Reference('.container.private.test.soon_private_service_decorated')),
+ 'test.soon_private_service_decorated' => new ServiceClosureArgument(new Reference('.container.private.test.soon_private_service_decorated')),
];
$privateServices = $container->getDefinition('test.private_services_locator')->getArgument(0);
unset($privateServices[\Symfony\Component\DependencyInjection\ContainerInterface::class], $privateServices[ContainerInterface::class]);
$this->assertEquals($expected, $privateServices);
- $this->assertFalse($container->getDefinition('Test\private_used_non_shared_service')->isShared());
+ $this->assertFalse($container->getDefinition('test.private_used_non_shared_service')->isShared());
}
}
diff --git a/Tests/DependencyInjection/ConfigurationTest.php b/Tests/DependencyInjection/ConfigurationTest.php
index c8142e98a..9bf8d5593 100644
--- a/Tests/DependencyInjection/ConfigurationTest.php
+++ b/Tests/DependencyInjection/ConfigurationTest.php
@@ -12,6 +12,7 @@
namespace Symfony\Bundle\FrameworkBundle\Tests\DependencyInjection;
use Doctrine\DBAL\Connection;
+use PHPUnit\Framework\Attributes\DataProvider;
use PHPUnit\Framework\TestCase;
use Symfony\Bundle\FrameworkBundle\DependencyInjection\Configuration;
use Symfony\Bundle\FullStack;
@@ -61,9 +62,7 @@ public function getTestValidSessionName()
];
}
- /**
- * @dataProvider getTestInvalidSessionName
- */
+ #[DataProvider('getTestInvalidSessionName')]
public function testInvalidSessionName($sessionName)
{
$processor = new Processor();
@@ -153,9 +152,7 @@ public function testAssetMapperCanBeEnabled()
$this->assertEquals($defaultConfig, $config['asset_mapper']);
}
- /**
- * @dataProvider provideImportmapPolyfillTests
- */
+ #[DataProvider('provideImportmapPolyfillTests')]
public function testAssetMapperPolyfillValue(mixed $polyfillValue, bool $isValid, mixed $expected)
{
$processor = new Processor();
@@ -189,9 +186,7 @@ public static function provideImportmapPolyfillTests()
yield [false, true, false];
}
- /**
- * @dataProvider provideValidAssetsPackageNameConfigurationTests
- */
+ #[DataProvider('provideValidAssetsPackageNameConfigurationTests')]
public function testValidAssetsPackageNameConfiguration($packageName)
{
$processor = new Processor();
@@ -221,9 +216,7 @@ public static function provideValidAssetsPackageNameConfigurationTests(): array
];
}
- /**
- * @dataProvider provideInvalidAssetConfigurationTests
- */
+ #[DataProvider('provideInvalidAssetConfigurationTests')]
public function testInvalidAssetsConfiguration(array $assetConfig, $expectedMessage)
{
$processor = new Processor();
@@ -275,9 +268,7 @@ public static function provideInvalidAssetConfigurationTests(): iterable
yield [$createPackageConfig($config), 'You cannot use both "version" and "json_manifest_path" at the same time under "assets" packages.'];
}
- /**
- * @dataProvider provideValidLockConfigurationTests
- */
+ #[DataProvider('provideValidLockConfigurationTests')]
public function testValidLockConfiguration($lockConfig, $processedConfig)
{
$processor = new Processor();
@@ -375,9 +366,7 @@ public function testLockMergeConfigs()
);
}
- /**
- * @dataProvider provideValidSemaphoreConfigurationTests
- */
+ #[DataProvider('provideValidSemaphoreConfigurationTests')]
public function testValidSemaphoreConfiguration($semaphoreConfig, $processedConfig)
{
$processor = new Processor();
diff --git a/Tests/DependencyInjection/FrameworkExtensionTestCase.php b/Tests/DependencyInjection/FrameworkExtensionTestCase.php
index 91a2d9198..ba9732239 100644
--- a/Tests/DependencyInjection/FrameworkExtensionTestCase.php
+++ b/Tests/DependencyInjection/FrameworkExtensionTestCase.php
@@ -11,8 +11,10 @@
namespace Symfony\Bundle\FrameworkBundle\Tests\DependencyInjection;
+use PHPUnit\Framework\Attributes\DataProvider;
use Psr\Cache\CacheItemPoolInterface;
use Psr\Log\LoggerAwareInterface;
+use Psr\Log\LogLevel;
use Symfony\Bundle\FrameworkBundle\DependencyInjection\FrameworkExtension;
use Symfony\Bundle\FrameworkBundle\FrameworkBundle;
use Symfony\Bundle\FrameworkBundle\Tests\DependencyInjection\Fixtures\Workflow\Validator\DefinitionValidator;
@@ -58,6 +60,10 @@
use Symfony\Component\HttpClient\ThrottlingHttpClient;
use Symfony\Component\HttpFoundation\IpUtils;
use Symfony\Component\HttpKernel\DependencyInjection\LoggerPass;
+use Symfony\Component\HttpKernel\Exception\BadRequestHttpException;
+use Symfony\Component\HttpKernel\Exception\ConflictHttpException;
+use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
+use Symfony\Component\HttpKernel\Exception\ServiceUnavailableHttpException;
use Symfony\Component\HttpKernel\Fragment\FragmentUriGeneratorInterface;
use Symfony\Component\Lock\Store\SemaphoreStore;
use Symfony\Component\Messenger\Bridge\AmazonSqs\Transport\AmazonSqsTransportFactory;
@@ -598,8 +604,8 @@ public function testPhpErrorsWithLogLevels()
$definition = $container->getDefinition('debug.error_handler_configurator');
$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,
+ \E_NOTICE => LogLevel::ERROR,
+ \E_WARNING => LogLevel::ERROR,
], $definition->getArgument(1));
}
@@ -610,35 +616,35 @@ public function testExceptionsConfig()
$configuration = $container->getDefinition('exception_listener')->getArgument(3);
$this->assertSame([
- \Symfony\Component\HttpKernel\Exception\BadRequestHttpException::class,
- \Symfony\Component\HttpKernel\Exception\NotFoundHttpException::class,
- \Symfony\Component\HttpKernel\Exception\ConflictHttpException::class,
- \Symfony\Component\HttpKernel\Exception\ServiceUnavailableHttpException::class,
+ BadRequestHttpException::class,
+ NotFoundHttpException::class,
+ ConflictHttpException::class,
+ ServiceUnavailableHttpException::class,
], array_keys($configuration));
$this->assertEqualsCanonicalizing([
'log_channel' => null,
'log_level' => 'info',
'status_code' => 422,
- ], $configuration[\Symfony\Component\HttpKernel\Exception\BadRequestHttpException::class]);
+ ], $configuration[BadRequestHttpException::class]);
$this->assertEqualsCanonicalizing([
'log_channel' => null,
'log_level' => 'info',
'status_code' => null,
- ], $configuration[\Symfony\Component\HttpKernel\Exception\NotFoundHttpException::class]);
+ ], $configuration[NotFoundHttpException::class]);
$this->assertEqualsCanonicalizing([
'log_channel' => null,
'log_level' => 'info',
'status_code' => null,
- ], $configuration[\Symfony\Component\HttpKernel\Exception\ConflictHttpException::class]);
+ ], $configuration[ConflictHttpException::class]);
$this->assertEqualsCanonicalizing([
'log_channel' => null,
'log_level' => null,
'status_code' => 500,
- ], $configuration[\Symfony\Component\HttpKernel\Exception\ServiceUnavailableHttpException::class]);
+ ], $configuration[ServiceUnavailableHttpException::class]);
}
public function testRouter()
@@ -1934,9 +1940,7 @@ public function testRedisTagAwareAdapter()
}
}
- /**
- * @dataProvider appRedisTagAwareConfigProvider
- */
+ #[DataProvider('appRedisTagAwareConfigProvider')]
public function testAppRedisTagAwareAdapter(string $configFile)
{
$container = $this->createContainerFromFile($configFile);
@@ -1980,9 +1984,7 @@ public function testCacheTaggableTagAppliedToPools()
}
}
- /**
- * @dataProvider appRedisTagAwareConfigProvider
- */
+ #[DataProvider('appRedisTagAwareConfigProvider')]
public function testCacheTaggableTagAppliedToRedisAwareAppPool(string $configFile)
{
$container = $this->createContainerFromFile($configFile);
@@ -2222,9 +2224,7 @@ public static function provideMailer(): iterable
];
}
- /**
- * @dataProvider provideMailer
- */
+ #[DataProvider('provideMailer')]
public function testMailer(string $configFile, array $expectedTransports, array $expectedRecipients, array $expectedAllowedRecipients)
{
$container = $this->createContainerFromFile($configFile);
diff --git a/Tests/DependencyInjection/PhpFrameworkExtensionTest.php b/Tests/DependencyInjection/PhpFrameworkExtensionTest.php
index c4f67c2f1..d3c1f8ef4 100644
--- a/Tests/DependencyInjection/PhpFrameworkExtensionTest.php
+++ b/Tests/DependencyInjection/PhpFrameworkExtensionTest.php
@@ -11,6 +11,7 @@
namespace Symfony\Bundle\FrameworkBundle\Tests\DependencyInjection;
+use PHPUnit\Framework\Attributes\DataProvider;
use Symfony\Component\Config\Definition\Exception\InvalidConfigurationException;
use Symfony\Component\Config\FileLocator;
use Symfony\Component\DependencyInjection\ContainerBuilder;
@@ -135,9 +136,7 @@ public function testWorkflowValidationStateMachine()
});
}
- /**
- * @dataProvider provideWorkflowValidationCustomTests
- */
+ #[DataProvider('provideWorkflowValidationCustomTests')]
public function testWorkflowValidationCustomBroken(string $class, string $message)
{
$this->expectException(InvalidConfigurationException::class);
@@ -431,9 +430,7 @@ public function testRateLimiterCompoundPolicyInvalidLimiters()
});
}
- /**
- * @dataProvider emailValidationModeProvider
- */
+ #[DataProvider('emailValidationModeProvider')]
public function testValidatorEmailValidationMode(string $mode)
{
$this->expectNotToPerformAssertions();
diff --git a/Tests/Fixtures/Descriptor/route_1_link.txt b/Tests/Fixtures/Descriptor/route_1_link.txt
index ad7a4c8c8..b44fb4dbd 100644
--- a/Tests/Fixtures/Descriptor/route_1_link.txt
+++ b/Tests/Fixtures/Descriptor/route_1_link.txt
@@ -10,7 +10,7 @@
| Method | GET|HEAD |
| Requirements | name: [a-z]+ |
| Class | Symfony\Bundle\FrameworkBundle\Tests\Console\Descriptor\RouteStub |
-| Defaults | _controller: ]8;;myeditor://open?file=[:file:]&line=58\Symfony\Bundle\FrameworkBundle\Tests\Console\Descriptor\MyController::__invoke()]8;;\ |
+| Defaults | _controller: ]8;;myeditor://open?file=[:file:]&line=59\Symfony\Bundle\FrameworkBundle\Tests\Console\Descriptor\MyController::__invoke()]8;;\ |
| | name: Joseph |
| Options | compiler_class: Symfony\Component\Routing\RouteCompiler |
| | opt1: val1 |
diff --git a/Tests/Fixtures/Descriptor/route_2_link.txt b/Tests/Fixtures/Descriptor/route_2_link.txt
index 8e3fe4ca7..f033787a7 100644
--- a/Tests/Fixtures/Descriptor/route_2_link.txt
+++ b/Tests/Fixtures/Descriptor/route_2_link.txt
@@ -10,7 +10,7 @@
| Method | PUT|POST |
| Requirements | NO CUSTOM |
| Class | Symfony\Bundle\FrameworkBundle\Tests\Console\Descriptor\RouteStub |
-| Defaults | _controller: ]8;;myeditor://open?file=[:file:]&line=58\Symfony\Bundle\FrameworkBundle\Tests\Console\Descriptor\MyController::__invoke()]8;;\ |
+| Defaults | _controller: ]8;;myeditor://open?file=[:file:]&line=59\Symfony\Bundle\FrameworkBundle\Tests\Console\Descriptor\MyController::__invoke()]8;;\ |
| Options | compiler_class: Symfony\Component\Routing\RouteCompiler |
| | opt1: val1 |
| | opt2: val2 |
diff --git a/Tests/Functional/AbstractAttributeRoutingTestCase.php b/Tests/Functional/AbstractAttributeRoutingTestCase.php
index 5166c8dda..842d7268f 100644
--- a/Tests/Functional/AbstractAttributeRoutingTestCase.php
+++ b/Tests/Functional/AbstractAttributeRoutingTestCase.php
@@ -11,13 +11,12 @@
namespace Symfony\Bundle\FrameworkBundle\Tests\Functional;
+use PHPUnit\Framework\Attributes\DataProvider;
use Symfony\Component\HttpFoundation\Request;
abstract class AbstractAttributeRoutingTestCase extends AbstractWebTestCase
{
- /**
- * @dataProvider getRoutes
- */
+ #[DataProvider('getRoutes')]
public function testAnnotatedController(string $path, string $expectedValue)
{
$client = $this->createClient(['test_case' => $this->getTestCaseApp(), 'root_config' => 'config.yml']);
diff --git a/Tests/Functional/ApiAttributesTest.php b/Tests/Functional/ApiAttributesTest.php
index 4848976ae..79c8a704b 100644
--- a/Tests/Functional/ApiAttributesTest.php
+++ b/Tests/Functional/ApiAttributesTest.php
@@ -11,6 +11,7 @@
namespace Symfony\Bundle\FrameworkBundle\Tests\Functional;
+use PHPUnit\Framework\Attributes\DataProvider;
use Symfony\Component\DomCrawler\Crawler;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Request;
@@ -21,9 +22,7 @@
class ApiAttributesTest extends AbstractWebTestCase
{
- /**
- * @dataProvider mapQueryStringProvider
- */
+ #[DataProvider('mapQueryStringProvider')]
public function testMapQueryString(string $uri, array $query, string $expectedResponse, int $expectedStatusCode)
{
$client = self::createClient(['test_case' => 'ApiAttributesTest']);
@@ -146,24 +145,24 @@ public static function mapQueryStringProvider(): iterable
];
$expectedResponse = <<<'JSON'
- {
- "type": "https:\/\/symfony.com\/errors\/validation",
- "title": "Validation Failed",
- "status": 404,
- "detail": "filter: This value should be of type Symfony\\Bundle\\FrameworkBundle\\Tests\\Functional\\Filter.",
- "violations": [
- {
- "parameters": {
- "hint": "Failed to create object because the class misses the \"filter\" property.",
- "{{ type }}": "Symfony\\Bundle\\FrameworkBundle\\Tests\\Functional\\Filter"
- },
- "propertyPath": "filter",
- "template": "This value should be of type {{ type }}.",
- "title": "This value should be of type Symfony\\Bundle\\FrameworkBundle\\Tests\\Functional\\Filter."
- }
- ]
- }
- JSON;
+ {
+ "type": "https:\/\/symfony.com\/errors\/validation",
+ "title": "Validation Failed",
+ "status": 404,
+ "detail": "filter: This value should be of type Symfony\\Bundle\\FrameworkBundle\\Tests\\Functional\\Filter.",
+ "violations": [
+ {
+ "parameters": {
+ "hint": "Failed to create object because the class misses the \"filter\" property.",
+ "{{ type }}": "Symfony\\Bundle\\FrameworkBundle\\Tests\\Functional\\Filter"
+ },
+ "propertyPath": "filter",
+ "template": "This value should be of type {{ type }}.",
+ "title": "This value should be of type Symfony\\Bundle\\FrameworkBundle\\Tests\\Functional\\Filter."
+ }
+ ]
+ }
+ JSON;
yield 'empty query string mapping non-nullable attribute without default value' => [
'uri' => '/map-query-string-to-non-nullable-attribute-without-default-value.json',
@@ -214,9 +213,7 @@ public static function mapQueryStringProvider(): iterable
];
}
- /**
- * @dataProvider mapRequestPayloadProvider
- */
+ #[DataProvider('mapRequestPayloadProvider')]
public function testMapRequestPayload(string $uri, string $format, array $parameters, ?string $content, callable $responseAssertion, int $expectedStatusCode)
{
$client = self::createClient(['test_case' => 'ApiAttributesTest']);
@@ -603,7 +600,7 @@ public static function mapRequestPayloadProvider(): iterable
self::assertIsArray($json['violations'] ?? null);
self::assertCount(1, $json['violations']);
self::assertSame('approved', $json['violations'][0]['propertyPath'] ?? null);
-},
+ },
'expectedStatusCode' => 422,
];
@@ -947,11 +944,11 @@ public function __invoke(#[MapRequestPayload] ?RequestBody $body, Request $reque
return new Response(
<<
- {$body->comment}
- {$body->approved}
-
- XML
+
+ {$body->comment}
+ {$body->approved}
+
+ XML
);
}
}
@@ -966,11 +963,11 @@ public function __invoke(Request $request, #[MapRequestPayload] RequestBody $bod
return new Response(
<<
- {$body->comment}
- {$body->approved}
-
- XML
+
+ {$body->comment}
+ {$body->approved}
+
+ XML
);
}
}
@@ -985,11 +982,11 @@ public function __invoke(Request $request, #[MapRequestPayload] RequestBody $bod
return new Response(
<<
- {$body->comment}
- {$body->approved}
-
- XML
+
+ {$body->comment}
+ {$body->approved}
+
+ XML
);
}
}
diff --git a/Tests/Functional/BundlePathsTest.php b/Tests/Functional/BundlePathsTest.php
index a06803434..45663f0bf 100644
--- a/Tests/Functional/BundlePathsTest.php
+++ b/Tests/Functional/BundlePathsTest.php
@@ -28,7 +28,7 @@ public function testBundlePublicDir()
$fs = new Filesystem();
$fs->remove($projectDir);
$fs->mkdir($projectDir.'/public');
- $command = (new Application($kernel))->add(new AssetsInstallCommand($fs, $projectDir));
+ $command = (new Application($kernel))->addCommand(new AssetsInstallCommand($fs, $projectDir));
$exitCode = (new CommandTester($command))->execute(['target' => $projectDir.'/public']);
$this->assertSame(0, $exitCode);
diff --git a/Tests/Functional/CachePoolClearCommandTest.php b/Tests/Functional/CachePoolClearCommandTest.php
index dbd78645d..53e8b5c48 100644
--- a/Tests/Functional/CachePoolClearCommandTest.php
+++ b/Tests/Functional/CachePoolClearCommandTest.php
@@ -11,6 +11,7 @@
namespace Symfony\Bundle\FrameworkBundle\Tests\Functional;
+use PHPUnit\Framework\Attributes\Group;
use Symfony\Bundle\FrameworkBundle\Command\CachePoolClearCommand;
use Symfony\Bundle\FrameworkBundle\Console\Application;
use Symfony\Component\Cache\Adapter\FilesystemAdapter;
@@ -19,9 +20,7 @@
use Symfony\Component\DependencyInjection\Exception\ServiceNotFoundException;
use Symfony\Component\Finder\SplFileInfo;
-/**
- * @group functional
- */
+#[Group('functional')]
class CachePoolClearCommandTest extends AbstractWebTestCase
{
protected function setUp(): void
@@ -146,7 +145,7 @@ public function testExcludedPool()
private function createCommandTester(?array $poolNames = null)
{
$application = new Application(static::$kernel);
- $application->add(new CachePoolClearCommand(static::getContainer()->get('cache.global_clearer'), $poolNames));
+ $application->addCommand(new CachePoolClearCommand(static::getContainer()->get('cache.global_clearer'), $poolNames));
return new CommandTester($application->find('cache:pool:clear'));
}
diff --git a/Tests/Functional/CachePoolListCommandTest.php b/Tests/Functional/CachePoolListCommandTest.php
index 8e9061845..6dcbc4294 100644
--- a/Tests/Functional/CachePoolListCommandTest.php
+++ b/Tests/Functional/CachePoolListCommandTest.php
@@ -11,13 +11,12 @@
namespace Symfony\Bundle\FrameworkBundle\Tests\Functional;
+use PHPUnit\Framework\Attributes\Group;
use Symfony\Bundle\FrameworkBundle\Command\CachePoolListCommand;
use Symfony\Bundle\FrameworkBundle\Console\Application;
use Symfony\Component\Console\Tester\CommandTester;
-/**
- * @group functional
- */
+#[Group('functional')]
class CachePoolListCommandTest extends AbstractWebTestCase
{
protected function setUp(): void
@@ -46,7 +45,7 @@ public function testEmptyList()
private function createCommandTester(array $poolNames)
{
$application = new Application(static::$kernel);
- $application->add(new CachePoolListCommand($poolNames));
+ $application->addCommand(new CachePoolListCommand($poolNames));
return new CommandTester($application->find('cache:pool:list'));
}
diff --git a/Tests/Functional/CachePoolsTest.php b/Tests/Functional/CachePoolsTest.php
index 23f4a116e..64829949a 100644
--- a/Tests/Functional/CachePoolsTest.php
+++ b/Tests/Functional/CachePoolsTest.php
@@ -11,6 +11,9 @@
namespace Symfony\Bundle\FrameworkBundle\Tests\Functional;
+use PHPUnit\Framework\Attributes\Group;
+use PHPUnit\Framework\Attributes\RequiresPhpExtension;
+use PHPUnit\Framework\Error\Warning;
use Symfony\Component\Cache\Adapter\AdapterInterface;
use Symfony\Component\Cache\Adapter\RedisAdapter;
use Symfony\Component\Cache\Adapter\TagAwareAdapter;
@@ -24,18 +27,15 @@ public function testCachePools()
$this->doTestCachePools([], AdapterInterface::class);
}
- /**
- * @requires extension redis
- *
- * @group integration
- */
+ #[RequiresPhpExtension('redis')]
+ #[Group('integration')]
public function testRedisCachePools()
{
$this->skipIfRedisUnavailable();
try {
$this->doTestCachePools(['root_config' => 'redis_config.yml', 'environment' => 'redis_cache'], RedisAdapter::class);
- } catch (\PHPUnit\Framework\Error\Warning $e) {
+ } catch (Warning $e) {
if (!str_starts_with($e->getMessage(), 'unable to connect to')) {
throw $e;
}
@@ -48,18 +48,15 @@ public function testRedisCachePools()
}
}
- /**
- * @requires extension redis
- *
- * @group integration
- */
+ #[RequiresPhpExtension('redis')]
+ #[Group('integration')]
public function testRedisCustomCachePools()
{
$this->skipIfRedisUnavailable();
try {
$this->doTestCachePools(['root_config' => 'redis_custom_config.yml', 'environment' => 'custom_redis_cache'], RedisAdapter::class);
- } catch (\PHPUnit\Framework\Error\Warning $e) {
+ } catch (Warning $e) {
if (!str_starts_with($e->getMessage(), 'unable to connect to')) {
throw $e;
}
diff --git a/Tests/Functional/ConfigDebugCommandTest.php b/Tests/Functional/ConfigDebugCommandTest.php
index 2c47121c1..ea4ee0788 100644
--- a/Tests/Functional/ConfigDebugCommandTest.php
+++ b/Tests/Functional/ConfigDebugCommandTest.php
@@ -11,6 +11,9 @@
namespace Symfony\Bundle\FrameworkBundle\Tests\Functional;
+use PHPUnit\Framework\Attributes\DataProvider;
+use PHPUnit\Framework\Attributes\Group;
+use PHPUnit\Framework\Attributes\TestWith;
use Symfony\Bundle\FrameworkBundle\Command\ConfigDebugCommand;
use Symfony\Bundle\FrameworkBundle\Console\Application;
use Symfony\Component\Console\Exception\InvalidArgumentException;
@@ -19,15 +22,11 @@
use Symfony\Component\Console\Tester\CommandCompletionTester;
use Symfony\Component\Console\Tester\CommandTester;
-/**
- * @group functional
- */
+#[Group('functional')]
class ConfigDebugCommandTest extends AbstractWebTestCase
{
- /**
- * @testWith [true]
- * [false]
- */
+ #[TestWith([true])]
+ #[TestWith([false])]
public function testShowList(bool $debug)
{
$tester = $this->createCommandTester($debug);
@@ -44,10 +43,8 @@ public function testShowList(bool $debug)
$this->assertStringContainsString(' test_dump', $tester->getDisplay());
}
- /**
- * @testWith [true]
- * [false]
- */
+ #[TestWith([true])]
+ #[TestWith([false])]
public function testDumpKernelExtension(bool $debug)
{
$tester = $this->createCommandTester($debug);
@@ -58,10 +55,8 @@ public function testDumpKernelExtension(bool $debug)
$this->assertStringContainsString(' foo: bar', $tester->getDisplay());
}
- /**
- * @testWith [true]
- * [false]
- */
+ #[TestWith([true])]
+ #[TestWith([false])]
public function testDumpBundleName(bool $debug)
{
$tester = $this->createCommandTester($debug);
@@ -71,10 +66,8 @@ public function testDumpBundleName(bool $debug)
$this->assertStringContainsString('custom: foo', $tester->getDisplay());
}
- /**
- * @testWith [true]
- * [false]
- */
+ #[TestWith([true])]
+ #[TestWith([false])]
public function testDumpBundleOption(bool $debug)
{
$tester = $this->createCommandTester($debug);
@@ -84,10 +77,8 @@ public function testDumpBundleOption(bool $debug)
$this->assertStringContainsString('foo', $tester->getDisplay());
}
- /**
- * @testWith [true]
- * [false]
- */
+ #[TestWith([true])]
+ #[TestWith([false])]
public function testDumpWithoutTitleIsValidJson(bool $debug)
{
$tester = $this->createCommandTester($debug);
@@ -97,10 +88,8 @@ public function testDumpWithoutTitleIsValidJson(bool $debug)
$this->assertJson($tester->getDisplay());
}
- /**
- * @testWith [true]
- * [false]
- */
+ #[TestWith([true])]
+ #[TestWith([false])]
public function testDumpWithUnsupportedFormat(bool $debug)
{
$tester = $this->createCommandTester($debug);
@@ -114,10 +103,8 @@ public function testDumpWithUnsupportedFormat(bool $debug)
]);
}
- /**
- * @testWith [true]
- * [false]
- */
+ #[TestWith([true])]
+ #[TestWith([false])]
public function testParametersValuesAreResolved(bool $debug)
{
$tester = $this->createCommandTester($debug);
@@ -128,10 +115,8 @@ public function testParametersValuesAreResolved(bool $debug)
$this->assertStringContainsString('secret: test', $tester->getDisplay());
}
- /**
- * @testWith [true]
- * [false]
- */
+ #[TestWith([true])]
+ #[TestWith([false])]
public function testParametersValuesAreFullyResolved(bool $debug)
{
$tester = $this->createCommandTester($debug);
@@ -144,10 +129,8 @@ public function testParametersValuesAreFullyResolved(bool $debug)
$this->assertStringContainsString('ide: '.($debug ? ($_ENV['SYMFONY_IDE'] ?? $_SERVER['SYMFONY_IDE'] ?? 'null') : 'null'), $tester->getDisplay());
}
- /**
- * @testWith [true]
- * [false]
- */
+ #[TestWith([true])]
+ #[TestWith([false])]
public function testDefaultParameterValueIsResolvedIfConfigIsExisting(bool $debug)
{
$tester = $this->createCommandTester($debug);
@@ -158,10 +141,8 @@ public function testDefaultParameterValueIsResolvedIfConfigIsExisting(bool $debu
$this->assertStringContainsString(\sprintf("dsn: 'file:%s/profiler'", $kernelCacheDir), $tester->getDisplay());
}
- /**
- * @testWith [true]
- * [false]
- */
+ #[TestWith([true])]
+ #[TestWith([false])]
public function testDumpExtensionConfigWithoutBundle(bool $debug)
{
$tester = $this->createCommandTester($debug);
@@ -171,10 +152,8 @@ public function testDumpExtensionConfigWithoutBundle(bool $debug)
$this->assertStringContainsString('enabled: true', $tester->getDisplay());
}
- /**
- * @testWith [true]
- * [false]
- */
+ #[TestWith([true])]
+ #[TestWith([false])]
public function testDumpUndefinedBundleOption(bool $debug)
{
$tester = $this->createCommandTester($debug);
@@ -183,10 +162,8 @@ public function testDumpUndefinedBundleOption(bool $debug)
$this->assertStringContainsString('Unable to find configuration for "test.foo"', $tester->getDisplay());
}
- /**
- * @testWith [true]
- * [false]
- */
+ #[TestWith([true])]
+ #[TestWith([false])]
public function testDumpWithPrefixedEnv(bool $debug)
{
$tester = $this->createCommandTester($debug);
@@ -195,10 +172,8 @@ public function testDumpWithPrefixedEnv(bool $debug)
$this->assertStringContainsString("cookie_httponly: '%env(bool:COOKIE_HTTPONLY)%'", $tester->getDisplay());
}
- /**
- * @testWith [true]
- * [false]
- */
+ #[TestWith([true])]
+ #[TestWith([false])]
public function testDumpFallsBackToDefaultConfigAndResolvesParameterValue(bool $debug)
{
$tester = $this->createCommandTester($debug);
@@ -208,10 +183,8 @@ public function testDumpFallsBackToDefaultConfigAndResolvesParameterValue(bool $
$this->assertStringContainsString('foo: bar', $tester->getDisplay());
}
- /**
- * @testWith [true]
- * [false]
- */
+ #[TestWith([true])]
+ #[TestWith([false])]
public function testDumpFallsBackToDefaultConfigAndResolvesEnvPlaceholder(bool $debug)
{
$tester = $this->createCommandTester($debug);
@@ -221,10 +194,8 @@ public function testDumpFallsBackToDefaultConfigAndResolvesEnvPlaceholder(bool $
$this->assertStringContainsString("baz: '%env(BAZ)%'", $tester->getDisplay());
}
- /**
- * @testWith [true]
- * [false]
- */
+ #[TestWith([true])]
+ #[TestWith([false])]
public function testDumpThrowsExceptionWhenDefaultConfigFallbackIsImpossible(bool $debug)
{
$this->expectException(\LogicException::class);
@@ -234,14 +205,12 @@ public function testDumpThrowsExceptionWhenDefaultConfigFallbackIsImpossible(boo
$tester->execute(['name' => 'ExtensionWithoutConfigTestBundle']);
}
- /**
- * @dataProvider provideCompletionSuggestions
- */
+ #[DataProvider('provideCompletionSuggestions')]
public function testComplete(bool $debug, array $input, array $expectedSuggestions)
{
$application = $this->createApplication($debug);
- $application->add(new ConfigDebugCommand());
+ $application->addCommand(new ConfigDebugCommand());
$tester = new CommandCompletionTester($application->get('debug:config'));
$suggestions = $tester->complete($input);
diff --git a/Tests/Functional/ConfigDumpReferenceCommandTest.php b/Tests/Functional/ConfigDumpReferenceCommandTest.php
index 8f5930faa..377a530e9 100644
--- a/Tests/Functional/ConfigDumpReferenceCommandTest.php
+++ b/Tests/Functional/ConfigDumpReferenceCommandTest.php
@@ -11,6 +11,9 @@
namespace Symfony\Bundle\FrameworkBundle\Tests\Functional;
+use PHPUnit\Framework\Attributes\DataProvider;
+use PHPUnit\Framework\Attributes\Group;
+use PHPUnit\Framework\Attributes\TestWith;
use Symfony\Bundle\FrameworkBundle\Command\ConfigDumpReferenceCommand;
use Symfony\Bundle\FrameworkBundle\Console\Application;
use Symfony\Component\Console\Input\ArrayInput;
@@ -18,15 +21,11 @@
use Symfony\Component\Console\Tester\CommandCompletionTester;
use Symfony\Component\Console\Tester\CommandTester;
-/**
- * @group functional
- */
+#[Group('functional')]
class ConfigDumpReferenceCommandTest extends AbstractWebTestCase
{
- /**
- * @testWith [true]
- * [false]
- */
+ #[TestWith([true])]
+ #[TestWith([false])]
public function testShowList(bool $debug)
{
$tester = $this->createCommandTester($debug);
@@ -43,10 +42,8 @@ public function testShowList(bool $debug)
$this->assertStringContainsString(' test_dump', $tester->getDisplay());
}
- /**
- * @testWith [true]
- * [false]
- */
+ #[TestWith([true])]
+ #[TestWith([false])]
public function testDumpKernelExtension(bool $debug)
{
$tester = $this->createCommandTester($debug);
@@ -57,10 +54,8 @@ public function testDumpKernelExtension(bool $debug)
$this->assertStringContainsString(' bar', $tester->getDisplay());
}
- /**
- * @testWith [true]
- * [false]
- */
+ #[TestWith([true])]
+ #[TestWith([false])]
public function testDumpBundleName(bool $debug)
{
$tester = $this->createCommandTester($debug);
@@ -71,10 +66,8 @@ public function testDumpBundleName(bool $debug)
$this->assertStringContainsString(' custom:', $tester->getDisplay());
}
- /**
- * @testWith [true]
- * [false]
- */
+ #[TestWith([true])]
+ #[TestWith([false])]
public function testDumpExtensionConfigWithoutBundle(bool $debug)
{
$tester = $this->createCommandTester($debug);
@@ -84,10 +77,8 @@ public function testDumpExtensionConfigWithoutBundle(bool $debug)
$this->assertStringContainsString('enabled: true', $tester->getDisplay());
}
- /**
- * @testWith [true]
- * [false]
- */
+ #[TestWith([true])]
+ #[TestWith([false])]
public function testDumpAtPath(bool $debug)
{
$tester = $this->createCommandTester($debug);
@@ -98,20 +89,19 @@ public function testDumpAtPath(bool $debug)
$this->assertSame(0, $ret, 'Returns 0 in case of success');
$this->assertSame(<<<'EOL'
-# Default configuration for extension with alias: "test" at path "array"
-array:
- child1: ~
- child2: ~
+ # Default configuration for extension with alias: "test" at path "array"
+ array:
+ child1: ~
+ child2: ~
-EOL
- , $tester->getDisplay(true));
+ EOL,
+ $tester->getDisplay(true)
+ );
}
- /**
- * @testWith [true]
- * [false]
- */
+ #[TestWith([true])]
+ #[TestWith([false])]
public function testDumpAtPathXml(bool $debug)
{
$tester = $this->createCommandTester($debug);
@@ -125,14 +115,12 @@ public function testDumpAtPathXml(bool $debug)
$this->assertStringContainsString('[ERROR] The "path" option is only available for the "yaml" format.', $tester->getDisplay());
}
- /**
- * @dataProvider provideCompletionSuggestions
- */
+ #[DataProvider('provideCompletionSuggestions')]
public function testComplete(bool $debug, array $input, array $expectedSuggestions)
{
$application = $this->createApplication($debug);
- $application->add(new ConfigDumpReferenceCommand());
+ $application->addCommand(new ConfigDumpReferenceCommand());
$tester = new CommandCompletionTester($application->get('config:dump-reference'));
$suggestions = $tester->complete($input);
$this->assertSame($expectedSuggestions, $suggestions);
diff --git a/Tests/Functional/ContainerDebugCommandTest.php b/Tests/Functional/ContainerDebugCommandTest.php
index d21d4d113..e1e7ce084 100644
--- a/Tests/Functional/ContainerDebugCommandTest.php
+++ b/Tests/Functional/ContainerDebugCommandTest.php
@@ -11,6 +11,8 @@
namespace Symfony\Bundle\FrameworkBundle\Tests\Functional;
+use PHPUnit\Framework\Attributes\DataProvider;
+use PHPUnit\Framework\Attributes\Group;
use Symfony\Bundle\FrameworkBundle\Console\Application;
use Symfony\Bundle\FrameworkBundle\Tests\Fixtures\BackslashClass;
use Symfony\Bundle\FrameworkBundle\Tests\Fixtures\ContainerExcluded;
@@ -18,9 +20,7 @@
use Symfony\Component\Console\Tester\CommandCompletionTester;
use Symfony\Component\HttpKernel\HttpKernelInterface;
-/**
- * @group functional
- */
+#[Group('functional')]
class ContainerDebugCommandTest extends AbstractWebTestCase
{
public function testDumpContainerIfNotExists()
@@ -113,9 +113,7 @@ public function testExcludedService()
$this->assertStringNotContainsString(ContainerExcluded::class, $tester->getDisplay());
}
- /**
- * @dataProvider provideIgnoreBackslashWhenFindingService
- */
+ #[DataProvider('provideIgnoreBackslashWhenFindingService')]
public function testIgnoreBackslashWhenFindingService(string $validServiceId)
{
static::bootKernel(['test_case' => 'ContainerDebug', 'root_config' => 'config.yml']);
@@ -168,25 +166,26 @@ public function testDescribeEnvVars()
$this->assertStringMatchesFormat(<<<'TXT'
-Symfony Container Environment Variables
-=======================================
+ Symfony Container Environment Variables
+ =======================================
- --------- ----------------- ------------%w
- Name Default value Real value%w
- --------- ----------------- ------------%w
- JSON "[1, "2.5", 3]" n/a%w
- REAL n/a "value"%w
- UNKNOWN n/a n/a%w
- --------- ----------------- ------------%w
+ --------- ----------------- ------------%w
+ Name Default value Real value%w
+ --------- ----------------- ------------%w
+ JSON "[1, "2.5", 3]" n/a%w
+ REAL n/a "value"%w
+ UNKNOWN n/a n/a%w
+ --------- ----------------- ------------%w
- // Note real values might be different between web and CLI.%w
+ // Note real values might be different between web and CLI.%w
- [WARNING] The following variables are missing:%w
+ [WARNING] The following variables are missing:%w
- * UNKNOWN
+ * UNKNOWN
-TXT
- , $tester->getDisplay(true));
+ TXT,
+ $tester->getDisplay(true)
+ );
putenv('REAL');
}
@@ -214,10 +213,10 @@ public function testGetDeprecation()
file_put_contents($path, serialize([[
'type' => 16384,
'message' => 'The "Symfony\Bundle\FrameworkBundle\Controller\Controller" class is deprecated since Symfony 4.2, use Symfony\Bundle\FrameworkBundle\Controller\AbstractController instead.',
- 'file' => '/home/hamza/projet/contrib/sf/vendor/symfony/framework-bundle/Controller/Controller.php',
+ 'file' => '/home/hamza/project/contrib/sf/vendor/symfony/framework-bundle/Controller/Controller.php',
'line' => 17,
'trace' => [[
- 'file' => '/home/hamza/projet/contrib/sf/src/Controller/DefaultController.php',
+ 'file' => '/home/hamza/project/contrib/sf/src/Controller/DefaultController.php',
'line' => 9,
'function' => 'spl_autoload_call',
]],
@@ -233,7 +232,7 @@ public function testGetDeprecation()
$tester->assertCommandIsSuccessful();
$this->assertStringContainsString('Symfony\Bundle\FrameworkBundle\Controller\Controller', $tester->getDisplay());
- $this->assertStringContainsString('/home/hamza/projet/contrib/sf/vendor/symfony/framework-bundle/Controller/Controller.php', $tester->getDisplay());
+ $this->assertStringContainsString('/home/hamza/project/contrib/sf/vendor/symfony/framework-bundle/Controller/Controller.php', $tester->getDisplay());
}
public function testGetDeprecationNone()
@@ -282,9 +281,7 @@ public static function provideIgnoreBackslashWhenFindingService(): array
];
}
- /**
- * @dataProvider provideCompletionSuggestions
- */
+ #[DataProvider('provideCompletionSuggestions')]
public function testComplete(array $input, array $expectedSuggestions, array $notExpectedSuggestions = [])
{
static::bootKernel(['test_case' => 'ContainerDebug', 'root_config' => 'config.yml', 'debug' => true]);
diff --git a/Tests/Functional/ContainerLintCommandTest.php b/Tests/Functional/ContainerLintCommandTest.php
index f0b6b4bd5..8e50caa01 100644
--- a/Tests/Functional/ContainerLintCommandTest.php
+++ b/Tests/Functional/ContainerLintCommandTest.php
@@ -11,19 +11,18 @@
namespace Symfony\Bundle\FrameworkBundle\Tests\Functional;
+use PHPUnit\Framework\Attributes\DataProvider;
+use PHPUnit\Framework\Attributes\Group;
use Symfony\Bundle\FrameworkBundle\Console\Application;
use Symfony\Component\Console\Tester\CommandTester;
+use Symfony\Component\DependencyInjection\Argument\ArgumentTrait;
-/**
- * @group functional
- */
+#[Group('functional')]
class ContainerLintCommandTest extends AbstractWebTestCase
{
private Application $application;
- /**
- * @dataProvider containerLintProvider
- */
+ #[DataProvider('containerLintProvider')]
public function testLintContainer(string $configFile, bool $resolveEnvVars, int $expectedExitCode, string $expectedOutput)
{
$kernel = static::createKernel([
@@ -40,13 +39,16 @@ public function testLintContainer(string $configFile, bool $resolveEnvVars, int
$this->assertStringContainsString($expectedOutput, $tester->getDisplay());
}
- public static function containerLintProvider(): array
+ public static function containerLintProvider(): iterable
{
- return [
- ['escaped_percent.yml', false, 0, 'The container was linted successfully'],
- ['missing_env_var.yml', false, 0, 'The container was linted successfully'],
- ['missing_env_var.yml', true, 1, 'Environment variable not found: "BAR"'],
- ];
+ yield ['escaped_percent.yml', false, 0, 'The container was linted successfully'];
+
+ if (trait_exists(ArgumentTrait::class)) {
+ yield ['escaped_percent.yml', true, 0, 'The container was linted successfully'];
+ }
+
+ yield ['missing_env_var.yml', false, 0, 'The container was linted successfully'];
+ yield ['missing_env_var.yml', true, 1, 'Environment variable not found: "BAR"'];
}
private function createCommandTester(): CommandTester
diff --git a/Tests/Functional/DebugAutowiringCommandTest.php b/Tests/Functional/DebugAutowiringCommandTest.php
index ca11e3fae..de94a1e71 100644
--- a/Tests/Functional/DebugAutowiringCommandTest.php
+++ b/Tests/Functional/DebugAutowiringCommandTest.php
@@ -11,6 +11,8 @@
namespace Symfony\Bundle\FrameworkBundle\Tests\Functional;
+use PHPUnit\Framework\Attributes\DataProvider;
+use PHPUnit\Framework\Attributes\Group;
use Psr\Log\LoggerInterface;
use Symfony\Bundle\FrameworkBundle\Command\DebugAutowiringCommand;
use Symfony\Bundle\FrameworkBundle\Console\Application;
@@ -20,9 +22,7 @@
use Symfony\Component\HttpKernel\HttpKernelInterface;
use Symfony\Component\Routing\RouterInterface;
-/**
- * @group functional
- */
+#[Group('functional')]
class DebugAutowiringCommandTest extends AbstractWebTestCase
{
public function testBasicFunctionality()
@@ -116,13 +116,11 @@ public function testNotConfusedByClassAliases()
$this->assertStringContainsString(ClassAliasExampleClass::class, $tester->getDisplay());
}
- /**
- * @dataProvider provideCompletionSuggestions
- */
+ #[DataProvider('provideCompletionSuggestions')]
public function testComplete(array $input, array $expectedSuggestions)
{
$kernel = static::bootKernel(['test_case' => 'ContainerDebug', 'root_config' => 'config.yml']);
- $command = (new Application($kernel))->add(new DebugAutowiringCommand());
+ $command = (new Application($kernel))->addCommand(new DebugAutowiringCommand());
$tester = new CommandCompletionTester($command);
diff --git a/Tests/Functional/FragmentTest.php b/Tests/Functional/FragmentTest.php
index 48d5c327a..b8cff1f48 100644
--- a/Tests/Functional/FragmentTest.php
+++ b/Tests/Functional/FragmentTest.php
@@ -11,11 +11,11 @@
namespace Symfony\Bundle\FrameworkBundle\Tests\Functional;
+use PHPUnit\Framework\Attributes\DataProvider;
+
class FragmentTest extends AbstractWebTestCase
{
- /**
- * @dataProvider getConfigs
- */
+ #[DataProvider('getConfigs')]
public function testFragment($insulate)
{
$client = $this->createClient(['test_case' => 'Fragment', 'root_config' => 'config.yml', 'debug' => true]);
@@ -26,15 +26,16 @@ public function testFragment($insulate)
$client->request('GET', '/fragment_home');
$this->assertEquals(<<getResponse()->getContent());
+ bar txt
+ --
+ html
+ --
+ es
+ --
+ fr
+ TXT,
+ $client->getResponse()->getContent()
+ );
}
public static function getConfigs()
diff --git a/Tests/Functional/MailerTest.php b/Tests/Functional/MailerTest.php
index 1ba71d74f..4193e3ff7 100644
--- a/Tests/Functional/MailerTest.php
+++ b/Tests/Functional/MailerTest.php
@@ -99,6 +99,7 @@ public function testMailerAssertions()
$this->assertEmailHtmlBodyContains($email, 'Foo');
$this->assertEmailHtmlBodyNotContains($email, 'Bar');
$this->assertEmailAttachmentCount($email, 1);
+ $this->assertEmailAddressNotContains($email, 'To', 'thomas@symfony.com');
$email = $this->getMailerMessage($second);
$this->assertEmailSubjectContains($email, 'Foo');
@@ -106,5 +107,7 @@ public function testMailerAssertions()
$this->assertEmailAddressContains($email, 'To', 'fabien@symfony.com');
$this->assertEmailAddressContains($email, 'To', 'thomas@symfony.com');
$this->assertEmailAddressContains($email, 'Reply-To', 'me@symfony.com');
+ $this->assertEmailAddressNotContains($email, 'To', 'helene@symfony.com');
+ $this->assertEmailAddressNotContains($email, 'Reply-To', 'helene@symfony.com');
}
}
diff --git a/Tests/Functional/NotificationTest.php b/Tests/Functional/NotificationTest.php
index 03b947a0f..7511591cb 100644
--- a/Tests/Functional/NotificationTest.php
+++ b/Tests/Functional/NotificationTest.php
@@ -11,11 +11,12 @@
namespace Symfony\Bundle\FrameworkBundle\Tests\Functional;
+use PHPUnit\Framework\Attributes\RequiresMethod;
+use Symfony\Bundle\MercureBundle\MercureBundle;
+
final class NotificationTest extends AbstractWebTestCase
{
- /**
- * @requires function \Symfony\Bundle\MercureBundle\MercureBundle::build
- */
+ #[RequiresMethod(MercureBundle::class, 'build')]
public function testNotifierAssertion()
{
$client = $this->createClient(['test_case' => 'Notifier', 'root_config' => 'config.yml', 'debug' => true]);
diff --git a/Tests/Functional/ProfilerTest.php b/Tests/Functional/ProfilerTest.php
index d78259795..b5853dd1a 100644
--- a/Tests/Functional/ProfilerTest.php
+++ b/Tests/Functional/ProfilerTest.php
@@ -11,11 +11,11 @@
namespace Symfony\Bundle\FrameworkBundle\Tests\Functional;
+use PHPUnit\Framework\Attributes\DataProvider;
+
class ProfilerTest extends AbstractWebTestCase
{
- /**
- * @dataProvider getConfigs
- */
+ #[DataProvider('getConfigs')]
public function testProfilerIsDisabled($insulate)
{
$client = $this->createClient(['test_case' => 'Profiler', 'root_config' => 'config.yml']);
@@ -36,9 +36,7 @@ public function testProfilerIsDisabled($insulate)
$this->assertNull($client->getProfile());
}
- /**
- * @dataProvider getConfigs
- */
+ #[DataProvider('getConfigs')]
public function testProfilerCollectParameter($insulate)
{
$client = $this->createClient(['test_case' => 'ProfilerCollectParameter', 'root_config' => 'config.yml']);
diff --git a/Tests/Functional/PropertyInfoTest.php b/Tests/Functional/PropertyInfoTest.php
index 18cd61b08..128932311 100644
--- a/Tests/Functional/PropertyInfoTest.php
+++ b/Tests/Functional/PropertyInfoTest.php
@@ -11,6 +11,8 @@
namespace Symfony\Bundle\FrameworkBundle\Tests\Functional;
+use PHPUnit\Framework\Attributes\Group;
+use PHPUnit\Framework\Attributes\IgnoreDeprecations;
use Symfony\Component\PropertyInfo\Type as LegacyType;
use Symfony\Component\TypeInfo\Type;
@@ -29,9 +31,8 @@ public function testPhpDocPriority()
$this->assertEquals(Type::list(Type::int()), $propertyInfo->getType(Dummy::class, 'codes'));
}
- /**
- * @group legacy
- */
+ #[IgnoreDeprecations]
+ #[Group('legacy')]
public function testPhpDocPriorityLegacy()
{
static::bootKernel(['test_case' => 'Serializer']);
diff --git a/Tests/Functional/RouterDebugCommandTest.php b/Tests/Functional/RouterDebugCommandTest.php
index 614078804..910e3b6f7 100644
--- a/Tests/Functional/RouterDebugCommandTest.php
+++ b/Tests/Functional/RouterDebugCommandTest.php
@@ -11,13 +11,14 @@
namespace Symfony\Bundle\FrameworkBundle\Tests\Functional;
+use PHPUnit\Framework\Attributes\DataProvider;
+use PHPUnit\Framework\Attributes\Group;
+use PHPUnit\Framework\Attributes\TestWith;
use Symfony\Bundle\FrameworkBundle\Console\Application;
use Symfony\Component\Console\Tester\CommandCompletionTester;
use Symfony\Component\Console\Tester\CommandTester;
-/**
- * @group functional
- */
+#[Group('functional')]
class RouterDebugCommandTest extends AbstractWebTestCase
{
private Application $application;
@@ -89,21 +90,17 @@ public function testSearchWithThrow()
$tester->execute(['name' => 'gerard'], ['interactive' => true]);
}
- /**
- * @dataProvider provideCompletionSuggestions
- */
+ #[DataProvider('provideCompletionSuggestions')]
public function testComplete(array $input, array $expectedSuggestions)
{
$tester = new CommandCompletionTester($this->application->get('debug:router'));
$this->assertSame($expectedSuggestions, $tester->complete($input));
}
- /**
- * @testWith ["txt"]
- * ["xml"]
- * ["json"]
- * ["md"]
- */
+ #[TestWith(['txt'])]
+ #[TestWith(['xml'])]
+ #[TestWith(['json'])]
+ #[TestWith(['md'])]
public function testShowAliases(string $format)
{
$tester = $this->createCommandTester();
diff --git a/Tests/Functional/RoutingConditionServiceTest.php b/Tests/Functional/RoutingConditionServiceTest.php
index 4f4caa6eb..f1f4f14cf 100644
--- a/Tests/Functional/RoutingConditionServiceTest.php
+++ b/Tests/Functional/RoutingConditionServiceTest.php
@@ -11,11 +11,11 @@
namespace Symfony\Bundle\FrameworkBundle\Tests\Functional;
+use PHPUnit\Framework\Attributes\DataProvider;
+
class RoutingConditionServiceTest extends AbstractWebTestCase
{
- /**
- * @dataProvider provideRoutes
- */
+ #[DataProvider('provideRoutes')]
public function testCondition(int $code, string $path)
{
$client = static::createClient(['test_case' => 'RoutingConditionService']);
diff --git a/Tests/Functional/SecurityTest.php b/Tests/Functional/SecurityTest.php
index c26fa717d..ab06b5f6c 100644
--- a/Tests/Functional/SecurityTest.php
+++ b/Tests/Functional/SecurityTest.php
@@ -11,13 +11,12 @@
namespace Symfony\Bundle\FrameworkBundle\Tests\Functional;
+use PHPUnit\Framework\Attributes\DataProvider;
use Symfony\Component\Security\Core\User\InMemoryUser;
class SecurityTest extends AbstractWebTestCase
{
- /**
- * @dataProvider getUsers
- */
+ #[DataProvider('getUsers')]
public function testLoginUser(string $username, array $roles, ?string $firewallContext)
{
$user = new InMemoryUser($username, 'the-password', $roles);
diff --git a/Tests/Functional/SessionTest.php b/Tests/Functional/SessionTest.php
index 4c1b92ccf..88ea3230a 100644
--- a/Tests/Functional/SessionTest.php
+++ b/Tests/Functional/SessionTest.php
@@ -11,13 +11,14 @@
namespace Symfony\Bundle\FrameworkBundle\Tests\Functional;
+use PHPUnit\Framework\Attributes\DataProvider;
+
class SessionTest extends AbstractWebTestCase
{
/**
* Tests session attributes persist.
- *
- * @dataProvider getConfigs
*/
+ #[DataProvider('getConfigs')]
public function testWelcome($config, $insulate)
{
$client = $this->createClient(['test_case' => 'Session', 'root_config' => $config]);
@@ -48,9 +49,8 @@ public function testWelcome($config, $insulate)
/**
* Tests flash messages work in practice.
- *
- * @dataProvider getConfigs
*/
+ #[DataProvider('getConfigs')]
public function testFlash($config, $insulate)
{
$client = $this->createClient(['test_case' => 'Session', 'root_config' => $config]);
@@ -72,9 +72,8 @@ public function testFlash($config, $insulate)
/**
* See if two separate insulated clients can run without
* polluting each other's session data.
- *
- * @dataProvider getConfigs
*/
+ #[DataProvider('getConfigs')]
public function testTwoClients($config, $insulate)
{
// start first client
@@ -128,9 +127,7 @@ public function testTwoClients($config, $insulate)
$this->assertStringContainsString('Welcome back client2, nice to meet you.', $crawler2->text());
}
- /**
- * @dataProvider getConfigs
- */
+ #[DataProvider('getConfigs')]
public function testCorrectCacheControlHeadersForCacheableAction($config, $insulate)
{
$client = $this->createClient(['test_case' => 'Session', 'root_config' => $config]);
diff --git a/Tests/Functional/SluggerLocaleAwareTest.php b/Tests/Functional/SluggerLocaleAwareTest.php
index 769012461..d09f969b0 100644
--- a/Tests/Functional/SluggerLocaleAwareTest.php
+++ b/Tests/Functional/SluggerLocaleAwareTest.php
@@ -11,16 +11,14 @@
namespace Symfony\Bundle\FrameworkBundle\Tests\Functional;
+use PHPUnit\Framework\Attributes\Group;
+use PHPUnit\Framework\Attributes\RequiresPhpExtension;
use Symfony\Bundle\FrameworkBundle\Tests\Functional\Bundle\TestBundle\Slugger\SlugConstructArgService;
-/**
- * @group functional
- */
+#[Group('functional')]
class SluggerLocaleAwareTest extends AbstractWebTestCase
{
- /**
- * @requires extension intl
- */
+ #[RequiresPhpExtension('intl')]
public function testLocalizedSlugger()
{
$kernel = static::createKernel(['test_case' => 'Slugger', 'root_config' => 'config.yml']);
diff --git a/Tests/Functional/TestServiceContainerTest.php b/Tests/Functional/TestServiceContainerTest.php
index fe7093081..8b8898ad8 100644
--- a/Tests/Functional/TestServiceContainerTest.php
+++ b/Tests/Functional/TestServiceContainerTest.php
@@ -11,6 +11,8 @@
namespace Symfony\Bundle\FrameworkBundle\Tests\Functional;
+use PHPUnit\Framework\Attributes\Depends;
+use PHPUnit\Framework\Attributes\DoesNotPerformAssertions;
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;
@@ -68,17 +70,13 @@ public function testSetDecoratedService()
$this->assertSame($service, $container->get('decorated')->inner);
}
- /**
- * @doesNotPerformAssertions
- */
+ #[DoesNotPerformAssertions]
public function testBootKernel()
{
static::bootKernel(['test_case' => 'TestServiceContainer']);
}
- /**
- * @depends testBootKernel
- */
+ #[Depends('testBootKernel')]
public function testKernelIsNotInitialized()
{
self::assertNull(self::$class);
diff --git a/Tests/Functional/TranslationDebugCommandTest.php b/Tests/Functional/TranslationDebugCommandTest.php
index 5e396440c..1d7e2952b 100644
--- a/Tests/Functional/TranslationDebugCommandTest.php
+++ b/Tests/Functional/TranslationDebugCommandTest.php
@@ -11,13 +11,12 @@
namespace Symfony\Bundle\FrameworkBundle\Tests\Functional;
+use PHPUnit\Framework\Attributes\Group;
use Symfony\Bundle\FrameworkBundle\Command\TranslationDebugCommand;
use Symfony\Bundle\FrameworkBundle\Console\Application;
use Symfony\Component\Console\Tester\CommandTester;
-/**
- * @group functional
- */
+#[Group('functional')]
class TranslationDebugCommandTest extends AbstractWebTestCase
{
private Application $application;
diff --git a/Tests/Functional/app/AppKernel.php b/Tests/Functional/app/AppKernel.php
index 59c28b2a6..5748b61cd 100644
--- a/Tests/Functional/app/AppKernel.php
+++ b/Tests/Functional/app/AppKernel.php
@@ -89,14 +89,16 @@ protected function build(ContainerBuilder $container): void
$container->registerExtension(new TestDumpExtension());
}
- public function __sleep(): array
+ public function __serialize(): array
{
- return ['varDir', 'testCase', 'rootConfig', 'environment', 'debug'];
+ return [$this->varDir, $this->testCase, $this->rootConfig, $this->environment, $this->debug];
}
- public function __wakeup(): void
+ public function __unserialize(array $data): void
{
- foreach ($this as $k => $v) {
+ [$this->varDir, $this->testCase, $this->rootConfig, $this->environment, $this->debug] = $data;
+
+ foreach ($this as $v) {
if (\is_object($v)) {
throw new \BadMethodCallException('Cannot unserialize '.__CLASS__);
}
diff --git a/Tests/Kernel/ConcreteMicroKernel.php b/Tests/Kernel/ConcreteMicroKernel.php
index a69618099..eac061e3b 100644
--- a/Tests/Kernel/ConcreteMicroKernel.php
+++ b/Tests/Kernel/ConcreteMicroKernel.php
@@ -55,12 +55,12 @@ public function getLogDir(): string
return $this->cacheDir;
}
- public function __sleep(): array
+ public function __serialize(): array
{
throw new \BadMethodCallException('Cannot serialize '.__CLASS__);
}
- public function __wakeup(): void
+ public function __unserialize(array $data): void
{
throw new \BadMethodCallException('Cannot unserialize '.__CLASS__);
}
diff --git a/Tests/Kernel/flex-style/src/FlexStyleMicroKernel.php b/Tests/Kernel/flex-style/src/FlexStyleMicroKernel.php
index 6f7c84d8b..5fa641c7f 100644
--- a/Tests/Kernel/flex-style/src/FlexStyleMicroKernel.php
+++ b/Tests/Kernel/flex-style/src/FlexStyleMicroKernel.php
@@ -64,12 +64,12 @@ public function getProjectDir(): string
return \dirname((new \ReflectionObject($this))->getFileName(), 2);
}
- public function __sleep(): array
+ public function __serialize(): array
{
throw new \BadMethodCallException('Cannot serialize '.__CLASS__);
}
- public function __wakeup(): void
+ public function __unserialize(array $data): void
{
throw new \BadMethodCallException('Cannot unserialize '.__CLASS__);
}
diff --git a/Tests/Routing/RouterTest.php b/Tests/Routing/RouterTest.php
index d2c021563..f46522a97 100644
--- a/Tests/Routing/RouterTest.php
+++ b/Tests/Routing/RouterTest.php
@@ -11,6 +11,7 @@
namespace Symfony\Bundle\FrameworkBundle\Tests\Routing;
+use PHPUnit\Framework\Attributes\DataProvider;
use PHPUnit\Framework\TestCase;
use Psr\Container\ContainerInterface;
use Symfony\Bundle\FrameworkBundle\Routing\Router;
@@ -438,9 +439,7 @@ public function testExceptionOnNonStringParameterWithSfContainer()
$router->getRouteCollection();
}
- /**
- * @dataProvider getNonStringValues
- */
+ #[DataProvider('getNonStringValues')]
public function testDefaultValuesAsNonStrings($value)
{
$routes = new RouteCollection();
@@ -455,9 +454,7 @@ public function testDefaultValuesAsNonStrings($value)
$this->assertSame($value, $route->getDefault('foo'));
}
- /**
- * @dataProvider getNonStringValues
- */
+ #[DataProvider('getNonStringValues')]
public function testDefaultValuesAsNonStringsWithSfContainer($value)
{
$routes = new RouteCollection();
@@ -525,9 +522,7 @@ public static function getNonStringValues()
return [[null], [false], [true], [new \stdClass()], [['foo', 'bar']], [[[]]]];
}
- /**
- * @dataProvider getContainerParameterForRoute
- */
+ #[DataProvider('getContainerParameterForRoute')]
public function testCacheValidityWithContainerParameters($parameter)
{
$cacheDir = tempnam(sys_get_temp_dir(), 'sf_router_');
diff --git a/Tests/Secrets/SodiumVaultTest.php b/Tests/Secrets/SodiumVaultTest.php
index f91f4bced..6d050386b 100644
--- a/Tests/Secrets/SodiumVaultTest.php
+++ b/Tests/Secrets/SodiumVaultTest.php
@@ -11,14 +11,13 @@
namespace Symfony\Bundle\FrameworkBundle\Tests\Secrets;
+use PHPUnit\Framework\Attributes\RequiresPhpExtension;
use PHPUnit\Framework\TestCase;
use Symfony\Bundle\FrameworkBundle\Secrets\SodiumVault;
use Symfony\Component\Filesystem\Filesystem;
use Symfony\Component\String\LazyString;
-/**
- * @requires extension sodium
- */
+#[RequiresPhpExtension('sodium')]
class SodiumVaultTest extends TestCase
{
private string $secretsDir;
diff --git a/Tests/Test/WebTestCaseTest.php b/Tests/Test/WebTestCaseTest.php
index 84f2ef0ef..a058d3628 100644
--- a/Tests/Test/WebTestCaseTest.php
+++ b/Tests/Test/WebTestCaseTest.php
@@ -12,13 +12,16 @@
namespace Symfony\Bundle\FrameworkBundle\Tests\Test;
use PHPUnit\Framework\AssertionFailedError;
+use PHPUnit\Framework\Attributes\RequiresMethod;
use PHPUnit\Framework\ExpectationFailedException;
+use PHPUnit\Framework\MockObject\MockObject;
use PHPUnit\Framework\TestCase;
use Symfony\Bundle\FrameworkBundle\KernelBrowser;
use Symfony\Bundle\FrameworkBundle\Test\WebTestAssertionsTrait;
use Symfony\Bundle\FrameworkBundle\Test\WebTestCase;
use Symfony\Component\BrowserKit\Cookie;
use Symfony\Component\BrowserKit\CookieJar;
+use Symfony\Component\BrowserKit\History;
use Symfony\Component\DomCrawler\Crawler;
use Symfony\Component\HttpFoundation\Cookie as HttpFoundationCookie;
use Symfony\Component\HttpFoundation\Request;
@@ -190,6 +193,42 @@ public function testAssertBrowserCookieValueSame()
$this->getClientTester()->assertBrowserCookieValueSame('foo', 'babar', false, '/path');
}
+ #[RequiresMethod(History::class, 'isFirstPage')]
+ public function testAssertBrowserHistoryIsOnFirstPage()
+ {
+ $this->createHistoryTester('isFirstPage', true)->assertBrowserHistoryIsOnFirstPage();
+ $this->expectException(AssertionFailedError::class);
+ $this->expectExceptionMessage('Failed asserting that the Browser history is on the first page.');
+ $this->createHistoryTester('isFirstPage', false)->assertBrowserHistoryIsOnFirstPage();
+ }
+
+ #[RequiresMethod(History::class, 'isFirstPage')]
+ public function testAssertBrowserHistoryIsNotOnFirstPage()
+ {
+ $this->createHistoryTester('isFirstPage', false)->assertBrowserHistoryIsNotOnFirstPage();
+ $this->expectException(AssertionFailedError::class);
+ $this->expectExceptionMessage('Failed asserting that the Browser history is not on the first page.');
+ $this->createHistoryTester('isFirstPage', true)->assertBrowserHistoryIsNotOnFirstPage();
+ }
+
+ #[RequiresMethod(History::class, 'isLastPage')]
+ public function testAssertBrowserHistoryIsOnLastPage()
+ {
+ $this->createHistoryTester('isLastPage', true)->assertBrowserHistoryIsOnLastPage();
+ $this->expectException(AssertionFailedError::class);
+ $this->expectExceptionMessage('Failed asserting that the Browser history is on the last page.');
+ $this->createHistoryTester('isLastPage', false)->assertBrowserHistoryIsOnLastPage();
+ }
+
+ #[RequiresMethod(History::class, 'isLastPage')]
+ public function testAssertBrowserHistoryIsNotOnLastPage()
+ {
+ $this->createHistoryTester('isLastPage', false)->assertBrowserHistoryIsNotOnLastPage();
+ $this->expectException(AssertionFailedError::class);
+ $this->expectExceptionMessage('Failed asserting that the Browser history is not on the last page.');
+ $this->createHistoryTester('isLastPage', true)->assertBrowserHistoryIsNotOnLastPage();
+ }
+
public function testAssertSelectorExists()
{
$this->getCrawlerTester(new Crawler(''))->assertSelectorExists('body > h1');
@@ -386,6 +425,19 @@ private function getRequestTester(): WebTestCase
return $this->getTester($client);
}
+ private function createHistoryTester(string $method, bool $returnValue): WebTestCase
+ {
+ /** @var KernelBrowser&MockObject $client */
+ $client = $this->createMock(KernelBrowser::class);
+ /** @var History&MockObject $history */
+ $history = $this->createMock(History::class);
+
+ $history->method($method)->willReturn($returnValue);
+ $client->method('getHistory')->willReturn($history);
+
+ return $this->getTester($client);
+ }
+
private function getTester(KernelBrowser $client): WebTestCase
{
$tester = new class(method_exists($this, 'name') ? $this->name() : $this->getName()) extends WebTestCase {
diff --git a/Tests/Translation/TranslatorTest.php b/Tests/Translation/TranslatorTest.php
index e481a965e..d5f5d88eb 100644
--- a/Tests/Translation/TranslatorTest.php
+++ b/Tests/Translation/TranslatorTest.php
@@ -11,6 +11,7 @@
namespace Symfony\Bundle\FrameworkBundle\Tests\Translation;
+use PHPUnit\Framework\Attributes\DataProvider;
use PHPUnit\Framework\TestCase;
use Symfony\Bundle\FrameworkBundle\Translation\Translator;
use Symfony\Component\Config\Resource\DirectoryResource;
@@ -130,7 +131,7 @@ public function testInvalidOptions()
new Translator(new Container(), new MessageFormatter(), 'en', [], ['foo' => 'bar']);
}
- /** @dataProvider getDebugModeAndCacheDirCombinations */
+ #[DataProvider('getDebugModeAndCacheDirCombinations')]
public function testResourceFilesOptionLoadsBeforeOtherAddedResources($debug, $enableCache)
{
$someCatalogue = $this->getCatalogue('some_locale', []);
diff --git a/composer.json b/composer.json
index a00bac1c3..3f7a22462 100644
--- a/composer.json
+++ b/composer.json
@@ -19,61 +19,63 @@
"php": ">=8.2",
"composer-runtime-api": ">=2.1",
"ext-xml": "*",
- "symfony/cache": "^6.4|^7.0",
- "symfony/config": "^7.3",
- "symfony/dependency-injection": "^7.2",
+ "symfony/cache": "^6.4|^7.0|^8.0",
+ "symfony/config": "^7.3|^8.0",
+ "symfony/dependency-injection": "^7.2|^8.0",
"symfony/deprecation-contracts": "^2.5|^3",
- "symfony/error-handler": "^7.3",
- "symfony/event-dispatcher": "^6.4|^7.0",
- "symfony/http-foundation": "^7.3",
- "symfony/http-kernel": "^7.2",
+ "symfony/error-handler": "^7.3|^8.0",
+ "symfony/event-dispatcher": "^6.4|^7.0|^8.0",
+ "symfony/http-foundation": "^7.3|^8.0",
+ "symfony/http-kernel": "^7.2|^8.0",
"symfony/polyfill-mbstring": "~1.0",
- "symfony/filesystem": "^7.1",
- "symfony/finder": "^6.4|^7.0",
- "symfony/routing": "^6.4|^7.0"
+ "symfony/polyfill-php85": "^1.32",
+ "symfony/filesystem": "^7.1|^8.0",
+ "symfony/finder": "^6.4|^7.0|^8.0",
+ "symfony/routing": "^6.4|^7.0|^8.0"
},
"require-dev": {
"doctrine/persistence": "^1.3|^2|^3",
"dragonmantank/cron-expression": "^3.1",
"seld/jsonlint": "^1.10",
- "symfony/asset": "^6.4|^7.0",
- "symfony/asset-mapper": "^6.4|^7.0",
- "symfony/browser-kit": "^6.4|^7.0",
- "symfony/console": "^6.4|^7.0",
- "symfony/clock": "^6.4|^7.0",
- "symfony/css-selector": "^6.4|^7.0",
- "symfony/dom-crawler": "^6.4|^7.0",
- "symfony/dotenv": "^6.4|^7.0",
+ "symfony/asset": "^6.4|^7.0|^8.0",
+ "symfony/asset-mapper": "^6.4|^7.0|^8.0",
+ "symfony/browser-kit": "^6.4|^7.0|^8.0",
+ "symfony/console": "^6.4|^7.0|^8.0",
+ "symfony/clock": "^6.4|^7.0|^8.0",
+ "symfony/css-selector": "^6.4|^7.0|^8.0",
+ "symfony/dom-crawler": "^6.4|^7.0|^8.0",
+ "symfony/dotenv": "^6.4|^7.0|^8.0",
"symfony/polyfill-intl-icu": "~1.0",
- "symfony/form": "^6.4|^7.0",
- "symfony/expression-language": "^6.4|^7.0",
- "symfony/html-sanitizer": "^6.4|^7.0",
- "symfony/http-client": "^6.4|^7.0",
- "symfony/lock": "^6.4|^7.0",
- "symfony/mailer": "^6.4|^7.0",
- "symfony/messenger": "^6.4|^7.0",
- "symfony/mime": "^6.4|^7.0",
- "symfony/notifier": "^6.4|^7.0",
- "symfony/object-mapper": "^v7.3.0-beta2",
- "symfony/process": "^6.4|^7.0",
- "symfony/rate-limiter": "^6.4|^7.0",
- "symfony/scheduler": "^6.4.4|^7.0.4",
- "symfony/security-bundle": "^6.4|^7.0",
- "symfony/semaphore": "^6.4|^7.0",
- "symfony/serializer": "^7.2.5",
- "symfony/stopwatch": "^6.4|^7.0",
- "symfony/string": "^6.4|^7.0",
- "symfony/translation": "^7.3",
- "symfony/twig-bundle": "^6.4|^7.0",
- "symfony/type-info": "^7.1.8",
- "symfony/validator": "^6.4|^7.0",
- "symfony/workflow": "^7.3",
- "symfony/yaml": "^6.4|^7.0",
- "symfony/property-info": "^6.4|^7.0",
- "symfony/json-streamer": "7.3.*",
- "symfony/uid": "^6.4|^7.0",
- "symfony/web-link": "^6.4|^7.0",
- "symfony/webhook": "^7.2",
+ "symfony/form": "^6.4|^7.0|^8.0",
+ "symfony/expression-language": "^6.4|^7.0|^8.0",
+ "symfony/html-sanitizer": "^6.4|^7.0|^8.0",
+ "symfony/http-client": "^6.4|^7.0|^8.0",
+ "symfony/lock": "^6.4|^7.0|^8.0",
+ "symfony/mailer": "^6.4|^7.0|^8.0",
+ "symfony/messenger": "^6.4|^7.0|^8.0",
+ "symfony/mime": "^6.4|^7.0|^8.0",
+ "symfony/notifier": "^6.4|^7.0|^8.0",
+ "symfony/object-mapper": "^7.3|^8.0",
+ "symfony/process": "^6.4|^7.0|^8.0",
+ "symfony/rate-limiter": "^6.4|^7.0|^8.0",
+ "symfony/runtime": "^6.4.13|^7.1.6|^8.0",
+ "symfony/scheduler": "^6.4.4|^7.0.4|^8.0",
+ "symfony/security-bundle": "^6.4|^7.0|^8.0",
+ "symfony/semaphore": "^6.4|^7.0|^8.0",
+ "symfony/serializer": "^7.2.5|^8.0",
+ "symfony/stopwatch": "^6.4|^7.0|^8.0",
+ "symfony/string": "^6.4|^7.0|^8.0",
+ "symfony/translation": "^7.3|^8.0",
+ "symfony/twig-bundle": "^6.4|^7.0|^8.0",
+ "symfony/type-info": "^7.1.8|^8.0",
+ "symfony/validator": "^7.4|^8.0",
+ "symfony/workflow": "^7.3|^8.0",
+ "symfony/yaml": "^6.4|^7.0|^8.0",
+ "symfony/property-info": "^6.4|^7.0|^8.0",
+ "symfony/json-streamer": "^7.3|^8.0",
+ "symfony/uid": "^6.4|^7.0|^8.0",
+ "symfony/web-link": "^6.4|^7.0|^8.0",
+ "symfony/webhook": "^7.2|^8.0",
"phpdocumentor/reflection-docblock": "^3.0|^4.0|^5.0",
"twig/twig": "^3.12"
},
@@ -89,12 +91,10 @@
"symfony/dom-crawler": "<6.4",
"symfony/http-client": "<6.4",
"symfony/form": "<6.4",
- "symfony/json-streamer": ">=7.4",
"symfony/lock": "<6.4",
"symfony/mailer": "<6.4",
"symfony/messenger": "<6.4",
"symfony/mime": "<6.4",
- "symfony/object-mapper": ">=7.4",
"symfony/property-info": "<6.4",
"symfony/property-access": "<6.4",
"symfony/runtime": "<6.4.13|>=7.0,<7.1.6",
@@ -117,5 +117,10 @@
"/Tests/"
]
},
- "minimum-stability": "dev"
+ "minimum-stability": "dev",
+ "config": {
+ "allow-plugins": {
+ "symfony/runtime": false
+ }
+ }
}
diff --git a/phpunit.xml.dist b/phpunit.xml.dist
index d00ee0f1e..90e1a751e 100644
--- a/phpunit.xml.dist
+++ b/phpunit.xml.dist
@@ -1,10 +1,11 @@
@@ -20,7 +21,7 @@
-
+
./
@@ -29,5 +30,9 @@
./Tests
./vendor
-
+
+
+
+
+