diff --git a/.appveyor.yml b/.appveyor.yml
index 5f9ba4577a64b..5474f89111c2a 100644
--- a/.appveyor.yml
+++ b/.appveyor.yml
@@ -62,9 +62,9 @@ test_script:
- copy /Y c:\php\php.ini-min c:\php\php.ini
- IF %APPVEYOR_REPO_BRANCH:~-2% neq .x (rm -Rf src\Symfony\Bridge\PhpUnit)
- mv src\Symfony\Component\HttpClient\phpunit.xml.dist src\Symfony\Component\HttpClient\phpunit.xml
- - php phpunit src\Symfony --exclude-group tty,benchmark,intl-data || SET X=!errorlevel!
+ - php phpunit src\Symfony --exclude-group tty,benchmark,intl-data,network,transient-on-windows || SET X=!errorlevel!
- php phpunit src\Symfony\Component\HttpClient || SET X=!errorlevel!
- copy /Y c:\php\php.ini-max c:\php\php.ini
- - php phpunit src\Symfony --exclude-group tty,benchmark,intl-data || SET X=!errorlevel!
+ - php phpunit src\Symfony --exclude-group tty,benchmark,intl-data,network,transient-on-windows || SET X=!errorlevel!
- php phpunit src\Symfony\Component\HttpClient || SET X=!errorlevel!
- exit %X%
diff --git a/.github/expected-missing-return-types.diff b/.github/expected-missing-return-types.diff
index 038db511c4403..594290521dab2 100644
--- a/.github/expected-missing-return-types.diff
+++ b/.github/expected-missing-return-types.diff
@@ -6,7 +6,7 @@ head=$(sed '/^diff /Q' .github/expected-missing-return-types.diff)
(echo "$head" && echo && git diff -U2 composer.json src/) > .github/expected-missing-return-types.diff
diff --git a/composer.json b/composer.json
-index 1bc576b112..589ef8c260 100644
+index 1750d55ee2..c18494167a 100644
--- a/composer.json
+++ b/composer.json
@@ -175,5 +175,5 @@
@@ -16,8 +16,19 @@ index 1bc576b112..589ef8c260 100644
+
]
},
+diff --git a/src/Symfony/Bundle/FrameworkBundle/Test/KernelTestCase.php b/src/Symfony/Bundle/FrameworkBundle/Test/KernelTestCase.php
+index d68ae4c8b3..8e980a9e70 100644
+--- a/src/Symfony/Bundle/FrameworkBundle/Test/KernelTestCase.php
++++ b/src/Symfony/Bundle/FrameworkBundle/Test/KernelTestCase.php
+@@ -88,5 +88,5 @@ abstract class KernelTestCase extends TestCase
+ * @return TestContainer
+ */
+- protected static function getContainer(): ContainerInterface
++ protected static function getContainer(): TestContainer
+ {
+ if (!static::$booted) {
diff --git a/src/Symfony/Component/BrowserKit/AbstractBrowser.php b/src/Symfony/Component/BrowserKit/AbstractBrowser.php
-index 152050159b..e2ec1aeea2 100644
+index 697e34cb77..9a1e4c5618 100644
--- a/src/Symfony/Component/BrowserKit/AbstractBrowser.php
+++ b/src/Symfony/Component/BrowserKit/AbstractBrowser.php
@@ -408,5 +408,5 @@ abstract class AbstractBrowser
@@ -144,7 +155,7 @@ index 6b1c6c5fbe..bb80ed461e 100644
+ public function isFresh(ResourceInterface $resource, int $timestamp): bool;
}
diff --git a/src/Symfony/Component/Console/Application.php b/src/Symfony/Component/Console/Application.php
-index b582435f7d..3d5f064773 100644
+index 0ed5649b8a..6c814bf82c 100644
--- a/src/Symfony/Component/Console/Application.php
+++ b/src/Symfony/Component/Console/Application.php
@@ -218,5 +218,5 @@ class Application implements ResetInterface
@@ -197,7 +208,7 @@ index b582435f7d..3d5f064773 100644
{
foreach ($command->getHelperSet() as $helper) {
diff --git a/src/Symfony/Component/Console/Command/Command.php b/src/Symfony/Component/Console/Command/Command.php
-index d6354b4ab1..b267917312 100644
+index 0bd3426c07..b38caf989e 100644
--- a/src/Symfony/Component/Console/Command/Command.php
+++ b/src/Symfony/Component/Console/Command/Command.php
@@ -171,5 +171,5 @@ class Command
@@ -250,10 +261,10 @@ index 024da1884e..943790e875 100644
/**
diff --git a/src/Symfony/Component/DependencyInjection/Compiler/AbstractRecursivePass.php b/src/Symfony/Component/DependencyInjection/Compiler/AbstractRecursivePass.php
-index 1acec50de5..904e67a47b 100644
+index 326d8d4f5f..e62124c7af 100644
--- a/src/Symfony/Component/DependencyInjection/Compiler/AbstractRecursivePass.php
+++ b/src/Symfony/Component/DependencyInjection/Compiler/AbstractRecursivePass.php
-@@ -70,5 +70,5 @@ abstract class AbstractRecursivePass implements CompilerPassInterface
+@@ -71,5 +71,5 @@ abstract class AbstractRecursivePass implements CompilerPassInterface
* @return mixed
*/
- protected function processValue(mixed $value, bool $isRoot = false)
@@ -261,7 +272,7 @@ index 1acec50de5..904e67a47b 100644
{
if (\is_array($value)) {
diff --git a/src/Symfony/Component/DependencyInjection/Container.php b/src/Symfony/Component/DependencyInjection/Container.php
-index 0532120adf..78fba5ef79 100644
+index b9dd838898..3a8cb63eac 100644
--- a/src/Symfony/Component/DependencyInjection/Container.php
+++ b/src/Symfony/Component/DependencyInjection/Container.php
@@ -108,5 +108,5 @@ class Container implements ContainerInterface, ResetInterface
@@ -535,7 +546,7 @@ index 1cb865fd66..f6f4efe7a7 100644
+ public function getName(): string;
}
diff --git a/src/Symfony/Component/HttpKernel/HttpCache/HttpCache.php b/src/Symfony/Component/HttpKernel/HttpCache/HttpCache.php
-index 8e7b80a909..d757429d36 100644
+index cf0e243c6b..292b907ea8 100644
--- a/src/Symfony/Component/HttpKernel/HttpCache/HttpCache.php
+++ b/src/Symfony/Component/HttpKernel/HttpCache/HttpCache.php
@@ -448,5 +448,5 @@ class HttpCache implements HttpKernelInterface, TerminableInterface
@@ -544,9 +555,9 @@ index 8e7b80a909..d757429d36 100644
- protected function forward(Request $request, bool $catch = false, Response $entry = null)
+ protected function forward(Request $request, bool $catch = false, Response $entry = null): Response
{
- if ($this->surrogate) {
+ $this->surrogate?->addSurrogateCapability($request);
diff --git a/src/Symfony/Component/HttpKernel/HttpKernelBrowser.php b/src/Symfony/Component/HttpKernel/HttpKernelBrowser.php
-index f4773eb62a..0ba648b57f 100644
+index 3ecc2c739c..d50834b6d9 100644
--- a/src/Symfony/Component/HttpKernel/HttpKernelBrowser.php
+++ b/src/Symfony/Component/HttpKernel/HttpKernelBrowser.php
@@ -61,5 +61,5 @@ class HttpKernelBrowser extends AbstractBrowser
@@ -581,8 +592,25 @@ index 19ff0db181..f0f4a5829f 100644
+ public function countErrors(Request $request = null): int;
/**
+diff --git a/src/Symfony/Component/Messenger/Envelope.php b/src/Symfony/Component/Messenger/Envelope.php
+index bb1194ad1b..bd7fc440ff 100644
+--- a/src/Symfony/Component/Messenger/Envelope.php
++++ b/src/Symfony/Component/Messenger/Envelope.php
+@@ -13,4 +13,5 @@ namespace Symfony\Component\Messenger;
+
+ use Symfony\Component\Messenger\Stamp\StampInterface;
++use Symfony\Component\Messenger\Stamp\StampInterface as TStamp;
+
+ /**
+@@ -101,5 +102,5 @@ final class Envelope
+ * @return TStamp|null
+ */
+- public function last(string $stampFqcn): ?StampInterface
++ public function last(string $stampFqcn): ?TStamp
+ {
+ return isset($this->stamps[$stampFqcn]) ? end($this->stamps[$stampFqcn]) : null;
diff --git a/src/Symfony/Component/OptionsResolver/OptionsResolver.php b/src/Symfony/Component/OptionsResolver/OptionsResolver.php
-index fe77644762..09dcfe166b 100644
+index 205c15b4cd..e93e460ed1 100644
--- a/src/Symfony/Component/OptionsResolver/OptionsResolver.php
+++ b/src/Symfony/Component/OptionsResolver/OptionsResolver.php
@@ -486,5 +486,5 @@ class OptionsResolver implements Options
@@ -858,7 +886,7 @@ index b0a1f3218b..893fe59e2f 100644
{
if (null !== $object = $this->extractObjectToPopulate($class, $context, self::OBJECT_TO_POPULATE)) {
diff --git a/src/Symfony/Component/Serializer/Normalizer/AbstractObjectNormalizer.php b/src/Symfony/Component/Serializer/Normalizer/AbstractObjectNormalizer.php
-index a241215133..2ed1af7a02 100644
+index 3e1e7edc8e..e025b2bc4a 100644
--- a/src/Symfony/Component/Serializer/Normalizer/AbstractObjectNormalizer.php
+++ b/src/Symfony/Component/Serializer/Normalizer/AbstractObjectNormalizer.php
@@ -136,5 +136,5 @@ abstract class AbstractObjectNormalizer extends AbstractNormalizer
@@ -1002,3 +1030,35 @@ index d6dcdf178f..0ab8d9c10e 100644
+ public function getTargets(): string|array
{
return self::PROPERTY_CONSTRAINT;
+diff --git a/src/Symfony/Component/Workflow/Event/Event.php b/src/Symfony/Component/Workflow/Event/Event.php
+index cd7fab7896..b340eba38e 100644
+--- a/src/Symfony/Component/Workflow/Event/Event.php
++++ b/src/Symfony/Component/Workflow/Event/Event.php
+@@ -42,5 +42,5 @@ class Event extends BaseEvent
+ * @return Marking
+ */
+- public function getMarking()
++ public function getMarking(): Marking
+ {
+ return $this->marking;
+@@ -50,5 +50,5 @@ class Event extends BaseEvent
+ * @return object
+ */
+- public function getSubject()
++ public function getSubject(): object
+ {
+ return $this->subject;
+@@ -58,5 +58,5 @@ class Event extends BaseEvent
+ * @return Transition|null
+ */
+- public function getTransition()
++ public function getTransition(): ?Transition
+ {
+ return $this->transition;
+@@ -71,5 +71,5 @@ class Event extends BaseEvent
+ * @return string
+ */
+- public function getWorkflowName()
++ public function getWorkflowName(): string
+ {
+ return $this->workflow->getName();
diff --git a/.github/workflows/unit-tests.yml b/.github/workflows/unit-tests.yml
index 801d9e270c20f..9dc6394adce41 100644
--- a/.github/workflows/unit-tests.yml
+++ b/.github/workflows/unit-tests.yml
@@ -72,7 +72,7 @@ jobs:
([ -d "$COMPOSER_HOME" ] || mkdir "$COMPOSER_HOME") && cp .github/composer-config.json "$COMPOSER_HOME/config.json"
echo COLUMNS=120 >> $GITHUB_ENV
- echo PHPUNIT="$(pwd)/phpunit --exclude-group tty,benchmark,intl-data" >> $GITHUB_ENV
+ echo PHPUNIT="$(pwd)/phpunit --exclude-group tty,benchmark,intl-data$([[ ${{ matrix.os }} = macos* ]] && echo ',transient-on-macos')" >> $GITHUB_ENV
echo COMPOSER_UP='composer update --no-progress --ansi' >> $GITHUB_ENV
SYMFONY_VERSIONS=$(git ls-remote -q --heads | cut -f2 | grep -o '/[1-9][0-9]*\.[0-9].*' | sort -V)
@@ -146,7 +146,7 @@ jobs:
echo "::endgroup::"
- name: Patch return types
- if: "matrix.php == '8.1' && ! matrix.mode && matrix.os == 'ubuntu-20.04'"
+ if: "matrix.php == '8.1' && ! matrix.mode && matrix.os != 'macos-11'"
run: |
patch -sp1 < .github/expected-missing-return-types.diff
git add .
@@ -224,7 +224,7 @@ jobs:
[[ ! $X ]] || (exit 1)
- name: Run tests with SIGCHLD enabled PHP
- if: "matrix.php == '8.0' && ! matrix.mode"
+ if: "matrix.php == '8.0' && ! matrix.mode && matrix.os != 'macos-11'"
run: |
mkdir build
cd build
diff --git a/.php-cs-fixer.dist.php b/.php-cs-fixer.dist.php
index 8b50502e98c7e..2333c06badd58 100644
--- a/.php-cs-fixer.dist.php
+++ b/.php-cs-fixer.dist.php
@@ -11,6 +11,7 @@
'@Symfony' => true,
'@Symfony:risky' => true,
'protected_to_private' => false,
+ 'native_constant_invocation' => ['strict' => false],
'nullable_type_declaration_for_default_null_value' => ['use_nullable_type_declaration' => false],
'modernize_strpos' => true,
])
diff --git a/composer.json b/composer.json
index 61a7251983f12..1750d55ee22ce 100644
--- a/composer.json
+++ b/composer.json
@@ -157,7 +157,7 @@
"egulias/email-validator": "~3.0.0",
"masterminds/html5": "<2.6",
"phpdocumentor/reflection-docblock": "<5.2",
- "phpdocumentor/type-resolver": "<1.4.0",
+ "phpdocumentor/type-resolver": "<1.5.1",
"ocramius/proxy-manager": "<2.1",
"phpunit/phpunit": "<5.4.3"
},
diff --git a/src/Symfony/Bridge/Doctrine/ContainerAwareEventManager.php b/src/Symfony/Bridge/Doctrine/ContainerAwareEventManager.php
index 82a4f36ce349c..d262c5e3591e4 100644
--- a/src/Symfony/Bridge/Doctrine/ContainerAwareEventManager.php
+++ b/src/Symfony/Bridge/Doctrine/ContainerAwareEventManager.php
@@ -56,7 +56,7 @@ public function dispatchEvent($eventName, EventArgs $eventArgs = null): void
return;
}
- $eventArgs = $eventArgs ?? EventArgs::getEmptyInstance();
+ $eventArgs ??= EventArgs::getEmptyInstance();
if (!isset($this->initialized[$eventName])) {
$this->initializeListeners($eventName);
diff --git a/src/Symfony/Bridge/Doctrine/DependencyInjection/AbstractDoctrineExtension.php b/src/Symfony/Bridge/Doctrine/DependencyInjection/AbstractDoctrineExtension.php
index 367eb12e29162..4774019da3349 100644
--- a/src/Symfony/Bridge/Doctrine/DependencyInjection/AbstractDoctrineExtension.php
+++ b/src/Symfony/Bridge/Doctrine/DependencyInjection/AbstractDoctrineExtension.php
@@ -134,8 +134,6 @@ protected function setMappingDriverConfig(array $mappingConfig, string $mappingN
* If this is a bundle controlled mapping all the missing information can be autodetected by this method.
*
* Returns false when autodetection failed, an array of the completed information otherwise.
- *
- * @return array|false
*/
protected function getMappingDriverBundleConfigDefaults(array $bundleConfig, \ReflectionClass $bundle, ContainerBuilder $container, string $bundleDir = null): array|false
{
diff --git a/src/Symfony/Bridge/Doctrine/Logger/DbalLogger.php b/src/Symfony/Bridge/Doctrine/Logger/DbalLogger.php
index f9bd6e0cbcf73..b4cc571bb56fc 100644
--- a/src/Symfony/Bridge/Doctrine/Logger/DbalLogger.php
+++ b/src/Symfony/Bridge/Doctrine/Logger/DbalLogger.php
@@ -37,9 +37,7 @@ public function __construct(LoggerInterface $logger = null, Stopwatch $stopwatch
*/
public function startQuery($sql, array $params = null, array $types = null): void
{
- if (null !== $this->stopwatch) {
- $this->stopwatch->start('doctrine', 'doctrine');
- }
+ $this->stopwatch?->start('doctrine', 'doctrine');
if (null !== $this->logger) {
$this->log($sql, null === $params ? [] : $this->normalizeParams($params));
@@ -51,9 +49,7 @@ public function startQuery($sql, array $params = null, array $types = null): voi
*/
public function stopQuery(): void
{
- if (null !== $this->stopwatch) {
- $this->stopwatch->stop('doctrine');
- }
+ $this->stopwatch?->stop('doctrine');
}
/**
diff --git a/src/Symfony/Bridge/Doctrine/Validator/DoctrineInitializer.php b/src/Symfony/Bridge/Doctrine/Validator/DoctrineInitializer.php
index 28d5fccc7459c..3e7922ec79276 100644
--- a/src/Symfony/Bridge/Doctrine/Validator/DoctrineInitializer.php
+++ b/src/Symfony/Bridge/Doctrine/Validator/DoctrineInitializer.php
@@ -30,9 +30,6 @@ public function __construct(ManagerRegistry $registry)
public function initialize(object $object)
{
- $manager = $this->registry->getManagerForClass(\get_class($object));
- if (null !== $manager) {
- $manager->initializeObject($object);
- }
+ $this->registry->getManagerForClass(\get_class($object))?->initializeObject($object);
}
}
diff --git a/src/Symfony/Bridge/Doctrine/Validator/DoctrineLoader.php b/src/Symfony/Bridge/Doctrine/Validator/DoctrineLoader.php
index d06a34a40f630..a4e695d37df1b 100644
--- a/src/Symfony/Bridge/Doctrine/Validator/DoctrineLoader.php
+++ b/src/Symfony/Bridge/Doctrine/Validator/DoctrineLoader.php
@@ -49,7 +49,7 @@ public function loadClassMetadata(ClassMetadata $metadata): bool
$className = $metadata->getClassName();
try {
$doctrineMetadata = $this->entityManager->getClassMetadata($className);
- } catch (MappingException | OrmMappingException $exception) {
+ } catch (MappingException|OrmMappingException $exception) {
return false;
}
diff --git a/src/Symfony/Bridge/Twig/AppVariable.php b/src/Symfony/Bridge/Twig/AppVariable.php
index d21f6448a481b..b46646b5461ae 100644
--- a/src/Symfony/Bridge/Twig/AppVariable.php
+++ b/src/Symfony/Bridge/Twig/AppVariable.php
@@ -100,7 +100,7 @@ public function getSession(): ?Session
}
$request = $this->getRequest();
- return $request && $request->hasSession() ? $request->getSession() : null;
+ return $request?->hasSession() ? $request->getSession() : null;
}
/**
diff --git a/src/Symfony/Bridge/Twig/Command/LintCommand.php b/src/Symfony/Bridge/Twig/Command/LintCommand.php
index 6e73b9c3bb573..dfe66054bc496 100644
--- a/src/Symfony/Bridge/Twig/Command/LintCommand.php
+++ b/src/Symfony/Bridge/Twig/Command/LintCommand.php
@@ -230,9 +230,7 @@ private function renderException(SymfonyStyle $output, string $template, Error $
{
$line = $exception->getTemplateLine();
- if ($githubReporter) {
- $githubReporter->error($exception->getRawMessage(), $file, $line <= 0 ? null : $line);
- }
+ $githubReporter?->error($exception->getRawMessage(), $file, $line <= 0 ? null : $line);
if ($file) {
$output->text(sprintf(' ERROR in %s (line %s)', $file, $line));
diff --git a/src/Symfony/Bridge/Twig/UndefinedCallableHandler.php b/src/Symfony/Bridge/Twig/UndefinedCallableHandler.php
index 360a386faedec..30dd92ff2ff3b 100644
--- a/src/Symfony/Bridge/Twig/UndefinedCallableHandler.php
+++ b/src/Symfony/Bridge/Twig/UndefinedCallableHandler.php
@@ -68,9 +68,6 @@ class UndefinedCallableHandler
'workflow' => 'enable "framework.workflows"',
];
- /**
- * @return TwigFilter|false
- */
public static function onUndefinedFilter(string $name): TwigFilter|false
{
if (!isset(self::FILTER_COMPONENTS[$name])) {
@@ -80,9 +77,6 @@ public static function onUndefinedFilter(string $name): TwigFilter|false
throw new SyntaxError(self::onUndefined($name, 'filter', self::FILTER_COMPONENTS[$name]));
}
- /**
- * @return TwigFunction|false
- */
public static function onUndefinedFunction(string $name): TwigFunction|false
{
if (!isset(self::FUNCTION_COMPONENTS[$name])) {
diff --git a/src/Symfony/Bundle/FrameworkBundle/CHANGELOG.md b/src/Symfony/Bundle/FrameworkBundle/CHANGELOG.md
index 862a1ae089c7c..d3c5731888f6e 100644
--- a/src/Symfony/Bundle/FrameworkBundle/CHANGELOG.md
+++ b/src/Symfony/Bundle/FrameworkBundle/CHANGELOG.md
@@ -1,6 +1,11 @@
CHANGELOG
=========
+6.1
+---
+
+ * Environment variable `SYMFONY_IDE` is read by default when `framework.ide` config is not set.
+
6.0
---
diff --git a/src/Symfony/Bundle/FrameworkBundle/CacheWarmer/ConfigBuilderCacheWarmer.php b/src/Symfony/Bundle/FrameworkBundle/CacheWarmer/ConfigBuilderCacheWarmer.php
index 70c42c1e05301..95f62d9202203 100644
--- a/src/Symfony/Bundle/FrameworkBundle/CacheWarmer/ConfigBuilderCacheWarmer.php
+++ b/src/Symfony/Bundle/FrameworkBundle/CacheWarmer/ConfigBuilderCacheWarmer.php
@@ -55,9 +55,7 @@ public function warmUp(string $cacheDir): array
try {
$this->dumpExtension($extension, $generator);
} catch (\Exception $e) {
- if ($this->logger) {
- $this->logger->warning('Failed to generate ConfigBuilder for extension {extensionClass}.', ['exception' => $e, 'extensionClass' => \get_class($extension)]);
- }
+ $this->logger?->warning('Failed to generate ConfigBuilder for extension {extensionClass}.', ['exception' => $e, 'extensionClass' => \get_class($extension)]);
}
}
diff --git a/src/Symfony/Bundle/FrameworkBundle/Command/SecretsListCommand.php b/src/Symfony/Bundle/FrameworkBundle/Command/SecretsListCommand.php
index 96f0f3762d393..a9d31e2217967 100644
--- a/src/Symfony/Bundle/FrameworkBundle/Command/SecretsListCommand.php
+++ b/src/Symfony/Bundle/FrameworkBundle/Command/SecretsListCommand.php
@@ -70,7 +70,7 @@ protected function execute(InputInterface $input, OutputInterface $output): int
}
$secrets = $this->vault->list($reveal);
- $localSecrets = null !== $this->localVault ? $this->localVault->list($reveal) : null;
+ $localSecrets = $this->localVault?->list($reveal);
$rows = [];
diff --git a/src/Symfony/Bundle/FrameworkBundle/Command/WorkflowDumpCommand.php b/src/Symfony/Bundle/FrameworkBundle/Command/WorkflowDumpCommand.php
index 3cb0a4ffcbb6d..eb96e65470ebf 100644
--- a/src/Symfony/Bundle/FrameworkBundle/Command/WorkflowDumpCommand.php
+++ b/src/Symfony/Bundle/FrameworkBundle/Command/WorkflowDumpCommand.php
@@ -36,7 +36,8 @@
class WorkflowDumpCommand extends Command
{
/**
- * string is the service id
+ * string is the service id.
+ *
* @var array
*/
private array $workflows = [];
diff --git a/src/Symfony/Bundle/FrameworkBundle/Controller/AbstractController.php b/src/Symfony/Bundle/FrameworkBundle/Controller/AbstractController.php
index 1ae52cb1ee1a1..86c365c258fb6 100644
--- a/src/Symfony/Bundle/FrameworkBundle/Controller/AbstractController.php
+++ b/src/Symfony/Bundle/FrameworkBundle/Controller/AbstractController.php
@@ -70,8 +70,6 @@ public function setContainer(ContainerInterface $container): ?ContainerInterface
/**
* Gets a container parameter by its name.
- *
- * @return array|bool|float|int|string|null
*/
protected function getParameter(string $name): array|bool|float|int|string|null
{
diff --git a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Configuration.php b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Configuration.php
index 198a434c98603..5b35c99ec6741 100644
--- a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Configuration.php
+++ b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Configuration.php
@@ -80,7 +80,7 @@ public function getConfigTreeBuilder(): TreeBuilder
->info("Set true to enable support for the '_method' request parameter to determine the intended HTTP method on POST requests. Note: When using the HttpCache, you need to call the method in your front controller instead")
->defaultTrue()
->end()
- ->scalarNode('ide')->defaultNull()->end()
+ ->scalarNode('ide')->defaultValue('%env(default::SYMFONY_IDE)%')->end()
->booleanNode('test')->end()
->scalarNode('default_locale')->defaultValue('en')->end()
->booleanNode('set_locale_from_accept_language')
@@ -2038,6 +2038,9 @@ private function addUidSection(ArrayNodeDefinition $rootNode, callable $enableIf
->scalarNode('time_based_uuid_node')
->cannotBeEmpty()
->end()
+ ->arrayNode('argument_value_resolver')
+ ->canBeEnabled()
+ ->end()
->end()
->end()
->end()
diff --git a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php
index 2a74d17458882..9451cd74efde1 100644
--- a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php
+++ b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php
@@ -190,6 +190,8 @@
use Symfony\Component\Translation\Command\XliffLintCommand as BaseXliffLintCommand;
use Symfony\Component\Translation\PseudoLocalizationTranslator;
use Symfony\Component\Translation\Translator;
+use Symfony\Component\Uid\AbstractUid;
+use Symfony\Component\Uid\ArgumentResolver\UidValueResolver;
use Symfony\Component\Uid\Factory\UuidFactory;
use Symfony\Component\Uid\UuidV4;
use Symfony\Component\Validator\ConstraintValidatorInterface;
@@ -2545,6 +2547,18 @@ private function registerUidConfiguration(array $config, ContainerBuilder $conta
$container->getDefinition('name_based_uuid.factory')
->setArguments([$config['name_based_uuid_namespace']]);
}
+
+ if (!$config['argument_value_resolver']['enabled']) {
+ $container->removeDefinition('argument_resolver.uid');
+
+ return;
+ } elseif (!class_exists(UidValueResolver::class)) {
+ throw new LogicException('Uid argument value resolver cannot be enabled as the installed Uid component version is too low. Try running "composer require symfony/uid:^6.1".');
+ }
+
+ $container->setParameter('uid.base58', AbstractUid::BASE58);
+ $container->setParameter('uid.base32', AbstractUid::BASE32);
+ $container->setParameter('uid.rfc4122', AbstractUid::RFC4122);
}
private function resolveTrustedHeaders(array $headers): int
diff --git a/src/Symfony/Bundle/FrameworkBundle/KernelBrowser.php b/src/Symfony/Bundle/FrameworkBundle/KernelBrowser.php
index a85eb3d017c1e..6795e3c22aa0e 100644
--- a/src/Symfony/Bundle/FrameworkBundle/KernelBrowser.php
+++ b/src/Symfony/Bundle/FrameworkBundle/KernelBrowser.php
@@ -62,8 +62,6 @@ public function getKernel(): KernelInterface
/**
* Gets the profile associated with the current Response.
- *
- * @return HttpProfile|false|null
*/
public function getProfile(): HttpProfile|false|null
{
diff --git a/src/Symfony/Bundle/FrameworkBundle/Resources/config/mailer_debug.php b/src/Symfony/Bundle/FrameworkBundle/Resources/config/mailer_debug.php
index 3fb6ce0a42d49..cdb205750f05d 100644
--- a/src/Symfony/Bundle/FrameworkBundle/Resources/config/mailer_debug.php
+++ b/src/Symfony/Bundle/FrameworkBundle/Resources/config/mailer_debug.php
@@ -12,7 +12,6 @@
namespace Symfony\Component\DependencyInjection\Loader\Configurator;
use Symfony\Component\Mailer\DataCollector\MessageDataCollector;
-use Symfony\Component\Mailer\EventListener\MessageLoggerListener;
return static function (ContainerConfigurator $container) {
$container->services()
diff --git a/src/Symfony/Bundle/FrameworkBundle/Resources/config/schema/symfony-1.0.xsd b/src/Symfony/Bundle/FrameworkBundle/Resources/config/schema/symfony-1.0.xsd
index d48e8ca1520f7..1a9b7f611bf04 100644
--- a/src/Symfony/Bundle/FrameworkBundle/Resources/config/schema/symfony-1.0.xsd
+++ b/src/Symfony/Bundle/FrameworkBundle/Resources/config/schema/symfony-1.0.xsd
@@ -735,6 +735,9 @@
+
+
+
@@ -765,6 +768,10 @@
+
+
+
+
diff --git a/src/Symfony/Bundle/FrameworkBundle/Resources/config/uid.php b/src/Symfony/Bundle/FrameworkBundle/Resources/config/uid.php
index 840fb97b5f5f5..f6a40a656feeb 100644
--- a/src/Symfony/Bundle/FrameworkBundle/Resources/config/uid.php
+++ b/src/Symfony/Bundle/FrameworkBundle/Resources/config/uid.php
@@ -11,6 +11,7 @@
namespace Symfony\Component\DependencyInjection\Loader\Configurator;
+use Symfony\Component\Uid\ArgumentResolver\UidValueResolver;
use Symfony\Component\Uid\Factory\NameBasedUuidFactory;
use Symfony\Component\Uid\Factory\RandomBasedUuidFactory;
use Symfony\Component\Uid\Factory\TimeBasedUuidFactory;
@@ -37,5 +38,8 @@
->set('time_based_uuid.factory', TimeBasedUuidFactory::class)
->factory([service('uuid.factory'), 'timeBased'])
->alias(TimeBasedUuidFactory::class, 'time_based_uuid.factory')
+
+ ->set('argument_resolver.uid', UidValueResolver::class)
+ ->tag('controller.argument_value_resolver', ['priority' => 150]) // Higher than RequestAttributeValueResolver
;
};
diff --git a/src/Symfony/Bundle/FrameworkBundle/Test/KernelTestCase.php b/src/Symfony/Bundle/FrameworkBundle/Test/KernelTestCase.php
index ba02c761d73dc..d68ae4c8b3ba5 100644
--- a/src/Symfony/Bundle/FrameworkBundle/Test/KernelTestCase.php
+++ b/src/Symfony/Bundle/FrameworkBundle/Test/KernelTestCase.php
@@ -84,6 +84,8 @@ protected static function bootKernel(array $options = []): KernelInterface
* used by other services.
*
* Using this method is the best way to get a container from your test code.
+ *
+ * @return TestContainer
*/
protected static function getContainer(): ContainerInterface
{
diff --git a/src/Symfony/Bundle/FrameworkBundle/Test/TestContainer.php b/src/Symfony/Bundle/FrameworkBundle/Test/TestContainer.php
index 4ce5772d91e63..75a87870691d2 100644
--- a/src/Symfony/Bundle/FrameworkBundle/Test/TestContainer.php
+++ b/src/Symfony/Bundle/FrameworkBundle/Test/TestContainer.php
@@ -63,8 +63,6 @@ public function getParameterBag(): ParameterBagInterface
/**
* {@inheritdoc}
- *
- * @return array|bool|float|int|string|null
*/
public function getParameter(string $name): array|bool|float|int|string|null
{
diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/ConfigurationTest.php b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/ConfigurationTest.php
index abf4503fad168..7c8f71011fc3f 100644
--- a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/ConfigurationTest.php
+++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/ConfigurationTest.php
@@ -368,7 +368,7 @@ protected static function getBundleDefaultConfig()
{
return [
'http_method_override' => true,
- 'ide' => null,
+ 'ide' => '%env(default::SYMFONY_IDE)%',
'default_locale' => 'en',
'enabled_locales' => [],
'set_locale_from_accept_language' => false,
@@ -580,6 +580,9 @@ class_exists(SemaphoreStore::class) && SemaphoreStore::isSupported() ? 'semaphor
'default_uuid_version' => 6,
'name_based_uuid_version' => 5,
'time_based_uuid_version' => 6,
+ 'argument_value_resolver' => [
+ 'enabled' => false,
+ ],
],
'exceptions' => [],
];
diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/FrameworkExtensionTest.php b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/FrameworkExtensionTest.php
index e0a90423700c2..4b34e561f10b7 100644
--- a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/FrameworkExtensionTest.php
+++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/FrameworkExtensionTest.php
@@ -14,7 +14,6 @@
use Doctrine\Common\Annotations\Annotation;
use Psr\Cache\CacheItemPoolInterface;
use Psr\Log\LoggerAwareInterface;
-use Symfony\Bridge\PhpUnit\ExpectDeprecationTrait;
use Symfony\Bundle\FrameworkBundle\DependencyInjection\Compiler\AddAnnotationsCachedReaderPass;
use Symfony\Bundle\FrameworkBundle\DependencyInjection\FrameworkExtension;
use Symfony\Bundle\FrameworkBundle\Tests\Fixtures\Messenger\DummyMessage;
diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/Bundle/TestBundle/Controller/UidController.php b/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/Bundle/TestBundle/Controller/UidController.php
new file mode 100644
index 0000000000000..a4238e3fa53c3
--- /dev/null
+++ b/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/Bundle/TestBundle/Controller/UidController.php
@@ -0,0 +1,48 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Bundle\FrameworkBundle\Tests\Functional\Bundle\TestBundle\Controller;
+
+use Symfony\Component\HttpFoundation\Response;
+use Symfony\Component\Routing\Annotation\Route;
+use Symfony\Component\Uid\Ulid;
+use Symfony\Component\Uid\UuidV1;
+
+class UidController
+{
+ #[Route(path: '/1/uuid-v1/{userId}')]
+ public function anyFormat(UuidV1 $userId): Response
+ {
+ return new Response($userId);
+ }
+
+ #[Route(path: '/2/ulid/{id}', requirements: ['id' => Ulid::BASE58])]
+ public function specificFormatInAttribute(Ulid $id): Response
+ {
+ return new Response($id);
+ }
+
+ #[Route(path: '/3/uuid-v1/{id<%uid.base32%>}')]
+ public function specificFormatInPath(UuidV1 $id): Response
+ {
+ return new Response($id);
+ }
+
+ #[Route(path: '/4/uuid-v1/{postId}/custom-uid/{commentId}')]
+ public function manyUids(UuidV1 $postId, TestCommentIdentifier $commentId): Response
+ {
+ return new Response($postId."\n".$commentId);
+ }
+}
+
+class TestCommentIdentifier extends Ulid
+{
+}
diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/Bundle/TestBundle/DependencyInjection/Configuration.php b/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/Bundle/TestBundle/DependencyInjection/Configuration.php
index fb70137ff7b22..9120032e11028 100644
--- a/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/Bundle/TestBundle/DependencyInjection/Configuration.php
+++ b/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/Bundle/TestBundle/DependencyInjection/Configuration.php
@@ -27,9 +27,7 @@ public function getConfigTreeBuilder(): TreeBuilder
{
$treeBuilder = new TreeBuilder('test');
- if ($this->customConfig) {
- $this->customConfig->addConfiguration($treeBuilder->getRootNode());
- }
+ $this->customConfig?->addConfiguration($treeBuilder->getRootNode());
return $treeBuilder;
}
diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/Bundle/TestBundle/Resources/config/routing.yml b/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/Bundle/TestBundle/Resources/config/routing.yml
index 8d41ce3267131..bfd37826b268b 100644
--- a/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/Bundle/TestBundle/Resources/config/routing.yml
+++ b/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/Bundle/TestBundle/Resources/config/routing.yml
@@ -60,3 +60,7 @@ array_controller:
send_email:
path: /send_email
defaults: { _controller: Symfony\Bundle\FrameworkBundle\Tests\Functional\Bundle\TestBundle\Controller\EmailController::indexAction }
+
+uid:
+ resource: "../../Controller/UidController.php"
+ type: "annotation"
diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/UidTest.php b/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/UidTest.php
new file mode 100644
index 0000000000000..a2ff1f4614000
--- /dev/null
+++ b/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/UidTest.php
@@ -0,0 +1,73 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Bundle\FrameworkBundle\Tests\Functional;
+
+use Symfony\Bundle\FrameworkBundle\Tests\Functional\Bundle\TestBundle\Controller\UidController;
+use Symfony\Component\Uid\ArgumentResolver\UidValueResolver;
+use Symfony\Component\Uid\Ulid;
+use Symfony\Component\Uid\UuidV1;
+use Symfony\Component\Uid\UuidV4;
+use Symfony\Component\Uid\UuidV6;
+
+class UidTest extends AbstractWebTestCase
+{
+ /**
+ * @see UidController
+ */
+ public function testArgumentValueResolverConfigAllDefaults()
+ {
+ if (!class_exists(UidValueResolver::class)) {
+ $this->markTestSkipped('Needs symfony/uid >= 6.1');
+ }
+
+ $client = $this->createClient(['test_case' => 'Uid', 'root_config' => 'config.yml']);
+
+ // Any format
+ $client->request('GET', '/1/uuid-v1/'.$uuidV1 = new UuidV1());
+ $this->assertSame((string) $uuidV1, $client->getResponse()->getContent());
+ $client->request('GET', '/1/uuid-v1/'.$uuidV1->toBase58());
+ $this->assertSame((string) $uuidV1, $client->getResponse()->getContent());
+ $client->request('GET', '/1/uuid-v1/'.$uuidV1->toRfc4122());
+ $this->assertSame((string) $uuidV1, $client->getResponse()->getContent());
+ // Bad version
+ $client->request('GET', '/1/uuid-v1/'.$uuidV4 = new UuidV4());
+ $this->assertSame(404, $client->getResponse()->getStatusCode());
+
+ // Only base58 format
+ $client->request('GET', '/2/ulid/'.($ulid = new Ulid())->toBase58());
+ $this->assertSame((string) $ulid, $client->getResponse()->getContent());
+ $client->request('GET', '/2/ulid/'.$ulid);
+ $this->assertSame(404, $client->getResponse()->getStatusCode());
+ $client->request('GET', '/2/ulid/'.$ulid->toRfc4122());
+ $this->assertSame(404, $client->getResponse()->getStatusCode());
+
+ // Only base32 format
+ $client->request('GET', '/3/uuid-v1/'.$uuidV1->toBase32());
+ $this->assertSame((string) $uuidV1, $client->getResponse()->getContent());
+ $client->request('GET', '/3/uuid-v1/'.$uuidV1);
+ $this->assertSame(404, $client->getResponse()->getStatusCode());
+ $client->request('GET', '/3/uuid-v1/'.$uuidV1->toBase58());
+ $this->assertSame(404, $client->getResponse()->getStatusCode());
+ // Bad version
+ $client->request('GET', '/3/uuid-v1/'.(new UuidV6())->toBase32());
+ $this->assertSame(404, $client->getResponse()->getStatusCode());
+
+ // Any format for both
+ $client->request('GET', '/4/uuid-v1/'.$uuidV1.'/custom-uid/'.$ulid->toRfc4122());
+ $this->assertSame($uuidV1."\n".$ulid, $client->getResponse()->getContent());
+ $client->request('GET', '/4/uuid-v1/'.$uuidV1->toBase58().'/custom-uid/'.$ulid->toBase58());
+ $this->assertSame($uuidV1."\n".$ulid, $client->getResponse()->getContent());
+ // Bad version
+ $client->request('GET', '/4/uuid-v1/'.$uuidV4.'/custom-uid/'.$ulid);
+ $this->assertSame(404, $client->getResponse()->getStatusCode());
+ }
+}
diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/app/Uid/bundles.php b/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/app/Uid/bundles.php
new file mode 100644
index 0000000000000..15ff182c6fed5
--- /dev/null
+++ b/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/app/Uid/bundles.php
@@ -0,0 +1,18 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+use Symfony\Bundle\FrameworkBundle\FrameworkBundle;
+use Symfony\Bundle\FrameworkBundle\Tests\Functional\Bundle\TestBundle\TestBundle;
+
+return [
+ new FrameworkBundle(),
+ new TestBundle(),
+];
diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/app/Uid/config.yml b/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/app/Uid/config.yml
new file mode 100644
index 0000000000000..fad7b8d7e56c4
--- /dev/null
+++ b/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/app/Uid/config.yml
@@ -0,0 +1,6 @@
+imports:
+ - { resource: "../config/default.yml" }
+
+framework:
+ uid:
+ argument_value_resolver: ~
diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/app/Uid/routing.yml b/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/app/Uid/routing.yml
new file mode 100644
index 0000000000000..46a625a0183cb
--- /dev/null
+++ b/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/app/Uid/routing.yml
@@ -0,0 +1,2 @@
+uid:
+ resource: "@TestBundle/Resources/config/routing.yml"
diff --git a/src/Symfony/Bundle/FrameworkBundle/composer.json b/src/Symfony/Bundle/FrameworkBundle/composer.json
index 1d73dd97e57c0..eaaec6be0e8b6 100644
--- a/src/Symfony/Bundle/FrameworkBundle/composer.json
+++ b/src/Symfony/Bundle/FrameworkBundle/composer.json
@@ -58,6 +58,7 @@
"symfony/string": "^5.4|^6.0",
"symfony/translation": "^5.4|^6.0",
"symfony/twig-bundle": "^5.4|^6.0",
+ "symfony/uid": "^5.4|^6.0",
"symfony/validator": "^5.4|^6.0",
"symfony/workflow": "^5.4|^6.0",
"symfony/yaml": "^5.4|^6.0",
diff --git a/src/Symfony/Bundle/SecurityBundle/DataCollector/SecurityDataCollector.php b/src/Symfony/Bundle/SecurityBundle/DataCollector/SecurityDataCollector.php
index 27c6e10bcfde0..394006f55b66b 100644
--- a/src/Symfony/Bundle/SecurityBundle/DataCollector/SecurityDataCollector.php
+++ b/src/Symfony/Bundle/SecurityBundle/DataCollector/SecurityDataCollector.php
@@ -110,9 +110,7 @@ public function collect(Request $request, Response $response, \Throwable $except
$logoutUrl = null;
try {
- if (null !== $this->logoutUrlGenerator) {
- $logoutUrl = $this->logoutUrlGenerator->getLogoutPath();
- }
+ $logoutUrl = $this->logoutUrlGenerator?->getLogoutPath();
} catch (\Exception $e) {
// fail silently when the logout URL cannot be generated
}
@@ -187,7 +185,6 @@ public function collect(Request $request, Response $response, \Throwable $except
'authenticators' => $firewallConfig->getAuthenticators(),
];
-
// generate exit impersonation path from current request
if ($this->data['impersonated'] && null !== $switchUserConfig = $firewallConfig->getSwitchUser()) {
$exitPath = $request->getRequestUri();
diff --git a/src/Symfony/Bundle/SecurityBundle/Debug/TraceableListenerTrait.php b/src/Symfony/Bundle/SecurityBundle/Debug/TraceableListenerTrait.php
index 2ae1f4af9bb34..357d2414d8bf2 100644
--- a/src/Symfony/Bundle/SecurityBundle/Debug/TraceableListenerTrait.php
+++ b/src/Symfony/Bundle/SecurityBundle/Debug/TraceableListenerTrait.php
@@ -45,7 +45,7 @@ public function getInfo(): array
return [
'response' => $this->response,
'time' => $this->time,
- 'stub' => $this->stub ?? $this->stub = ClassStub::wrapCallable($this->listener instanceof TraceableAuthenticatorManagerListener ? $this->listener->getAuthenticatorManagerListener() : $this->listener),
+ 'stub' => $this->stub ??= ClassStub::wrapCallable($this->listener instanceof TraceableAuthenticatorManagerListener ? $this->listener->getAuthenticatorManagerListener() : $this->listener),
];
}
}
diff --git a/src/Symfony/Bundle/SecurityBundle/DependencyInjection/MainConfiguration.php b/src/Symfony/Bundle/SecurityBundle/DependencyInjection/MainConfiguration.php
index d9ec8167f20fe..d6973f2b668d4 100644
--- a/src/Symfony/Bundle/SecurityBundle/DependencyInjection/MainConfiguration.php
+++ b/src/Symfony/Bundle/SecurityBundle/DependencyInjection/MainConfiguration.php
@@ -65,7 +65,7 @@ public function getConfigTreeBuilder(): TreeBuilder
->end()
->booleanNode('hide_user_not_found')->defaultTrue()->end()
->booleanNode('erase_credentials')->defaultTrue()->end()
- ->booleanNode('enable_authenticator_manager')->defaultFalse()->info('Enables the new Symfony Security system based on Authenticators, all used authenticators must support this before enabling this.')->end()
+ ->booleanNode('enable_authenticator_manager')->defaultTrue()->end()
->arrayNode('access_decision_manager')
->addDefaultsIfNotSet()
->children()
diff --git a/src/Symfony/Bundle/WebProfilerBundle/Controller/ProfilerController.php b/src/Symfony/Bundle/WebProfilerBundle/Controller/ProfilerController.php
index 4e76f9bcc1404..6b73f21ec2b41 100644
--- a/src/Symfony/Bundle/WebProfilerBundle/Controller/ProfilerController.php
+++ b/src/Symfony/Bundle/WebProfilerBundle/Controller/ProfilerController.php
@@ -71,9 +71,7 @@ public function panelAction(Request $request, string $token): Response
{
$this->denyAccessIfProfilerDisabled();
- if (null !== $this->cspHandler) {
- $this->cspHandler->disableCsp();
- }
+ $this->cspHandler?->disableCsp();
$panel = $request->query->get('panel');
$page = $request->query->get('page', 'home');
@@ -172,9 +170,7 @@ public function searchBarAction(Request $request): Response
{
$this->denyAccessIfProfilerDisabled();
- if (null !== $this->cspHandler) {
- $this->cspHandler->disableCsp();
- }
+ $this->cspHandler?->disableCsp();
if (!$request->hasSession()) {
$ip =
@@ -224,9 +220,7 @@ public function searchResultsAction(Request $request, string $token): Response
{
$this->denyAccessIfProfilerDisabled();
- if (null !== $this->cspHandler) {
- $this->cspHandler->disableCsp();
- }
+ $this->cspHandler?->disableCsp();
$profile = $this->profiler->loadProfile($token);
@@ -312,9 +306,7 @@ public function phpinfoAction(): Response
{
$this->denyAccessIfProfilerDisabled();
- if (null !== $this->cspHandler) {
- $this->cspHandler->disableCsp();
- }
+ $this->cspHandler?->disableCsp();
ob_start();
phpinfo();
@@ -336,9 +328,7 @@ public function xdebugAction(): Response
throw new NotFoundHttpException('Xdebug must be installed in version 3.');
}
- if (null !== $this->cspHandler) {
- $this->cspHandler->disableCsp();
- }
+ $this->cspHandler?->disableCsp();
ob_start();
xdebug_info();
@@ -358,9 +348,7 @@ public function openAction(Request $request): Response
throw new NotFoundHttpException('The base dir should be set.');
}
- if ($this->profiler) {
- $this->profiler->disable();
- }
+ $this->profiler?->disable();
$file = $request->query->get('file');
$line = $request->query->get('line');
diff --git a/src/Symfony/Bundle/WebProfilerBundle/EventListener/WebDebugToolbarListener.php b/src/Symfony/Bundle/WebProfilerBundle/EventListener/WebDebugToolbarListener.php
index f4bfec100e3a6..5152223669c8d 100644
--- a/src/Symfony/Bundle/WebProfilerBundle/EventListener/WebDebugToolbarListener.php
+++ b/src/Symfony/Bundle/WebProfilerBundle/EventListener/WebDebugToolbarListener.php
@@ -95,7 +95,7 @@ public function onKernelResponse(ResponseEvent $event)
$nonces = [];
if ($this->cspHandler) {
- if ($this->dumpDataCollector && $this->dumpDataCollector->getDumpsCount() > 0) {
+ if ($this->dumpDataCollector?->getDumpsCount() > 0) {
$this->cspHandler->disableCsp();
}
diff --git a/src/Symfony/Component/Cache/Adapter/AbstractAdapter.php b/src/Symfony/Component/Cache/Adapter/AbstractAdapter.php
index 19f282e23391b..19be14f1d01a4 100644
--- a/src/Symfony/Component/Cache/Adapter/AbstractAdapter.php
+++ b/src/Symfony/Component/Cache/Adapter/AbstractAdapter.php
@@ -74,7 +74,7 @@ static function ($deferred, $namespace, &$expiredIds, $getId, $defaultLifetime)
$key = (string) $key;
if (null === $item->expiry) {
$ttl = 0 < $defaultLifetime ? $defaultLifetime : 0;
- } elseif (0 === $item->expiry) {
+ } elseif (!$item->expiry) {
$ttl = 0;
} elseif (0 >= $ttl = (int) (0.1 + $item->expiry - $now)) {
$expiredIds[] = $getId($key);
diff --git a/src/Symfony/Component/Cache/Adapter/AbstractTagAwareAdapter.php b/src/Symfony/Component/Cache/Adapter/AbstractTagAwareAdapter.php
index 476cec9d15a49..f66c8370d5b91 100644
--- a/src/Symfony/Component/Cache/Adapter/AbstractTagAwareAdapter.php
+++ b/src/Symfony/Component/Cache/Adapter/AbstractTagAwareAdapter.php
@@ -79,7 +79,7 @@ static function ($deferred, &$expiredIds, $getId, $tagPrefix, $defaultLifetime)
$key = (string) $key;
if (null === $item->expiry) {
$ttl = 0 < $defaultLifetime ? $defaultLifetime : 0;
- } elseif (0 === $item->expiry) {
+ } elseif (!$item->expiry) {
$ttl = 0;
} elseif (0 >= $ttl = (int) (0.1 + $item->expiry - $now)) {
$expiredIds[] = $getId($key);
diff --git a/src/Symfony/Component/Cache/Adapter/ArrayAdapter.php b/src/Symfony/Component/Cache/Adapter/ArrayAdapter.php
index 3a37297cddba1..d6eb152f08fcb 100644
--- a/src/Symfony/Component/Cache/Adapter/ArrayAdapter.php
+++ b/src/Symfony/Component/Cache/Adapter/ArrayAdapter.php
@@ -182,14 +182,14 @@ public function save(CacheItemInterface $item): bool
$now = microtime(true);
- if (0 === $expiry) {
- $expiry = \PHP_INT_MAX;
- }
-
- if (null !== $expiry && $expiry <= $now) {
- $this->deleteItem($key);
+ if (null !== $expiry) {
+ if (!$expiry) {
+ $expiry = \PHP_INT_MAX;
+ } elseif ($expiry <= $now) {
+ $this->deleteItem($key);
- return true;
+ return true;
+ }
}
if ($this->storeSerialized && null === $value = $this->freeze($value, $key)) {
return false;
diff --git a/src/Symfony/Component/Cache/Adapter/ChainAdapter.php b/src/Symfony/Component/Cache/Adapter/ChainAdapter.php
index 925e9f2f6b5bc..64ae546440aad 100644
--- a/src/Symfony/Component/Cache/Adapter/ChainAdapter.php
+++ b/src/Symfony/Component/Cache/Adapter/ChainAdapter.php
@@ -66,10 +66,10 @@ public function __construct(array $adapters, int $defaultLifetime = 0)
$this->adapterCount = \count($this->adapters);
$this->defaultLifetime = $defaultLifetime;
- self::$syncItem ?? self::$syncItem = \Closure::bind(
+ self::$syncItem ??= \Closure::bind(
static function ($sourceItem, $item, $defaultLifetime, $sourceMetadata = null) {
$sourceItem->isTaggable = false;
- $sourceMetadata = $sourceMetadata ?? $sourceItem->metadata;
+ $sourceMetadata ??= $sourceItem->metadata;
unset($sourceMetadata[CacheItem::METADATA_TAGS]);
$item->value = $sourceItem->value;
@@ -108,7 +108,7 @@ public function get(string $key, callable $callback, float $beta = null, array &
$value = $this->doGet($adapter, $key, $callback, $beta, $metadata);
}
if (null !== $item) {
- (self::$syncItem)($lastItem = $lastItem ?? $item, $item, $this->defaultLifetime, $metadata);
+ (self::$syncItem)($lastItem ??= $item, $item, $this->defaultLifetime, $metadata);
}
return $value;
diff --git a/src/Symfony/Component/Cache/Adapter/PhpFilesAdapter.php b/src/Symfony/Component/Cache/Adapter/PhpFilesAdapter.php
index 13e45435f0f75..7ec96f5d88eba 100644
--- a/src/Symfony/Component/Cache/Adapter/PhpFilesAdapter.php
+++ b/src/Symfony/Component/Cache/Adapter/PhpFilesAdapter.php
@@ -135,7 +135,7 @@ protected function doFetch(array $ids): iterable
foreach ($missingIds as $k => $id) {
try {
- $file = $this->files[$id] ?? $this->files[$id] = $this->getFile($id);
+ $file = $this->files[$id] ??= $this->getFile($id);
if (isset(self::$valuesCache[$file])) {
[$expiresAt, $this->values[$id]] = self::$valuesCache[$file];
@@ -176,7 +176,7 @@ protected function doHave(string $id): bool
set_error_handler($this->includeHandler);
try {
- $file = $this->files[$id] ?? $this->files[$id] = $this->getFile($id);
+ $file = $this->files[$id] ??= $this->getFile($id);
$getExpiry = true;
if (isset(self::$valuesCache[$file])) {
diff --git a/src/Symfony/Component/Cache/Adapter/ProxyAdapter.php b/src/Symfony/Component/Cache/Adapter/ProxyAdapter.php
index c90b80e4cbd51..23434cd4714c9 100644
--- a/src/Symfony/Component/Cache/Adapter/ProxyAdapter.php
+++ b/src/Symfony/Component/Cache/Adapter/ProxyAdapter.php
@@ -92,7 +92,7 @@ static function (CacheItemInterface $innerItem, array $item) {
$item["\0*\0value"] = ["\x9D".pack('VN', (int) (0.1 + $metadata[self::METADATA_EXPIRY] - self::METADATA_EXPIRY_OFFSET), $metadata[self::METADATA_CTIME])."\x5F" => $item["\0*\0value"]];
}
$innerItem->set($item["\0*\0value"]);
- $innerItem->expiresAt(null !== $item["\0*\0expiry"] ? \DateTime::createFromFormat('U.u', sprintf('%.6F', 0 === $item["\0*\0expiry"] ? \PHP_INT_MAX : $item["\0*\0expiry"])) : null);
+ $innerItem->expiresAt(null !== $item["\0*\0expiry"] ? \DateTime::createFromFormat('U.u', sprintf('%.6F', $item["\0*\0expiry"])) : null);
},
null,
CacheItem::class
diff --git a/src/Symfony/Component/Cache/Adapter/RedisTagAwareAdapter.php b/src/Symfony/Component/Cache/Adapter/RedisTagAwareAdapter.php
index 1ec5a8cc30846..cb1c638c5c0db 100644
--- a/src/Symfony/Component/Cache/Adapter/RedisTagAwareAdapter.php
+++ b/src/Symfony/Component/Cache/Adapter/RedisTagAwareAdapter.php
@@ -55,7 +55,7 @@ class RedisTagAwareAdapter extends AbstractTagAwareAdapter
private const DEFAULT_CACHE_TTL = 8640000;
/**
- * detected eviction policy used on Redis server
+ * detected eviction policy used on Redis server.
*/
private string $redisEvictionPolicy;
diff --git a/src/Symfony/Component/Cache/Adapter/TagAwareAdapter.php b/src/Symfony/Component/Cache/Adapter/TagAwareAdapter.php
index a36551d308de7..0176383ef063c 100644
--- a/src/Symfony/Component/Cache/Adapter/TagAwareAdapter.php
+++ b/src/Symfony/Component/Cache/Adapter/TagAwareAdapter.php
@@ -48,7 +48,7 @@ public function __construct(AdapterInterface $itemsPool, AdapterInterface $tagsP
$this->pool = $itemsPool;
$this->tags = $tagsPool ?? $itemsPool;
$this->knownTagVersionsTtl = $knownTagVersionsTtl;
- self::$createCacheItem ?? self::$createCacheItem = \Closure::bind(
+ self::$createCacheItem ??= \Closure::bind(
static function ($key, $value, CacheItem $protoItem) {
$item = new CacheItem();
$item->key = $key;
@@ -61,7 +61,7 @@ static function ($key, $value, CacheItem $protoItem) {
null,
CacheItem::class
);
- self::$setCacheItemTags ?? self::$setCacheItemTags = \Closure::bind(
+ self::$setCacheItemTags ??= \Closure::bind(
static function (CacheItem $item, $key, array &$itemTags) {
$item->isTaggable = true;
if (!$item->isHit) {
@@ -82,7 +82,7 @@ static function (CacheItem $item, $key, array &$itemTags) {
null,
CacheItem::class
);
- self::$getTagsByKey ?? self::$getTagsByKey = \Closure::bind(
+ self::$getTagsByKey ??= \Closure::bind(
static function ($deferred) {
$tagsByKey = [];
foreach ($deferred as $key => $item) {
@@ -95,7 +95,7 @@ static function ($deferred) {
null,
CacheItem::class
);
- self::$saveTags ?? self::$saveTags = \Closure::bind(
+ self::$saveTags ??= \Closure::bind(
static function (AdapterInterface $tagsAdapter, array $tags) {
ksort($tags);
@@ -394,7 +394,7 @@ private function getTagVersions(array $tagsByKey): array
$newVersion = null;
foreach ($this->tags->getItems(array_keys($tags)) as $tag => $version) {
if (!$version->isHit()) {
- $newTags[$tag] = $version->set($newVersion ?? $newVersion = random_int(\PHP_INT_MIN, \PHP_INT_MAX));
+ $newTags[$tag] = $version->set($newVersion ??= random_int(\PHP_INT_MIN, \PHP_INT_MAX));
}
$tagVersions[$tag = $tags[$tag]] = $version->get();
$this->knownTagVersions[$tag] = [$now, $tagVersions[$tag]];
diff --git a/src/Symfony/Component/Cache/CHANGELOG.md b/src/Symfony/Component/Cache/CHANGELOG.md
index a1dc4617e5b13..1f54db7b8bd80 100644
--- a/src/Symfony/Component/Cache/CHANGELOG.md
+++ b/src/Symfony/Component/Cache/CHANGELOG.md
@@ -10,7 +10,6 @@ CHANGELOG
5.4
---
- * Make `LockRegistry` use semaphores when possible
* Deprecate `DoctrineProvider` and `DoctrineAdapter` because these classes have been added to the `doctrine/cache` package
* Add `DoctrineDbalAdapter` identical to `PdoAdapter` for `Doctrine\DBAL\Connection` or DBAL URL
* Deprecate usage of `PdoAdapter` with `Doctrine\DBAL\Connection` or DBAL URL
diff --git a/src/Symfony/Component/Cache/LockRegistry.php b/src/Symfony/Component/Cache/LockRegistry.php
index 5803bccc7688d..da67036dc4666 100644
--- a/src/Symfony/Component/Cache/LockRegistry.php
+++ b/src/Symfony/Component/Cache/LockRegistry.php
@@ -27,7 +27,7 @@
final class LockRegistry
{
private static $openedFiles = [];
- private static $lockedKeys;
+ private static $lockedFiles;
/**
* The number of items in this list controls the max number of concurrent processes.
@@ -76,25 +76,21 @@ public static function setFiles(array $files): array
fclose($file);
}
}
- self::$openedFiles = self::$lockedKeys = [];
+ self::$openedFiles = self::$lockedFiles = [];
return $previousFiles;
}
public static function compute(callable $callback, ItemInterface $item, bool &$save, CacheInterface $pool, \Closure $setMetadata = null, LoggerInterface $logger = null)
{
- if ('\\' === \DIRECTORY_SEPARATOR && null === self::$lockedKeys) {
+ if ('\\' === \DIRECTORY_SEPARATOR && null === self::$lockedFiles) {
// disable locking on Windows by default
- self::$files = self::$lockedKeys = [];
+ self::$files = self::$lockedFiles = [];
}
- $key = unpack('i', md5($item->getKey(), true))[1];
+ $key = self::$files ? abs(crc32($item->getKey())) % \count(self::$files) : -1;
- if (!\function_exists('sem_get')) {
- $key = self::$files ? abs($key) % \count(self::$files) : null;
- }
-
- if (null === $key || (self::$lockedKeys[$key] ?? false) || !$lock = self::open($key)) {
+ if ($key < 0 || (self::$lockedFiles[$key] ?? false) || !$lock = self::open($key)) {
return $callback($item, $save);
}
@@ -102,15 +98,11 @@ public static function compute(callable $callback, ItemInterface $item, bool &$s
try {
$locked = false;
// race to get the lock in non-blocking mode
- if ($wouldBlock = \function_exists('sem_get')) {
- $locked = @sem_acquire($lock, true);
- } else {
- $locked = flock($lock, \LOCK_EX | \LOCK_NB, $wouldBlock);
- }
+ $locked = flock($lock, \LOCK_EX | \LOCK_NB, $wouldBlock);
if ($locked || !$wouldBlock) {
- $logger && $logger->info(sprintf('Lock %s, now computing item "{key}"', $locked ? 'acquired' : 'not supported'), ['key' => $item->getKey()]);
- self::$lockedKeys[$key] = true;
+ $logger?->info(sprintf('Lock %s, now computing item "{key}"', $locked ? 'acquired' : 'not supported'), ['key' => $item->getKey()]);
+ self::$lockedFiles[$key] = true;
$value = $callback($item, $save);
@@ -125,25 +117,12 @@ public static function compute(callable $callback, ItemInterface $item, bool &$s
return $value;
}
-
// if we failed the race, retry locking in blocking mode to wait for the winner
- $logger && $logger->info('Item "{key}" is locked, waiting for it to be released', ['key' => $item->getKey()]);
-
- if (\function_exists('sem_get')) {
- $lock = sem_get($key);
- @sem_acquire($lock);
- } else {
- flock($lock, \LOCK_SH);
- }
+ $logger?->info('Item "{key}" is locked, waiting for it to be released', ['key' => $item->getKey()]);
+ flock($lock, \LOCK_SH);
} finally {
- if ($locked) {
- if (\function_exists('sem_get')) {
- sem_remove($lock);
- } else {
- flock($lock, \LOCK_UN);
- }
- }
- unset(self::$lockedKeys[$key]);
+ flock($lock, \LOCK_UN);
+ unset(self::$lockedFiles[$key]);
}
static $signalingException, $signalingCallback;
$signalingException = $signalingException ?? unserialize("O:9:\"Exception\":1:{s:16:\"\0Exception\0trace\";a:0:{}}");
@@ -151,7 +130,7 @@ public static function compute(callable $callback, ItemInterface $item, bool &$s
try {
$value = $pool->get($item->getKey(), $signalingCallback, 0);
- $logger && $logger->info('Item "{key}" retrieved after lock was released', ['key' => $item->getKey()]);
+ $logger?->info('Item "{key}" retrieved after lock was released', ['key' => $item->getKey()]);
$save = false;
return $value;
@@ -159,7 +138,7 @@ public static function compute(callable $callback, ItemInterface $item, bool &$s
if ($signalingException !== $e) {
throw $e;
}
- $logger && $logger->info('Item "{key}" not found while lock was released, now retrying', ['key' => $item->getKey()]);
+ $logger?->info('Item "{key}" not found while lock was released, now retrying', ['key' => $item->getKey()]);
}
}
@@ -168,10 +147,6 @@ public static function compute(callable $callback, ItemInterface $item, bool &$s
private static function open(int $key)
{
- if (\function_exists('sem_get')) {
- return sem_get($key);
- }
-
if (null !== $h = self::$openedFiles[$key] ?? null) {
return $h;
}
diff --git a/src/Symfony/Component/Cache/Marshaller/DefaultMarshaller.php b/src/Symfony/Component/Cache/Marshaller/DefaultMarshaller.php
index 7459a9db47029..5c34fb2ea59d3 100644
--- a/src/Symfony/Component/Cache/Marshaller/DefaultMarshaller.php
+++ b/src/Symfony/Component/Cache/Marshaller/DefaultMarshaller.php
@@ -71,7 +71,7 @@ public function unmarshall(string $value): mixed
return null;
}
static $igbinaryNull;
- if ($value === ($igbinaryNull ?? $igbinaryNull = \extension_loaded('igbinary') ? igbinary_serialize(null) : false)) {
+ if ($value === $igbinaryNull ??= \extension_loaded('igbinary') ? igbinary_serialize(null) : false) {
return null;
}
$unserializeCallbackHandler = ini_set('unserialize_callback_func', __CLASS__.'::handleUnserializeCallback');
diff --git a/src/Symfony/Component/Cache/Messenger/EarlyExpirationDispatcher.php b/src/Symfony/Component/Cache/Messenger/EarlyExpirationDispatcher.php
index 25b5023b32fd3..5aeacf1d598ef 100644
--- a/src/Symfony/Component/Cache/Messenger/EarlyExpirationDispatcher.php
+++ b/src/Symfony/Component/Cache/Messenger/EarlyExpirationDispatcher.php
@@ -38,7 +38,7 @@ public function __invoke(callable $callback, CacheItem $item, bool &$save, Adapt
{
if (!$item->isHit() || null === $message = EarlyExpirationMessage::create($this->reverseContainer, $callback, $item, $pool)) {
// The item is stale or the callback cannot be reversed: we must compute the value now
- $logger && $logger->info('Computing item "{key}" online: '.($item->isHit() ? 'callback cannot be reversed' : 'item is stale'), ['key' => $item->getKey()]);
+ $logger?->info('Computing item "{key}" online: '.($item->isHit() ? 'callback cannot be reversed' : 'item is stale'), ['key' => $item->getKey()]);
return null !== $this->callbackWrapper ? ($this->callbackWrapper)($callback, $item, $save, $pool, $setMetadata, $logger) : $callback($item, $save);
}
diff --git a/src/Symfony/Component/Cache/Messenger/EarlyExpirationHandler.php b/src/Symfony/Component/Cache/Messenger/EarlyExpirationHandler.php
index 043b4a177c6fb..9d2aaecc76c83 100644
--- a/src/Symfony/Component/Cache/Messenger/EarlyExpirationHandler.php
+++ b/src/Symfony/Component/Cache/Messenger/EarlyExpirationHandler.php
@@ -59,7 +59,7 @@ public function __invoke(EarlyExpirationMessage $message)
static $setMetadata;
- $setMetadata ?? $setMetadata = \Closure::bind(
+ $setMetadata ??= \Closure::bind(
function (CacheItem $item, float $startTime) {
if ($item->expiry > $endTime = microtime(true)) {
$item->newMetadata[CacheItem::METADATA_EXPIRY] = $item->expiry;
diff --git a/src/Symfony/Component/Cache/Tests/Adapter/AdapterTestCase.php b/src/Symfony/Component/Cache/Tests/Adapter/AdapterTestCase.php
index f7c5b83124970..eee85bff6ee53 100644
--- a/src/Symfony/Component/Cache/Tests/Adapter/AdapterTestCase.php
+++ b/src/Symfony/Component/Cache/Tests/Adapter/AdapterTestCase.php
@@ -128,7 +128,7 @@ public function testGetMetadata()
$metadata = $item->getMetadata();
$this->assertArrayHasKey(CacheItem::METADATA_CTIME, $metadata);
- $this->assertEqualsWithDelta(999, $metadata[CacheItem::METADATA_CTIME], 10);
+ $this->assertEqualsWithDelta(999, $metadata[CacheItem::METADATA_CTIME], 150);
$this->assertArrayHasKey(CacheItem::METADATA_EXPIRY, $metadata);
$this->assertEqualsWithDelta(9 + time(), $metadata[CacheItem::METADATA_EXPIRY], 1);
}
diff --git a/src/Symfony/Component/Cache/Tests/Adapter/ProxyAdapterAndRedisAdapterTest.php b/src/Symfony/Component/Cache/Tests/Adapter/ProxyAdapterAndRedisAdapterTest.php
new file mode 100644
index 0000000000000..46516e0095e6e
--- /dev/null
+++ b/src/Symfony/Component/Cache/Tests/Adapter/ProxyAdapterAndRedisAdapterTest.php
@@ -0,0 +1,72 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Cache\Tests\Adapter;
+
+use Psr\Cache\CacheItemPoolInterface;
+use Symfony\Component\Cache\Adapter\AbstractAdapter;
+use Symfony\Component\Cache\Adapter\ProxyAdapter;
+use Symfony\Component\Cache\Adapter\RedisAdapter;
+use Symfony\Component\Cache\CacheItem;
+
+/**
+ * @group integration
+ */
+class ProxyAdapterAndRedisAdapterTest extends AbstractRedisAdapterTest
+{
+ protected $skippedTests = [
+ 'testPrune' => 'RedisAdapter does not implement PruneableInterface.',
+ ];
+
+ public static function setUpBeforeClass(): void
+ {
+ parent::setUpBeforeClass();
+ self::$redis = AbstractAdapter::createConnection('redis://'.getenv('REDIS_HOST'));
+ }
+
+ public function createCachePool($defaultLifetime = 0, string $testMethod = null): CacheItemPoolInterface
+ {
+ return new ProxyAdapter(new RedisAdapter(self::$redis, str_replace('\\', '.', __CLASS__), 100), 'ProxyNS', $defaultLifetime);
+ }
+
+ public function testSaveItemPermanently()
+ {
+ $setCacheItemExpiry = \Closure::bind(
+ static function (CacheItem $item, $expiry) {
+ $item->expiry = $expiry;
+
+ return $item;
+ },
+ null,
+ CacheItem::class
+ );
+
+ $cache = $this->createCachePool(1);
+ $value = rand();
+ $item = $cache->getItem('foo');
+ $setCacheItemExpiry($item, 0);
+ $cache->save($item->set($value));
+ $item = $cache->getItem('bar');
+ $setCacheItemExpiry($item, 0.0);
+ $cache->save($item->set($value));
+ $item = $cache->getItem('baz');
+ $cache->save($item->set($value));
+
+ $this->assertSame($value, $this->cache->getItem('foo')->get());
+ $this->assertSame($value, $this->cache->getItem('bar')->get());
+ $this->assertSame($value, $this->cache->getItem('baz')->get());
+
+ sleep(1);
+ $this->assertSame($value, $this->cache->getItem('foo')->get());
+ $this->assertSame($value, $this->cache->getItem('bar')->get());
+ $this->assertFalse($this->cache->getItem('baz')->isHit());
+ }
+}
diff --git a/src/Symfony/Component/Cache/Tests/Adapter/TagAwareAdapterTest.php b/src/Symfony/Component/Cache/Tests/Adapter/TagAwareAdapterTest.php
index 54ce7822e06af..81e943c144f56 100644
--- a/src/Symfony/Component/Cache/Tests/Adapter/TagAwareAdapterTest.php
+++ b/src/Symfony/Component/Cache/Tests/Adapter/TagAwareAdapterTest.php
@@ -14,12 +14,10 @@
use PHPUnit\Framework\MockObject\MockObject;
use Psr\Cache\CacheItemInterface;
use Psr\Cache\CacheItemPoolInterface;
-use Psr\Log\LoggerInterface;
use Symfony\Component\Cache\Adapter\AdapterInterface;
use Symfony\Component\Cache\Adapter\ArrayAdapter;
use Symfony\Component\Cache\Adapter\FilesystemAdapter;
use Symfony\Component\Cache\Adapter\TagAwareAdapter;
-use Symfony\Component\Cache\LockRegistry;
use Symfony\Component\Cache\Tests\Fixtures\PrunableAdapter;
use Symfony\Component\Filesystem\Filesystem;
@@ -181,24 +179,6 @@ public function testGetItemReturnsCacheMissWhenPoolDoesNotHaveItemAndOnlyHasTags
$this->assertFalse($item->isHit());
}
- public function testLog()
- {
- $lockFiles = LockRegistry::setFiles([__FILE__]);
-
- $logger = $this->createMock(LoggerInterface::class);
- $logger
- ->expects($this->atLeastOnce())
- ->method($this->anything());
-
- $cache = new TagAwareAdapter(new ArrayAdapter());
- $cache->setLogger($logger);
-
- // Computing will produce at least one log
- $cache->get('foo', static function (): string { return 'ccc'; });
-
- LockRegistry::setFiles($lockFiles);
- }
-
/**
* @return MockObject&PruneableCacheInterface
*/
diff --git a/src/Symfony/Component/Cache/Traits/AbstractAdapterTrait.php b/src/Symfony/Component/Cache/Traits/AbstractAdapterTrait.php
index 0149b7674c50e..64e35a47a174f 100644
--- a/src/Symfony/Component/Cache/Traits/AbstractAdapterTrait.php
+++ b/src/Symfony/Component/Cache/Traits/AbstractAdapterTrait.php
@@ -26,12 +26,12 @@ trait AbstractAdapterTrait
use LoggerAwareTrait;
/**
- * needs to be set by class, signature is function(string , mixed , bool )
+ * needs to be set by class, signature is function(string , mixed , bool ).
*/
private static \Closure $createCacheItem;
/**
- * needs to be set by class, signature is function(array , string , array <&expiredIds>)
+ * needs to be set by class, signature is function(array , string , array <&expiredIds>).
*/
private static \Closure $mergeByLifetime;
diff --git a/src/Symfony/Component/Cache/Traits/ContractsTrait.php b/src/Symfony/Component/Cache/Traits/ContractsTrait.php
index 6361f95161a29..f63b4957ac9ac 100644
--- a/src/Symfony/Component/Cache/Traits/ContractsTrait.php
+++ b/src/Symfony/Component/Cache/Traits/ContractsTrait.php
@@ -41,12 +41,20 @@ trait ContractsTrait
*/
public function setCallbackWrapper(?callable $callbackWrapper): callable
{
- $previousWrapper = $this->callbackWrapper ??= \Closure::fromCallable([LockRegistry::class, 'compute']);
+ if (!isset($this->callbackWrapper)) {
+ $this->callbackWrapper = \Closure::fromCallable([LockRegistry::class, 'compute']);
+
+ if (\in_array(\PHP_SAPI, ['cli', 'phpdbg'], true)) {
+ $this->setCallbackWrapper(null);
+ }
+ }
+
if (null !== $callbackWrapper && !$callbackWrapper instanceof \Closure) {
$callbackWrapper = \Closure::fromCallable($callbackWrapper);
}
- $this->callbackWrapper = $callbackWrapper ?? function (callable $callback, ItemInterface $item, bool &$save, CacheInterface $pool, \Closure $setMetadata, ?LoggerInterface $logger) {
+ $previousWrapper = $this->callbackWrapper;
+ $this->callbackWrapper = $callbackWrapper ?? static function (callable $callback, ItemInterface $item, bool &$save, CacheInterface $pool, \Closure $setMetadata, ?LoggerInterface $logger) {
return $callback($item, $save);
};
@@ -55,13 +63,13 @@ public function setCallbackWrapper(?callable $callbackWrapper): callable
private function doGet(AdapterInterface $pool, string $key, callable $callback, ?float $beta, array &$metadata = null)
{
- if (0 > $beta = $beta ?? 1.0) {
+ if (0 > $beta ??= 1.0) {
throw new InvalidArgumentException(sprintf('Argument "$beta" provided to "%s::get()" must be a positive number, %f given.', static::class, $beta));
}
static $setMetadata;
- $setMetadata ?? $setMetadata = \Closure::bind(
+ $setMetadata ??= \Closure::bind(
static function (CacheItem $item, float $startTime, ?array &$metadata) {
if ($item->expiry > $endTime = microtime(true)) {
$item->newMetadata[CacheItem::METADATA_EXPIRY] = $metadata[CacheItem::METADATA_EXPIRY] = $item->expiry;
@@ -88,6 +96,10 @@ static function (CacheItem $item, float $startTime, ?array &$metadata) {
$this->computing[$key] = $key;
$startTime = microtime(true);
+ if (!isset($this->callbackWrapper)) {
+ $this->setCallbackWrapper($this->setCallbackWrapper(null));
+ }
+
try {
$value = ($this->callbackWrapper)($callback, $item, $save, $pool, function (CacheItem $item) use ($setMetadata, $startTime, &$metadata) {
$setMetadata($item, $startTime, $metadata);
diff --git a/src/Symfony/Component/Cache/Traits/RedisTrait.php b/src/Symfony/Component/Cache/Traits/RedisTrait.php
index fc833beb7f23a..9a48944bafd4a 100644
--- a/src/Symfony/Component/Cache/Traits/RedisTrait.php
+++ b/src/Symfony/Component/Cache/Traits/RedisTrait.php
@@ -441,7 +441,7 @@ protected function doDelete(array $ids): bool
if ($this->redis instanceof \Predis\ClientInterface && $this->redis->getConnection() instanceof ClusterInterface) {
static $del;
- $del = $del ?? (class_exists(UNLINK::class) ? 'unlink' : 'del');
+ $del ??= (class_exists(UNLINK::class) ? 'unlink' : 'del');
$this->pipeline(function () use ($ids, $del) {
foreach ($ids as $id) {
@@ -498,7 +498,7 @@ protected function doSave(array $values, int $lifetime): array|bool
private function pipeline(\Closure $generator, object $redis = null): \Generator
{
$ids = [];
- $redis = $redis ?? $this->redis;
+ $redis ??= $this->redis;
if ($redis instanceof RedisClusterProxy || $redis instanceof \RedisCluster || ($redis instanceof \Predis\ClientInterface && $redis->getConnection() instanceof RedisCluster)) {
// phpredis & predis don't support pipelining with RedisCluster
diff --git a/src/Symfony/Component/Config/Definition/Builder/ExprBuilder.php b/src/Symfony/Component/Config/Definition/Builder/ExprBuilder.php
index 71d156dfc47a1..22f8280d6018a 100644
--- a/src/Symfony/Component/Config/Definition/Builder/ExprBuilder.php
+++ b/src/Symfony/Component/Config/Definition/Builder/ExprBuilder.php
@@ -204,8 +204,6 @@ public function thenUnset(): static
/**
* Returns the related node.
*
- * @return NodeDefinition|ArrayNodeDefinition|VariableNodeDefinition
- *
* @throws \RuntimeException
*/
public function end(): NodeDefinition|ArrayNodeDefinition|VariableNodeDefinition
diff --git a/src/Symfony/Component/Config/Definition/Builder/MergeBuilder.php b/src/Symfony/Component/Config/Definition/Builder/MergeBuilder.php
index 1b55b185bd970..f8980a6e041c9 100644
--- a/src/Symfony/Component/Config/Definition/Builder/MergeBuilder.php
+++ b/src/Symfony/Component/Config/Definition/Builder/MergeBuilder.php
@@ -53,8 +53,6 @@ public function denyOverwrite(bool $deny = true): static
/**
* Returns the related node.
- *
- * @return NodeDefinition|ArrayNodeDefinition|VariableNodeDefinition
*/
public function end(): NodeDefinition|ArrayNodeDefinition|VariableNodeDefinition
{
diff --git a/src/Symfony/Component/Config/Definition/Builder/TreeBuilder.php b/src/Symfony/Component/Config/Definition/Builder/TreeBuilder.php
index 4a106d1d289d2..e469e69044c3f 100644
--- a/src/Symfony/Component/Config/Definition/Builder/TreeBuilder.php
+++ b/src/Symfony/Component/Config/Definition/Builder/TreeBuilder.php
@@ -25,7 +25,7 @@ class TreeBuilder implements NodeParentInterface
public function __construct(string $name, string $type = 'array', NodeBuilder $builder = null)
{
- $builder = $builder ?? new NodeBuilder();
+ $builder ??= new NodeBuilder();
$this->root = $builder->node($name, $type)->setParent($this);
}
diff --git a/src/Symfony/Component/Config/Tests/Builder/GeneratedConfigTest.php b/src/Symfony/Component/Config/Tests/Builder/GeneratedConfigTest.php
index e85558cac8d96..c988c0ab30bb7 100644
--- a/src/Symfony/Component/Config/Tests/Builder/GeneratedConfigTest.php
+++ b/src/Symfony/Component/Config/Tests/Builder/GeneratedConfigTest.php
@@ -148,7 +148,7 @@ public function testSetExtraKeyMethodIsNotGeneratedWhenAllowExtraKeysIsFalse()
*/
private function generateConfigBuilder(string $configurationClass, string $outputDir = null)
{
- $outputDir ?? $outputDir = sys_get_temp_dir().\DIRECTORY_SEPARATOR.uniqid('sf_config_builder', true);
+ $outputDir ??= sys_get_temp_dir().\DIRECTORY_SEPARATOR.uniqid('sf_config_builder', true);
if (!str_contains($outputDir, __DIR__)) {
$this->tempDir[] = $outputDir;
}
diff --git a/src/Symfony/Component/Config/Tests/Util/XmlUtilsTest.php b/src/Symfony/Component/Config/Tests/Util/XmlUtilsTest.php
index 184917b9eddbb..ce6772f06556d 100644
--- a/src/Symfony/Component/Config/Tests/Util/XmlUtilsTest.php
+++ b/src/Symfony/Component/Config/Tests/Util/XmlUtilsTest.php
@@ -169,6 +169,8 @@ public function getDataForPhpize(): array
[1, '1'],
[-1, '-1'],
[0777, '0777'],
+ [-511, '-0777'],
+ ['0877', '0877'],
[255, '0xFF'],
[100.0, '1e2'],
[-120.0, '-1.2E2'],
diff --git a/src/Symfony/Component/Config/Util/XmlUtils.php b/src/Symfony/Component/Config/Util/XmlUtils.php
index 1f81a2cd2a792..7d1644b701d0a 100644
--- a/src/Symfony/Component/Config/Util/XmlUtils.php
+++ b/src/Symfony/Component/Config/Util/XmlUtils.php
@@ -216,15 +216,11 @@ public static function phpize(string|\Stringable $value): mixed
case 'null' === $lowercaseValue:
return null;
case ctype_digit($value):
- $raw = $value;
- $cast = (int) $value;
-
- return '0' == $value[0] ? octdec($value) : (($raw === (string) $cast) ? $cast : $raw);
case isset($value[1]) && '-' === $value[0] && ctype_digit(substr($value, 1)):
$raw = $value;
$cast = (int) $value;
- return '0' == $value[1] ? octdec($value) : (($raw === (string) $cast) ? $cast : $raw);
+ return self::isOctal($value) ? \intval($value, 8) : (($raw === (string) $cast) ? $cast : $raw);
case 'true' === $lowercaseValue:
return true;
case 'false' === $lowercaseValue:
@@ -261,4 +257,13 @@ protected static function getXmlErrors(bool $internalErrors)
return $errors;
}
+
+ private static function isOctal(string $str): bool
+ {
+ if ('-' === $str[0]) {
+ $str = substr($str, 1);
+ }
+
+ return $str === '0'.decoct(\intval($str, 8));
+ }
}
diff --git a/src/Symfony/Component/Console/Application.php b/src/Symfony/Component/Console/Application.php
index b582435f7d102..0ed5649b8ac55 100644
--- a/src/Symfony/Component/Console/Application.php
+++ b/src/Symfony/Component/Console/Application.php
@@ -558,7 +558,7 @@ public function has(string $name): bool
{
$this->init();
- return isset($this->commands[$name]) || ($this->commandLoader && $this->commandLoader->has($name) && $this->add($this->commandLoader->get($name)));
+ return isset($this->commands[$name]) || ($this->commandLoader?->has($name) && $this->add($this->commandLoader->get($name)));
}
/**
diff --git a/src/Symfony/Component/Console/Command/Command.php b/src/Symfony/Component/Console/Command/Command.php
index d6354b4ab119c..0bd3426c07eb3 100644
--- a/src/Symfony/Component/Console/Command/Command.php
+++ b/src/Symfony/Component/Console/Command/Command.php
@@ -421,9 +421,7 @@ public function getNativeDefinition(): InputDefinition
public function addArgument(string $name, int $mode = null, string $description = '', mixed $default = null): static
{
$this->definition->addArgument(new InputArgument($name, $mode, $description, $default));
- if (null !== $this->fullDefinition) {
- $this->fullDefinition->addArgument(new InputArgument($name, $mode, $description, $default));
- }
+ $this->fullDefinition?->addArgument(new InputArgument($name, $mode, $description, $default));
return $this;
}
@@ -442,9 +440,7 @@ public function addArgument(string $name, int $mode = null, string $description
public function addOption(string $name, string|array $shortcut = null, int $mode = null, string $description = '', mixed $default = null): static
{
$this->definition->addOption(new InputOption($name, $shortcut, $mode, $description, $default));
- if (null !== $this->fullDefinition) {
- $this->fullDefinition->addOption(new InputOption($name, $shortcut, $mode, $description, $default));
- }
+ $this->fullDefinition?->addOption(new InputOption($name, $shortcut, $mode, $description, $default));
return $this;
}
@@ -560,7 +556,7 @@ public function getHelp(): string
public function getProcessedHelp(): string
{
$name = $this->name;
- $isSingleCommand = $this->application && $this->application->isSingleCommand();
+ $isSingleCommand = $this->application?->isSingleCommand();
$placeholders = [
'%command.name%',
diff --git a/src/Symfony/Component/Console/Command/CompleteCommand.php b/src/Symfony/Component/Console/Command/CompleteCommand.php
index 97357d6737ed3..4fb3398eb9586 100644
--- a/src/Symfony/Component/Console/Command/CompleteCommand.php
+++ b/src/Symfony/Component/Console/Command/CompleteCommand.php
@@ -15,6 +15,7 @@
use Symfony\Component\Console\Completion\CompletionSuggestions;
use Symfony\Component\Console\Completion\Output\BashCompletionOutput;
use Symfony\Component\Console\Completion\Output\CompletionOutputInterface;
+use Symfony\Component\Console\Completion\Output\FishCompletionOutput;
use Symfony\Component\Console\Exception\CommandNotFoundException;
use Symfony\Component\Console\Exception\ExceptionInterface;
use Symfony\Component\Console\Input\InputInterface;
@@ -41,7 +42,10 @@ final class CompleteCommand extends Command
public function __construct(array $completionOutputs = [])
{
// must be set before the parent constructor, as the property value is used in configure()
- $this->completionOutputs = $completionOutputs + ['bash' => BashCompletionOutput::class];
+ $this->completionOutputs = $completionOutputs + [
+ 'bash' => BashCompletionOutput::class,
+ 'fish' => FishCompletionOutput::class,
+ ];
parent::__construct();
}
diff --git a/src/Symfony/Component/Console/Completion/CompletionInput.php b/src/Symfony/Component/Console/Completion/CompletionInput.php
index eda95bef55468..b0f00088e7150 100644
--- a/src/Symfony/Component/Console/Completion/CompletionInput.php
+++ b/src/Symfony/Component/Console/Completion/CompletionInput.php
@@ -84,7 +84,7 @@ public function bind(InputDefinition $definition): void
return;
}
- if (null !== $option && $option->acceptValue()) {
+ if ($option?->acceptValue()) {
$this->completionType = self::TYPE_OPTION_VALUE;
$this->completionName = $option->getName();
$this->completionValue = $optionValue ?: (!str_starts_with($optionToken, '--') ? substr($optionToken, 2) : '');
@@ -97,7 +97,7 @@ public function bind(InputDefinition $definition): void
if ('-' === $previousToken[0] && '' !== trim($previousToken, '-')) {
// check if previous option accepted a value
$previousOption = $this->getOptionFromToken($previousToken);
- if (null !== $previousOption && $previousOption->acceptValue()) {
+ if ($previousOption?->acceptValue()) {
$this->completionType = self::TYPE_OPTION_VALUE;
$this->completionName = $previousOption->getName();
$this->completionValue = $relevantToken;
diff --git a/src/Symfony/Component/Console/Completion/Output/FishCompletionOutput.php b/src/Symfony/Component/Console/Completion/Output/FishCompletionOutput.php
new file mode 100644
index 0000000000000..9b02f09aa8250
--- /dev/null
+++ b/src/Symfony/Component/Console/Completion/Output/FishCompletionOutput.php
@@ -0,0 +1,30 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Console\Completion\Output;
+
+use Symfony\Component\Console\Completion\CompletionSuggestions;
+use Symfony\Component\Console\Output\OutputInterface;
+
+/**
+ * @author Guillaume Aveline
+ */
+class FishCompletionOutput implements CompletionOutputInterface
+{
+ public function write(CompletionSuggestions $suggestions, OutputInterface $output): void
+ {
+ $values = $suggestions->getValueSuggestions();
+ foreach ($suggestions->getOptionSuggestions() as $option) {
+ $values[] = '--'.$option->getName();
+ }
+ $output->write(implode("\n", $values));
+ }
+}
diff --git a/src/Symfony/Component/Console/DependencyInjection/AddConsoleCommandPass.php b/src/Symfony/Component/Console/DependencyInjection/AddConsoleCommandPass.php
index efaf39a2c9a20..4334556663078 100644
--- a/src/Symfony/Component/Console/DependencyInjection/AddConsoleCommandPass.php
+++ b/src/Symfony/Component/Console/DependencyInjection/AddConsoleCommandPass.php
@@ -87,7 +87,7 @@ public function process(ContainerBuilder $container)
$lazyCommandMap[$tag['command']] = $id;
}
- $description = $description ?? $tag['description'] ?? null;
+ $description ??= $tag['description'] ?? null;
}
$definition->addMethodCall('setName', [$commandName]);
diff --git a/src/Symfony/Component/Console/EventListener/ErrorListener.php b/src/Symfony/Component/Console/EventListener/ErrorListener.php
index bcd9183311de7..773a13a1c0df2 100644
--- a/src/Symfony/Component/Console/EventListener/ErrorListener.php
+++ b/src/Symfony/Component/Console/EventListener/ErrorListener.php
@@ -79,7 +79,7 @@ public static function getSubscribedEvents(): array
private static function getInputString(ConsoleEvent $event): ?string
{
- $commandName = $event->getCommand() ? $event->getCommand()->getName() : null;
+ $commandName = $event->getCommand()?->getName();
$input = $event->getInput();
if ($input instanceof \Stringable) {
diff --git a/src/Symfony/Component/Console/Formatter/NullOutputFormatter.php b/src/Symfony/Component/Console/Formatter/NullOutputFormatter.php
index d14db326a050d..7950fad1ede30 100644
--- a/src/Symfony/Component/Console/Formatter/NullOutputFormatter.php
+++ b/src/Symfony/Component/Console/Formatter/NullOutputFormatter.php
@@ -32,7 +32,7 @@ public function format(?string $message): ?string
public function getStyle(string $name): OutputFormatterStyleInterface
{
// to comply with the interface we must return a OutputFormatterStyleInterface
- return $this->style ?? $this->style = new NullOutputFormatterStyle();
+ return $this->style ??= new NullOutputFormatterStyle();
}
/**
diff --git a/src/Symfony/Component/Console/Helper/Dumper.php b/src/Symfony/Component/Console/Helper/Dumper.php
index 76b76c0a4047d..29263d853e26f 100644
--- a/src/Symfony/Component/Console/Helper/Dumper.php
+++ b/src/Symfony/Component/Console/Helper/Dumper.php
@@ -34,10 +34,10 @@ public function __construct(OutputInterface $output, CliDumper $dumper = null, C
if (class_exists(CliDumper::class)) {
$this->handler = function ($var): string {
- $dumper = $this->dumper ?? $this->dumper = new CliDumper(null, null, CliDumper::DUMP_LIGHT_ARRAY | CliDumper::DUMP_COMMA_SEPARATOR);
+ $dumper = $this->dumper ??= new CliDumper(null, null, CliDumper::DUMP_LIGHT_ARRAY | CliDumper::DUMP_COMMA_SEPARATOR);
$dumper->setColors($this->output->isDecorated());
- return rtrim($dumper->dump(($this->cloner ?? $this->cloner = new VarCloner())->cloneVar($var)->withRefHandles(false), true));
+ return rtrim($dumper->dump(($this->cloner ??= new VarCloner())->cloneVar($var)->withRefHandles(false), true));
};
} else {
$this->handler = function ($var): string {
diff --git a/src/Symfony/Component/Console/Helper/Helper.php b/src/Symfony/Component/Console/Helper/Helper.php
index 01e39a9b38804..44e3199a987c8 100644
--- a/src/Symfony/Component/Console/Helper/Helper.php
+++ b/src/Symfony/Component/Console/Helper/Helper.php
@@ -45,7 +45,7 @@ public function getHelperSet(): ?HelperSet
*/
public static function width(?string $string): int
{
- $string ?? $string = '';
+ $string ??= '';
if (preg_match('//u', $string)) {
return (new UnicodeString($string))->width(false);
@@ -64,7 +64,7 @@ public static function width(?string $string): int
*/
public static function length(?string $string): int
{
- $string ?? $string = '';
+ $string ??= '';
if (preg_match('//u', $string)) {
return (new UnicodeString($string))->length();
@@ -82,7 +82,7 @@ public static function length(?string $string): int
*/
public static function substr(?string $string, int $from, int $length = null): string
{
- $string ?? $string = '';
+ $string ??= '';
if (false === $encoding = mb_detect_encoding($string, null, true)) {
return substr($string, $from, $length);
diff --git a/src/Symfony/Component/Console/Input/ArgvInput.php b/src/Symfony/Component/Console/Input/ArgvInput.php
index 4e90c812e2cbd..a9585de17e5ca 100644
--- a/src/Symfony/Component/Console/Input/ArgvInput.php
+++ b/src/Symfony/Component/Console/Input/ArgvInput.php
@@ -45,7 +45,7 @@ class ArgvInput extends Input
public function __construct(array $argv = null, InputDefinition $definition = null)
{
- $argv = $argv ?? $_SERVER['argv'] ?? [];
+ $argv ??= $_SERVER['argv'] ?? [];
// strip the application name
array_shift($argv);
diff --git a/src/Symfony/Component/Console/Input/InputArgument.php b/src/Symfony/Component/Console/Input/InputArgument.php
index f89fa33c97eaf..143e4b10ae71f 100644
--- a/src/Symfony/Component/Console/Input/InputArgument.php
+++ b/src/Symfony/Component/Console/Input/InputArgument.php
@@ -105,8 +105,6 @@ public function setDefault(string|bool|int|float|array $default = null)
/**
* Returns the default value.
- *
- * @return string|bool|int|float|array|null
*/
public function getDefault(): string|bool|int|float|array|null
{
diff --git a/src/Symfony/Component/Console/Input/InputOption.php b/src/Symfony/Component/Console/Input/InputOption.php
index 613af20353f08..f9d74a8961ce2 100644
--- a/src/Symfony/Component/Console/Input/InputOption.php
+++ b/src/Symfony/Component/Console/Input/InputOption.php
@@ -187,8 +187,6 @@ public function setDefault(string|bool|int|float|array $default = null)
/**
* Returns the default value.
- *
- * @return string|bool|int|float|array|null
*/
public function getDefault(): string|bool|int|float|array|null
{
diff --git a/src/Symfony/Component/Console/Question/Question.php b/src/Symfony/Component/Console/Question/Question.php
index 7d5e3accb0c05..f25e938a83197 100644
--- a/src/Symfony/Component/Console/Question/Question.php
+++ b/src/Symfony/Component/Console/Question/Question.php
@@ -52,8 +52,6 @@ public function getQuestion(): string
/**
* Returns the default answer.
- *
- * @return string|bool|int|float|null
*/
public function getDefault(): string|bool|int|float|null
{
@@ -154,7 +152,7 @@ public function setAutocompleterValues(?iterable $values): static
} elseif ($values instanceof \Traversable) {
$valueCache = null;
$callback = static function () use ($values, &$valueCache) {
- return $valueCache ?? $valueCache = iterator_to_array($values, false);
+ return $valueCache ??= iterator_to_array($values, false);
};
} else {
$callback = null;
diff --git a/src/Symfony/Component/Console/Resources/completion.fish b/src/Symfony/Component/Console/Resources/completion.fish
new file mode 100644
index 0000000000000..6566c58a3f9ea
--- /dev/null
+++ b/src/Symfony/Component/Console/Resources/completion.fish
@@ -0,0 +1,29 @@
+# This file is part of the Symfony package.
+#
+# (c) Fabien Potencier
+#
+# For the full copyright and license information, please view
+# https://symfony.com/doc/current/contributing/code/license.html
+
+function _sf_{{ COMMAND_NAME }}
+ set sf_cmd (commandline -o)
+ set c (math (count (commandline -oc))) - 1)
+
+ set completecmd "$sf_cmd[1]" "_complete" "-sfish" "-S{{ VERSION }}"
+
+ for i in $sf_cmd
+ if [ $i != "" ]
+ set completecmd $completecmd "-i$i"
+ end
+ end
+
+ set completecmd $completecmd "-c$c"
+
+ set sfcomplete ($completecmd)
+
+ for i in $sfcomplete
+ echo $i
+ end
+end
+
+complete -c '{{ COMMAND_NAME }}' -a '(_sf_{{ COMMAND_NAME }})' -f
diff --git a/src/Symfony/Component/Console/Style/SymfonyStyle.php b/src/Symfony/Component/Console/Style/SymfonyStyle.php
index 58640ab5f0f3d..5e0aabb6e7b4d 100644
--- a/src/Symfony/Component/Console/Style/SymfonyStyle.php
+++ b/src/Symfony/Component/Console/Style/SymfonyStyle.php
@@ -59,7 +59,7 @@ public function __construct(InputInterface $input, OutputInterface $output)
/**
* Formats a message as a block of text.
*/
- public function block(string|array $messages, ?string $type = null, string $style = null, string $prefix = ' ', bool $padding = false, bool $escape = true)
+ public function block(string|array $messages, string $type = null, string $style = null, string $prefix = ' ', bool $padding = false, bool $escape = true)
{
$messages = \is_array($messages) ? array_values($messages) : [$messages];
diff --git a/src/Symfony/Component/Console/Tests/ApplicationTest.php b/src/Symfony/Component/Console/Tests/ApplicationTest.php
index a4fe5b8e4638a..619009efe29cb 100644
--- a/src/Symfony/Component/Console/Tests/ApplicationTest.php
+++ b/src/Symfony/Component/Console/Tests/ApplicationTest.php
@@ -883,6 +883,9 @@ public function testRenderExceptionLineBreaks()
$this->assertStringMatchesFormatFile(self::$fixturesPath.'/application_renderexception_linebreaks.txt', $tester->getDisplay(true), '->renderException() keep multiple line breaks');
}
+ /**
+ * @group transient-on-windows
+ */
public function testRenderAnonymousException()
{
$application = new Application();
@@ -906,6 +909,9 @@ public function testRenderAnonymousException()
$this->assertStringContainsString('Dummy type "class@anonymous" is invalid.', $tester->getDisplay(true));
}
+ /**
+ * @group transient-on-windows
+ */
public function testRenderExceptionStackTraceContainsRootException()
{
$application = new Application();
diff --git a/src/Symfony/Component/Console/Tests/Command/CompleteCommandTest.php b/src/Symfony/Component/Console/Tests/Command/CompleteCommandTest.php
index 189928897cc7c..74caa246c7b03 100644
--- a/src/Symfony/Component/Console/Tests/Command/CompleteCommandTest.php
+++ b/src/Symfony/Component/Console/Tests/Command/CompleteCommandTest.php
@@ -47,7 +47,7 @@ public function testRequiredShellOption()
public function testUnsupportedShellOption()
{
- $this->expectExceptionMessage('Shell completion is not supported for your shell: "unsupported" (supported: "bash").');
+ $this->expectExceptionMessage('Shell completion is not supported for your shell: "unsupported" (supported: "bash", "fish").');
$this->execute(['--shell' => 'unsupported']);
}
diff --git a/src/Symfony/Component/Console/Tests/Command/DumpCompletionCommandTest.php b/src/Symfony/Component/Console/Tests/Command/DumpCompletionCommandTest.php
index de8a3d4a60a3a..b50e42b160378 100644
--- a/src/Symfony/Component/Console/Tests/Command/DumpCompletionCommandTest.php
+++ b/src/Symfony/Component/Console/Tests/Command/DumpCompletionCommandTest.php
@@ -23,7 +23,7 @@ public function provideCompletionSuggestions()
{
yield 'shell' => [
[''],
- ['bash'],
+ ['bash', 'fish'],
];
}
}
diff --git a/src/Symfony/Component/Console/Tests/Fixtures/application_1.json b/src/Symfony/Component/Console/Tests/Fixtures/application_1.json
index 280a4247eb39f..2cd6ee9618f79 100644
--- a/src/Symfony/Component/Console/Tests/Fixtures/application_1.json
+++ b/src/Symfony/Component/Console/Tests/Fixtures/application_1.json
@@ -89,7 +89,7 @@
"accept_value": true,
"is_value_required": true,
"is_multiple": false,
- "description": "The shell type (\"bash\")",
+ "description": "The shell type (\"bash\", \"fish\")",
"default": null
},
"current": {
diff --git a/src/Symfony/Component/Console/Tests/Fixtures/application_1.xml b/src/Symfony/Component/Console/Tests/Fixtures/application_1.xml
index 5a17229343fcf..0f78ec5d36448 100644
--- a/src/Symfony/Component/Console/Tests/Fixtures/application_1.xml
+++ b/src/Symfony/Component/Console/Tests/Fixtures/application_1.xml
@@ -10,7 +10,7 @@