diff --git a/.git-blame-ignore-revs b/.git-blame-ignore-revs
new file mode 100644
index 0000000000000..1171d75845cba
--- /dev/null
+++ b/.git-blame-ignore-revs
@@ -0,0 +1,6 @@
+# Apply php-cs-fixer fix --rules nullable_type_declaration_for_default_null_value
+f4118e110a46de3ffb799e7d79bf15128d1646ea
+9519b54417c09c49496a4a6be238e63be9a73465
+ae0a783425b80b78376488619bf9106e69193fa4
+9c1e36257c4df0929179462d6b2bdd00453ac8aa
+6ae74d38e3d20d0ffcc66c7c3d28767fab76bdfb
diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md
index be833bfec1a14..00a24cbcfc13c 100644
--- a/.github/PULL_REQUEST_TEMPLATE.md
+++ b/.github/PULL_REQUEST_TEMPLATE.md
@@ -1,6 +1,6 @@
| Q | A
| ------------- | ---
-| Branch? | 7.1 for features / 5.4, 6.3, 6.4, or 7.0 for bug fixes
+| Branch? | 7.1 for features / 5.4, 6.4, or 7.0 for bug fixes
| Bug fix? | yes/no
| New feature? | yes/no
| Deprecations? | yes/no
diff --git a/.github/expected-missing-return-types.diff b/.github/expected-missing-return-types.diff
index e477abe0fa71b..36cf1d6177550 100644
--- a/.github/expected-missing-return-types.diff
+++ b/.github/expected-missing-return-types.diff
@@ -22,7 +22,7 @@ diff --git a/src/Symfony/Component/BrowserKit/AbstractBrowser.php b/src/Symfony/
*/
- abstract protected function doRequest(object $request);
+ abstract protected function doRequest(object $request): object;
-
+
/**
@@ -451,5 +451,5 @@ abstract class AbstractBrowser
* @throws LogicException When this abstract class is not implemented
@@ -146,21 +146,21 @@ diff --git a/src/Symfony/Component/DependencyInjection/Extension/ExtensionInterf
*/
- public function load(array $configs, ContainerBuilder $container);
+ public function load(array $configs, ContainerBuilder $container): void;
-
+
/**
@@ -37,5 +37,5 @@ interface ExtensionInterface
* @return string
*/
- public function getNamespace();
+ public function getNamespace(): string;
-
+
/**
@@ -44,5 +44,5 @@ interface ExtensionInterface
* @return string|false
*/
- public function getXsdValidationBasePath();
+ public function getXsdValidationBasePath(): string|false;
-
+
/**
@@ -53,4 +53,4 @@ interface ExtensionInterface
* @return string
@@ -249,35 +249,35 @@ diff --git a/src/Symfony/Component/Form/FormTypeInterface.php b/src/Symfony/Comp
*/
- public function getParent();
+ public function getParent(): ?string;
-
+
/**
@@ -34,5 +34,5 @@ interface FormTypeInterface
* @return void
*/
- public function configureOptions(OptionsResolver $resolver);
+ public function configureOptions(OptionsResolver $resolver): void;
-
+
/**
@@ -48,5 +48,5 @@ interface FormTypeInterface
* @see FormTypeExtensionInterface::buildForm()
*/
- public function buildForm(FormBuilderInterface $builder, array $options);
+ public function buildForm(FormBuilderInterface $builder, array $options): void;
-
+
/**
@@ -66,5 +66,5 @@ interface FormTypeInterface
* @see FormTypeExtensionInterface::buildView()
*/
- public function buildView(FormView $view, FormInterface $form, array $options);
+ public function buildView(FormView $view, FormInterface $form, array $options): void;
-
+
/**
@@ -85,5 +85,5 @@ interface FormTypeInterface
* @see FormTypeExtensionInterface::finishView()
*/
- public function finishView(FormView $view, FormInterface $form, array $options);
+ public function finishView(FormView $view, FormInterface $form, array $options): void;
-
+
/**
@@ -95,4 +95,4 @@ interface FormTypeInterface
* @return string
@@ -324,21 +324,21 @@ diff --git a/src/Symfony/Component/HttpKernel/Bundle/BundleInterface.php b/src/S
*/
- public function boot();
+ public function boot(): void;
-
+
/**
@@ -35,5 +35,5 @@ interface BundleInterface
* @return void
*/
- public function shutdown();
+ public function shutdown(): void;
-
+
/**
@@ -44,5 +44,5 @@ interface BundleInterface
* @return void
*/
- public function build(ContainerBuilder $container);
+ public function build(ContainerBuilder $container): void;
-
+
/**
diff --git a/src/Symfony/Component/HttpKernel/DataCollector/DataCollector.php b/src/Symfony/Component/HttpKernel/DataCollector/DataCollector.php
--- a/src/Symfony/Component/HttpKernel/DataCollector/DataCollector.php
@@ -356,9 +356,9 @@ diff --git a/src/Symfony/Component/HttpKernel/DataCollector/DataCollectorInterfa
@@ -28,5 +28,5 @@ interface DataCollectorInterface extends ResetInterface
* @return void
*/
-- public function collect(Request $request, Response $response, \Throwable $exception = null);
-+ public function collect(Request $request, Response $response, \Throwable $exception = null): void;
-
+- public function collect(Request $request, Response $response, ?\Throwable $exception = null);
++ public function collect(Request $request, Response $response, ?\Throwable $exception = null): void;
+
/**
@@ -35,4 +35,4 @@ interface DataCollectorInterface extends ResetInterface
* @return string
@@ -383,21 +383,21 @@ diff --git a/src/Symfony/Component/HttpKernel/KernelInterface.php b/src/Symfony/
*/
- public function registerContainerConfiguration(LoaderInterface $loader);
+ public function registerContainerConfiguration(LoaderInterface $loader): void;
-
+
/**
@@ -44,5 +44,5 @@ interface KernelInterface extends HttpKernelInterface
* @return void
*/
- public function boot();
+ public function boot(): void;
-
+
/**
@@ -53,5 +53,5 @@ interface KernelInterface extends HttpKernelInterface
* @return void
*/
- public function shutdown();
+ public function shutdown(): void;
-
+
/**
diff --git a/src/Symfony/Component/Routing/Loader/AttributeClassLoader.php b/src/Symfony/Component/Routing/Loader/AttributeClassLoader.php
--- a/src/Symfony/Component/Routing/Loader/AttributeClassLoader.php
@@ -414,7 +414,7 @@ diff --git a/src/Symfony/Component/Routing/Loader/AttributeClassLoader.php b/src
*/
- abstract protected function configureRoute(Route $route, \ReflectionClass $class, \ReflectionMethod $method, object $annot);
+ abstract protected function configureRoute(Route $route, \ReflectionClass $class, \ReflectionMethod $method, object $annot): void;
-
+
/**
diff --git a/src/Symfony/Component/Security/Core/Authentication/RememberMe/TokenProviderInterface.php b/src/Symfony/Component/Security/Core/Authentication/RememberMe/TokenProviderInterface.php
--- a/src/Symfony/Component/Security/Core/Authentication/RememberMe/TokenProviderInterface.php
@@ -424,21 +424,21 @@ diff --git a/src/Symfony/Component/Security/Core/Authentication/RememberMe/Token
*/
- public function loadTokenBySeries(string $series);
+ public function loadTokenBySeries(string $series): PersistentTokenInterface;
-
+
/**
@@ -35,5 +35,5 @@ interface TokenProviderInterface
* @return void
*/
- public function deleteTokenBySeries(string $series);
+ public function deleteTokenBySeries(string $series): void;
-
+
/**
@@ -44,5 +44,5 @@ interface TokenProviderInterface
* @throws TokenNotFoundException if the token is not found
*/
- public function updateToken(string $series, #[\SensitiveParameter] string $tokenValue, \DateTimeInterface $lastUsed);
+ public function updateToken(string $series, #[\SensitiveParameter] string $tokenValue, \DateTimeInterface $lastUsed): void;
-
+
/**
@@ -51,4 +51,4 @@ interface TokenProviderInterface
* @return void
@@ -485,7 +485,7 @@ diff --git a/src/Symfony/Component/Translation/Extractor/ExtractorInterface.php
*/
- public function extract(string|iterable $resource, MessageCatalogue $catalogue);
+ public function extract(string|iterable $resource, MessageCatalogue $catalogue): void;
-
+
/**
@@ -36,4 +36,4 @@ interface ExtractorInterface
* @return void
@@ -501,7 +501,7 @@ diff --git a/src/Symfony/Component/Validator/ConstraintValidatorInterface.php b/
*/
- public function initialize(ExecutionContextInterface $context);
+ public function initialize(ExecutionContextInterface $context): void;
-
+
/**
@@ -31,4 +31,4 @@ interface ConstraintValidatorInterface
* @return void
@@ -526,7 +526,7 @@ diff --git a/src/Symfony/Contracts/Translation/LocaleAwareInterface.php b/src/Sy
*/
- public function setLocale(string $locale);
+ public function setLocale(string $locale): void;
-
+
/**
diff --git a/src/Symfony/Contracts/Translation/TranslatorTrait.php b/src/Symfony/Contracts/Translation/TranslatorTrait.php
--- a/src/Symfony/Contracts/Translation/TranslatorTrait.php
diff --git a/.github/sync-translations.php b/.github/sync-translations.php
index b1f7c237c39c0..eb3f8e840ab4a 100644
--- a/.github/sync-translations.php
+++ b/.github/sync-translations.php
@@ -33,6 +33,9 @@ function dumpXliff1(string $defaultLocale, MessageCatalogue $messages, string $d
$metadata = $messages->getMetadata($source, $domain);
$translation->setAttribute('id', $metadata['id']);
+ if (isset($metadata['resname'])) {
+ $translation->setAttribute('resname', $metadata['resname']);
+ }
$s = $translation->appendChild($dom->createElement('source'));
$s->appendChild($dom->createTextNode($source));
@@ -64,23 +67,32 @@ function dumpXliff1(string $defaultLocale, MessageCatalogue $messages, string $d
$dir = __DIR__.'/../src/Symfony/Component/'.$component.'/Resources/translations';
$enCatalogue = (new XliffFileLoader())->load($dir.'/'.$domain.'.en.xlf', 'en', $domain);
+ file_put_contents($dir.'/'.$domain.'.en.xlf', dumpXliff1('en', $enCatalogue, $domain));
+
$finder = new Finder();
foreach ($finder->files()->in($dir)->name('*.xlf') as $file) {
$locale = substr($file->getBasename(), 1 + strlen($domain), -4);
+ if ('en' === $locale) {
+ continue;
+ }
+
$catalogue = (new XliffFileLoader())->load($file, $locale, $domain);
$localeCatalogue = new MessageCatalogue($locale);
- foreach ($enCatalogue->all($domain) as $id => $translation) {
+ foreach ($enCatalogue->all($domain) as $resname => $source) {
$metadata = [];
- if ($catalogue->defines($id, $domain)) {
- $translation = $catalogue->get($id, $domain);
- $metadata = $catalogue->getMetadata($id, $domain);
+ if ($catalogue->defines($resname, $domain)) {
+ $translation = $catalogue->get($resname, $domain);
+ $metadata = $catalogue->getMetadata($resname, $domain);
+ }
+ $metadata['id'] = $enCatalogue->getMetadata($resname, $domain)['id'];
+ if ($resname !== $source) {
+ $metadata['resname'] = $resname;
}
- $metadata['id'] = $enCatalogue->getMetadata($id, $domain)['id'];
- $localeCatalogue->set($id, $translation, $domain);
- $localeCatalogue->setMetadata($id, $metadata, $domain);
+ $localeCatalogue->set($source, $translation, $domain);
+ $localeCatalogue->setMetadata($source, $metadata, $domain);
}
file_put_contents($file, dumpXliff1('en', $localeCatalogue, $domain));
diff --git a/.github/workflows/integration-tests.yml b/.github/workflows/integration-tests.yml
index 71182fcbaaa32..9ef1476bd7bd7 100644
--- a/.github/workflows/integration-tests.yml
+++ b/.github/workflows/integration-tests.yml
@@ -95,9 +95,9 @@ jobs:
- 8094:8094
- 11210:11210
sqs:
- image: asyncaws/testing-sqs
+ image: localstack/localstack:3.0.2
ports:
- - 9494:9494
+ - 4566:4566
zookeeper:
image: wurstmeister/zookeeper:3.4.6
kafka:
@@ -182,8 +182,8 @@ jobs:
REDIS_SENTINEL_SERVICE: redis_sentinel
MESSENGER_REDIS_DSN: redis://127.0.0.1:7006/messages
MESSENGER_AMQP_DSN: amqp://localhost/%2f/messages
- MESSENGER_SQS_DSN: "sqs://localhost:9494/messages?sslmode=disable&poll_timeout=0.01"
- MESSENGER_SQS_FIFO_QUEUE_DSN: "sqs://localhost:9494/messages.fifo?sslmode=disable&poll_timeout=0.01"
+ MESSENGER_SQS_DSN: "sqs://localhost:4566/messages?sslmode=disable&poll_timeout=0.01"
+ MESSENGER_SQS_FIFO_QUEUE_DSN: "sqs://localhost:4566/messages.fifo?sslmode=disable&poll_timeout=0.01"
KAFKA_BROKER: 127.0.0.1:9092
POSTGRES_HOST: localhost
diff --git a/.github/workflows/intl-data-tests.yml b/.github/workflows/intl-data-tests.yml
index 01401fedc232f..a02bd73ac5b8f 100644
--- a/.github/workflows/intl-data-tests.yml
+++ b/.github/workflows/intl-data-tests.yml
@@ -1,8 +1,11 @@
-name: Intl data
+name: Intl/Emoji data
on:
push:
paths:
+ - 'src/Symfony/Component/Emoji/*.php'
+ - 'src/Symfony/Component/Emoji/Resources/data/**'
+ - 'src/Symfony/Component/Emoji/Tests/*Test.php'
- 'src/Symfony/Component/Intl/*.php'
- 'src/Symfony/Component/Intl/Util/GitRepository.php'
- 'src/Symfony/Component/Intl/Resources/data/**'
@@ -10,6 +13,9 @@ on:
- 'src/Symfony/Component/Intl/Tests/Util/GitRepositoryTest.php'
pull_request:
paths:
+ - 'src/Symfony/Component/Emoji/*.php'
+ - 'src/Symfony/Component/Emoji/Resources/data/**'
+ - 'src/Symfony/Component/Emoji/Tests/*Test.php'
- 'src/Symfony/Component/Intl/*.php'
- 'src/Symfony/Component/Intl/Util/GitRepository.php'
- 'src/Symfony/Component/Intl/Resources/data/**'
@@ -29,7 +35,7 @@ permissions:
jobs:
tests:
- name: Intl data
+ name: Intl/Emoji data
runs-on: Ubuntu-20.04
steps:
@@ -80,15 +86,23 @@ jobs:
- name: Run intl-data tests
run: ./phpunit --group intl-data -v
- - name: Test with compressed data
+ - name: Test intl-data with compressed data
run: |
[ -f src/Symfony/Component/Intl/Resources/data/locales/en.php ]
[ ! -f src/Symfony/Component/Intl/Resources/data/locales/en.php.gz ]
- [ -f src/Symfony/Component/Intl/Resources/data/transliterator/emoji/emoji-en.php ]
- [ ! -f src/Symfony/Component/Intl/Resources/data/transliterator/emoji/emoji-en.php.gz ]
src/Symfony/Component/Intl/Resources/bin/compress
[ ! -f src/Symfony/Component/Intl/Resources/data/locales/en.php ]
[ -f src/Symfony/Component/Intl/Resources/data/locales/en.php.gz ]
- [ ! -f src/Symfony/Component/Intl/Resources/data/transliterator/emoji/emoji-en.php ]
- [ -f src/Symfony/Component/Intl/Resources/data/transliterator/emoji/emoji-en.php.gz ]
./phpunit src/Symfony/Component/Intl
+
+ - name: Run Emoji tests
+ run: ./phpunit src/Symfony/Component/Emoji -v
+
+ - name: Test Emoji with compressed data
+ run: |
+ [ -f src/Symfony/Component/Emoji/Resources/data/emoji-en.php ]
+ [ ! -f src/Symfony/Component/Emoji/Resources/data/emoji-en.php.gz ]
+ src/Symfony/Component/Emoji/Resources/bin/compress
+ [ ! -f src/Symfony/Component/Emoji/Resources/data/emoji-en.php ]
+ [ -f src/Symfony/Component/Emoji/Resources/data/emoji-en.php.gz ]
+ ./phpunit src/Symfony/Component/Emoji
diff --git a/.github/workflows/package-tests.yml b/.github/workflows/package-tests.yml
index 96b7451b7f945..bc6f8eec683c7 100644
--- a/.github/workflows/package-tests.yml
+++ b/.github/workflows/package-tests.yml
@@ -21,7 +21,7 @@ jobs:
- name: Find packages
id: find-packages
- run: echo "packages=$(php .github/get-modified-packages.php $(find src/Symfony -mindepth 2 -type f -name composer.json -printf '%h\n' | grep -v src/Symfony/Component/Intl/Resources/emoji |jq -R -s -c 'split("\n")[:-1]') $(git diff --name-only origin/${{ github.base_ref }} HEAD | grep src/ | jq -R -s -c 'split("\n")[:-1]'))" >> $GITHUB_OUTPUT
+ run: echo "packages=$(php .github/get-modified-packages.php $(find src/Symfony -mindepth 2 -type f -name composer.json -printf '%h\n' | grep -v src/Symfony/Component/Emoji/Resources/bin |jq -R -s -c 'split("\n")[:-1]') $(git diff --name-only origin/${{ github.base_ref }} HEAD | grep src/ | jq -R -s -c 'split("\n")[:-1]'))" >> $GITHUB_OUTPUT
- name: Verify meta files are correct
run: |
diff --git a/.github/workflows/unit-tests.yml b/.github/workflows/unit-tests.yml
index 414408098f091..08d67bfa91b7f 100644
--- a/.github/workflows/unit-tests.yml
+++ b/.github/workflows/unit-tests.yml
@@ -95,7 +95,7 @@ jobs:
echo SYMFONY_DEPRECATIONS_HELPER=weak >> $GITHUB_ENV
cp composer.json composer.json.orig
echo -e '{\n"require":{'"$(grep phpunit-bridge composer.json)"'"php":"*"},"minimum-stability":"dev"}' > composer.json
- php .github/build-packages.php HEAD^ $SYMFONY_VERSION $(find src/Symfony -mindepth 2 -type f -name composer.json -printf '%h\n' | grep -v src/Symfony/Component/Intl/Resources/emoji)
+ php .github/build-packages.php HEAD^ $SYMFONY_VERSION $(find src/Symfony -mindepth 2 -type f -name composer.json -printf '%h\n' | grep -v src/Symfony/Component/Emoji/Resources/bin)
mv composer.json composer.json.phpunit
mv composer.json.orig composer.json
fi
@@ -129,7 +129,7 @@ jobs:
[[ "${{ matrix.mode }}" = *-deps ]] && mv composer.json.phpunit composer.json || true
if [[ "${{ matrix.mode }}" = low-deps ]]; then
- echo SYMFONY_PHPUNIT_REQUIRE="nikic/php-parser:^4.16" >> $GITHUB_ENV
+ echo SYMFONY_PHPUNIT_REQUIRE="nikic/php-parser:^4.18" >> $GITHUB_ENV
fi
- name: Install dependencies
diff --git a/.php-cs-fixer.dist.php b/.php-cs-fixer.dist.php
index 86c5b0f1b7371..5ae76ab4312d6 100644
--- a/.php-cs-fixer.dist.php
+++ b/.php-cs-fixer.dist.php
@@ -34,10 +34,12 @@
'remove_inheritdoc' => true,
'allow_unused_params' => true, // for future-ready params, to be replaced with https://github.com/PHP-CS-Fixer/PHP-CS-Fixer/issues/7377
],
+ 'nullable_type_declaration_for_default_null_value' => true,
'header_comment' => ['header' => $fileHeaderComment],
'modernize_strpos' => true,
'get_class_to_class_keyword' => true,
'nullable_type_declaration' => true,
+ 'ordered_types' => ['null_adjustment' => 'always_last', 'sort_algorithm' => 'none'],
'trailing_comma_in_multiline' => ['elements' => ['arrays', 'match', 'parameters']],
])
->setRiskyAllowed(true)
@@ -54,6 +56,7 @@
'Symfony/Bundle/FrameworkBundle/Resources/views/Form',
// explicit trigger_error tests
'Symfony/Bridge/PhpUnit/Tests/DeprecationErrorHandler/',
+ 'Symfony/Component/Emoji/Resources/',
'Symfony/Component/Intl/Resources/data/',
])
// explicit tests for ommited @param type, against `no_superfluous_phpdoc_tags`
diff --git a/CHANGELOG-7.0.md b/CHANGELOG-7.0.md
index 17289415f1144..6edcfe85bf1f4 100644
--- a/CHANGELOG-7.0.md
+++ b/CHANGELOG-7.0.md
@@ -7,6 +7,65 @@ in 7.0 minor versions.
To get the diff for a specific change, go to https://github.com/symfony/symfony/commit/XXX where XXX is the change hash
To get the diff between two versions, go to https://github.com/symfony/symfony/compare/v7.0.0...v7.0.1
+* 7.0.3 (2024-01-31)
+
+ * bug #52913 [Routing] Fixed priority getting lost when setting localized prefix (pritasil)
+ * bug #53681 [DoctrineBridge] Fix detection of Xml/Yaml driver in DoctrineExtension (GromNaN)
+ * bug #53183 [Messenger] PhpSerializer: TypeError should throw `MessageDecodingFailedException` (B-Galati)
+ * bug #52131 [HttpKernel] Fix `RequestPayloadValueResolver` handling error with no ExpectedTypes (Jeroeny)
+ * bug #51559 [DependencyInjection] `#[Autowire]` attribute should have precedence over bindings (HypeMC)
+ * bug #53678 [Mime] Fix serializing uninitialized `RawMessage::$message` to null (nicolas-grekas)
+ * bug #53634 [Notifer][Smsapi] Set messageId of SentMessage (tomasz-kusy)
+ * bug #53501 [DependencyInjection] support lazy evaluated exception messages with Xdebug 3 (xabbuh)
+ * bug #53672 [FrameworkBundle] `ConfigBuilderCacheWarmer` should be non-optional (nicolas-grekas)
+ * bug #52994 [MonologBridge] Fix context data and display extra data (louismariegaborit)
+ * bug #53671 [HttpClient] Fix pausing responses before they start when using curl (nicolas-grekas)
+ * bug #53594 [Notifier] Updated the NTFY notifier to run without a user parameter (lostfocus)
+ * bug #53620 [Validator] Fix option filenameMaxLength to the File constraint (Image) (mindaugasvcs)
+ * bug #53624 [Translation] Fix constant domain resolution in PhpAstExtractor (VincentLanglet)
+ * bug #53663 [TwigBridge] separate child and parent context in NotificationEmail on writes (xabbuh)
+ * bug #53667 [Mailer] [Mailgun] Fix sender header encoding (spajxo)
+ * bug #53631 [DependencyInjection] Fix loading all env vars from secrets when only a subset is needed (nicolas-grekas)
+ * bug #53656 [Form] Use self-closing `` syntax again, reverting #47715 (mpdude)
+ * bug #53653 [Mailer] [Scaleway] Fix attachment handling (madbob)
+ * bug #53157 [Mailer] Throw `TransportException` when unable to read from socket (xdanik)
+ * bug #53361 [Serializer] Take unnamed variadic parameters into account when denormalizing (thijsBreker)
+ * bug #53530 [Serializer] Rewrite `AbstractObjectNormalizer::createChildContext()` to use the provided `cache_key` from original context when creating child contexts (amne)
+ * bug #53506 [HttpClient] Fix error chunk creation in passthru (rmikalkenas)
+ * bug #53260 [AssetMapper] Handle assets with non-ascii characters in dev server (fbourigault)
+ * bug #53357 [Translation] Fix `TranslationNodeVisitor` with constant domain (VincentLanglet)
+ * bug #53525 [Messenger] [AMQP] Throw exception on `nack` callback (kvrushifa)
+ * bug #53432 [HttpFoundation] Request without content-type or content-length header should result in null values, not empty strings (priyadi)
+ * bug #53593 [Cache] Fix possible infinite loop in `CachePoolPass` (HypeMC)
+ * bug #53588 [Translation] fix multi-byte code area to convert (xabbuh)
+ * bug #53572 [FrameworkBundle] grab a service from the container only if it exists (xabbuh)
+ * bug #53565 [Mime] Fix undefined array key 0 when empty sender (0x346e3730)
+ * bug #53516 [Console] Allow '0' as a $shortcut in InputOption.php (lawsonjl-ornl)
+ * bug #53576 [Console] Only execute additional checks for color support if the output (theofidry)
+ * bug #53582 [TwigBundle] Fix configuration when "paths" is null (smnandre)
+ * bug #53575 [Mailer] register the MailPaceTransportFactory (xabbuh)
+ * bug #53581 [String] fix aircraft inflection (renanbr)
+ * bug #53509 [Security] Fix `AuthenticationUtils::getLastUsername()` returning null (alexandre-daubois)
+ * bug #53529 [Ldap] Use `{user_identifier}` over deprecated `{username}` in factories (tcitworld)
+ * bug #53567 [String] Correct inflection of axis (Vladislav Iurciuc)
+ * bug #53537 [VarDumper] Fix missing colors initialization in `CliDumper` (nicolas-grekas)
+ * bug #53521 [VarDumper] Fixes `Typed property Symfony\Component\VarDumper\Dumper\CliDumper::$colors must not be accessed before initialization` (crynobone)
+ * bug #53481 [Process] Fix executable finder when the command starts with a dash (kayw-geek)
+ * bug #53006 [ErrorHandler] Don't format binary strings (aleho)
+ * bug #53453 [Translation] add support for nikic/php-parser 5.0 (xabbuh)
+ * bug #53434 [ErrorHandler] fix rendering exception pages without the HttpKernel component (xabbuh)
+ * bug #53441 [Messenger] Amazon SQS Delay has a max of 15 minutes (alamirault)
+ * bug #53414 [Serializer] `GetSetMethodNormalizer`: fix BC break with `#[Ignore]` attribute (nikophil)
+ * bug #53383 [Validator] re-allow an empty list of fields (xabbuh)
+ * bug #53418 [FrameworkBundle][Notifier] Fix service registration (MessageBird + TurboSms) (smnandre)
+ * bug #53381 [Form] Fix assigning data in `PostSetDataEvent` and `PostSubmitEvent` (fancyweb)
+ * bug #53350 [Validator] fix the exception being thrown (xabbuh)
+ * bug #52930 [Messenger] Fix Redis messenger scheme comparison (freswa)
+ * bug #52874 [Scheduler] Separate id and description in message providers (valtzu)
+ * bug #53341 [FrameworkBundle] append instead of replacing potentially non-existent named-arguments (xabbuh)
+ * bug #53320 [Cache][DependencyInjection][Lock][Mailer][Messenger][Notifier][Translation] Url decode username and passwords from `parse_url()` results (alexandre-daubois)
+ * bug #53108 [Serializer] Fix using deserialization path 5.4 (HypeMC)
+
* 7.0.2 (2023-12-30)
* bug #53282 [RateLimiter] Fix RateLimit->getRetryAfter() return value when consuming 0 or last tokens (wouterj, ERuban)
diff --git a/CONTRIBUTORS.md b/CONTRIBUTORS.md
index ca870dd304464..8ae25e554297b 100644
--- a/CONTRIBUTORS.md
+++ b/CONTRIBUTORS.md
@@ -15,9 +15,9 @@ The Symfony Connect username in parenthesis allows to get more information
- Thomas Calvet (fancyweb)
- Christophe Coevoet (stof)
- Wouter de Jong (wouterj)
+ - Alexandre Daubois (alexandre-daubois)
- Jordi Boggiano (seldaek)
- Maxime Steinhausser (ogizanagi)
- - Alexandre Daubois (alexandre-daubois)
- Kévin Dunglas (dunglas)
- Victor Berchet (victor)
- Ryan Weaver (weaverryan)
@@ -26,9 +26,9 @@ The Symfony Connect username in parenthesis allows to get more information
- Jules Pietri (heah)
- Roland Franssen
- Johannes S (johannes)
+ - Oskar Stark (oskarstark)
- Kris Wallsmith (kriswallsmith)
- Jakub Zalas (jakubzalas)
- - Oskar Stark (oskarstark)
- Yonel Ceruto (yonelceruto)
- Hugo Hamon (hhamon)
- Tobias Nyholm (tobias)
@@ -38,11 +38,11 @@ The Symfony Connect username in parenthesis allows to get more information
- Romain Neutron
- Antoine Lamirault (alamirault)
- Joseph Bielawski (stloyd)
+ - HypeMC (hypemc)
- Drak (drak)
- Abdellatif Ait boudad (aitboudad)
- - HypeMC (hypemc)
- - Lukas Kahwe Smith (lsmith)
- Kevin Bond (kbond)
+ - Lukas Kahwe Smith (lsmith)
- Hamza Amrouche (simperfit)
- Martin Hasoň (hason)
- Jeremy Mikola (jmikola)
@@ -64,25 +64,26 @@ The Symfony Connect username in parenthesis allows to get more information
- Diego Saint Esteben (dosten)
- stealth35 (stealth35)
- Alexander Mols (asm89)
+ - Gábor Egyed (1ed)
- Francis Besset (francisbesset)
- Titouan Galopin (tgalopin)
- Pierre du Plessis (pierredup)
- - Gábor Egyed (1ed)
- David Maicher (dmaicher)
- Bulat Shakirzyanov (avalanche123)
- - Iltar van der Berg
- Vincent Langlet (deviling)
+ - Iltar van der Berg
- Miha Vrhovnik (mvrhov)
- Gary PEGEOT (gary-p)
- Saša Stamenković (umpirsky)
- Allison Guilhem (a_guilhem)
- Mathieu Piot (mpiot)
+ - Mathieu Santostefano (welcomattic)
- Alexander Schranz (alexander-schranz)
- Vasilij Duško (staff)
- - Mathieu Santostefano (welcomattic)
- Sarah Khalil (saro0h)
- Laurent VOULLEMIER (lvo)
- Konstantin Kudryashov (everzet)
+ - Tomasz Kowalczyk (thunderer)
- Guilhem N (guilhemn)
- Bilal Amarni (bamarni)
- Eriksen Costa
@@ -91,10 +92,11 @@ The Symfony Connect username in parenthesis allows to get more information
- Peter Rehm (rpet)
- Henrik Bjørnskov (henrikbjorn)
- Mathias Arlaud (mtarld)
+ - Dariusz Ruminski
- Andrej Hudec (pulzarraider)
- Jáchym Toušek (enumag)
+ - Simon André (simonandre)
- David Buchmann (dbu)
- - Dariusz Ruminski
- Christian Raue
- Eric Clemmons (ericclemmons)
- Denis (yethee)
@@ -103,36 +105,36 @@ The Symfony Connect username in parenthesis allows to get more information
- Douglas Greenshields (shieldo)
- Frank A. Fiebig (fafiebig)
- Baldini
+ - Ruud Kamphuis (ruudk)
- Alex Pott
- Fran Moreno (franmomu)
- Arnout Boks (aboks)
- - Simon André (simonandre)
- Charles Sarrazin (csarrazi)
- - Ruud Kamphuis (ruudk)
- Henrik Westphal (snc)
- Dariusz Górecki (canni)
- Ener-Getick
- Graham Campbell (graham)
+ - Tomas Norkūnas (norkunas)
- Tugdual Saunier (tucksaun)
- Lee McDermott
- Brandon Turner
+ - Massimiliano Arione (garak)
- Luis Cordova (cordoval)
- Antoine Makdessi (amakdessi)
- Konstantin Myakshin (koc)
- Hubert Lenoir (hubert_lenoir)
- Daniel Holmes (dholmes)
- Julien Falque (julienfalque)
- - Tomas Norkūnas (norkunas)
- Toni Uebernickel (havvg)
- Bart van den Burg (burgov)
- Vasilij Dusko | CREATION
- Jordan Alliot (jalliot)
- - Massimiliano Arione (garak)
- John Wards (johnwards)
- Phil E. Taylor (philetaylor)
- Antoine Hérault (herzult)
- Konstantin.Myakshin
- Yanick Witschi (toflar)
+ - Théo FIDRY
- Arnaud Le Blanc (arnaud-lb)
- Joel Wurtz (brouznouf)
- Sebastiaan Stok (sstok)
@@ -140,15 +142,14 @@ The Symfony Connect username in parenthesis allows to get more information
- gnito-org
- Jeroen Spee (jeroens)
- Tim Nagel (merk)
- - Théo FIDRY
- Chris Wilkinson (thewilkybarkid)
- Jérôme Vasseur (jvasseur)
+ - Rokas Mikalkėnas (rokasm)
- Peter Kokot (peterkokot)
- Brice BERNARD (brikou)
- Tac Tacelosky (tacman1123)
- Michal Piotrowski
- marc.weistroff
- - Rokas Mikalkėnas (rokasm)
- Lars Strojny (lstrojny)
- lenar
- Vladimir Tsykun (vtsykun)
@@ -178,6 +179,7 @@ The Symfony Connect username in parenthesis allows to get more information
- François-Xavier de Guillebon (de-gui_f)
- noniagriconomie
- Eric GELOEN (gelo)
+ - Nicolas Philippe (nikophil)
- Gabriel Caruso
- Stefano Sala (stefano.sala)
- Ion Bazan (ionbazan)
@@ -187,7 +189,6 @@ The Symfony Connect username in parenthesis allows to get more information
- Gregor Harlan (gharlan)
- Michael Babker (mbabker)
- Anthony MARTIN
- - Nicolas Philippe (nikophil)
- Sebastian Hörl (blogsh)
- Tigran Azatyan (tigranazatyan)
- Christopher Hertel (chertel)
@@ -207,17 +208,19 @@ The Symfony Connect username in parenthesis allows to get more information
- Andreas Braun
- Hugo Alliaume (kocal)
- Pablo Godel (pgodel)
+ - Florent Mata (fmata)
- Alessandro Chitolina (alekitto)
- - Tomasz Kowalczyk (thunderer)
+ - Dāvis Zālītis (k0d3r1s)
- Rafael Dohms (rdohms)
- jwdeitch
+ - David Prévot (taffit)
- Jérôme Parmentier (lctrs)
- Ahmed TAILOULOUTE (ahmedtai)
- Simon Berger
- Jérémy Derussé
+ - Valtteri R (valtzu)
- Matthieu Napoli (mnapoli)
- Tomas Votruba (tomas_votruba)
- - Florent Mata (fmata)
- Arman Hosseini (arman)
- Sokolov Evgeniy (ewgraf)
- Andréia Bohner (andreia)
@@ -227,15 +230,15 @@ The Symfony Connect username in parenthesis allows to get more information
- George Mponos (gmponos)
- Roman Martinuk (a2a4)
- Richard Shank (iampersistent)
- - David Prévot (taffit)
+ - Thomas Landauer (thomas-landauer)
- Romain Monteil (ker0x)
- Sergey (upyx)
- Marco Pivetta (ocramius)
- Antonio Pauletich (x-coder264)
- Vincent Touzet (vincenttouzet)
+ - Fabien Bourigault (fbourigault)
- Olivier Dolbeau (odolbeau)
- Rouven Weßling (realityking)
- - Valtteri R (valtzu)
- Ben Davies (bendavies)
- YaFou
- Clemens Tolboom
@@ -248,7 +251,6 @@ The Symfony Connect username in parenthesis allows to get more information
- Matthieu Ouellette-Vachon (maoueh)
- Michał Pipa (michal.pipa)
- Dawid Nowak
- - Dāvis Zālītis (k0d3r1s)
- Jannik Zschiesche
- Amal Raghav (kertz)
- Jonathan Ingram
@@ -259,7 +261,6 @@ The Symfony Connect username in parenthesis allows to get more information
- GDIBass
- Samuel NELA (snela)
- Vincent AUBERT (vincent)
- - Fabien Bourigault (fbourigault)
- Michael Voříšek
- zairig imad (zairigimad)
- Colin O'Dell (colinodell)
@@ -282,6 +283,7 @@ The Symfony Connect username in parenthesis allows to get more information
- Martin Hujer (martinhujer)
- Sergey Linnik (linniksa)
- Richard Miller
+ - Aleksandar Jakovljevic (ajakov)
- Mario A. Alvarez Garcia (nomack84)
- Thomas Rabaix (rande)
- D (denderello)
@@ -310,11 +312,9 @@ The Symfony Connect username in parenthesis allows to get more information
- sun (sun)
- Larry Garfield (crell)
- Leo Feyer
- - Thomas Landauer (thomas-landauer)
- Philipp Wahala (hifi)
- Victor Bocharsky (bocharsky_bw)
- Nikolay Labinskiy (e-moe)
- - Aleksandar Jakovljevic (ajakov)
- Martin Schuhfuß (usefulthink)
- apetitpa
- Guilliam Xavier
@@ -366,6 +366,7 @@ The Symfony Connect username in parenthesis allows to get more information
- Florent Morselli (spomky_)
- dFayet
- Rob Frawley 2nd (robfrawley)
+ - Renan (renanbr)
- Nikita Konstantinov (unkind)
- Dariusz
- Francois Zaninotto
@@ -402,6 +403,7 @@ The Symfony Connect username in parenthesis allows to get more information
- Sullivan SENECHAL (soullivaneuh)
- Loick Piera (pyrech)
- Uwe Jäger (uwej711)
+ - W0rma
- Lynn van der Berg (kjarli)
- Michaël Perrin (michael.perrin)
- Eugene Leonovich (rybakit)
@@ -425,7 +427,6 @@ The Symfony Connect username in parenthesis allows to get more information
- Frank de Jonge
- Andrii Bodnar
- Dane Powell
- - Renan (renanbr)
- Sebastien Morel (plopix)
- Christopher Davis (chrisguitarguy)
- Karoly Gossler (connorhu)
@@ -473,7 +474,6 @@ The Symfony Connect username in parenthesis allows to get more information
- Chris Smith (cs278)
- Thomas Bisignani (toma)
- Florian Klein (docteurklein)
- - W0rma
- Damien Alexandre (damienalexandre)
- Manuel Kießling (manuelkiessling)
- Alexey Kopytko (sanmai)
@@ -544,6 +544,7 @@ The Symfony Connect username in parenthesis allows to get more information
- Pavel Kirpitsov (pavel-kirpichyov)
- Robert Meijers
- Artur Eshenbrener
+ - Priyadi Iman Nurcahyo (priyadi)
- Harm van Tilborg (hvt)
- Thomas Perez (scullwm)
- Cédric Anne
@@ -588,6 +589,7 @@ The Symfony Connect username in parenthesis allows to get more information
- Greg Thornton (xdissent)
- Alex Bowers
- Michel Roca (mroca)
+ - Asis Pattisahusiwa
- Costin Bereveanu (schniper)
- Andrii Dembitskyi
- Gasan Guseynov (gassan)
@@ -604,9 +606,11 @@ The Symfony Connect username in parenthesis allows to get more information
- Saif Eddin G
- Endre Fejes
- Tobias Naumann (tna)
+ - Mathieu Rochette (mathroc)
- Daniel Beyer
- flack (flack)
- Shein Alexey
+ - Joppe De Cuyper (joppedc)
- Joe Lencioni
- Daniel Tschinder
- Diego Agulló (aeoris)
@@ -683,6 +687,7 @@ The Symfony Connect username in parenthesis allows to get more information
- vagrant
- Matthias Krauser (mkrauser)
- Benjamin Cremer (bcremer)
+ - Alex Hofbauer (alexhofbauer)
- Maarten de Boer (mdeboer)
- Asier Illarramendi (doup)
- AKeeman (akeeman)
@@ -690,7 +695,6 @@ The Symfony Connect username in parenthesis allows to get more information
- Restless-ET
- Vlad Gregurco (vgregurco)
- Artem Stepin (astepin)
- - Priyadi Iman Nurcahyo (priyadi)
- Boris Vujicic (boris.vujicic)
- Dries Vints
- Judicaël RUFFIEUX (axanagor)
@@ -709,6 +713,7 @@ The Symfony Connect username in parenthesis allows to get more information
- Vitaliy Tverdokhlib (vitaliytv)
- Ariel Ferrandini (aferrandini)
- BASAK Semih (itsemih)
+ - Kai Dederichs
- Dirk Pahl (dirkaholic)
- Cédric Lombardot (cedriclombardot)
- Jérémy REYNAUD (babeuloula)
@@ -779,7 +784,6 @@ The Symfony Connect username in parenthesis allows to get more information
- Eduardo Oliveira (entering)
- Oleksii Zhurbytskyi
- Bilge
- - Asis Pattisahusiwa
- Anatoly Pashin (b1rdex)
- Jonathan Johnson (jrjohnson)
- Eugene Wissner
@@ -787,6 +791,7 @@ The Symfony Connect username in parenthesis allows to get more information
- Roy Van Ginneken (rvanginneken)
- ondrowan
- Barry vd. Heuvel (barryvdh)
+ - Antonin CLAUZIER (0x346e3730)
- Chad Sikorra (chadsikorra)
- Evan S Kaufman (evanskaufman)
- mcben
@@ -803,7 +808,6 @@ The Symfony Connect username in parenthesis allows to get more information
- Leevi Graham (leevigraham)
- Anthony Ferrara
- tim
- - Mathieu Rochette (mathroc)
- Ioan Negulescu
- Greg ORIOL
- Jakub Škvára (jskvara)
@@ -813,7 +817,6 @@ The Symfony Connect username in parenthesis allows to get more information
- alexpods
- Adam Szaraniec
- Dariusz Ruminski
- - Joppe De Cuyper (joppedc)
- Romain Gautier (mykiwi)
- Matthieu Bontemps
- Erik Trapman
@@ -905,6 +908,7 @@ The Symfony Connect username in parenthesis allows to get more information
- julien57
- Mátyás Somfai (smatyas)
- Bastien DURAND (deamon)
+ - Nicolas Rigaud
- Dmitry Simushev
- alcaeus
- Ahmed Ghanem (ahmedghanem00)
@@ -976,7 +980,6 @@ The Symfony Connect username in parenthesis allows to get more information
- Dustin Dobervich (dustin10)
- Luis Tacón (lutacon)
- Dmitrii Tarasov (dtarasov)
- - Alex Hofbauer (alexhofbauer)
- dantleech
- Philipp Kolesnikov
- Jack Worman (jworman)
@@ -1086,7 +1089,6 @@ The Symfony Connect username in parenthesis allows to get more information
- Tiago Brito (blackmx)
- Gintautas Miselis (naktibalda)
- Richard van den Brand (ricbra)
- - Kai Dederichs
- Toon Verwerft (veewee)
- develop
- flip111
@@ -1100,6 +1102,7 @@ The Symfony Connect username in parenthesis allows to get more information
- Mark Sonnabaum
- Chris Jones (magikid)
- Massimiliano Braglia (massimilianobraglia)
+ - Thijs-jan Veldhuizen (tjveldhuizen)
- Richard Quadling
- James Hudson (mrthehud)
- Raphaëll Roussel
@@ -1123,6 +1126,7 @@ The Symfony Connect username in parenthesis allows to get more information
- Wybren Koelmans (wybren_koelmans)
- Roberto Nygaard
- victor-prdh
+ - Kev
- Davide Borsatto (davide.borsatto)
- Florian Hermann (fhermann)
- zenas1210
@@ -1156,6 +1160,7 @@ The Symfony Connect username in parenthesis allows to get more information
- Tarjei Huse (tarjei)
- Besnik Br
- Issam Raouf (iraouf)
+ - Simon Mönch
- Jose Gonzalez
- Jonathan (jlslew)
- Claudio Zizza
@@ -1222,6 +1227,7 @@ The Symfony Connect username in parenthesis allows to get more information
- Evan C
- buffcode
- Glodzienski
+ - Natsuki Ikeguchi
- Krzysztof Łabuś (crozin)
- Xavier Lacot (xavier)
- Jon Dufresne
@@ -1229,7 +1235,6 @@ The Symfony Connect username in parenthesis allows to get more information
- Denis Zunke (donalberto)
- Adrien Roches (neirda24)
- _sir_kane (waly)
- - Antonin CLAUZIER (0x346e3730)
- Olivier Maisonneuve
- Andrei C. (moldman)
- Mike Meier (mykon)
@@ -1309,6 +1314,7 @@ The Symfony Connect username in parenthesis allows to get more information
- Maksim Kotlyar (makasim)
- Neil Ferreira
- Julie Hourcade (juliehde)
+ - Marc Biorklund (mbiork)
- Dmitry Parnas (parnas)
- Loïc Beurlet
- Ana Raro
@@ -1412,6 +1418,7 @@ The Symfony Connect username in parenthesis allows to get more information
- Daniel Cestari
- Matt Janssen
- Stéphane Delprat
+ - Mior Muhammad Zaki (crynobone)
- Elan Ruusamäe (glen)
- Brunet Laurent (lbrunet)
- Florent Viel (luxifer)
@@ -1487,6 +1494,7 @@ The Symfony Connect username in parenthesis allows to get more information
- Jules Matsounga (hyoa)
- Yewhen Khoptynskyi (khoptynskyi)
- Jérôme Nadaud (jnadaud)
+ - Frank Naegler
- Sam Malone
- Ha Phan (haphan)
- Chris Jones (leek)
@@ -1495,6 +1503,7 @@ The Symfony Connect username in parenthesis allows to get more information
- xaav
- Jean-Christophe Cuvelier [Artack]
- Mahmoud Mostafa (mahmoud)
+ - Ninos
- Alexandre Tranchant (alexandre_t)
- Anthony Moutte
- Ahmed Abdou
@@ -1514,6 +1523,7 @@ The Symfony Connect username in parenthesis allows to get more information
- Grégoire Hébert (gregoirehebert)
- Franz Wilding (killerpoke)
- Ferenczi Krisztian (fchris82)
+ - Ioan Ovidiu Enache (ionutenache)
- Artyum Petrov
- Oleg Golovakhin (doc_tr)
- Guillaume Smolders (guillaumesmo)
@@ -1839,7 +1849,6 @@ The Symfony Connect username in parenthesis allows to get more information
- Gustavo Adrian
- Jorrit Schippers (jorrit)
- Matthias Neid
- - Kev
- Yannick
- Kuzia
- Vladimir Luchaninov (luchaninov)
@@ -2055,6 +2064,7 @@ The Symfony Connect username in parenthesis allows to get more information
- Maxime THIRY
- Norman Soetbeer
- Ludek Stepan
+ - Frederik Schwan
- Mark van den Berg
- Aaron Stephens (astephens)
- Craig Menning (cmenning)
@@ -2181,6 +2191,7 @@ The Symfony Connect username in parenthesis allows to get more information
- Aurélien Fontaine
- ncou
- Ian Carroll
+ - Dennis Fehr
- caponica
- jdcook
- Daniel Kay (danielkay-cp)
@@ -2197,6 +2208,7 @@ The Symfony Connect username in parenthesis allows to get more information
- Martin Pärtel
- Daniel Rotter (danrot)
- Frédéric Bouchery (fbouchery)
+ - Jacek Kobus (jackks)
- Patrick Daley (padrig)
- Phillip Look (plook)
- Foxprodev
@@ -2215,6 +2227,7 @@ The Symfony Connect username in parenthesis allows to get more information
- mfettig
- Oleksii Bulba
- Ramon Cuñat
+ - mboultoureau
- Raphaëll Roussel
- Vitalii
- Tadcka
@@ -2231,7 +2244,6 @@ The Symfony Connect username in parenthesis allows to get more information
- parinz1234
- Romain Geissler
- Adrien Moiruad
- - Natsuki Ikeguchi
- Viktoriia Zolotova
- Tomaz Ahlin
- Nasim
@@ -2298,6 +2310,7 @@ The Symfony Connect username in parenthesis allows to get more information
- Jos Elstgeest
- Kirill Lazarev
- Thomas Counsell
+ - Joe
- BilgeXA
- mmokhi
- Serhii Smirnov
@@ -2401,6 +2414,7 @@ The Symfony Connect username in parenthesis allows to get more information
- izenin
- Mephistofeles
- Oleh Korneliuk
+ - Evgeny Ruban
- Hoffmann András
- LubenZA
- Victor Garcia
@@ -2481,7 +2495,6 @@ The Symfony Connect username in parenthesis allows to get more information
- Anton Sukhachev (mrsuh)
- Pavlo Pelekh (pelekh)
- Stefan Kleff (stefanxl)
- - Thijs-jan Veldhuizen (tjveldhuizen)
- Vitaliy Zhuk (zhukv)
- Marcel Siegert
- ryunosuke
@@ -2635,7 +2648,6 @@ The Symfony Connect username in parenthesis allows to get more information
- Grayson Koonce
- Ruben Jansen
- Wissame MEKHILEF
- - Marc Biorklund
- shreypuranik
- NanoSector
- Thibaut Salanon
@@ -2686,6 +2698,7 @@ The Symfony Connect username in parenthesis allows to get more information
- downace
- Aarón Nieves Fernández
- Mikolaj Czajkowski
+ - Ahto Türkson
- Ph3nol
- Kirill Saksin
- Shiro
@@ -2737,6 +2750,7 @@ The Symfony Connect username in parenthesis allows to get more information
- Mohammad Ali Sarbanha (sarbanha)
- Sergii Dolgushev (sergii-swds)
- Steeve Titeca (stiteca)
+ - Thomas Citharel (tcit)
- Artem Lopata (bumz)
- alex
- evgkord
@@ -2804,6 +2818,7 @@ The Symfony Connect username in parenthesis allows to get more information
- Shamimul Alam
- Cyril HERRERA
- dropfen
+ - RAHUL K JHA
- Andrey Chernykh
- Edvinas Klovas
- Drew Butler
@@ -2901,6 +2916,7 @@ The Symfony Connect username in parenthesis allows to get more information
- John Nickell (jrnickell)
- Martin Mayer (martin)
- Grzegorz Łukaszewicz (newicz)
+ - Nico Müller (nicomllr)
- Omar Yepez (oyepez003)
- Jonny Schmid (schmidjon)
- Toby Griffiths (tog)
@@ -2912,6 +2928,7 @@ The Symfony Connect username in parenthesis allows to get more information
- Ernest Hymel
- Andrea Civita
- Nicolás Alonso
+ - Roman Tyshyk
- LoginovIlya
- andreyserdjuk
- Nick Chiu
@@ -2975,6 +2992,7 @@ The Symfony Connect username in parenthesis allows to get more information
- NothingWeAre
- Storkeus
- goabonga
+ - Vladislav Iurciuc
- Alan Chen
- Anton Zagorskii
- ging-dev
@@ -2995,7 +3013,6 @@ The Symfony Connect username in parenthesis allows to get more information
- Matheus Gontijo
- Gerrit Drost
- Linnaea Von Lavia
- - Simon Mönch
- Javan Eskander
- Lenar Lõhmus
- Cristian Gonzalez
@@ -3169,6 +3186,7 @@ The Symfony Connect username in parenthesis allows to get more information
- helmi
- Michael Steininger
- Nardberjean
+ - Dylan
- ghazy ben ahmed
- Karolis
- Myke79
@@ -3190,6 +3208,7 @@ The Symfony Connect username in parenthesis allows to get more information
- Steffen Keuper
- Kai Eichinger
- Antonio Angelino
+ - Kay Wei
- Jens Schulze
- Tema Yud
- Matt Fields
@@ -3424,6 +3443,7 @@ The Symfony Connect username in parenthesis allows to get more information
- Andreas Forsblom (aforsblo)
- Alex Olmos (alexolmos)
- Cedric BERTOLINI (alsciende)
+ - Cornel Cruceru (amne)
- Robin Kanters (anddarerobin)
- Antoine (antoinela_adveris)
- Juan Ases García (ases)
@@ -3443,7 +3463,6 @@ The Symfony Connect username in parenthesis allows to get more information
- Bermon Clément (chou666)
- Kousuke Ebihara (co3k)
- Loïc Vernet (coil)
- - Mior Muhammad Zaki (crynobone)
- Christoph Vincent Schaefer (cvschaefer)
- Kamil Piwowarski (cyklista)
- Damon Jones (damon__jones)
diff --git a/README.md b/README.md
index f7b8a37a30284..6f69c1c7e6f2b 100644
--- a/README.md
+++ b/README.md
@@ -1,5 +1,5 @@
-
+
[Symfony][1] is a **PHP framework** for web and console applications and a set
@@ -17,26 +17,16 @@ Installation
Sponsor
-------
-Symfony 7.0 is [backed][27] by
-- [Shopware][28]
-- [Sulu][29]
-- [Les-Tilleuls.coop][30]
+Symfony 7.1 is [backed][27] by
+- [Rector][29]
-**Shopware** is an open headless commerce platform powered by Symfony and Vue.js
-that is used by thousands of shops and supported by a huge, worldwide community
-of developers, agencies and merchants.
+**Rector** helps successful and growing companies to get the most of the code
+they already have. Including upgrading to the latest Symfony LTS. They deliver
+automated refactoring, reduce maintenance costs, speed up feature delivery, and
+transform legacy code into a strategic asset. They can handle the dirty work,
+so you can focus on the features.
-**Sulu** is the CMS for Symfony developers. It provides pre-built content-management
-features while giving developers the freedom to build, deploy, and maintain custom
-solutions using full-stack Symfony. Sulu is ideal for creating complex websites,
-integrating external tools, and building custom-built solutions.
-
-**Les-Tilleuls.coop** is a team of 70+ Symfony experts who can help you design,
-develop and fix your projects. We provide a wide range of professional services
-including development, consulting, coaching, training and audits. We also are
-highly skilled in JS, Go and DevOps. We are a worker cooperative!
-
-Help Symfony by [sponsoring][31] its development!
+Help Symfony by [sponsoring][28] its development!
Documentation
-------------
@@ -99,7 +89,5 @@ and supported by [Symfony contributors][19].
[25]: https://symfony.com/doc/current/contributing/code_of_conduct/care_team.html
[26]: https://symfony.com/book
[27]: https://symfony.com/backers
-[28]: https://www.shopware.com
-[29]: https://sulu.io
-[30]: https://les-tilleuls.coop/
-[31]: https://symfony.com/sponsor
+[28]: https://symfony.com/sponsor
+[29]: https://getrector.com
diff --git a/UPGRADE-7.0.md b/UPGRADE-7.0.md
index dc4b8bca419b7..d7833e13492d3 100644
--- a/UPGRADE-7.0.md
+++ b/UPGRADE-7.0.md
@@ -429,6 +429,8 @@ SecurityBundle
--------------
* Enabling SecurityBundle and not configuring it is not allowed, either remove the bundle or configure at least one firewall
+ * Remove the `enable_authenticator_manager` config option
+ * Remove the `security.firewalls.logout.csrf_token_generator` config option, use `security.firewalls.logout.csrf_token_manager` instead
* Remove the `require_previous_session` config option from authenticators
Serializer
diff --git a/UPGRADE-7.1.md b/UPGRADE-7.1.md
index ce3a26a180664..34a816fb78412 100644
--- a/UPGRADE-7.1.md
+++ b/UPGRADE-7.1.md
@@ -16,6 +16,11 @@ Messenger
* Make `#[AsMessageHandler]` final
+PropertyInfo
+------------
+
+ * The `PropertyTypeExtractorInterface::getTypes` method is deprecated, use `PropertyTypeExtractorInterface::getType` instead
+
SecurityBundle
--------------
diff --git a/composer.json b/composer.json
index e9b9ae71d3ee3..5918ff73ae31d 100644
--- a/composer.json
+++ b/composer.json
@@ -71,6 +71,7 @@
"symfony/doctrine-bridge": "self.version",
"symfony/dom-crawler": "self.version",
"symfony/dotenv": "self.version",
+ "symfony/emoji": "self.version",
"symfony/error-handler": "self.version",
"symfony/event-dispatcher": "self.version",
"symfony/expression-language": "self.version",
@@ -125,7 +126,7 @@
"amphp/http-client": "^4.2.1",
"amphp/http-tunnel": "^1.0",
"async-aws/ses": "^1.0",
- "async-aws/sqs": "^1.0",
+ "async-aws/sqs": "^1.0|^2.0",
"async-aws/sns": "^1.0",
"cache/integration-tests": "dev-master",
"doctrine/collections": "^1.0|^2.0",
@@ -139,7 +140,7 @@
"league/uri": "^6.5|^7.0",
"masterminds/html5": "^2.7.2",
"monolog/monolog": "^3.0",
- "nikic/php-parser": "^4.16|^5.0",
+ "nikic/php-parser": "^4.18|^5.0",
"nyholm/psr7": "^1.0",
"pda/pheanstalk": "^4.0",
"php-http/discovery": "^1.15",
diff --git a/psalm.xml b/psalm.xml
index a21be22fe248f..f5f9c5b4c4e88 100644
--- a/psalm.xml
+++ b/psalm.xml
@@ -17,7 +17,8 @@
-
+
+
diff --git a/src/Symfony/Bridge/Doctrine/ArgumentResolver/EntityValueResolver.php b/src/Symfony/Bridge/Doctrine/ArgumentResolver/EntityValueResolver.php
index bdf975b32befd..c1ede525e0f2e 100644
--- a/src/Symfony/Bridge/Doctrine/ArgumentResolver/EntityValueResolver.php
+++ b/src/Symfony/Bridge/Doctrine/ArgumentResolver/EntityValueResolver.php
@@ -73,7 +73,7 @@ public function resolve(Request $request, ArgumentMetadata $argument): array
}
if (null === $object && !$argument->isNullable()) {
- throw new NotFoundHttpException(sprintf('"%s" object not found by "%s".', $options->class, self::class).$message);
+ throw new NotFoundHttpException($options->message ?? (sprintf('"%s" object not found by "%s".', $options->class, self::class).$message));
}
return [$object];
diff --git a/src/Symfony/Bridge/Doctrine/Attribute/MapEntity.php b/src/Symfony/Bridge/Doctrine/Attribute/MapEntity.php
index 73bb1aa398f37..0c3ab0cd0ed9f 100644
--- a/src/Symfony/Bridge/Doctrine/Attribute/MapEntity.php
+++ b/src/Symfony/Bridge/Doctrine/Attribute/MapEntity.php
@@ -44,6 +44,7 @@ public function __construct(
public ?bool $evictCache = null,
bool $disabled = false,
string $resolver = EntityValueResolver::class,
+ public ?string $message = null,
) {
parent::__construct($resolver, $disabled);
}
@@ -59,6 +60,7 @@ public function withDefaults(self $defaults, ?string $class): static
$clone->stripNull ??= $defaults->stripNull ?? false;
$clone->id ??= $defaults->id;
$clone->evictCache ??= $defaults->evictCache ?? false;
+ $clone->message ??= $defaults->message;
return $clone;
}
diff --git a/src/Symfony/Bridge/Doctrine/CacheWarmer/ProxyCacheWarmer.php b/src/Symfony/Bridge/Doctrine/CacheWarmer/ProxyCacheWarmer.php
index 62e1836fbd268..ddf222e2940d2 100644
--- a/src/Symfony/Bridge/Doctrine/CacheWarmer/ProxyCacheWarmer.php
+++ b/src/Symfony/Bridge/Doctrine/CacheWarmer/ProxyCacheWarmer.php
@@ -39,7 +39,7 @@ public function isOptional(): bool
return false;
}
- public function warmUp(string $cacheDir, string $buildDir = null): array
+ public function warmUp(string $cacheDir, ?string $buildDir = null): array
{
$files = [];
foreach ($this->registry->getManagers() as $em) {
diff --git a/src/Symfony/Bridge/Doctrine/ContainerAwareEventManager.php b/src/Symfony/Bridge/Doctrine/ContainerAwareEventManager.php
index 26d31a2247802..3d331ac010e1b 100644
--- a/src/Symfony/Bridge/Doctrine/ContainerAwareEventManager.php
+++ b/src/Symfony/Bridge/Doctrine/ContainerAwareEventManager.php
@@ -44,7 +44,7 @@ public function __construct(ContainerInterface $container, array $listeners = []
$this->listeners = $listeners;
}
- public function dispatchEvent(string $eventName, EventArgs $eventArgs = null): void
+ public function dispatchEvent(string $eventName, ?EventArgs $eventArgs = null): void
{
if (!$this->initializedSubscribers) {
$this->initializeSubscribers();
diff --git a/src/Symfony/Bridge/Doctrine/DataCollector/DoctrineDataCollector.php b/src/Symfony/Bridge/Doctrine/DataCollector/DoctrineDataCollector.php
index 7b01e98712f8c..ef0a369db9f95 100644
--- a/src/Symfony/Bridge/Doctrine/DataCollector/DoctrineDataCollector.php
+++ b/src/Symfony/Bridge/Doctrine/DataCollector/DoctrineDataCollector.php
@@ -39,7 +39,7 @@ public function __construct(
$this->managers = $registry->getManagerNames();
}
- public function collect(Request $request, Response $response, \Throwable $exception = null): void
+ public function collect(Request $request, Response $response, ?\Throwable $exception = null): void
{
$this->data = [
'queries' => $this->collectQueries(),
diff --git a/src/Symfony/Bridge/Doctrine/DependencyInjection/AbstractDoctrineExtension.php b/src/Symfony/Bridge/Doctrine/DependencyInjection/AbstractDoctrineExtension.php
index 54b6c8bf924f2..94b99d8d7e925 100644
--- a/src/Symfony/Bridge/Doctrine/DependencyInjection/AbstractDoctrineExtension.php
+++ b/src/Symfony/Bridge/Doctrine/DependencyInjection/AbstractDoctrineExtension.php
@@ -134,7 +134,7 @@ protected function setMappingDriverConfig(array $mappingConfig, string $mappingN
*
* Returns false when autodetection failed, an array of the completed information otherwise.
*/
- protected function getMappingDriverBundleConfigDefaults(array $bundleConfig, \ReflectionClass $bundle, ContainerBuilder $container, string $bundleDir = null): array|false
+ protected function getMappingDriverBundleConfigDefaults(array $bundleConfig, \ReflectionClass $bundle, ContainerBuilder $container, ?string $bundleDir = null): array|false
{
$bundleClassDir = \dirname($bundle->getFileName());
$bundleDir ??= $bundleClassDir;
@@ -193,7 +193,9 @@ protected function registerMappingDrivers(array $objectManager, ContainerBuilder
array_values($driverPaths),
]);
}
- if (str_contains($mappingDriverDef->getClass(), 'yml') || str_contains($mappingDriverDef->getClass(), 'xml')) {
+ if (str_contains($mappingDriverDef->getClass(), 'yml') || str_contains($mappingDriverDef->getClass(), 'xml')
+ || str_contains($mappingDriverDef->getClass(), 'Yaml') || str_contains($mappingDriverDef->getClass(), 'Xml')
+ ) {
$mappingDriverDef->setArguments([array_flip($driverPaths)]);
$mappingDriverDef->addMethodCall('setGlobalBasename', ['mapping']);
}
@@ -386,7 +388,7 @@ abstract protected function getMappingObjectDefaultName(): string;
/**
* Relative path from the bundle root to the directory where mapping files reside.
*/
- abstract protected function getMappingResourceConfigDirectory(string $bundleDir = null): string;
+ abstract protected function getMappingResourceConfigDirectory(?string $bundleDir = null): string;
/**
* Extension used by the mapping files.
diff --git a/src/Symfony/Bridge/Doctrine/Form/ChoiceList/IdReader.php b/src/Symfony/Bridge/Doctrine/Form/ChoiceList/IdReader.php
index b03c832ac13e6..1baed3b718d1c 100644
--- a/src/Symfony/Bridge/Doctrine/Form/ChoiceList/IdReader.php
+++ b/src/Symfony/Bridge/Doctrine/Form/ChoiceList/IdReader.php
@@ -76,7 +76,7 @@ public function isIntId(): bool
*
* This method assumes that the object has a single-column ID.
*/
- public function getIdValue(object $object = null): string
+ public function getIdValue(?object $object = null): string
{
if (!$object) {
return '';
diff --git a/src/Symfony/Bridge/Doctrine/Form/DoctrineOrmTypeGuesser.php b/src/Symfony/Bridge/Doctrine/Form/DoctrineOrmTypeGuesser.php
index 19b683b3e14b8..6ef7b258808ec 100644
--- a/src/Symfony/Bridge/Doctrine/Form/DoctrineOrmTypeGuesser.php
+++ b/src/Symfony/Bridge/Doctrine/Form/DoctrineOrmTypeGuesser.php
@@ -14,6 +14,7 @@
use Doctrine\DBAL\Types\Types;
use Doctrine\ORM\Mapping\ClassMetadata;
use Doctrine\ORM\Mapping\ClassMetadataInfo;
+use Doctrine\ORM\Mapping\JoinColumnMapping;
use Doctrine\ORM\Mapping\MappingException as LegacyMappingException;
use Doctrine\Persistence\ManagerRegistry;
use Doctrine\Persistence\Mapping\MappingException;
@@ -110,13 +111,13 @@ public function guessRequired(string $class, string $property): ?ValueGuess
if ($classMetadata->isAssociationWithSingleJoinColumn($property)) {
$mapping = $classMetadata->getAssociationMapping($property);
- if (!isset($mapping['joinColumns'][0]['nullable'])) {
+ if (null === self::getMappingValue($mapping['joinColumns'][0], 'nullable')) {
// The "nullable" option defaults to true, in that case the
// field should not be required.
return new ValueGuess(false, Guess::HIGH_CONFIDENCE);
}
- return new ValueGuess(!$mapping['joinColumns'][0]['nullable'], Guess::HIGH_CONFIDENCE);
+ return new ValueGuess(!self::getMappingValue($mapping['joinColumns'][0], 'nullable'), Guess::HIGH_CONFIDENCE);
}
return null;
@@ -190,4 +191,13 @@ private static function getRealClass(string $class): string
return substr($class, $pos + Proxy::MARKER_LENGTH + 2);
}
+
+ private static function getMappingValue(array|JoinColumnMapping $mapping, string $key): mixed
+ {
+ if ($mapping instanceof JoinColumnMapping) {
+ return $mapping->$key;
+ }
+
+ return $mapping[$key] ?? null;
+ }
}
diff --git a/src/Symfony/Bridge/Doctrine/IdGenerator/UuidGenerator.php b/src/Symfony/Bridge/Doctrine/IdGenerator/UuidGenerator.php
index 408b1e19af995..72bab54129e28 100644
--- a/src/Symfony/Bridge/Doctrine/IdGenerator/UuidGenerator.php
+++ b/src/Symfony/Bridge/Doctrine/IdGenerator/UuidGenerator.php
@@ -26,7 +26,7 @@ final class UuidGenerator extends AbstractIdGenerator
private UuidFactory|NameBasedUuidFactory|RandomBasedUuidFactory|TimeBasedUuidFactory $factory;
private ?string $entityGetter = null;
- public function __construct(UuidFactory $factory = null)
+ public function __construct(?UuidFactory $factory = null)
{
$this->protoFactory = $this->factory = $factory ?? new UuidFactory();
}
@@ -52,7 +52,7 @@ public function generateId(EntityManagerInterface $em, $entity): Uuid
return $this->factory->create();
}
- public function nameBased(string $entityGetter, Uuid|string $namespace = null): static
+ public function nameBased(string $entityGetter, Uuid|string|null $namespace = null): static
{
$clone = clone $this;
$clone->factory = $clone->protoFactory->nameBased($namespace);
@@ -70,7 +70,7 @@ public function randomBased(): static
return $clone;
}
- public function timeBased(Uuid|string $node = null): static
+ public function timeBased(Uuid|string|null $node = null): static
{
$clone = clone $this;
$clone->factory = $clone->protoFactory->timeBased($node);
diff --git a/src/Symfony/Bridge/Doctrine/Messenger/AbstractDoctrineMiddleware.php b/src/Symfony/Bridge/Doctrine/Messenger/AbstractDoctrineMiddleware.php
index 95fcf21d210bb..649a19716f16f 100644
--- a/src/Symfony/Bridge/Doctrine/Messenger/AbstractDoctrineMiddleware.php
+++ b/src/Symfony/Bridge/Doctrine/Messenger/AbstractDoctrineMiddleware.php
@@ -28,7 +28,7 @@ abstract class AbstractDoctrineMiddleware implements MiddlewareInterface
protected ManagerRegistry $managerRegistry;
protected ?string $entityManagerName;
- public function __construct(ManagerRegistry $managerRegistry, string $entityManagerName = null)
+ public function __construct(ManagerRegistry $managerRegistry, ?string $entityManagerName = null)
{
$this->managerRegistry = $managerRegistry;
$this->entityManagerName = $entityManagerName;
diff --git a/src/Symfony/Bridge/Doctrine/Messenger/DoctrineOpenTransactionLoggerMiddleware.php b/src/Symfony/Bridge/Doctrine/Messenger/DoctrineOpenTransactionLoggerMiddleware.php
index 78e6af93792b1..75187a1e490c5 100644
--- a/src/Symfony/Bridge/Doctrine/Messenger/DoctrineOpenTransactionLoggerMiddleware.php
+++ b/src/Symfony/Bridge/Doctrine/Messenger/DoctrineOpenTransactionLoggerMiddleware.php
@@ -28,7 +28,7 @@ class DoctrineOpenTransactionLoggerMiddleware extends AbstractDoctrineMiddleware
public function __construct(
ManagerRegistry $managerRegistry,
- string $entityManagerName = null,
+ ?string $entityManagerName = null,
private readonly ?LoggerInterface $logger = null,
) {
parent::__construct($managerRegistry, $entityManagerName);
diff --git a/src/Symfony/Bridge/Doctrine/PropertyInfo/DoctrineExtractor.php b/src/Symfony/Bridge/Doctrine/PropertyInfo/DoctrineExtractor.php
index 89edf1ce2d2ff..fbe25db53766f 100644
--- a/src/Symfony/Bridge/Doctrine/PropertyInfo/DoctrineExtractor.php
+++ b/src/Symfony/Bridge/Doctrine/PropertyInfo/DoctrineExtractor.php
@@ -16,12 +16,17 @@
use Doctrine\ORM\EntityManagerInterface;
use Doctrine\ORM\Mapping\AssociationMapping;
use Doctrine\ORM\Mapping\ClassMetadata;
+use Doctrine\ORM\Mapping\EmbeddedClassMapping;
+use Doctrine\ORM\Mapping\FieldMapping;
+use Doctrine\ORM\Mapping\JoinColumnMapping;
use Doctrine\ORM\Mapping\MappingException as OrmMappingException;
use Doctrine\Persistence\Mapping\MappingException;
use Symfony\Component\PropertyInfo\PropertyAccessExtractorInterface;
use Symfony\Component\PropertyInfo\PropertyListExtractorInterface;
use Symfony\Component\PropertyInfo\PropertyTypeExtractorInterface;
-use Symfony\Component\PropertyInfo\Type;
+use Symfony\Component\PropertyInfo\Type as LegacyType;
+use Symfony\Component\TypeInfo\Type;
+use Symfony\Component\TypeInfo\TypeIdentifier;
/**
* Extracts data using Doctrine ORM and ODM metadata.
@@ -52,8 +57,149 @@ public function getProperties(string $class, array $context = []): ?array
return $properties;
}
+ public function getType(string $class, string $property, array $context = []): ?Type
+ {
+ if (null === $metadata = $this->getMetadata($class)) {
+ return null;
+ }
+
+ if ($metadata->hasAssociation($property)) {
+ $class = $metadata->getAssociationTargetClass($property);
+
+ if ($metadata->isSingleValuedAssociation($property)) {
+ if ($metadata instanceof ClassMetadata) {
+ $associationMapping = $metadata->getAssociationMapping($property);
+ $nullable = $this->isAssociationNullable($associationMapping);
+ } else {
+ $nullable = false;
+ }
+
+ $t = Type::object($class);
+
+ return $nullable ? Type::nullable($t) : $t;
+ }
+
+ $collectionKeyType = TypeIdentifier::INT;
+
+ if ($metadata instanceof ClassMetadata) {
+ $associationMapping = $metadata->getAssociationMapping($property);
+
+ if (self::getMappingValue($associationMapping, 'indexBy')) {
+ $subMetadata = $this->entityManager->getClassMetadata(self::getMappingValue($associationMapping, 'targetEntity'));
+
+ // Check if indexBy value is a property
+ $fieldName = self::getMappingValue($associationMapping, 'indexBy');
+ if (null === ($typeOfField = $subMetadata->getTypeOfField($fieldName))) {
+ $fieldName = $subMetadata->getFieldForColumn(self::getMappingValue($associationMapping, 'indexBy'));
+ // Not a property, maybe a column name?
+ if (null === ($typeOfField = $subMetadata->getTypeOfField($fieldName))) {
+ // Maybe the column name is the association join column?
+ $associationMapping = $subMetadata->getAssociationMapping($fieldName);
+
+ $indexProperty = $subMetadata->getSingleAssociationReferencedJoinColumnName($fieldName);
+ $subMetadata = $this->entityManager->getClassMetadata(self::getMappingValue($associationMapping, 'targetEntity'));
+
+ // Not a property, maybe a column name?
+ if (null === ($typeOfField = $subMetadata->getTypeOfField($indexProperty))) {
+ $fieldName = $subMetadata->getFieldForColumn($indexProperty);
+ $typeOfField = $subMetadata->getTypeOfField($fieldName);
+ }
+ }
+ }
+
+ if (!$collectionKeyType = $this->getPhpType($typeOfField)) {
+ return null;
+ }
+ }
+ }
+
+ return Type::collection(Type::object(Collection::class), Type::object($class), Type::builtin($collectionKeyType));
+ }
+
+ if ($metadata instanceof ClassMetadata && isset($metadata->embeddedClasses[$property])) {
+ return Type::object(self::getMappingValue($metadata->embeddedClasses[$property], 'class'));
+ }
+
+ if ($metadata->hasField($property)) {
+ $typeOfField = $metadata->getTypeOfField($property);
+
+ if (!$builtinType = $this->getPhpType($typeOfField)) {
+ return null;
+ }
+
+ $nullable = $metadata instanceof ClassMetadata && $metadata->isNullable($property);
+ $enumType = null;
+ if (null !== $enumClass = self::getMappingValue($metadata->getFieldMapping($property), 'enumType') ?? null) {
+ $enumType = Type::enum($enumClass);
+ $enumType = $nullable ? Type::nullable($enumType) : $enumType;
+ }
+
+ switch ($builtinType) {
+ case TypeIdentifier::OBJECT:
+ switch ($typeOfField) {
+ case Types::DATE_MUTABLE:
+ case Types::DATETIME_MUTABLE:
+ case Types::DATETIMETZ_MUTABLE:
+ case 'vardatetime':
+ case Types::TIME_MUTABLE:
+ $t = Type::object(\DateTime::class);
+
+ return $nullable ? Type::nullable($t) : $t;
+
+ case Types::DATE_IMMUTABLE:
+ case Types::DATETIME_IMMUTABLE:
+ case Types::DATETIMETZ_IMMUTABLE:
+ case Types::TIME_IMMUTABLE:
+ $t = Type::object(\DateTimeImmutable::class);
+
+ return $nullable ? Type::nullable($t) : $t;
+
+ case Types::DATEINTERVAL:
+ $t = Type::object(\DateInterval::class);
+
+ return $nullable ? Type::nullable($t) : $t;
+ }
+
+ break;
+ case TypeIdentifier::ARRAY:
+ switch ($typeOfField) {
+ case 'array': // DBAL < 4
+ case 'json_array': // DBAL < 3
+ // return null if $enumType is set, because we can't determine if collectionKeyType is string or int
+ if ($enumType) {
+ return null;
+ }
+
+ $t = Type::array();
+
+ return $nullable ? Type::nullable($t) : $t;
+
+ case Types::SIMPLE_ARRAY:
+ $t = Type::list($enumType ?? Type::string());
+
+ return $nullable ? Type::nullable($t) : $t;
+ }
+ break;
+ case TypeIdentifier::INT:
+ case TypeIdentifier::STRING:
+ if ($enumType) {
+ return $enumType;
+ }
+ break;
+ }
+
+ $t = Type::builtin($builtinType);
+
+ return $nullable ? Type::nullable($t) : $t;
+ }
+
+ return null;
+ }
+
public function getTypes(string $class, string $property, array $context = []): ?array
{
+ trigger_deprecation('symfony/doctrine-bridge', '7.1', 'The "%s()" method is deprecated, use "%s::getType()" instead.', __METHOD__, self::class);
+
if (null === $metadata = $this->getMetadata($class)) {
return null;
}
@@ -70,10 +216,10 @@ public function getTypes(string $class, string $property, array $context = []):
$nullable = false;
}
- return [new Type(Type::BUILTIN_TYPE_OBJECT, $nullable, $class)];
+ return [new LegacyType(LegacyType::BUILTIN_TYPE_OBJECT, $nullable, $class)];
}
- $collectionKeyType = Type::BUILTIN_TYPE_INT;
+ $collectionKeyType = LegacyType::BUILTIN_TYPE_INT;
if ($metadata instanceof ClassMetadata) {
$associationMapping = $metadata->getAssociationMapping($property);
@@ -101,61 +247,61 @@ public function getTypes(string $class, string $property, array $context = []):
}
}
- if (!$collectionKeyType = $this->getPhpType($typeOfField)) {
+ if (!$collectionKeyType = $this->getPhpType($typeOfField)?->value) {
return null;
}
}
}
- return [new Type(
- Type::BUILTIN_TYPE_OBJECT,
+ return [new LegacyType(
+ LegacyType::BUILTIN_TYPE_OBJECT,
false,
Collection::class,
true,
- new Type($collectionKeyType),
- new Type(Type::BUILTIN_TYPE_OBJECT, false, $class)
+ new LegacyType($collectionKeyType),
+ new LegacyType(LegacyType::BUILTIN_TYPE_OBJECT, false, $class)
)];
}
if ($metadata instanceof ClassMetadata && isset($metadata->embeddedClasses[$property])) {
- return [new Type(Type::BUILTIN_TYPE_OBJECT, false, $metadata->embeddedClasses[$property]['class'])];
+ return [new LegacyType(LegacyType::BUILTIN_TYPE_OBJECT, false, $metadata->embeddedClasses[$property]['class'])];
}
if ($metadata->hasField($property)) {
$typeOfField = $metadata->getTypeOfField($property);
- if (!$builtinType = $this->getPhpType($typeOfField)) {
+ if (!$builtinType = $this->getPhpType($typeOfField)?->value) {
return null;
}
$nullable = $metadata instanceof ClassMetadata && $metadata->isNullable($property);
$enumType = null;
if (null !== $enumClass = $metadata->getFieldMapping($property)['enumType'] ?? null) {
- $enumType = new Type(Type::BUILTIN_TYPE_OBJECT, $nullable, $enumClass);
+ $enumType = new LegacyType(LegacyType::BUILTIN_TYPE_OBJECT, $nullable, $enumClass);
}
switch ($builtinType) {
- case Type::BUILTIN_TYPE_OBJECT:
+ case LegacyType::BUILTIN_TYPE_OBJECT:
switch ($typeOfField) {
case Types::DATE_MUTABLE:
case Types::DATETIME_MUTABLE:
case Types::DATETIMETZ_MUTABLE:
case 'vardatetime':
case Types::TIME_MUTABLE:
- return [new Type(Type::BUILTIN_TYPE_OBJECT, $nullable, 'DateTime')];
+ return [new LegacyType(LegacyType::BUILTIN_TYPE_OBJECT, $nullable, 'DateTime')];
case Types::DATE_IMMUTABLE:
case Types::DATETIME_IMMUTABLE:
case Types::DATETIMETZ_IMMUTABLE:
case Types::TIME_IMMUTABLE:
- return [new Type(Type::BUILTIN_TYPE_OBJECT, $nullable, 'DateTimeImmutable')];
+ return [new LegacyType(LegacyType::BUILTIN_TYPE_OBJECT, $nullable, 'DateTimeImmutable')];
case Types::DATEINTERVAL:
- return [new Type(Type::BUILTIN_TYPE_OBJECT, $nullable, 'DateInterval')];
+ return [new LegacyType(LegacyType::BUILTIN_TYPE_OBJECT, $nullable, 'DateInterval')];
}
break;
- case Type::BUILTIN_TYPE_ARRAY:
+ case LegacyType::BUILTIN_TYPE_ARRAY:
switch ($typeOfField) {
case 'array': // DBAL < 4
case 'json_array': // DBAL < 3
@@ -164,21 +310,21 @@ public function getTypes(string $class, string $property, array $context = []):
return null;
}
- return [new Type(Type::BUILTIN_TYPE_ARRAY, $nullable, null, true)];
+ return [new LegacyType(LegacyType::BUILTIN_TYPE_ARRAY, $nullable, null, true)];
case Types::SIMPLE_ARRAY:
- return [new Type(Type::BUILTIN_TYPE_ARRAY, $nullable, null, true, new Type(Type::BUILTIN_TYPE_INT), $enumType ?? new Type(Type::BUILTIN_TYPE_STRING))];
+ return [new LegacyType(LegacyType::BUILTIN_TYPE_ARRAY, $nullable, null, true, new LegacyType(LegacyType::BUILTIN_TYPE_INT), $enumType ?? new LegacyType(LegacyType::BUILTIN_TYPE_STRING))];
}
break;
- case Type::BUILTIN_TYPE_INT:
- case Type::BUILTIN_TYPE_STRING:
+ case LegacyType::BUILTIN_TYPE_INT:
+ case LegacyType::BUILTIN_TYPE_STRING:
if ($enumType) {
return [$enumType];
}
break;
}
- return [new Type($builtinType, $nullable)];
+ return [new LegacyType($builtinType, $nullable)];
}
return null;
@@ -220,17 +366,17 @@ private function getMetadata(string $class): ?ClassMetadata
*/
private function isAssociationNullable(array|AssociationMapping $associationMapping): bool
{
- if (isset($associationMapping['id']) && $associationMapping['id']) {
+ if (self::getMappingValue($associationMapping, 'id')) {
return false;
}
- if (!isset($associationMapping['joinColumns'])) {
+ if (!self::getMappingValue($associationMapping, 'joinColumns')) {
return true;
}
- $joinColumns = $associationMapping['joinColumns'];
+ $joinColumns = self::getMappingValue($associationMapping, 'joinColumns');
foreach ($joinColumns as $joinColumn) {
- if (isset($joinColumn['nullable']) && !$joinColumn['nullable']) {
+ if (false === self::getMappingValue($joinColumn, 'nullable')) {
return false;
}
}
@@ -241,20 +387,20 @@ private function isAssociationNullable(array|AssociationMapping $associationMapp
/**
* Gets the corresponding built-in PHP type.
*/
- private function getPhpType(string $doctrineType): ?string
+ private function getPhpType(string $doctrineType): ?TypeIdentifier
{
return match ($doctrineType) {
Types::SMALLINT,
- Types::INTEGER => Type::BUILTIN_TYPE_INT,
- Types::FLOAT => Type::BUILTIN_TYPE_FLOAT,
+ Types::INTEGER => TypeIdentifier::INT,
+ Types::FLOAT => TypeIdentifier::FLOAT,
Types::BIGINT,
Types::STRING,
Types::TEXT,
Types::GUID,
- Types::DECIMAL => Type::BUILTIN_TYPE_STRING,
- Types::BOOLEAN => Type::BUILTIN_TYPE_BOOL,
+ Types::DECIMAL => TypeIdentifier::STRING,
+ Types::BOOLEAN => TypeIdentifier::BOOL,
Types::BLOB,
- Types::BINARY => Type::BUILTIN_TYPE_RESOURCE,
+ Types::BINARY => TypeIdentifier::RESOURCE,
'object', // DBAL < 4
Types::DATE_MUTABLE,
Types::DATETIME_MUTABLE,
@@ -265,11 +411,20 @@ private function getPhpType(string $doctrineType): ?string
Types::DATETIME_IMMUTABLE,
Types::DATETIMETZ_IMMUTABLE,
Types::TIME_IMMUTABLE,
- Types::DATEINTERVAL => Type::BUILTIN_TYPE_OBJECT,
+ Types::DATEINTERVAL => TypeIdentifier::OBJECT,
'array', // DBAL < 4
'json_array', // DBAL < 3
- Types::SIMPLE_ARRAY => Type::BUILTIN_TYPE_ARRAY,
+ Types::SIMPLE_ARRAY => TypeIdentifier::ARRAY,
default => null,
};
}
+
+ private static function getMappingValue(array|AssociationMapping|EmbeddedClassMapping|FieldMapping|JoinColumnMapping $mapping, string $key): mixed
+ {
+ if ($mapping instanceof AssociationMapping || $mapping instanceof EmbeddedClassMapping || $mapping instanceof FieldMapping || $mapping instanceof JoinColumnMapping) {
+ return $mapping->$key;
+ }
+
+ return $mapping[$key] ?? null;
+ }
}
diff --git a/src/Symfony/Bridge/Doctrine/Tests/ArgumentResolver/EntityValueResolverTest.php b/src/Symfony/Bridge/Doctrine/Tests/ArgumentResolver/EntityValueResolverTest.php
index f45c8b6d27f66..64ccc1656d75c 100644
--- a/src/Symfony/Bridge/Doctrine/Tests/ArgumentResolver/EntityValueResolverTest.php
+++ b/src/Symfony/Bridge/Doctrine/Tests/ArgumentResolver/EntityValueResolverTest.php
@@ -153,7 +153,7 @@ public function testResolveWithConversionFailedException()
$request = new Request();
$request->attributes->set('id', 'test');
- $argument = $this->createArgument('stdClass', new MapEntity(id: 'id'));
+ $argument = $this->createArgument('stdClass', new MapEntity(id: 'id', message: 'Test'));
$repository = $this->getMockBuilder(ObjectRepository::class)->getMock();
$repository->expects($this->once())
@@ -167,6 +167,7 @@ public function testResolveWithConversionFailedException()
->willReturn($repository);
$this->expectException(NotFoundHttpException::class);
+ $this->expectExceptionMessage('Test');
$resolver->resolve($request, $argument);
}
@@ -388,12 +389,12 @@ public function testAlreadyResolved()
$this->assertSame([], $resolver->resolve($request, $argument));
}
- private function createArgument(string $class = null, MapEntity $entity = null, string $name = 'arg', bool $isNullable = false): ArgumentMetadata
+ private function createArgument(?string $class = null, ?MapEntity $entity = null, string $name = 'arg', bool $isNullable = false): ArgumentMetadata
{
return new ArgumentMetadata($name, $class ?? \stdClass::class, false, false, null, $isNullable, $entity ? [$entity] : []);
}
- private function createRegistry(ObjectManager $manager = null): ManagerRegistry&MockObject
+ private function createRegistry(?ObjectManager $manager = null): ManagerRegistry&MockObject
{
$registry = $this->getMockBuilder(ManagerRegistry::class)->getMock();
diff --git a/src/Symfony/Bridge/Doctrine/Tests/DoctrineTestHelper.php b/src/Symfony/Bridge/Doctrine/Tests/DoctrineTestHelper.php
index 509d250e12afc..e8d36c892b942 100644
--- a/src/Symfony/Bridge/Doctrine/Tests/DoctrineTestHelper.php
+++ b/src/Symfony/Bridge/Doctrine/Tests/DoctrineTestHelper.php
@@ -33,7 +33,7 @@ final class DoctrineTestHelper
/**
* Returns an entity manager for testing.
*/
- public static function createTestEntityManager(Configuration $config = null): EntityManager
+ public static function createTestEntityManager(?Configuration $config = null): EntityManager
{
if (!\extension_loaded('pdo_sqlite')) {
TestCase::markTestSkipped('Extension pdo_sqlite is required.');
diff --git a/src/Symfony/Bridge/Doctrine/Tests/Form/Type/EntityTypeTest.php b/src/Symfony/Bridge/Doctrine/Tests/Form/Type/EntityTypeTest.php
index a3946c624f85d..783cf5a5524e9 100644
--- a/src/Symfony/Bridge/Doctrine/Tests/Form/Type/EntityTypeTest.php
+++ b/src/Symfony/Bridge/Doctrine/Tests/Form/Type/EntityTypeTest.php
@@ -766,7 +766,7 @@ public function testOverrideChoicesValuesWithCallable()
'em' => 'default',
'class' => self::ITEM_GROUP_CLASS,
'choice_label' => 'name',
- 'choice_value' => function (GroupableEntity $entity = null) {
+ 'choice_value' => function (?GroupableEntity $entity = null) {
if (null === $entity) {
return '';
}
diff --git a/src/Symfony/Bridge/Doctrine/Tests/PropertyInfo/DoctrineExtractorTest.php b/src/Symfony/Bridge/Doctrine/Tests/PropertyInfo/DoctrineExtractorTest.php
index a4e254da35307..35919529be459 100644
--- a/src/Symfony/Bridge/Doctrine/Tests/PropertyInfo/DoctrineExtractorTest.php
+++ b/src/Symfony/Bridge/Doctrine/Tests/PropertyInfo/DoctrineExtractorTest.php
@@ -29,7 +29,8 @@
use Symfony\Bridge\Doctrine\Tests\PropertyInfo\Fixtures\DoctrineWithEmbedded;
use Symfony\Bridge\Doctrine\Tests\PropertyInfo\Fixtures\EnumInt;
use Symfony\Bridge\Doctrine\Tests\PropertyInfo\Fixtures\EnumString;
-use Symfony\Component\PropertyInfo\Type;
+use Symfony\Component\PropertyInfo\Type as LegacyType;
+use Symfony\Component\TypeInfo\Type;
/**
* @author Kévin Dunglas
@@ -106,17 +107,22 @@ public function testTestGetPropertiesWithEmbedded()
}
/**
- * @dataProvider typesProvider
+ * @group legacy
+ *
+ * @dataProvider legacyTypesProvider
*/
- public function testExtract(string $property, array $type = null)
+ public function testExtractLegacy(string $property, ?array $type = null)
{
$this->assertEquals($type, $this->createExtractor()->getTypes(DoctrineDummy::class, $property, []));
}
- public function testExtractWithEmbedded()
+ /**
+ * @group legacy
+ */
+ public function testExtractWithEmbeddedLegacy()
{
- $expectedTypes = [new Type(
- Type::BUILTIN_TYPE_OBJECT,
+ $expectedTypes = [new LegacyType(
+ LegacyType::BUILTIN_TYPE_OBJECT,
false,
DoctrineEmbeddable::class
)];
@@ -130,97 +136,103 @@ public function testExtractWithEmbedded()
$this->assertEquals($expectedTypes, $actualTypes);
}
- public function testExtractEnum()
+ /**
+ * @group legacy
+ */
+ public function testExtractEnumLegacy()
{
- $this->assertEquals([new Type(Type::BUILTIN_TYPE_OBJECT, false, EnumString::class)], $this->createExtractor()->getTypes(DoctrineEnum::class, 'enumString', []));
- $this->assertEquals([new Type(Type::BUILTIN_TYPE_OBJECT, false, EnumInt::class)], $this->createExtractor()->getTypes(DoctrineEnum::class, 'enumInt', []));
+ $this->assertEquals([new LegacyType(LegacyType::BUILTIN_TYPE_OBJECT, false, EnumString::class)], $this->createExtractor()->getTypes(DoctrineEnum::class, 'enumString', []));
+ $this->assertEquals([new LegacyType(LegacyType::BUILTIN_TYPE_OBJECT, false, EnumInt::class)], $this->createExtractor()->getTypes(DoctrineEnum::class, 'enumInt', []));
$this->assertNull($this->createExtractor()->getTypes(DoctrineEnum::class, 'enumStringArray', []));
- $this->assertEquals([new Type(Type::BUILTIN_TYPE_ARRAY, false, null, true, new Type(Type::BUILTIN_TYPE_INT), new Type(Type::BUILTIN_TYPE_OBJECT, false, EnumInt::class))], $this->createExtractor()->getTypes(DoctrineEnum::class, 'enumIntArray', []));
+ $this->assertEquals([new LegacyType(LegacyType::BUILTIN_TYPE_ARRAY, false, null, true, new LegacyType(LegacyType::BUILTIN_TYPE_INT), new LegacyType(LegacyType::BUILTIN_TYPE_OBJECT, false, EnumInt::class))], $this->createExtractor()->getTypes(DoctrineEnum::class, 'enumIntArray', []));
$this->assertNull($this->createExtractor()->getTypes(DoctrineEnum::class, 'enumCustom', []));
}
- public static function typesProvider(): array
+ /**
+ * @group legacy
+ */
+ public static function legacyTypesProvider(): array
{
return [
- ['id', [new Type(Type::BUILTIN_TYPE_INT)]],
- ['guid', [new Type(Type::BUILTIN_TYPE_STRING)]],
- ['bigint', [new Type(Type::BUILTIN_TYPE_STRING)]],
- ['time', [new Type(Type::BUILTIN_TYPE_OBJECT, false, 'DateTime')]],
- ['timeImmutable', [new Type(Type::BUILTIN_TYPE_OBJECT, false, 'DateTimeImmutable')]],
- ['dateInterval', [new Type(Type::BUILTIN_TYPE_OBJECT, false, 'DateInterval')]],
- ['float', [new Type(Type::BUILTIN_TYPE_FLOAT)]],
- ['decimal', [new Type(Type::BUILTIN_TYPE_STRING)]],
- ['bool', [new Type(Type::BUILTIN_TYPE_BOOL)]],
- ['binary', [new Type(Type::BUILTIN_TYPE_RESOURCE)]],
- ['jsonArray', [new Type(Type::BUILTIN_TYPE_ARRAY, false, null, true)]],
- ['foo', [new Type(Type::BUILTIN_TYPE_OBJECT, true, 'Symfony\Bridge\Doctrine\Tests\PropertyInfo\Fixtures\DoctrineRelation')]],
- ['bar', [new Type(
- Type::BUILTIN_TYPE_OBJECT,
+ ['id', [new LegacyType(LegacyType::BUILTIN_TYPE_INT)]],
+ ['guid', [new LegacyType(LegacyType::BUILTIN_TYPE_STRING)]],
+ ['bigint', [new LegacyType(LegacyType::BUILTIN_TYPE_STRING)]],
+ ['time', [new LegacyType(LegacyType::BUILTIN_TYPE_OBJECT, false, 'DateTime')]],
+ ['timeImmutable', [new LegacyType(LegacyType::BUILTIN_TYPE_OBJECT, false, 'DateTimeImmutable')]],
+ ['dateInterval', [new LegacyType(LegacyType::BUILTIN_TYPE_OBJECT, false, 'DateInterval')]],
+ ['float', [new LegacyType(LegacyType::BUILTIN_TYPE_FLOAT)]],
+ ['decimal', [new LegacyType(LegacyType::BUILTIN_TYPE_STRING)]],
+ ['bool', [new LegacyType(LegacyType::BUILTIN_TYPE_BOOL)]],
+ ['binary', [new LegacyType(LegacyType::BUILTIN_TYPE_RESOURCE)]],
+ ['jsonArray', [new LegacyType(LegacyType::BUILTIN_TYPE_ARRAY, false, null, true)]],
+ ['foo', [new LegacyType(LegacyType::BUILTIN_TYPE_OBJECT, true, 'Symfony\Bridge\Doctrine\Tests\PropertyInfo\Fixtures\DoctrineRelation')]],
+ ['bar', [new LegacyType(
+ LegacyType::BUILTIN_TYPE_OBJECT,
false,
'Doctrine\Common\Collections\Collection',
true,
- new Type(Type::BUILTIN_TYPE_INT),
- new Type(Type::BUILTIN_TYPE_OBJECT, false, 'Symfony\Bridge\Doctrine\Tests\PropertyInfo\Fixtures\DoctrineRelation')
+ new LegacyType(LegacyType::BUILTIN_TYPE_INT),
+ new LegacyType(LegacyType::BUILTIN_TYPE_OBJECT, false, 'Symfony\Bridge\Doctrine\Tests\PropertyInfo\Fixtures\DoctrineRelation')
)]],
- ['indexedRguid', [new Type(
- Type::BUILTIN_TYPE_OBJECT,
+ ['indexedRguid', [new LegacyType(
+ LegacyType::BUILTIN_TYPE_OBJECT,
false,
'Doctrine\Common\Collections\Collection',
true,
- new Type(Type::BUILTIN_TYPE_STRING),
- new Type(Type::BUILTIN_TYPE_OBJECT, false, 'Symfony\Bridge\Doctrine\Tests\PropertyInfo\Fixtures\DoctrineRelation')
+ new LegacyType(LegacyType::BUILTIN_TYPE_STRING),
+ new LegacyType(LegacyType::BUILTIN_TYPE_OBJECT, false, 'Symfony\Bridge\Doctrine\Tests\PropertyInfo\Fixtures\DoctrineRelation')
)]],
- ['indexedBar', [new Type(
- Type::BUILTIN_TYPE_OBJECT,
+ ['indexedBar', [new LegacyType(
+ LegacyType::BUILTIN_TYPE_OBJECT,
false,
'Doctrine\Common\Collections\Collection',
true,
- new Type(Type::BUILTIN_TYPE_STRING),
- new Type(Type::BUILTIN_TYPE_OBJECT, false, 'Symfony\Bridge\Doctrine\Tests\PropertyInfo\Fixtures\DoctrineRelation')
+ new LegacyType(LegacyType::BUILTIN_TYPE_STRING),
+ new LegacyType(LegacyType::BUILTIN_TYPE_OBJECT, false, 'Symfony\Bridge\Doctrine\Tests\PropertyInfo\Fixtures\DoctrineRelation')
)]],
- ['indexedFoo', [new Type(
- Type::BUILTIN_TYPE_OBJECT,
+ ['indexedFoo', [new LegacyType(
+ LegacyType::BUILTIN_TYPE_OBJECT,
false,
'Doctrine\Common\Collections\Collection',
true,
- new Type(Type::BUILTIN_TYPE_STRING),
- new Type(Type::BUILTIN_TYPE_OBJECT, false, 'Symfony\Bridge\Doctrine\Tests\PropertyInfo\Fixtures\DoctrineRelation')
+ new LegacyType(LegacyType::BUILTIN_TYPE_STRING),
+ new LegacyType(LegacyType::BUILTIN_TYPE_OBJECT, false, 'Symfony\Bridge\Doctrine\Tests\PropertyInfo\Fixtures\DoctrineRelation')
)]],
- ['indexedBaz', [new Type(
- Type::BUILTIN_TYPE_OBJECT,
+ ['indexedBaz', [new LegacyType(
+ LegacyType::BUILTIN_TYPE_OBJECT,
false,
Collection::class,
true,
- new Type(Type::BUILTIN_TYPE_INT),
- new Type(Type::BUILTIN_TYPE_OBJECT, false, DoctrineRelation::class)
+ new LegacyType(LegacyType::BUILTIN_TYPE_INT),
+ new LegacyType(LegacyType::BUILTIN_TYPE_OBJECT, false, DoctrineRelation::class)
)]],
- ['simpleArray', [new Type(Type::BUILTIN_TYPE_ARRAY, false, null, true, new Type(Type::BUILTIN_TYPE_INT), new Type(Type::BUILTIN_TYPE_STRING))]],
+ ['simpleArray', [new LegacyType(LegacyType::BUILTIN_TYPE_ARRAY, false, null, true, new LegacyType(LegacyType::BUILTIN_TYPE_INT), new LegacyType(LegacyType::BUILTIN_TYPE_STRING))]],
['customFoo', null],
['notMapped', null],
- ['indexedByDt', [new Type(
- Type::BUILTIN_TYPE_OBJECT,
+ ['indexedByDt', [new LegacyType(
+ LegacyType::BUILTIN_TYPE_OBJECT,
false,
Collection::class,
true,
- new Type(Type::BUILTIN_TYPE_OBJECT),
- new Type(Type::BUILTIN_TYPE_OBJECT, false, DoctrineRelation::class)
+ new LegacyType(LegacyType::BUILTIN_TYPE_OBJECT),
+ new LegacyType(LegacyType::BUILTIN_TYPE_OBJECT, false, DoctrineRelation::class)
)]],
['indexedByCustomType', null],
- ['indexedBuz', [new Type(
- Type::BUILTIN_TYPE_OBJECT,
+ ['indexedBuz', [new LegacyType(
+ LegacyType::BUILTIN_TYPE_OBJECT,
false,
Collection::class,
true,
- new Type(Type::BUILTIN_TYPE_STRING),
- new Type(Type::BUILTIN_TYPE_OBJECT, false, DoctrineRelation::class)
+ new LegacyType(LegacyType::BUILTIN_TYPE_STRING),
+ new LegacyType(LegacyType::BUILTIN_TYPE_OBJECT, false, DoctrineRelation::class)
)]],
- ['dummyGeneratedValueList', [new Type(
- Type::BUILTIN_TYPE_OBJECT,
+ ['dummyGeneratedValueList', [new LegacyType(
+ LegacyType::BUILTIN_TYPE_OBJECT,
false,
'Doctrine\Common\Collections\Collection',
true,
- new Type(Type::BUILTIN_TYPE_INT),
- new Type(Type::BUILTIN_TYPE_OBJECT, false, DoctrineRelation::class)
+ new LegacyType(LegacyType::BUILTIN_TYPE_INT),
+ new LegacyType(LegacyType::BUILTIN_TYPE_OBJECT, false, DoctrineRelation::class)
)]],
['json', null],
];
@@ -231,7 +243,10 @@ public function testGetPropertiesCatchException()
$this->assertNull($this->createExtractor()->getProperties('Not\Exist'));
}
- public function testGetTypesCatchException()
+ /**
+ * @group legacy
+ */
+ public function testGetTypesCatchExceptionLegacy()
{
$this->assertNull($this->createExtractor()->getTypes('Not\Exist', 'baz'));
}
@@ -244,4 +259,66 @@ public function testGeneratedValueNotWritable()
$this->assertNull($extractor->isWritable(DoctrineGeneratedValue::class, 'foo'));
$this->assertNull($extractor->isReadable(DoctrineGeneratedValue::class, 'foo'));
}
+
+ public function testExtractWithEmbedded()
+ {
+ $this->assertEquals(
+ Type::object(DoctrineEmbeddable::class),
+ $this->createExtractor()->getType(DoctrineWithEmbedded::class, 'embedded'),
+ );
+ }
+
+ public function testExtractEnum()
+ {
+ $this->assertEquals(Type::enum(EnumString::class), $this->createExtractor()->getType(DoctrineEnum::class, 'enumString'));
+ $this->assertEquals(Type::enum(EnumInt::class), $this->createExtractor()->getType(DoctrineEnum::class, 'enumInt'));
+ $this->assertNull($this->createExtractor()->getType(DoctrineEnum::class, 'enumStringArray'));
+ $this->assertEquals(Type::list(Type::enum(EnumInt::class)), $this->createExtractor()->getType(DoctrineEnum::class, 'enumIntArray'));
+ $this->assertNull($this->createExtractor()->getType(DoctrineEnum::class, 'enumCustom'));
+ }
+
+ /**
+ * @dataProvider typeProvider
+ */
+ public function testExtract(string $property, ?Type $type)
+ {
+ $this->assertEquals($type, $this->createExtractor()->getType(DoctrineDummy::class, $property, []));
+ }
+
+ /**
+ * @return iterable
+ */
+ public static function typeProvider(): iterable
+ {
+ yield ['id', Type::int()];
+ yield ['guid', Type::string()];
+ yield ['bigint', Type::string()];
+ yield ['time', Type::object(\DateTime::class)];
+ yield ['timeImmutable', Type::object(\DateTimeImmutable::class)];
+ yield ['dateInterval', Type::object(\DateInterval::class)];
+ yield ['float', Type::float()];
+ yield ['decimal', Type::string()];
+ yield ['bool', Type::bool()];
+ yield ['binary', Type::resource()];
+ yield ['jsonArray', Type::array()];
+ yield ['foo', Type::nullable(Type::object(DoctrineRelation::class))];
+ yield ['bar', Type::collection(Type::object(Collection::class), Type::object(DoctrineRelation::class), Type::int())];
+ yield ['indexedRguid', Type::collection(Type::object(Collection::class), Type::object(DoctrineRelation::class), Type::string())];
+ yield ['indexedBar', Type::collection(Type::object(Collection::class), Type::object(DoctrineRelation::class), Type::string())];
+ yield ['indexedFoo', Type::collection(Type::object(Collection::class), Type::object(DoctrineRelation::class), Type::string())];
+ yield ['indexedBaz', Type::collection(Type::object(Collection::class), Type::object(DoctrineRelation::class), Type::int())];
+ yield ['simpleArray', Type::list(Type::string())];
+ yield ['customFoo', null];
+ yield ['notMapped', null];
+ yield ['indexedByDt', Type::collection(Type::object(Collection::class), Type::object(DoctrineRelation::class), Type::object())];
+ yield ['indexedByCustomType', null];
+ yield ['indexedBuz', Type::collection(Type::object(Collection::class), Type::object(DoctrineRelation::class), Type::string())];
+ yield ['dummyGeneratedValueList', Type::collection(Type::object(Collection::class), Type::object(DoctrineRelation::class), Type::int())];
+ yield ['json', null];
+ }
+
+ public function testGetTypeCatchException()
+ {
+ $this->assertNull($this->createExtractor()->getType('Not\Exist', 'baz'));
+ }
}
diff --git a/src/Symfony/Bridge/Doctrine/Tests/Validator/DoctrineLoaderTest.php b/src/Symfony/Bridge/Doctrine/Tests/Validator/DoctrineLoaderTest.php
index 8d63457a9406d..ef304114be0c4 100644
--- a/src/Symfony/Bridge/Doctrine/Tests/Validator/DoctrineLoaderTest.php
+++ b/src/Symfony/Bridge/Doctrine/Tests/Validator/DoctrineLoaderTest.php
@@ -178,7 +178,7 @@ public function testFieldMappingsConfiguration()
/**
* @dataProvider regexpProvider
*/
- public function testClassValidator(bool $expected, string $classValidatorRegexp = null)
+ public function testClassValidator(bool $expected, ?string $classValidatorRegexp = null)
{
$doctrineLoader = new DoctrineLoader(DoctrineTestHelper::createTestEntityManager(), $classValidatorRegexp, false);
diff --git a/src/Symfony/Bridge/Doctrine/Validator/Constraints/UniqueEntity.php b/src/Symfony/Bridge/Doctrine/Validator/Constraints/UniqueEntity.php
index 36b372476a9fc..02e853016d202 100644
--- a/src/Symfony/Bridge/Doctrine/Validator/Constraints/UniqueEntity.php
+++ b/src/Symfony/Bridge/Doctrine/Validator/Constraints/UniqueEntity.php
@@ -47,14 +47,14 @@ class UniqueEntity extends Constraint
*/
public function __construct(
array|string $fields,
- string $message = null,
- string $service = null,
- string $em = null,
- string $entityClass = null,
- string $repositoryMethod = null,
- string $errorPath = null,
- bool|string|array $ignoreNull = null,
- array $groups = null,
+ ?string $message = null,
+ ?string $service = null,
+ ?string $em = null,
+ ?string $entityClass = null,
+ ?string $repositoryMethod = null,
+ ?string $errorPath = null,
+ bool|string|array|null $ignoreNull = null,
+ ?array $groups = null,
$payload = null,
array $options = [],
) {
diff --git a/src/Symfony/Bridge/Doctrine/Validator/DoctrineLoader.php b/src/Symfony/Bridge/Doctrine/Validator/DoctrineLoader.php
index e3a939955ca84..fdaec0c72ce30 100644
--- a/src/Symfony/Bridge/Doctrine/Validator/DoctrineLoader.php
+++ b/src/Symfony/Bridge/Doctrine/Validator/DoctrineLoader.php
@@ -13,10 +13,10 @@
use Doctrine\ORM\EntityManagerInterface;
use Doctrine\ORM\Mapping\ClassMetadata as OrmClassMetadata;
+use Doctrine\ORM\Mapping\FieldMapping;
use Doctrine\ORM\Mapping\MappingException as OrmMappingException;
use Doctrine\Persistence\Mapping\MappingException;
use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity;
-use Symfony\Component\PropertyInfo\Type;
use Symfony\Component\Validator\Constraints\Length;
use Symfony\Component\Validator\Constraints\Valid;
use Symfony\Component\Validator\Mapping\AutoMappingStrategy;
@@ -65,11 +65,11 @@ public function loadClassMetadata(ClassMetadata $metadata): bool
*/
$existingUniqueFields = $this->getExistingUniqueFields($metadata);
- // Type and nullable aren't handled here, use the PropertyInfo Loader instead.
+ // type and nullable aren't handled here, use the PropertyInfo Loader instead.
foreach ($doctrineMetadata->fieldMappings as $mapping) {
$enabledForProperty = $enabledForClass;
$lengthConstraint = null;
- foreach ($metadata->getPropertyMetadata($mapping['fieldName']) as $propertyMetadata) {
+ foreach ($metadata->getPropertyMetadata(self::getFieldMappingValue($mapping, 'fieldName')) as $propertyMetadata) {
// Enabling or disabling auto-mapping explicitly always takes precedence
if (AutoMappingStrategy::DISABLED === $propertyMetadata->getAutoMappingStrategy()) {
continue 2;
@@ -89,26 +89,26 @@ public function loadClassMetadata(ClassMetadata $metadata): bool
continue;
}
- if (true === ($mapping['unique'] ?? false) && !isset($existingUniqueFields[$mapping['fieldName']])) {
- $metadata->addConstraint(new UniqueEntity(['fields' => $mapping['fieldName']]));
+ if (true === (self::getFieldMappingValue($mapping, 'unique') ?? false) && !isset($existingUniqueFields[self::getFieldMappingValue($mapping, 'fieldName')])) {
+ $metadata->addConstraint(new UniqueEntity(['fields' => self::getFieldMappingValue($mapping, 'fieldName')]));
$loaded = true;
}
- if (null === ($mapping['length'] ?? null) || null !== ($mapping['enumType'] ?? null) || !\in_array($mapping['type'], ['string', 'text'], true)) {
+ if (null === (self::getFieldMappingValue($mapping, 'length') ?? null) || null !== (self::getFieldMappingValue($mapping, 'enumType') ?? null) || !\in_array(self::getFieldMappingValue($mapping, 'type'), ['string', 'text'], true)) {
continue;
}
if (null === $lengthConstraint) {
- if (isset($mapping['originalClass']) && !str_contains($mapping['declaredField'], '.')) {
- $metadata->addPropertyConstraint($mapping['declaredField'], new Valid());
+ if (self::getFieldMappingValue($mapping, 'originalClass') && !str_contains(self::getFieldMappingValue($mapping, 'declaredField'), '.')) {
+ $metadata->addPropertyConstraint(self::getFieldMappingValue($mapping, 'declaredField'), new Valid());
$loaded = true;
- } elseif (property_exists($className, $mapping['fieldName']) && (!$doctrineMetadata->isMappedSuperclass || $metadata->getReflectionClass()->getProperty($mapping['fieldName'])->isPrivate())) {
- $metadata->addPropertyConstraint($mapping['fieldName'], new Length(['max' => $mapping['length']]));
+ } elseif (property_exists($className, self::getFieldMappingValue($mapping, 'fieldName')) && (!$doctrineMetadata->isMappedSuperclass || $metadata->getReflectionClass()->getProperty(self::getFieldMappingValue($mapping, 'fieldName'))->isPrivate())) {
+ $metadata->addPropertyConstraint(self::getFieldMappingValue($mapping, 'fieldName'), new Length(['max' => self::getFieldMappingValue($mapping, 'length')]));
$loaded = true;
}
} elseif (null === $lengthConstraint->max) {
// If a Length constraint exists and no max length has been explicitly defined, set it
- $lengthConstraint->max = $mapping['length'];
+ $lengthConstraint->max = self::getFieldMappingValue($mapping, 'length');
}
}
@@ -132,4 +132,13 @@ private function getExistingUniqueFields(ClassMetadata $metadata): array
return $fields;
}
+
+ private static function getFieldMappingValue(array|FieldMapping $mapping, string $key): mixed
+ {
+ if ($mapping instanceof FieldMapping) {
+ return $mapping->$key;
+ }
+
+ return $mapping[$key] ?? null;
+ }
}
diff --git a/src/Symfony/Bridge/Doctrine/composer.json b/src/Symfony/Bridge/Doctrine/composer.json
index a5d1e1e09ba0c..e616e817e16c3 100644
--- a/src/Symfony/Bridge/Doctrine/composer.json
+++ b/src/Symfony/Bridge/Doctrine/composer.json
@@ -19,6 +19,7 @@
"php": ">=8.2",
"doctrine/event-manager": "^2",
"doctrine/persistence": "^3.1",
+ "symfony/deprecation-contracts": "^2.5|^3",
"symfony/polyfill-ctype": "~1.8",
"symfony/polyfill-mbstring": "~1.0",
"symfony/service-contracts": "^2.5|^3"
@@ -58,7 +59,7 @@
"symfony/http-kernel": "<6.4",
"symfony/lock": "<6.4",
"symfony/messenger": "<6.4",
- "symfony/property-info": "<6.4",
+ "symfony/property-info": "<7.1",
"symfony/security-bundle": "<6.4",
"symfony/security-core": "<6.4",
"symfony/validator": "<6.4"
diff --git a/src/Symfony/Bridge/Monolog/Formatter/ConsoleFormatter.php b/src/Symfony/Bridge/Monolog/Formatter/ConsoleFormatter.php
index a1d55e18fce9a..b8f797e34d1ed 100644
--- a/src/Symfony/Bridge/Monolog/Formatter/ConsoleFormatter.php
+++ b/src/Symfony/Bridge/Monolog/Formatter/ConsoleFormatter.php
@@ -176,7 +176,7 @@ private function replacePlaceHolder(LogRecord $record): LogRecord
return $record->with(message: strtr($message, $replacements));
}
- private function dumpData(mixed $data, bool $colors = null): string
+ private function dumpData(mixed $data, ?bool $colors = null): string
{
if (!isset($this->dumper)) {
return '';
diff --git a/src/Symfony/Bridge/Monolog/Formatter/VarDumperFormatter.php b/src/Symfony/Bridge/Monolog/Formatter/VarDumperFormatter.php
index 08af56ebbc0a8..b7c0a01e8d069 100644
--- a/src/Symfony/Bridge/Monolog/Formatter/VarDumperFormatter.php
+++ b/src/Symfony/Bridge/Monolog/Formatter/VarDumperFormatter.php
@@ -22,7 +22,7 @@ final class VarDumperFormatter implements FormatterInterface
{
private VarCloner $cloner;
- public function __construct(VarCloner $cloner = null)
+ public function __construct(?VarCloner $cloner = null)
{
$this->cloner = $cloner ?? new VarCloner();
}
diff --git a/src/Symfony/Bridge/Monolog/Handler/ConsoleHandler.php b/src/Symfony/Bridge/Monolog/Handler/ConsoleHandler.php
index 6fcd9e88a940d..3f5df8bbed7b0 100644
--- a/src/Symfony/Bridge/Monolog/Handler/ConsoleHandler.php
+++ b/src/Symfony/Bridge/Monolog/Handler/ConsoleHandler.php
@@ -61,7 +61,7 @@ final class ConsoleHandler extends AbstractProcessingHandler implements EventSub
* @param array $verbosityLevelMap Array that maps the OutputInterface verbosity to a minimum logging
* level (leave empty to use the default mapping)
*/
- public function __construct(OutputInterface $output = null, bool $bubble = true, array $verbosityLevelMap = [], array $consoleFormatterOptions = [])
+ public function __construct(?OutputInterface $output = null, bool $bubble = true, array $verbosityLevelMap = [], array $consoleFormatterOptions = [])
{
parent::__construct(Level::Debug, $bubble);
$this->output = $output;
diff --git a/src/Symfony/Bridge/Monolog/Handler/ElasticsearchLogstashHandler.php b/src/Symfony/Bridge/Monolog/Handler/ElasticsearchLogstashHandler.php
index a86ac18229178..004a68ccedb16 100644
--- a/src/Symfony/Bridge/Monolog/Handler/ElasticsearchLogstashHandler.php
+++ b/src/Symfony/Bridge/Monolog/Handler/ElasticsearchLogstashHandler.php
@@ -56,7 +56,7 @@ final class ElasticsearchLogstashHandler extends AbstractHandler
*/
private \SplObjectStorage $responses;
- public function __construct(string $endpoint = 'http://127.0.0.1:9200', string $index = 'monolog', HttpClientInterface $client = null, string|int|Level $level = Level::Debug, bool $bubble = true, string $elasticsearchVersion = '1.0.0')
+ public function __construct(string $endpoint = 'http://127.0.0.1:9200', string $index = 'monolog', ?HttpClientInterface $client = null, string|int|Level $level = Level::Debug, bool $bubble = true, string $elasticsearchVersion = '1.0.0')
{
if (!interface_exists(HttpClientInterface::class)) {
throw new \LogicException(sprintf('The "%s" handler needs an HTTP client. Try running "composer require symfony/http-client".', __CLASS__));
diff --git a/src/Symfony/Bridge/Monolog/Processor/DebugProcessor.php b/src/Symfony/Bridge/Monolog/Processor/DebugProcessor.php
index a551ac5fa25b2..df9182becada9 100644
--- a/src/Symfony/Bridge/Monolog/Processor/DebugProcessor.php
+++ b/src/Symfony/Bridge/Monolog/Processor/DebugProcessor.php
@@ -24,7 +24,7 @@ class DebugProcessor implements DebugLoggerInterface, ResetInterface
private array $errorCount = [];
private ?RequestStack $requestStack;
- public function __construct(RequestStack $requestStack = null)
+ public function __construct(?RequestStack $requestStack = null)
{
$this->requestStack = $requestStack;
}
@@ -54,7 +54,7 @@ public function __invoke(LogRecord $record): LogRecord
return $record;
}
- public function getLogs(Request $request = null): array
+ public function getLogs(?Request $request = null): array
{
if (null !== $request) {
return $this->records[spl_object_id($request)] ?? [];
@@ -67,7 +67,7 @@ public function getLogs(Request $request = null): array
return array_merge(...array_values($this->records));
}
- public function countErrors(Request $request = null): int
+ public function countErrors(?Request $request = null): int
{
if (null !== $request) {
return $this->errorCount[spl_object_id($request)] ?? 0;
diff --git a/src/Symfony/Bridge/Monolog/Processor/WebProcessor.php b/src/Symfony/Bridge/Monolog/Processor/WebProcessor.php
index e34219b97cc4c..8e5b6e7bd9e83 100644
--- a/src/Symfony/Bridge/Monolog/Processor/WebProcessor.php
+++ b/src/Symfony/Bridge/Monolog/Processor/WebProcessor.php
@@ -25,7 +25,7 @@
*/
class WebProcessor extends BaseWebProcessor implements EventSubscriberInterface
{
- public function __construct(array $extraFields = null)
+ public function __construct(?array $extraFields = null)
{
// Pass an empty array as the default null value would access $_SERVER
parent::__construct([], $extraFields);
diff --git a/src/Symfony/Bridge/Monolog/Tests/Processor/ClassThatInheritDebugProcessor.php b/src/Symfony/Bridge/Monolog/Tests/Processor/ClassThatInheritDebugProcessor.php
index bc87c724c9d31..697b5872cb579 100644
--- a/src/Symfony/Bridge/Monolog/Tests/Processor/ClassThatInheritDebugProcessor.php
+++ b/src/Symfony/Bridge/Monolog/Tests/Processor/ClassThatInheritDebugProcessor.php
@@ -16,12 +16,12 @@
class ClassThatInheritDebugProcessor extends DebugProcessor
{
- public function getLogs(Request $request = null): array
+ public function getLogs(?Request $request = null): array
{
return parent::getLogs($request);
}
- public function countErrors(Request $request = null): int
+ public function countErrors(?Request $request = null): int
{
return parent::countErrors($request);
}
diff --git a/src/Symfony/Bridge/PhpUnit/CoverageListener.php b/src/Symfony/Bridge/PhpUnit/CoverageListener.php
index 766252b8728b7..65d6aa9dc9dcc 100644
--- a/src/Symfony/Bridge/PhpUnit/CoverageListener.php
+++ b/src/Symfony/Bridge/PhpUnit/CoverageListener.php
@@ -26,7 +26,7 @@ class CoverageListener implements TestListener
private $sutFqcnResolver;
private $warningOnSutNotFound;
- public function __construct(callable $sutFqcnResolver = null, bool $warningOnSutNotFound = false)
+ public function __construct(?callable $sutFqcnResolver = null, bool $warningOnSutNotFound = false)
{
$this->sutFqcnResolver = $sutFqcnResolver ?? static function (Test $test): ?string {
$class = \get_class($test);
diff --git a/src/Symfony/Bridge/PhpUnit/DeprecationErrorHandler/Configuration.php b/src/Symfony/Bridge/PhpUnit/DeprecationErrorHandler/Configuration.php
index d9162e81e328e..000deca6f2e6c 100644
--- a/src/Symfony/Bridge/PhpUnit/DeprecationErrorHandler/Configuration.php
+++ b/src/Symfony/Bridge/PhpUnit/DeprecationErrorHandler/Configuration.php
@@ -70,7 +70,7 @@ class Configuration
* @param string $baselineFile The path to the baseline file
* @param string|null $logFile The path to the log file
*/
- private function __construct(array $thresholds = [], string $regex = '', array $verboseOutput = [], string $ignoreFile = '', bool $generateBaseline = false, string $baselineFile = '', string $logFile = null)
+ private function __construct(array $thresholds = [], string $regex = '', array $verboseOutput = [], string $ignoreFile = '', bool $generateBaseline = false, string $baselineFile = '', ?string $logFile = null)
{
$groups = ['total', 'indirect', 'direct', 'self'];
diff --git a/src/Symfony/Bridge/PsrHttpMessage/EventListener/PsrResponseListener.php b/src/Symfony/Bridge/PsrHttpMessage/EventListener/PsrResponseListener.php
index e709ef9de2343..dd7ef6cbc5521 100644
--- a/src/Symfony/Bridge/PsrHttpMessage/EventListener/PsrResponseListener.php
+++ b/src/Symfony/Bridge/PsrHttpMessage/EventListener/PsrResponseListener.php
@@ -28,7 +28,7 @@ final class PsrResponseListener implements EventSubscriberInterface
{
private readonly HttpFoundationFactoryInterface $httpFoundationFactory;
- public function __construct(HttpFoundationFactoryInterface $httpFoundationFactory = null)
+ public function __construct(?HttpFoundationFactoryInterface $httpFoundationFactory = null)
{
$this->httpFoundationFactory = $httpFoundationFactory ?? new HttpFoundationFactory();
}
diff --git a/src/Symfony/Bridge/PsrHttpMessage/Factory/PsrHttpFactory.php b/src/Symfony/Bridge/PsrHttpMessage/Factory/PsrHttpFactory.php
index 76b6a5a07d5f5..78a36ded1d709 100644
--- a/src/Symfony/Bridge/PsrHttpMessage/Factory/PsrHttpFactory.php
+++ b/src/Symfony/Bridge/PsrHttpMessage/Factory/PsrHttpFactory.php
@@ -41,10 +41,10 @@ class PsrHttpFactory implements HttpMessageFactoryInterface
private readonly ResponseFactoryInterface $responseFactory;
public function __construct(
- ServerRequestFactoryInterface $serverRequestFactory = null,
- StreamFactoryInterface $streamFactory = null,
- UploadedFileFactoryInterface $uploadedFileFactory = null,
- ResponseFactoryInterface $responseFactory = null,
+ ?ServerRequestFactoryInterface $serverRequestFactory = null,
+ ?StreamFactoryInterface $streamFactory = null,
+ ?UploadedFileFactoryInterface $uploadedFileFactory = null,
+ ?ResponseFactoryInterface $responseFactory = null,
) {
if (null === $serverRequestFactory || null === $streamFactory || null === $uploadedFileFactory || null === $responseFactory) {
$psr17Factory = match (true) {
diff --git a/src/Symfony/Bridge/PsrHttpMessage/Factory/UploadedFile.php b/src/Symfony/Bridge/PsrHttpMessage/Factory/UploadedFile.php
index c6da856376614..f680dd5ab5040 100644
--- a/src/Symfony/Bridge/PsrHttpMessage/Factory/UploadedFile.php
+++ b/src/Symfony/Bridge/PsrHttpMessage/Factory/UploadedFile.php
@@ -48,7 +48,7 @@ public function __construct(
);
}
- public function move(string $directory, string $name = null): File
+ public function move(string $directory, ?string $name = null): File
{
if (!$this->isValid() || $this->test) {
return parent::move($directory, $name);
diff --git a/src/Symfony/Bridge/Twig/AppVariable.php b/src/Symfony/Bridge/Twig/AppVariable.php
index 600362fd28f15..e7b976e3eacf8 100644
--- a/src/Symfony/Bridge/Twig/AppVariable.php
+++ b/src/Symfony/Bridge/Twig/AppVariable.php
@@ -165,7 +165,7 @@ public function getEnabled_locales(): array
* * getFlashes('notice') returns a simple array with flash messages of that type
* * getFlashes(['notice', 'error']) returns a nested array of type => messages.
*/
- public function getFlashes(string|array $types = null): array
+ public function getFlashes(string|array|null $types = null): array
{
try {
$session = $this->getSession();
diff --git a/src/Symfony/Bridge/Twig/Command/DebugCommand.php b/src/Symfony/Bridge/Twig/Command/DebugCommand.php
index 1e1c446dbdbf3..43fab03ca37da 100644
--- a/src/Symfony/Bridge/Twig/Command/DebugCommand.php
+++ b/src/Symfony/Bridge/Twig/Command/DebugCommand.php
@@ -48,7 +48,7 @@ class DebugCommand extends Command
private ?FileLinkFormatter $fileLinkFormatter;
- public function __construct(Environment $twig, string $projectDir = null, array $bundlesMetadata = [], string $twigDefaultPath = null, FileLinkFormatter $fileLinkFormatter = null)
+ public function __construct(Environment $twig, ?string $projectDir = null, array $bundlesMetadata = [], ?string $twigDefaultPath = null, ?FileLinkFormatter $fileLinkFormatter = null)
{
parent::__construct();
@@ -214,7 +214,7 @@ private function displayPathsJson(SymfonyStyle $io, string $name): void
$io->writeln(json_encode($data));
}
- private function displayGeneralText(SymfonyStyle $io, string $filter = null): void
+ private function displayGeneralText(SymfonyStyle $io, ?string $filter = null): void
{
$decorated = $io->isDecorated();
$types = ['functions', 'filters', 'tests', 'globals'];
@@ -276,7 +276,7 @@ private function displayGeneralJson(SymfonyStyle $io, ?string $filter): void
$io->writeln($decorated ? OutputFormatter::escape($data) : $data);
}
- private function getLoaderPaths(string $name = null): array
+ private function getLoaderPaths(?string $name = null): array
{
$loaderPaths = [];
foreach ($this->getFilesystemLoaders() as $loader) {
diff --git a/src/Symfony/Bridge/Twig/Command/LintCommand.php b/src/Symfony/Bridge/Twig/Command/LintCommand.php
index 77427920d3ed7..14c00ba112659 100644
--- a/src/Symfony/Bridge/Twig/Command/LintCommand.php
+++ b/src/Symfony/Bridge/Twig/Command/LintCommand.php
@@ -39,6 +39,7 @@
#[AsCommand(name: 'lint:twig', description: 'Lint a Twig template and outputs encountered errors')]
class LintCommand extends Command
{
+ private array $excludes;
private string $format;
public function __construct(
@@ -54,6 +55,7 @@ protected function configure(): void
->addOption('format', null, InputOption::VALUE_REQUIRED, sprintf('The output format ("%s")', implode('", "', $this->getAvailableFormatOptions())))
->addOption('show-deprecations', null, InputOption::VALUE_NONE, 'Show deprecations as errors')
->addArgument('filename', InputArgument::IS_ARRAY, 'A file, a directory or "-" for reading from STDIN')
+ ->addOption('excludes', null, InputOption::VALUE_OPTIONAL | InputOption::VALUE_IS_ARRAY, 'Excluded directories', [])
->setHelp(<<<'EOF'
The %command.name% command lints a template and outputs to STDOUT
the first encountered syntax error.
@@ -81,6 +83,7 @@ protected function execute(InputInterface $input, OutputInterface $output): int
$io = new SymfonyStyle($input, $output);
$filenames = $input->getArgument('filename');
$showDeprecations = $input->getOption('show-deprecations');
+ $this->excludes = $input->getOption('excludes');
$this->format = $input->getOption('format') ?? (GithubActionReporter::isGithubActionEnvironment() ? 'github' : 'txt');
if (['-'] === $filenames) {
@@ -145,7 +148,7 @@ protected function findFiles(string $filename): iterable
if (is_file($filename)) {
return [$filename];
} elseif (is_dir($filename)) {
- return Finder::create()->files()->in($filename)->name($this->namePatterns);
+ return Finder::create()->files()->in($filename)->name($this->namePatterns)->exclude($this->excludes);
}
throw new RuntimeException(sprintf('File or directory "%s" is not readable.', $filename));
@@ -221,7 +224,7 @@ private function displayJson(OutputInterface $output, array $filesInfo): int
return min($errors, 1);
}
- private function renderException(SymfonyStyle $output, string $template, Error $exception, string $file = null, GithubActionReporter $githubReporter = null): void
+ private function renderException(SymfonyStyle $output, string $template, Error $exception, ?string $file = null, ?GithubActionReporter $githubReporter = null): void
{
$line = $exception->getTemplateLine();
diff --git a/src/Symfony/Bridge/Twig/DataCollector/TwigDataCollector.php b/src/Symfony/Bridge/Twig/DataCollector/TwigDataCollector.php
index 3994cbe30e495..a5786d2f82f6c 100644
--- a/src/Symfony/Bridge/Twig/DataCollector/TwigDataCollector.php
+++ b/src/Symfony/Bridge/Twig/DataCollector/TwigDataCollector.php
@@ -32,13 +32,13 @@ class TwigDataCollector extends DataCollector implements LateDataCollectorInterf
private ?Environment $twig;
private array $computed;
- public function __construct(Profile $profile, Environment $twig = null)
+ public function __construct(Profile $profile, ?Environment $twig = null)
{
$this->profile = $profile;
$this->twig = $twig;
}
- public function collect(Request $request, Response $response, \Throwable $exception = null): void
+ public function collect(Request $request, Response $response, ?\Throwable $exception = null): void
{
}
diff --git a/src/Symfony/Bridge/Twig/ErrorRenderer/TwigErrorRenderer.php b/src/Symfony/Bridge/Twig/ErrorRenderer/TwigErrorRenderer.php
index 9086c22d5c3cb..50d8b44d2a742 100644
--- a/src/Symfony/Bridge/Twig/ErrorRenderer/TwigErrorRenderer.php
+++ b/src/Symfony/Bridge/Twig/ErrorRenderer/TwigErrorRenderer.php
@@ -32,7 +32,7 @@ class TwigErrorRenderer implements ErrorRendererInterface
/**
* @param bool|callable $debug The debugging mode as a boolean or a callable that should return it
*/
- public function __construct(Environment $twig, HtmlErrorRenderer $fallbackErrorRenderer = null, bool|callable $debug = false)
+ public function __construct(Environment $twig, ?HtmlErrorRenderer $fallbackErrorRenderer = null, bool|callable $debug = false)
{
$this->twig = $twig;
$this->fallbackErrorRenderer = $fallbackErrorRenderer ?? new HtmlErrorRenderer();
diff --git a/src/Symfony/Bridge/Twig/Extension/AssetExtension.php b/src/Symfony/Bridge/Twig/Extension/AssetExtension.php
index feb25ed5c2062..7a7aba0d69148 100644
--- a/src/Symfony/Bridge/Twig/Extension/AssetExtension.php
+++ b/src/Symfony/Bridge/Twig/Extension/AssetExtension.php
@@ -43,7 +43,7 @@ public function getFunctions(): array
* If the package used to generate the path is an instance of
* UrlPackage, you will always get a URL and not a path.
*/
- public function getAssetUrl(string $path, string $packageName = null): string
+ public function getAssetUrl(string $path, ?string $packageName = null): string
{
return $this->packages->getUrl($path, $packageName);
}
@@ -51,7 +51,7 @@ public function getAssetUrl(string $path, string $packageName = null): string
/**
* Returns the version of an asset.
*/
- public function getAssetVersion(string $path, string $packageName = null): string
+ public function getAssetVersion(string $path, ?string $packageName = null): string
{
return $this->packages->getVersion($path, $packageName);
}
diff --git a/src/Symfony/Bridge/Twig/Extension/DumpExtension.php b/src/Symfony/Bridge/Twig/Extension/DumpExtension.php
index c84e1e751a0f8..1bf2beeed5d1c 100644
--- a/src/Symfony/Bridge/Twig/Extension/DumpExtension.php
+++ b/src/Symfony/Bridge/Twig/Extension/DumpExtension.php
@@ -29,7 +29,7 @@ final class DumpExtension extends AbstractExtension
private ClonerInterface $cloner;
private ?HtmlDumper $dumper;
- public function __construct(ClonerInterface $cloner, HtmlDumper $dumper = null)
+ public function __construct(ClonerInterface $cloner, ?HtmlDumper $dumper = null)
{
$this->cloner = $cloner;
$this->dumper = $dumper;
diff --git a/src/Symfony/Bridge/Twig/Extension/FormExtension.php b/src/Symfony/Bridge/Twig/Extension/FormExtension.php
index 827145963a8e6..673f8199f9a2a 100644
--- a/src/Symfony/Bridge/Twig/Extension/FormExtension.php
+++ b/src/Symfony/Bridge/Twig/Extension/FormExtension.php
@@ -35,7 +35,7 @@ final class FormExtension extends AbstractExtension
{
private ?TranslatorInterface $translator;
- public function __construct(TranslatorInterface $translator = null)
+ public function __construct(?TranslatorInterface $translator = null)
{
$this->translator = $translator;
}
diff --git a/src/Symfony/Bridge/Twig/Extension/HtmlSanitizerExtension.php b/src/Symfony/Bridge/Twig/Extension/HtmlSanitizerExtension.php
index bec5ceb94e34e..9549c2a36e1bd 100644
--- a/src/Symfony/Bridge/Twig/Extension/HtmlSanitizerExtension.php
+++ b/src/Symfony/Bridge/Twig/Extension/HtmlSanitizerExtension.php
@@ -33,7 +33,7 @@ public function getFilters(): array
];
}
- public function sanitize(string $html, string $sanitizer = null): string
+ public function sanitize(string $html, ?string $sanitizer = null): string
{
return $this->sanitizers->get($sanitizer ?? $this->defaultSanitizer)->sanitize($html);
}
diff --git a/src/Symfony/Bridge/Twig/Extension/HttpKernelRuntime.php b/src/Symfony/Bridge/Twig/Extension/HttpKernelRuntime.php
index b059bf1aae4c3..5456de33d2b6a 100644
--- a/src/Symfony/Bridge/Twig/Extension/HttpKernelRuntime.php
+++ b/src/Symfony/Bridge/Twig/Extension/HttpKernelRuntime.php
@@ -25,7 +25,7 @@ final class HttpKernelRuntime
private FragmentHandler $handler;
private ?FragmentUriGeneratorInterface $fragmentUriGenerator;
- public function __construct(FragmentHandler $handler, FragmentUriGeneratorInterface $fragmentUriGenerator = null)
+ public function __construct(FragmentHandler $handler, ?FragmentUriGeneratorInterface $fragmentUriGenerator = null)
{
$this->handler = $handler;
$this->fragmentUriGenerator = $fragmentUriGenerator;
diff --git a/src/Symfony/Bridge/Twig/Extension/LogoutUrlExtension.php b/src/Symfony/Bridge/Twig/Extension/LogoutUrlExtension.php
index abced287f999c..a576a6dd6b152 100644
--- a/src/Symfony/Bridge/Twig/Extension/LogoutUrlExtension.php
+++ b/src/Symfony/Bridge/Twig/Extension/LogoutUrlExtension.php
@@ -42,7 +42,7 @@ public function getFunctions(): array
*
* @param string|null $key The firewall key or null to use the current firewall key
*/
- public function getLogoutPath(string $key = null): string
+ public function getLogoutPath(?string $key = null): string
{
return $this->generator->getLogoutPath($key);
}
@@ -52,7 +52,7 @@ public function getLogoutPath(string $key = null): string
*
* @param string|null $key The firewall key or null to use the current firewall key
*/
- public function getLogoutUrl(string $key = null): string
+ public function getLogoutUrl(?string $key = null): string
{
return $this->generator->getLogoutUrl($key);
}
diff --git a/src/Symfony/Bridge/Twig/Extension/ProfilerExtension.php b/src/Symfony/Bridge/Twig/Extension/ProfilerExtension.php
index f63aa41cf2738..ab56f22a1efd6 100644
--- a/src/Symfony/Bridge/Twig/Extension/ProfilerExtension.php
+++ b/src/Symfony/Bridge/Twig/Extension/ProfilerExtension.php
@@ -28,7 +28,7 @@ final class ProfilerExtension extends BaseProfilerExtension
*/
private \SplObjectStorage $events;
- public function __construct(Profile $profile, Stopwatch $stopwatch = null)
+ public function __construct(Profile $profile, ?Stopwatch $stopwatch = null)
{
parent::__construct($profile);
diff --git a/src/Symfony/Bridge/Twig/Extension/SecurityExtension.php b/src/Symfony/Bridge/Twig/Extension/SecurityExtension.php
index 3c3881ad00d04..c94912e35f683 100644
--- a/src/Symfony/Bridge/Twig/Extension/SecurityExtension.php
+++ b/src/Symfony/Bridge/Twig/Extension/SecurityExtension.php
@@ -28,13 +28,13 @@ final class SecurityExtension extends AbstractExtension
private ?AuthorizationCheckerInterface $securityChecker;
private ?ImpersonateUrlGenerator $impersonateUrlGenerator;
- public function __construct(AuthorizationCheckerInterface $securityChecker = null, ImpersonateUrlGenerator $impersonateUrlGenerator = null)
+ public function __construct(?AuthorizationCheckerInterface $securityChecker = null, ?ImpersonateUrlGenerator $impersonateUrlGenerator = null)
{
$this->securityChecker = $securityChecker;
$this->impersonateUrlGenerator = $impersonateUrlGenerator;
}
- public function isGranted(mixed $role, mixed $object = null, string $field = null): bool
+ public function isGranted(mixed $role, mixed $object = null, ?string $field = null): bool
{
if (null === $this->securityChecker) {
return false;
@@ -51,7 +51,7 @@ public function isGranted(mixed $role, mixed $object = null, string $field = nul
}
}
- public function getImpersonateExitUrl(string $exitTo = null): string
+ public function getImpersonateExitUrl(?string $exitTo = null): string
{
if (null === $this->impersonateUrlGenerator) {
return '';
@@ -60,7 +60,7 @@ public function getImpersonateExitUrl(string $exitTo = null): string
return $this->impersonateUrlGenerator->generateExitUrl($exitTo);
}
- public function getImpersonateExitPath(string $exitTo = null): string
+ public function getImpersonateExitPath(?string $exitTo = null): string
{
if (null === $this->impersonateUrlGenerator) {
return '';
diff --git a/src/Symfony/Bridge/Twig/Extension/StopwatchExtension.php b/src/Symfony/Bridge/Twig/Extension/StopwatchExtension.php
index 972cd1acda44c..49df52cff7e58 100644
--- a/src/Symfony/Bridge/Twig/Extension/StopwatchExtension.php
+++ b/src/Symfony/Bridge/Twig/Extension/StopwatchExtension.php
@@ -26,7 +26,7 @@ final class StopwatchExtension extends AbstractExtension
private ?Stopwatch $stopwatch;
private bool $enabled;
- public function __construct(Stopwatch $stopwatch = null, bool $enabled = true)
+ public function __construct(?Stopwatch $stopwatch = null, bool $enabled = true)
{
$this->stopwatch = $stopwatch;
$this->enabled = $enabled;
diff --git a/src/Symfony/Bridge/Twig/Extension/TranslationExtension.php b/src/Symfony/Bridge/Twig/Extension/TranslationExtension.php
index 67835e2b87e75..ba5758f3f1bfc 100644
--- a/src/Symfony/Bridge/Twig/Extension/TranslationExtension.php
+++ b/src/Symfony/Bridge/Twig/Extension/TranslationExtension.php
@@ -37,7 +37,7 @@ final class TranslationExtension extends AbstractExtension
private ?TranslatorInterface $translator;
private ?TranslationNodeVisitor $translationNodeVisitor;
- public function __construct(TranslatorInterface $translator = null, TranslationNodeVisitor $translationNodeVisitor = null)
+ public function __construct(?TranslatorInterface $translator = null, ?TranslationNodeVisitor $translationNodeVisitor = null)
{
$this->translator = $translator;
$this->translationNodeVisitor = $translationNodeVisitor;
@@ -96,7 +96,7 @@ public function getTranslationNodeVisitor(): TranslationNodeVisitor
/**
* @param array|string $arguments Can be the locale as a string when $message is a TranslatableInterface
*/
- public function trans(string|\Stringable|TranslatableInterface|null $message, array|string $arguments = [], string $domain = null, string $locale = null, int $count = null): string
+ public function trans(string|\Stringable|TranslatableInterface|null $message, array|string $arguments = [], ?string $domain = null, ?string $locale = null, ?int $count = null): string
{
if ($message instanceof TranslatableInterface) {
if ([] !== $arguments && !\is_string($arguments)) {
@@ -125,7 +125,7 @@ public function trans(string|\Stringable|TranslatableInterface|null $message, ar
return $this->getTranslator()->trans($message, $arguments, $domain, $locale);
}
- public function createTranslatable(string $message, array $parameters = [], string $domain = null): TranslatableMessage
+ public function createTranslatable(string $message, array $parameters = [], ?string $domain = null): TranslatableMessage
{
if (!class_exists(TranslatableMessage::class)) {
throw new \LogicException(sprintf('You cannot use the "%s" as the Translation Component is not installed. Try running "composer require symfony/translation".', __CLASS__));
diff --git a/src/Symfony/Bridge/Twig/Extension/WorkflowExtension.php b/src/Symfony/Bridge/Twig/Extension/WorkflowExtension.php
index 661a063f98e61..b50130ccbc5a9 100644
--- a/src/Symfony/Bridge/Twig/Extension/WorkflowExtension.php
+++ b/src/Symfony/Bridge/Twig/Extension/WorkflowExtension.php
@@ -48,7 +48,7 @@ public function getFunctions(): array
/**
* Returns true if the transition is enabled.
*/
- public function canTransition(object $subject, string $transitionName, string $name = null): bool
+ public function canTransition(object $subject, string $transitionName, ?string $name = null): bool
{
return $this->workflowRegistry->get($subject, $name)->can($subject, $transitionName);
}
@@ -58,12 +58,12 @@ public function canTransition(object $subject, string $transitionName, string $n
*
* @return Transition[]
*/
- public function getEnabledTransitions(object $subject, string $name = null): array
+ public function getEnabledTransitions(object $subject, ?string $name = null): array
{
return $this->workflowRegistry->get($subject, $name)->getEnabledTransitions($subject);
}
- public function getEnabledTransition(object $subject, string $transition, string $name = null): ?Transition
+ public function getEnabledTransition(object $subject, string $transition, ?string $name = null): ?Transition
{
return $this->workflowRegistry->get($subject, $name)->getEnabledTransition($subject, $transition);
}
@@ -71,7 +71,7 @@ public function getEnabledTransition(object $subject, string $transition, string
/**
* Returns true if the place is marked.
*/
- public function hasMarkedPlace(object $subject, string $placeName, string $name = null): bool
+ public function hasMarkedPlace(object $subject, string $placeName, ?string $name = null): bool
{
return $this->workflowRegistry->get($subject, $name)->getMarking($subject)->has($placeName);
}
@@ -81,7 +81,7 @@ public function hasMarkedPlace(object $subject, string $placeName, string $name
*
* @return string[]|int[]
*/
- public function getMarkedPlaces(object $subject, bool $placesNameOnly = true, string $name = null): array
+ public function getMarkedPlaces(object $subject, bool $placesNameOnly = true, ?string $name = null): array
{
$places = $this->workflowRegistry->get($subject, $name)->getMarking($subject)->getPlaces();
@@ -99,7 +99,7 @@ public function getMarkedPlaces(object $subject, bool $placesNameOnly = true, st
* Use a string (the place name) to get place metadata
* Use a Transition instance to get transition metadata
*/
- public function getMetadata(object $subject, string $key, string|Transition $metadataSubject = null, string $name = null): mixed
+ public function getMetadata(object $subject, string $key, string|Transition|null $metadataSubject = null, ?string $name = null): mixed
{
return $this
->workflowRegistry
@@ -109,7 +109,7 @@ public function getMetadata(object $subject, string $key, string|Transition $met
;
}
- public function buildTransitionBlockerList(object $subject, string $transitionName, string $name = null): TransitionBlockerList
+ public function buildTransitionBlockerList(object $subject, string $transitionName, ?string $name = null): TransitionBlockerList
{
$workflow = $this->workflowRegistry->get($subject, $name);
diff --git a/src/Symfony/Bridge/Twig/Mime/BodyRenderer.php b/src/Symfony/Bridge/Twig/Mime/BodyRenderer.php
index 18e0eb1f86693..d5b6d14c139a0 100644
--- a/src/Symfony/Bridge/Twig/Mime/BodyRenderer.php
+++ b/src/Symfony/Bridge/Twig/Mime/BodyRenderer.php
@@ -31,7 +31,7 @@ final class BodyRenderer implements BodyRendererInterface
private HtmlToTextConverterInterface $converter;
private ?LocaleSwitcher $localeSwitcher = null;
- public function __construct(Environment $twig, array $context = [], HtmlToTextConverterInterface $converter = null, LocaleSwitcher $localeSwitcher = null)
+ public function __construct(Environment $twig, array $context = [], ?HtmlToTextConverterInterface $converter = null, ?LocaleSwitcher $localeSwitcher = null)
{
$this->twig = $twig;
$this->context = $context;
diff --git a/src/Symfony/Bridge/Twig/Mime/NotificationEmail.php b/src/Symfony/Bridge/Twig/Mime/NotificationEmail.php
index 5bd54e64463e5..6e33d33dfa89a 100644
--- a/src/Symfony/Bridge/Twig/Mime/NotificationEmail.php
+++ b/src/Symfony/Bridge/Twig/Mime/NotificationEmail.php
@@ -42,7 +42,7 @@ class NotificationEmail extends TemplatedEmail
];
private bool $rendered = false;
- public function __construct(Headers $headers = null, AbstractPart $body = null)
+ public function __construct(?Headers $headers = null, ?AbstractPart $body = null)
{
$missingPackages = [];
if (!class_exists(CssInlinerExtension::class)) {
@@ -63,7 +63,7 @@ public function __construct(Headers $headers = null, AbstractPart $body = null)
/**
* Creates a NotificationEmail instance that is appropriate to send to normal (non-admin) users.
*/
- public static function asPublicEmail(Headers $headers = null, AbstractPart $body = null): self
+ public static function asPublicEmail(?Headers $headers = null, ?AbstractPart $body = null): self
{
$email = new static($headers, $body);
$email->markAsPublic();
@@ -174,6 +174,26 @@ public function getHtmlTemplate(): ?string
return '@email/'.$this->theme.'/notification/body.html.twig';
}
+ /**
+ * @return $this
+ */
+ public function context(array $context): static
+ {
+ $parentContext = [];
+
+ foreach ($context as $key => $value) {
+ if (\array_key_exists($key, $this->context)) {
+ $this->context[$key] = $value;
+ } else {
+ $parentContext[$key] = $value;
+ }
+ }
+
+ parent::context($parentContext);
+
+ return $this;
+ }
+
public function getContext(): array
{
return array_merge($this->context, parent::getContext());
diff --git a/src/Symfony/Bridge/Twig/Mime/WrappedTemplatedEmail.php b/src/Symfony/Bridge/Twig/Mime/WrappedTemplatedEmail.php
index c4e0003fac1a4..e72335a5ececd 100644
--- a/src/Symfony/Bridge/Twig/Mime/WrappedTemplatedEmail.php
+++ b/src/Symfony/Bridge/Twig/Mime/WrappedTemplatedEmail.php
@@ -43,7 +43,7 @@ public function toName(): string
* @param string|null $contentType The media type (i.e. MIME type) of the image file (e.g. 'image/png').
* Some email clients require this to display embedded images.
*/
- public function image(string $image, string $contentType = null): string
+ public function image(string $image, ?string $contentType = null): string
{
$file = $this->twig->getLoader()->getSourceContext($image);
$body = $file->getPath() ? new File($file->getPath()) : $file->getCode();
@@ -59,7 +59,7 @@ public function image(string $image, string $contentType = null): string
* @param string|null $contentType The media type (i.e. MIME type) of the file (e.g. 'application/pdf').
* Some email clients require this to display attached files.
*/
- public function attach(string $file, string $name = null, string $contentType = null): void
+ public function attach(string $file, ?string $name = null, ?string $contentType = null): void
{
$file = $this->twig->getLoader()->getSourceContext($file);
$body = $file->getPath() ? new File($file->getPath()) : $file->getCode();
diff --git a/src/Symfony/Bridge/Twig/Node/DumpNode.php b/src/Symfony/Bridge/Twig/Node/DumpNode.php
index 8ce2bd8c4fa51..086ff7a68aaea 100644
--- a/src/Symfony/Bridge/Twig/Node/DumpNode.php
+++ b/src/Symfony/Bridge/Twig/Node/DumpNode.php
@@ -21,7 +21,7 @@ final class DumpNode extends Node
{
private string $varPrefix;
- public function __construct(string $varPrefix, ?Node $values, int $lineno, string $tag = null)
+ public function __construct(string $varPrefix, ?Node $values, int $lineno, ?string $tag = null)
{
$nodes = [];
if (null !== $values) {
diff --git a/src/Symfony/Bridge/Twig/Node/FormThemeNode.php b/src/Symfony/Bridge/Twig/Node/FormThemeNode.php
index e37311267bb17..2d4659ae7bb61 100644
--- a/src/Symfony/Bridge/Twig/Node/FormThemeNode.php
+++ b/src/Symfony/Bridge/Twig/Node/FormThemeNode.php
@@ -20,7 +20,7 @@
*/
final class FormThemeNode extends Node
{
- public function __construct(Node $form, Node $resources, int $lineno, string $tag = null, bool $only = false)
+ public function __construct(Node $form, Node $resources, int $lineno, ?string $tag = null, bool $only = false)
{
parent::__construct(['form' => $form, 'resources' => $resources], ['only' => $only], $lineno, $tag);
}
diff --git a/src/Symfony/Bridge/Twig/Node/StopwatchNode.php b/src/Symfony/Bridge/Twig/Node/StopwatchNode.php
index cfa4d8a197f9b..796ee4dab8d16 100644
--- a/src/Symfony/Bridge/Twig/Node/StopwatchNode.php
+++ b/src/Symfony/Bridge/Twig/Node/StopwatchNode.php
@@ -22,7 +22,7 @@
*/
final class StopwatchNode extends Node
{
- public function __construct(Node $name, Node $body, AssignNameExpression $var, int $lineno = 0, string $tag = null)
+ public function __construct(Node $name, Node $body, AssignNameExpression $var, int $lineno = 0, ?string $tag = null)
{
parent::__construct(['body' => $body, 'name' => $name, 'var' => $var], [], $lineno, $tag);
}
diff --git a/src/Symfony/Bridge/Twig/Node/TransDefaultDomainNode.php b/src/Symfony/Bridge/Twig/Node/TransDefaultDomainNode.php
index df29f0a19931f..5a96d7420122f 100644
--- a/src/Symfony/Bridge/Twig/Node/TransDefaultDomainNode.php
+++ b/src/Symfony/Bridge/Twig/Node/TransDefaultDomainNode.php
@@ -20,7 +20,7 @@
*/
final class TransDefaultDomainNode extends Node
{
- public function __construct(AbstractExpression $expr, int $lineno = 0, string $tag = null)
+ public function __construct(AbstractExpression $expr, int $lineno = 0, ?string $tag = null)
{
parent::__construct(['expr' => $expr], [], $lineno, $tag);
}
diff --git a/src/Symfony/Bridge/Twig/Node/TransNode.php b/src/Symfony/Bridge/Twig/Node/TransNode.php
index 8a126ba569172..881104c8cc3fd 100644
--- a/src/Symfony/Bridge/Twig/Node/TransNode.php
+++ b/src/Symfony/Bridge/Twig/Node/TransNode.php
@@ -24,7 +24,7 @@
*/
final class TransNode extends Node
{
- public function __construct(Node $body, Node $domain = null, AbstractExpression $count = null, AbstractExpression $vars = null, AbstractExpression $locale = null, int $lineno = 0, string $tag = null)
+ public function __construct(Node $body, ?Node $domain = null, ?AbstractExpression $count = null, ?AbstractExpression $vars = null, ?AbstractExpression $locale = null, int $lineno = 0, ?string $tag = null)
{
$nodes = ['body' => $body];
if (null !== $domain) {
diff --git a/src/Symfony/Bridge/Twig/NodeVisitor/Scope.php b/src/Symfony/Bridge/Twig/NodeVisitor/Scope.php
index efa354d03feac..66904b09b5303 100644
--- a/src/Symfony/Bridge/Twig/NodeVisitor/Scope.php
+++ b/src/Symfony/Bridge/Twig/NodeVisitor/Scope.php
@@ -20,7 +20,7 @@ class Scope
private array $data = [];
private bool $left = false;
- public function __construct(self $parent = null)
+ public function __construct(?self $parent = null)
{
$this->parent = $parent;
}
diff --git a/src/Symfony/Bridge/Twig/NodeVisitor/TranslationNodeVisitor.php b/src/Symfony/Bridge/Twig/NodeVisitor/TranslationNodeVisitor.php
index d5e95040d6bf2..3a7ea67cac90b 100644
--- a/src/Symfony/Bridge/Twig/NodeVisitor/TranslationNodeVisitor.php
+++ b/src/Symfony/Bridge/Twig/NodeVisitor/TranslationNodeVisitor.php
@@ -149,6 +149,22 @@ private function getReadDomainFromNode(Node $node): ?string
return $node->getAttribute('value');
}
+ if (
+ $node instanceof FunctionExpression
+ && 'constant' === $node->getAttribute('name')
+ ) {
+ $nodeArguments = $node->getNode('arguments');
+ if ($nodeArguments->getIterator()->current() instanceof ConstantExpression) {
+ $constantName = $nodeArguments->getIterator()->current()->getAttribute('value');
+ if (\defined($constantName)) {
+ $value = \constant($constantName);
+ if (\is_string($value)) {
+ return $value;
+ }
+ }
+ }
+ }
+
return self::UNDEFINED_DOMAIN;
}
diff --git a/src/Symfony/Bridge/Twig/Resources/views/Form/form_div_layout.html.twig b/src/Symfony/Bridge/Twig/Resources/views/Form/form_div_layout.html.twig
index d57a4e1197e1e..1e421d5f9f5a9 100644
--- a/src/Symfony/Bridge/Twig/Resources/views/Form/form_div_layout.html.twig
+++ b/src/Symfony/Bridge/Twig/Resources/views/Form/form_div_layout.html.twig
@@ -14,7 +14,7 @@
{# Attribute "required" is not supported #}
{%- set required = false -%}
{%- endif -%}
-
+
{%- endblock form_widget_simple -%}
{%- block form_widget_compound -%}
@@ -95,11 +95,11 @@
{%- endblock choice_widget_options -%}
{%- block checkbox_widget -%}
-
+
{%- endblock checkbox_widget -%}
{%- block radio_widget -%}
-
+
{%- endblock radio_widget -%}
{%- block datetime_widget -%}
@@ -406,7 +406,7 @@
{%- endif -%}
{% endblock %}
diff --git a/src/Symfony/Bundle/SecurityBundle/Tests/Functional/Bundle/FirewallEntryPointBundle/Security/EntryPointStub.php b/src/Symfony/Bundle/SecurityBundle/Tests/Functional/Bundle/FirewallEntryPointBundle/Security/EntryPointStub.php
index 56552b99c7983..16a757260cf27 100644
--- a/src/Symfony/Bundle/SecurityBundle/Tests/Functional/Bundle/FirewallEntryPointBundle/Security/EntryPointStub.php
+++ b/src/Symfony/Bundle/SecurityBundle/Tests/Functional/Bundle/FirewallEntryPointBundle/Security/EntryPointStub.php
@@ -20,7 +20,7 @@ class EntryPointStub implements AuthenticationEntryPointInterface
{
public const RESPONSE_TEXT = '2be8e651259189d841a19eecdf37e771e2431741';
- public function start(Request $request, AuthenticationException $authException = null): Response
+ public function start(Request $request, ?AuthenticationException $authException = null): Response
{
return new Response(self::RESPONSE_TEXT);
}
diff --git a/src/Symfony/Bundle/SecurityBundle/Tests/Functional/Bundle/FormLoginBundle/Controller/LoginController.php b/src/Symfony/Bundle/SecurityBundle/Tests/Functional/Bundle/FormLoginBundle/Controller/LoginController.php
index dd8c1a2d055ef..16e823a03c36b 100644
--- a/src/Symfony/Bundle/SecurityBundle/Tests/Functional/Bundle/FormLoginBundle/Controller/LoginController.php
+++ b/src/Symfony/Bundle/SecurityBundle/Tests/Functional/Bundle/FormLoginBundle/Controller/LoginController.php
@@ -29,7 +29,7 @@ public function __construct(ContainerInterface $container)
$this->container = $container;
}
- public function loginAction(Request $request, UserInterface $user = null)
+ public function loginAction(Request $request, ?UserInterface $user = null)
{
// get the login error if there is one
if ($request->attributes->has(SecurityRequestAttributes::AUTHENTICATION_ERROR)) {
diff --git a/src/Symfony/Bundle/SecurityBundle/Tests/Functional/Bundle/FormLoginBundle/Resources/views/Localized/login.html.twig b/src/Symfony/Bundle/SecurityBundle/Tests/Functional/Bundle/FormLoginBundle/Resources/views/Localized/login.html.twig
index d147bd1addc64..de0da3bb589c0 100644
--- a/src/Symfony/Bundle/SecurityBundle/Tests/Functional/Bundle/FormLoginBundle/Resources/views/Localized/login.html.twig
+++ b/src/Symfony/Bundle/SecurityBundle/Tests/Functional/Bundle/FormLoginBundle/Resources/views/Localized/login.html.twig
@@ -8,14 +8,14 @@
{% endblock %}
diff --git a/src/Symfony/Bundle/SecurityBundle/Tests/Functional/Bundle/FormLoginBundle/Resources/views/Login/after_login.html.twig b/src/Symfony/Bundle/SecurityBundle/Tests/Functional/Bundle/FormLoginBundle/Resources/views/Login/after_login.html.twig
index d48269aeca674..fd51df2a4383f 100644
--- a/src/Symfony/Bundle/SecurityBundle/Tests/Functional/Bundle/FormLoginBundle/Resources/views/Login/after_login.html.twig
+++ b/src/Symfony/Bundle/SecurityBundle/Tests/Functional/Bundle/FormLoginBundle/Resources/views/Login/after_login.html.twig
@@ -1,7 +1,7 @@
{% extends "base.html.twig" %}
{% block body %}
- Hello {{ user.userIdentifier }}!
+ Hello {{ user.userIdentifier }}!
You're browsing to path "{{ app.request.pathInfo }}".
Log out.
diff --git a/src/Symfony/Bundle/SecurityBundle/Tests/Functional/Bundle/FormLoginBundle/Resources/views/Login/login.html.twig b/src/Symfony/Bundle/SecurityBundle/Tests/Functional/Bundle/FormLoginBundle/Resources/views/Login/login.html.twig
index 9e41e0223337d..34ea19f2bde62 100644
--- a/src/Symfony/Bundle/SecurityBundle/Tests/Functional/Bundle/FormLoginBundle/Resources/views/Login/login.html.twig
+++ b/src/Symfony/Bundle/SecurityBundle/Tests/Functional/Bundle/FormLoginBundle/Resources/views/Login/login.html.twig
@@ -9,14 +9,14 @@
{% endblock %}
diff --git a/src/Symfony/Bundle/SecurityBundle/Tests/Functional/app/AccessToken/config_cas.yml b/src/Symfony/Bundle/SecurityBundle/Tests/Functional/app/AccessToken/config_cas.yml
new file mode 100644
index 0000000000000..2cd2abc566c05
--- /dev/null
+++ b/src/Symfony/Bundle/SecurityBundle/Tests/Functional/app/AccessToken/config_cas.yml
@@ -0,0 +1,41 @@
+imports:
+ - { resource: ./../config/framework.yml }
+
+framework:
+ http_method_override: false
+ serializer: ~
+
+security:
+ password_hashers:
+ Symfony\Component\Security\Core\User\InMemoryUser: plaintext
+
+ providers:
+ in_memory:
+ memory:
+ users:
+ dunglas: { password: foo, roles: [ROLE_USER] }
+
+ firewalls:
+ main:
+ pattern: ^/
+ access_token:
+ token_handler:
+ cas:
+ validation_url: 'https://www.example.com/cas/serviceValidate'
+ http_client: 'Symfony\Contracts\HttpClient\HttpClientInterface'
+ token_extractors:
+ - security.access_token_extractor.cas
+
+ access_control:
+ - { path: ^/foo, roles: ROLE_USER }
+
+services:
+ _defaults:
+ public: true
+
+ security.access_token_extractor.cas:
+ class: Symfony\Component\Security\Http\AccessToken\QueryAccessTokenExtractor
+ arguments:
+ - 'ticket'
+
+ Symfony\Contracts\HttpClient\HttpClientInterface: ~
diff --git a/src/Symfony/Bundle/SecurityBundle/Tests/Functional/app/templates/base.html.twig b/src/Symfony/Bundle/SecurityBundle/Tests/Functional/app/templates/base.html.twig
index 32645815dc359..caf6f6efb6db1 100644
--- a/src/Symfony/Bundle/SecurityBundle/Tests/Functional/app/templates/base.html.twig
+++ b/src/Symfony/Bundle/SecurityBundle/Tests/Functional/app/templates/base.html.twig
@@ -1,7 +1,7 @@
-
+
{% block title %}Welcome!{% endblock %}
{% block stylesheets %}{% endblock %}
diff --git a/src/Symfony/Bundle/SecurityBundle/Tests/LoginLink/FirewallAwareLoginLinkHandlerTest.php b/src/Symfony/Bundle/SecurityBundle/Tests/LoginLink/FirewallAwareLoginLinkHandlerTest.php
index 92703f41ec3c7..eff35a8304749 100644
--- a/src/Symfony/Bundle/SecurityBundle/Tests/LoginLink/FirewallAwareLoginLinkHandlerTest.php
+++ b/src/Symfony/Bundle/SecurityBundle/Tests/LoginLink/FirewallAwareLoginLinkHandlerTest.php
@@ -12,10 +12,10 @@
namespace Symfony\Bundle\SecurityBundle\Tests\LoginLink;
use PHPUnit\Framework\TestCase;
-use Psr\Container\ContainerInterface;
use Symfony\Bundle\SecurityBundle\LoginLink\FirewallAwareLoginLinkHandler;
use Symfony\Bundle\SecurityBundle\Security\FirewallConfig;
use Symfony\Bundle\SecurityBundle\Security\FirewallMap;
+use Symfony\Component\DependencyInjection\Container;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\RequestStack;
use Symfony\Component\Security\Core\User\UserInterface;
@@ -66,13 +66,11 @@ private function createFirewallMap(string $firewallName)
private function createLocator(array $linkers)
{
- $locator = $this->createMock(ContainerInterface::class);
- $locator->expects($this->any())
- ->method('has')
- ->willReturnCallback(fn ($firewallName) => isset($linkers[$firewallName]));
- $locator->expects($this->any())
- ->method('get')
- ->willReturnCallback(fn ($firewallName) => $linkers[$firewallName]);
+ $locator = new Container();
+
+ foreach ($linkers as $class => $service) {
+ $locator->set($class, $service);
+ }
return $locator;
}
diff --git a/src/Symfony/Bundle/SecurityBundle/Tests/SecurityTest.php b/src/Symfony/Bundle/SecurityBundle/Tests/SecurityTest.php
index 844e4b387aac8..4be14111682bb 100644
--- a/src/Symfony/Bundle/SecurityBundle/Tests/SecurityTest.php
+++ b/src/Symfony/Bundle/SecurityBundle/Tests/SecurityTest.php
@@ -16,6 +16,7 @@
use Symfony\Bundle\SecurityBundle\Security;
use Symfony\Bundle\SecurityBundle\Security\FirewallConfig;
use Symfony\Bundle\SecurityBundle\Security\FirewallMap;
+use Symfony\Component\DependencyInjection\Container;
use Symfony\Component\DependencyInjection\ServiceLocator;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\RequestStack;
@@ -135,17 +136,11 @@ public function testLogin()
$user = $this->createMock(UserInterface::class);
$userChecker = $this->createMock(UserCheckerInterface::class);
- $container = $this->createMock(ContainerInterface::class);
- $container
- ->expects($this->atLeastOnce())
- ->method('get')
- ->willReturnMap([
- ['request_stack', $requestStack],
- ['security.firewall.map', $firewallMap],
- ['security.authenticator.managers_locator', $this->createContainer('main', $userAuthenticator)],
- ['security.user_checker', $userChecker],
- ])
- ;
+ $container = new Container();
+ $container->set('request_stack', $requestStack);
+ $container->set('security.firewall.map', $firewallMap);
+ $container->set('security.authenticator.managers_locator', $this->createContainer('main', $userAuthenticator));
+ $container->set('security.user_checker', $userChecker);
$firewallMap->expects($this->once())->method('getFirewallConfig')->willReturn($firewall);
$userAuthenticator->expects($this->once())->method('authenticateUser')->with($user, $authenticator, $request);
@@ -181,17 +176,11 @@ public function testLoginReturnsAuthenticatorResponse()
$userChecker = $this->createMock(UserCheckerInterface::class);
$userAuthenticator = $this->createMock(UserAuthenticatorInterface::class);
- $container = $this->createMock(ContainerInterface::class);
- $container
- ->expects($this->atLeastOnce())
- ->method('get')
- ->willReturnMap([
- ['request_stack', $requestStack],
- ['security.firewall.map', $firewallMap],
- ['security.authenticator.managers_locator', $this->createContainer('main', $userAuthenticator)],
- ['security.user_checker', $userChecker],
- ])
- ;
+ $container = new Container();
+ $container->set('request_stack', $requestStack);
+ $container->set('security.firewall.map', $firewallMap);
+ $container->set('security.authenticator.managers_locator', $this->createContainer('main', $userAuthenticator));
+ $container->set('security.user_checker', $userChecker);
$firewallMap->expects($this->once())->method('getFirewallConfig')->willReturn($firewall);
$userChecker->expects($this->once())->method('checkPreAuth')->with($user);
@@ -230,16 +219,10 @@ public function testLoginWithoutAuthenticatorThrows()
$user = $this->createMock(UserInterface::class);
$userChecker = $this->createMock(UserCheckerInterface::class);
- $container = $this->createMock(ContainerInterface::class);
- $container
- ->expects($this->atLeastOnce())
- ->method('get')
- ->willReturnMap([
- ['request_stack', $requestStack],
- ['security.firewall.map', $firewallMap],
- ['security.user_checker', $userChecker],
- ])
- ;
+ $container = new Container();
+ $container->set('request_stack', $requestStack);
+ $container->set('security.firewall.map', $firewallMap);
+ $container->set('security.user_checker', $userChecker);
$firewallMap->expects($this->once())->method('getFirewallConfig')->willReturn($firewall);
@@ -256,14 +239,8 @@ public function testLoginWithoutRequestContext()
$requestStack = new RequestStack();
$user = $this->createMock(UserInterface::class);
- $container = $this->createMock(ContainerInterface::class);
- $container
- ->expects($this->atLeastOnce())
- ->method('get')
- ->willReturnMap([
- ['request_stack', $requestStack],
- ])
- ;
+ $container = new Container();
+ $container->set('request_stack', $requestStack);
$security = new Security($container, ['main' => null]);
@@ -300,26 +277,14 @@ public function testLogout()
->willReturn($firewallConfig)
;
- $eventDispatcherLocator = $this->createMock(ContainerInterface::class);
- $eventDispatcherLocator
- ->expects($this->atLeastOnce())
- ->method('get')
- ->willReturnMap([
- ['my_firewall', $eventDispatcher],
- ])
- ;
+ $eventDispatcherLocator = new Container();
+ $eventDispatcherLocator->set('my_firewall', $eventDispatcher);
- $container = $this->createMock(ContainerInterface::class);
- $container
- ->expects($this->atLeastOnce())
- ->method('get')
- ->willReturnMap([
- ['request_stack', $requestStack],
- ['security.token_storage', $tokenStorage],
- ['security.firewall.map', $firewallMap],
- ['security.firewall.event_dispatcher_locator', $eventDispatcherLocator],
- ])
- ;
+ $container = new Container();
+ $container->set('request_stack', $requestStack);
+ $container->set('security.token_storage', $tokenStorage);
+ $container->set('security.firewall.map', $firewallMap);
+ $container->set('security.firewall.event_dispatcher_locator', $eventDispatcherLocator);
$security = new Security($container);
$security->logout(false);
}
@@ -346,16 +311,10 @@ public function testLogoutWithoutFirewall()
->willReturn(null)
;
- $container = $this->createMock(ContainerInterface::class);
- $container
- ->expects($this->atLeastOnce())
- ->method('get')
- ->willReturnMap([
- ['request_stack', $requestStack],
- ['security.token_storage', $tokenStorage],
- ['security.firewall.map', $firewallMap],
- ])
- ;
+ $container = new Container();
+ $container->set('request_stack', $requestStack);
+ $container->set('security.token_storage', $tokenStorage);
+ $container->set('security.firewall.map', $firewallMap);
$this->expectException(LogicException::class);
$security = new Security($container);
@@ -393,24 +352,14 @@ public function testLogoutWithResponse()
$firewallConfig = new FirewallConfig('my_firewall', 'user_checker');
$firewallMap->expects($this->once())->method('getFirewallConfig')->willReturn($firewallConfig);
- $eventDispatcherLocator = $this->createMock(ContainerInterface::class);
- $eventDispatcherLocator
- ->expects($this->atLeastOnce())
- ->method('get')
- ->willReturnMap([['my_firewall', $eventDispatcher]])
- ;
+ $eventDispatcherLocator = new Container();
+ $eventDispatcherLocator->set('my_firewall', $eventDispatcher);
- $container = $this->createMock(ContainerInterface::class);
- $container
- ->expects($this->atLeastOnce())
- ->method('get')
- ->willReturnMap([
- ['request_stack', $requestStack],
- ['security.token_storage', $tokenStorage],
- ['security.firewall.map', $firewallMap],
- ['security.firewall.event_dispatcher_locator', $eventDispatcherLocator],
- ])
- ;
+ $container = new Container();
+ $container->set('request_stack', $requestStack);
+ $container->set('security.token_storage', $tokenStorage);
+ $container->set('security.firewall.map', $firewallMap);
+ $container->set('security.firewall.event_dispatcher_locator', $eventDispatcherLocator);
$security = new Security($container);
$response = $security->logout(false);
@@ -449,29 +398,18 @@ public function testLogoutWithValidCsrf()
$firewallConfig = new FirewallConfig(name: 'my_firewall', userChecker: 'user_checker', logout: ['csrf_parameter' => '_csrf_token', 'csrf_token_id' => 'logout']);
$firewallMap->expects($this->once())->method('getFirewallConfig')->willReturn($firewallConfig);
- $eventDispatcherLocator = $this->createMock(ContainerInterface::class);
- $eventDispatcherLocator
- ->expects($this->atLeastOnce())
- ->method('get')
- ->willReturnMap([['my_firewall', $eventDispatcher]])
- ;
+ $eventDispatcherLocator = new Container();
+ $eventDispatcherLocator->set('my_firewall', $eventDispatcher);
$csrfTokenManager = $this->createMock(CsrfTokenManagerInterface::class);
$csrfTokenManager->expects($this->once())->method('isTokenValid')->with($this->equalTo(new CsrfToken('logout', 'dummytoken')))->willReturn(true);
- $container = $this->createMock(ContainerInterface::class);
- $container->expects($this->once())->method('has')->with('security.csrf.token_manager')->willReturn(true);
- $container
- ->expects($this->atLeastOnce())
- ->method('get')
- ->willReturnMap([
- ['request_stack', $requestStack],
- ['security.token_storage', $tokenStorage],
- ['security.firewall.map', $firewallMap],
- ['security.firewall.event_dispatcher_locator', $eventDispatcherLocator],
- ['security.csrf.token_manager', $csrfTokenManager],
- ])
- ;
+ $container = new Container();
+ $container->set('request_stack', $requestStack);
+ $container->set('security.token_storage', $tokenStorage);
+ $container->set('security.firewall.map', $firewallMap);
+ $container->set('security.firewall.event_dispatcher_locator', $eventDispatcherLocator);
+ $container->set('security.csrf.token_manager', $csrfTokenManager);
$security = new Security($container);
$response = $security->logout();
@@ -483,14 +421,8 @@ public function testLogoutWithoutRequestContext()
{
$requestStack = new RequestStack();
- $container = $this->createMock(ContainerInterface::class);
- $container
- ->expects($this->atLeastOnce())
- ->method('get')
- ->willReturnMap([
- ['request_stack', $requestStack],
- ])
- ;
+ $container = new Container();
+ $container->set('request_stack', $requestStack);
$security = new Security($container, ['main' => null]);
diff --git a/src/Symfony/Bundle/TwigBundle/CacheWarmer/TemplateCacheWarmer.php b/src/Symfony/Bundle/TwigBundle/CacheWarmer/TemplateCacheWarmer.php
index c40425f460b2f..69b0b2cecbd83 100644
--- a/src/Symfony/Bundle/TwigBundle/CacheWarmer/TemplateCacheWarmer.php
+++ b/src/Symfony/Bundle/TwigBundle/CacheWarmer/TemplateCacheWarmer.php
@@ -37,7 +37,7 @@ public function __construct(ContainerInterface $container, iterable $iterator)
$this->iterator = $iterator;
}
- public function warmUp(string $cacheDir, string $buildDir = null): array
+ public function warmUp(string $cacheDir, ?string $buildDir = null): array
{
$this->twig ??= $this->container->get('twig');
diff --git a/src/Symfony/Bundle/TwigBundle/DependencyInjection/Configuration.php b/src/Symfony/Bundle/TwigBundle/DependencyInjection/Configuration.php
index ab6ceb2932f46..9d08c976a8982 100644
--- a/src/Symfony/Bundle/TwigBundle/DependencyInjection/Configuration.php
+++ b/src/Symfony/Bundle/TwigBundle/DependencyInjection/Configuration.php
@@ -153,7 +153,7 @@ private function addTwigOptions(ArrayNodeDefinition $rootNode): void
->normalizeKeys(false)
->useAttributeAsKey('paths')
->beforeNormalization()
- ->always()
+ ->ifArray()
->then(function ($paths) {
$normalized = [];
foreach ($paths as $path => $namespace) {
diff --git a/src/Symfony/Bundle/TwigBundle/TemplateIterator.php b/src/Symfony/Bundle/TwigBundle/TemplateIterator.php
index 7242cfb0c5d44..bd42f1ac07e8d 100644
--- a/src/Symfony/Bundle/TwigBundle/TemplateIterator.php
+++ b/src/Symfony/Bundle/TwigBundle/TemplateIterator.php
@@ -36,7 +36,7 @@ class TemplateIterator implements \IteratorAggregate
* @param string|null $defaultPath The directory where global templates can be stored
* @param string[] $namePatterns Pattern of file names
*/
- public function __construct(KernelInterface $kernel, array $paths = [], string $defaultPath = null, array $namePatterns = [])
+ public function __construct(KernelInterface $kernel, array $paths = [], ?string $defaultPath = null, array $namePatterns = [])
{
$this->kernel = $kernel;
$this->paths = $paths;
@@ -78,7 +78,7 @@ public function getIterator(): \Traversable
*
* @return string[]
*/
- private function findTemplatesInDirectory(string $dir, string $namespace = null, array $excludeDirs = []): array
+ private function findTemplatesInDirectory(string $dir, ?string $namespace = null, array $excludeDirs = []): array
{
if (!is_dir($dir)) {
return [];
diff --git a/src/Symfony/Bundle/TwigBundle/Tests/DependencyInjection/ConfigurationTest.php b/src/Symfony/Bundle/TwigBundle/Tests/DependencyInjection/ConfigurationTest.php
index 41627c48041e3..6ed43087579ce 100644
--- a/src/Symfony/Bundle/TwigBundle/Tests/DependencyInjection/ConfigurationTest.php
+++ b/src/Symfony/Bundle/TwigBundle/Tests/DependencyInjection/ConfigurationTest.php
@@ -52,4 +52,16 @@ public function testArrayKeysInGlobalsAreNotNormalized()
$this->assertSame(['global' => ['value' => ['some-key' => 'some-value']]], $config['globals']);
}
+
+ public function testNullPathsAreConvertedToIterable()
+ {
+ $input = [
+ 'paths' => null,
+ ];
+
+ $processor = new Processor();
+ $config = $processor->processConfiguration(new Configuration(), [$input]);
+
+ $this->assertSame([], $config['paths']);
+ }
}
diff --git a/src/Symfony/Bundle/WebProfilerBundle/Controller/ExceptionPanelController.php b/src/Symfony/Bundle/WebProfilerBundle/Controller/ExceptionPanelController.php
index 1e3168bafc44b..a0704bb532cf8 100644
--- a/src/Symfony/Bundle/WebProfilerBundle/Controller/ExceptionPanelController.php
+++ b/src/Symfony/Bundle/WebProfilerBundle/Controller/ExceptionPanelController.php
@@ -28,7 +28,7 @@ class ExceptionPanelController
private HtmlErrorRenderer $errorRenderer;
private ?Profiler $profiler;
- public function __construct(HtmlErrorRenderer $errorRenderer, Profiler $profiler = null)
+ public function __construct(HtmlErrorRenderer $errorRenderer, ?Profiler $profiler = null)
{
$this->errorRenderer = $errorRenderer;
$this->profiler = $profiler;
diff --git a/src/Symfony/Bundle/WebProfilerBundle/Controller/ProfilerController.php b/src/Symfony/Bundle/WebProfilerBundle/Controller/ProfilerController.php
index df36246cb7604..23895f70bb6ec 100644
--- a/src/Symfony/Bundle/WebProfilerBundle/Controller/ProfilerController.php
+++ b/src/Symfony/Bundle/WebProfilerBundle/Controller/ProfilerController.php
@@ -41,7 +41,7 @@ class ProfilerController
private ?ContentSecurityPolicyHandler $cspHandler;
private ?string $baseDir;
- public function __construct(UrlGeneratorInterface $generator, ?Profiler $profiler, Environment $twig, array $templates, ContentSecurityPolicyHandler $cspHandler = null, string $baseDir = null)
+ public function __construct(UrlGeneratorInterface $generator, ?Profiler $profiler, Environment $twig, array $templates, ?ContentSecurityPolicyHandler $cspHandler = null, ?string $baseDir = null)
{
$this->generator = $generator;
$this->profiler = $profiler;
@@ -127,7 +127,7 @@ public function panelAction(Request $request, string $token): Response
*
* @throws NotFoundHttpException
*/
- public function toolbarAction(Request $request, string $token = null): Response
+ public function toolbarAction(Request $request, ?string $token = null): Response
{
if (null === $this->profiler) {
throw new NotFoundHttpException('The profiler must be enabled.');
diff --git a/src/Symfony/Bundle/WebProfilerBundle/Controller/RouterController.php b/src/Symfony/Bundle/WebProfilerBundle/Controller/RouterController.php
index 04841e3cf3703..f9f7686dcb249 100644
--- a/src/Symfony/Bundle/WebProfilerBundle/Controller/RouterController.php
+++ b/src/Symfony/Bundle/WebProfilerBundle/Controller/RouterController.php
@@ -40,7 +40,7 @@ class RouterController
*/
private iterable $expressionLanguageProviders;
- public function __construct(?Profiler $profiler, Environment $twig, UrlMatcherInterface $matcher = null, RouteCollection $routes = null, iterable $expressionLanguageProviders = [])
+ public function __construct(?Profiler $profiler, Environment $twig, ?UrlMatcherInterface $matcher = null, ?RouteCollection $routes = null, iterable $expressionLanguageProviders = [])
{
$this->profiler = $profiler;
$this->twig = $twig;
diff --git a/src/Symfony/Bundle/WebProfilerBundle/EventListener/WebDebugToolbarListener.php b/src/Symfony/Bundle/WebProfilerBundle/EventListener/WebDebugToolbarListener.php
index 891ede6c94d0b..c2b350ff05d68 100644
--- a/src/Symfony/Bundle/WebProfilerBundle/EventListener/WebDebugToolbarListener.php
+++ b/src/Symfony/Bundle/WebProfilerBundle/EventListener/WebDebugToolbarListener.php
@@ -48,7 +48,7 @@ class WebDebugToolbarListener implements EventSubscriberInterface
private ?ContentSecurityPolicyHandler $cspHandler;
private ?DumpDataCollector $dumpDataCollector;
- public function __construct(Environment $twig, bool $interceptRedirects = false, int $mode = self::ENABLED, UrlGeneratorInterface $urlGenerator = null, string $excludedAjaxPaths = '^/bundles|^/_wdt', ContentSecurityPolicyHandler $cspHandler = null, DumpDataCollector $dumpDataCollector = null)
+ public function __construct(Environment $twig, bool $interceptRedirects = false, int $mode = self::ENABLED, ?UrlGeneratorInterface $urlGenerator = null, string $excludedAjaxPaths = '^/bundles|^/_wdt', ?ContentSecurityPolicyHandler $cspHandler = null, ?DumpDataCollector $dumpDataCollector = null)
{
$this->twig = $twig;
$this->urlGenerator = $urlGenerator;
diff --git a/src/Symfony/Bundle/WebProfilerBundle/Profiler/CodeExtension.php b/src/Symfony/Bundle/WebProfilerBundle/Profiler/CodeExtension.php
index 40657a0f645ce..7fb51772d6d3d 100644
--- a/src/Symfony/Bundle/WebProfilerBundle/Profiler/CodeExtension.php
+++ b/src/Symfony/Bundle/WebProfilerBundle/Profiler/CodeExtension.php
@@ -157,7 +157,7 @@ public function fileExcerpt(string $file, int $line, int $srcContext = 3): ?stri
/**
* Formats a file path.
*/
- public function formatFile(string $file, int $line, string $text = null): string
+ public function formatFile(string $file, int $line, ?string $text = null): string
{
$file = trim($file);
diff --git a/src/Symfony/Bundle/WebProfilerBundle/Resources/views/Collector/notifier.html.twig b/src/Symfony/Bundle/WebProfilerBundle/Resources/views/Collector/notifier.html.twig
index 3884c8e71e784..7d108394f37da 100644
--- a/src/Symfony/Bundle/WebProfilerBundle/Resources/views/Collector/notifier.html.twig
+++ b/src/Symfony/Bundle/WebProfilerBundle/Resources/views/Collector/notifier.html.twig
@@ -134,11 +134,11 @@
Notification
- {{- 'Subject: ' ~ notification.getSubject() }}
- {{- 'Content: ' ~ notification.getContent() }}
- {{- 'Importance: ' ~ notification.getImportance() }}
- {{- 'Emoji: ' ~ (notification.getEmoji() is empty ? '(empty)' : notification.getEmoji()) }}
- {{- 'Exception: ' ~ notification.getException() ?? '(empty)' }}
+ {{- 'Subject: ' ~ notification.getSubject() }}
+ {{- 'Content: ' ~ notification.getContent() }}
+ {{- 'Importance: ' ~ notification.getImportance() }}
+ {{- 'Emoji: ' ~ (notification.getEmoji() is empty ? '(empty)' : notification.getEmoji()) }}
+ {{- 'Exception: ' ~ notification.getException() ?? '(empty)' }}
{{- 'ExceptionAsString: ' ~ (notification.getExceptionAsString() is empty ? '(empty)' : notification.getExceptionAsString()) }}
diff --git a/src/Symfony/Bundle/WebProfilerBundle/Resources/views/Profiler/base.html.twig b/src/Symfony/Bundle/WebProfilerBundle/Resources/views/Profiler/base.html.twig
index 9c11fe9199b81..1eaa87b976d4c 100644
--- a/src/Symfony/Bundle/WebProfilerBundle/Resources/views/Profiler/base.html.twig
+++ b/src/Symfony/Bundle/WebProfilerBundle/Resources/views/Profiler/base.html.twig
@@ -1,9 +1,9 @@
-
-
-
+
+
+
{% block title %}Symfony Profiler{% endblock %}
{% set request_collector = profile is defined ? profile.collectors.request|default(null) : null %}
diff --git a/src/Symfony/Bundle/WebProfilerBundle/Twig/WebProfilerExtension.php b/src/Symfony/Bundle/WebProfilerBundle/Twig/WebProfilerExtension.php
index 6df2a24727e10..59361f4018bb3 100644
--- a/src/Symfony/Bundle/WebProfilerBundle/Twig/WebProfilerExtension.php
+++ b/src/Symfony/Bundle/WebProfilerBundle/Twig/WebProfilerExtension.php
@@ -37,7 +37,7 @@ class WebProfilerExtension extends ProfilerExtension
private int $stackLevel = 0;
- public function __construct(HtmlDumper $dumper = null)
+ public function __construct(?HtmlDumper $dumper = null)
{
$this->dumper = $dumper ?? new HtmlDumper();
$this->dumper->setOutput($this->output = fopen('php://memory', 'r+'));
@@ -77,7 +77,7 @@ public function dumpData(Environment $env, Data $data, int $maxDepth = 0): strin
return str_replace("\n$1"', $message);
diff --git a/src/Symfony/Component/Asset/Exception/AssetNotFoundException.php b/src/Symfony/Component/Asset/Exception/AssetNotFoundException.php
index ac3d2fa8f37bd..82e88947cb461 100644
--- a/src/Symfony/Component/Asset/Exception/AssetNotFoundException.php
+++ b/src/Symfony/Component/Asset/Exception/AssetNotFoundException.php
@@ -24,7 +24,7 @@ class AssetNotFoundException extends RuntimeException
* @param int $code Exception code
* @param \Throwable $previous Previous exception used for the exception chaining
*/
- public function __construct(string $message, array $alternatives = [], int $code = 0, \Throwable $previous = null)
+ public function __construct(string $message, array $alternatives = [], int $code = 0, ?\Throwable $previous = null)
{
parent::__construct($message, $code, $previous);
diff --git a/src/Symfony/Component/Asset/Package.php b/src/Symfony/Component/Asset/Package.php
index a9c9dca3eae20..c696c328f6075 100644
--- a/src/Symfony/Component/Asset/Package.php
+++ b/src/Symfony/Component/Asset/Package.php
@@ -27,7 +27,7 @@ class Package implements PackageInterface
public function __construct(
private VersionStrategyInterface $versionStrategy,
- ContextInterface $context = null,
+ ?ContextInterface $context = null,
) {
$this->context = $context ?? new NullContext();
}
diff --git a/src/Symfony/Component/Asset/Packages.php b/src/Symfony/Component/Asset/Packages.php
index 8c31e21de280c..01b4e814cca58 100644
--- a/src/Symfony/Component/Asset/Packages.php
+++ b/src/Symfony/Component/Asset/Packages.php
@@ -54,7 +54,7 @@ public function addPackage(string $name, PackageInterface $package): void
* @throws InvalidArgumentException If there is no package by that name
* @throws LogicException If no default package is defined
*/
- public function getPackage(string $name = null): PackageInterface
+ public function getPackage(?string $name = null): PackageInterface
{
if (null === $name) {
if (null === $this->defaultPackage) {
@@ -77,7 +77,7 @@ public function getPackage(string $name = null): PackageInterface
* @param string $path A public path
* @param string|null $packageName A package name
*/
- public function getVersion(string $path, string $packageName = null): string
+ public function getVersion(string $path, ?string $packageName = null): string
{
return $this->getPackage($packageName)->getVersion($path);
}
@@ -92,7 +92,7 @@ public function getVersion(string $path, string $packageName = null): string
*
* @return string A public path which takes into account the base path and URL path
*/
- public function getUrl(string $path, string $packageName = null): string
+ public function getUrl(string $path, ?string $packageName = null): string
{
return $this->getPackage($packageName)->getUrl($path);
}
diff --git a/src/Symfony/Component/Asset/PathPackage.php b/src/Symfony/Component/Asset/PathPackage.php
index d8e08a3c34807..d03a8c8d1b7e4 100644
--- a/src/Symfony/Component/Asset/PathPackage.php
+++ b/src/Symfony/Component/Asset/PathPackage.php
@@ -31,7 +31,7 @@ class PathPackage extends Package
/**
* @param string $basePath The base path to be prepended to relative paths
*/
- public function __construct(string $basePath, VersionStrategyInterface $versionStrategy, ContextInterface $context = null)
+ public function __construct(string $basePath, VersionStrategyInterface $versionStrategy, ?ContextInterface $context = null)
{
parent::__construct($versionStrategy, $context);
diff --git a/src/Symfony/Component/Asset/UrlPackage.php b/src/Symfony/Component/Asset/UrlPackage.php
index 34c0e4ff909b9..0b884f42e9803 100644
--- a/src/Symfony/Component/Asset/UrlPackage.php
+++ b/src/Symfony/Component/Asset/UrlPackage.php
@@ -41,7 +41,7 @@ class UrlPackage extends Package
/**
* @param string|string[] $baseUrls Base asset URLs
*/
- public function __construct(string|array $baseUrls, VersionStrategyInterface $versionStrategy, ContextInterface $context = null)
+ public function __construct(string|array $baseUrls, VersionStrategyInterface $versionStrategy, ?ContextInterface $context = null)
{
parent::__construct($versionStrategy, $context);
diff --git a/src/Symfony/Component/Asset/VersionStrategy/StaticVersionStrategy.php b/src/Symfony/Component/Asset/VersionStrategy/StaticVersionStrategy.php
index 9fa2ee1d459c5..7df7c86cb6d2d 100644
--- a/src/Symfony/Component/Asset/VersionStrategy/StaticVersionStrategy.php
+++ b/src/Symfony/Component/Asset/VersionStrategy/StaticVersionStrategy.php
@@ -26,7 +26,7 @@ class StaticVersionStrategy implements VersionStrategyInterface
*/
public function __construct(
private string $version,
- string $format = null,
+ ?string $format = null,
) {
$this->format = $format ?: '%s?%s';
}
diff --git a/src/Symfony/Component/AssetMapper/AssetMapperDevServerSubscriber.php b/src/Symfony/Component/AssetMapper/AssetMapperDevServerSubscriber.php
index 4d6cb0682d7c6..abdedfa0099c8 100644
--- a/src/Symfony/Component/AssetMapper/AssetMapperDevServerSubscriber.php
+++ b/src/Symfony/Component/AssetMapper/AssetMapperDevServerSubscriber.php
@@ -119,7 +119,7 @@ public function onKernelRequest(RequestEvent $event): void
return;
}
- $pathInfo = $event->getRequest()->getPathInfo();
+ $pathInfo = rawurldecode($event->getRequest()->getPathInfo());
if (!str_starts_with($pathInfo, $this->publicPrefix)) {
return;
}
diff --git a/src/Symfony/Component/AssetMapper/AssetMapperRepository.php b/src/Symfony/Component/AssetMapper/AssetMapperRepository.php
index b001c49bead9e..f79d17318feec 100644
--- a/src/Symfony/Component/AssetMapper/AssetMapperRepository.php
+++ b/src/Symfony/Component/AssetMapper/AssetMapperRepository.php
@@ -34,6 +34,7 @@ public function __construct(
private readonly string $projectRootDir,
private readonly array $excludedPathPatterns = [],
private readonly bool $excludeDotFiles = true,
+ private readonly bool $debug = true,
) {
}
@@ -147,7 +148,7 @@ private function getDirectories(): array
$this->absolutePaths = [];
foreach ($this->paths as $path => $namespace) {
if ($filesystem->isAbsolutePath($path)) {
- if (!file_exists($path)) {
+ if (!file_exists($path) && $this->debug) {
throw new \InvalidArgumentException(sprintf('The asset mapper directory "%s" does not exist.', $path));
}
$this->absolutePaths[realpath($path)] = $namespace;
@@ -161,7 +162,9 @@ private function getDirectories(): array
continue;
}
- throw new \InvalidArgumentException(sprintf('The asset mapper directory "%s" does not exist.', $path));
+ if ($this->debug) {
+ throw new \InvalidArgumentException(sprintf('The asset mapper directory "%s" does not exist.', $path));
+ }
}
return $this->absolutePaths;
diff --git a/src/Symfony/Component/AssetMapper/Compiler/CssAssetUrlCompiler.php b/src/Symfony/Component/AssetMapper/Compiler/CssAssetUrlCompiler.php
index c159f97ef0aa6..09a8beb8b1a2c 100644
--- a/src/Symfony/Component/AssetMapper/Compiler/CssAssetUrlCompiler.php
+++ b/src/Symfony/Component/AssetMapper/Compiler/CssAssetUrlCompiler.php
@@ -70,7 +70,7 @@ public function supports(MappedAsset $asset): bool
return 'css' === $asset->publicExtension;
}
- private function handleMissingImport(string $message, \Throwable $e = null): void
+ private function handleMissingImport(string $message, ?\Throwable $e = null): void
{
match ($this->missingImportMode) {
AssetCompilerInterface::MISSING_IMPORT_IGNORE => null,
diff --git a/src/Symfony/Component/AssetMapper/Compiler/JavaScriptImportPathCompiler.php b/src/Symfony/Component/AssetMapper/Compiler/JavaScriptImportPathCompiler.php
index 93e04846fce96..be81a58027edf 100644
--- a/src/Symfony/Component/AssetMapper/Compiler/JavaScriptImportPathCompiler.php
+++ b/src/Symfony/Component/AssetMapper/Compiler/JavaScriptImportPathCompiler.php
@@ -27,8 +27,8 @@
*/
final class JavaScriptImportPathCompiler implements AssetCompilerInterface
{
- // https://regex101.com/r/fquriB/1
- private const IMPORT_PATTERN = '/(?:import\s*(?:(?:\*\s*as\s+\w+|[\w\s{},*]+)\s*from\s*)?|\bimport\()\s*[\'"`](\.\/[^\'"`]+|(\.\.\/)*[^\'"`]+)[\'"`]\s*[;\)]?/m';
+ // https://regex101.com/r/qFoeoR/1
+ private const IMPORT_PATTERN = '/(?:\'(?:[^\'\\\\]|\\\\.)*\'|"(?:[^"\\\\]|\\\\.)*")|(?:import\s*(?:(?:\*\s*as\s+\w+|[\w\s{},*]+)\s*from\s*)?|\bimport\()\s*[\'"`](\.\/[^\'"`]+|(\.\.\/)*[^\'"`]+)[\'"`]\s*[;\)]?/m';
public function __construct(
private readonly ImportMapConfigReader $importMapConfigReader,
@@ -42,6 +42,11 @@ public function compile(string $content, MappedAsset $asset, AssetMapperInterfac
return preg_replace_callback(self::IMPORT_PATTERN, function ($matches) use ($asset, $assetMapper, $content) {
$fullImportString = $matches[0][0];
+ // Ignore enquoted strings (e.g. console.log("import 'foo';")
+ if (!isset($matches[1][0])) {
+ return $fullImportString;
+ }
+
if ($this->isCommentedOut($matches[0][1], $content)) {
return $fullImportString;
}
@@ -105,7 +110,7 @@ private function makeRelativeForJavaScript(string $path): string
return './'.$path;
}
- private function handleMissingImport(string $message, \Throwable $e = null): void
+ private function handleMissingImport(string $message, ?\Throwable $e = null): void
{
match ($this->missingImportMode) {
AssetCompilerInterface::MISSING_IMPORT_IGNORE => null,
diff --git a/src/Symfony/Component/AssetMapper/Exception/CircularAssetsException.php b/src/Symfony/Component/AssetMapper/Exception/CircularAssetsException.php
index a7e39ace40cbc..fc61149370dfd 100644
--- a/src/Symfony/Component/AssetMapper/Exception/CircularAssetsException.php
+++ b/src/Symfony/Component/AssetMapper/Exception/CircularAssetsException.php
@@ -18,7 +18,7 @@
*/
class CircularAssetsException extends RuntimeException
{
- public function __construct(private MappedAsset $mappedAsset, string $message = '', int $code = 0, \Throwable $previous = null)
+ public function __construct(private MappedAsset $mappedAsset, string $message = '', int $code = 0, ?\Throwable $previous = null)
{
parent::__construct($message, $code, $previous);
}
diff --git a/src/Symfony/Component/AssetMapper/ImportMap/ImportMapAuditor.php b/src/Symfony/Component/AssetMapper/ImportMap/ImportMapAuditor.php
index 112e68906dfd7..f53e8df2df704 100644
--- a/src/Symfony/Component/AssetMapper/ImportMap/ImportMapAuditor.php
+++ b/src/Symfony/Component/AssetMapper/ImportMap/ImportMapAuditor.php
@@ -23,7 +23,7 @@ class ImportMapAuditor
public function __construct(
private readonly ImportMapConfigReader $configReader,
- HttpClientInterface $httpClient = null,
+ ?HttpClientInterface $httpClient = null,
) {
$this->httpClient = $httpClient ?? HttpClient::create();
}
diff --git a/src/Symfony/Component/AssetMapper/ImportMap/ImportMapVersionChecker.php b/src/Symfony/Component/AssetMapper/ImportMap/ImportMapVersionChecker.php
index d07d8ce1ac2f1..b0af5736eb821 100644
--- a/src/Symfony/Component/AssetMapper/ImportMap/ImportMapVersionChecker.php
+++ b/src/Symfony/Component/AssetMapper/ImportMap/ImportMapVersionChecker.php
@@ -26,7 +26,7 @@ class ImportMapVersionChecker
public function __construct(
private ImportMapConfigReader $importMapConfigReader,
private RemotePackageDownloader $packageDownloader,
- HttpClientInterface $httpClient = null,
+ ?HttpClientInterface $httpClient = null,
) {
$this->httpClient = $httpClient ?? HttpClient::create();
}
diff --git a/src/Symfony/Component/AssetMapper/ImportMap/PackageRequireOptions.php b/src/Symfony/Component/AssetMapper/ImportMap/PackageRequireOptions.php
index 6875bca9d1e59..c1bb34a8f66cd 100644
--- a/src/Symfony/Component/AssetMapper/ImportMap/PackageRequireOptions.php
+++ b/src/Symfony/Component/AssetMapper/ImportMap/PackageRequireOptions.php
@@ -26,7 +26,7 @@ public function __construct(
*/
public readonly string $packageModuleSpecifier,
public readonly ?string $versionConstraint = null,
- string $importName = null,
+ ?string $importName = null,
public readonly ?string $path = null,
public readonly bool $entrypoint = false,
) {
diff --git a/src/Symfony/Component/AssetMapper/ImportMap/RemotePackageDownloader.php b/src/Symfony/Component/AssetMapper/ImportMap/RemotePackageDownloader.php
index a5f2849817eec..0d18ef2c5d533 100644
--- a/src/Symfony/Component/AssetMapper/ImportMap/RemotePackageDownloader.php
+++ b/src/Symfony/Component/AssetMapper/ImportMap/RemotePackageDownloader.php
@@ -32,7 +32,7 @@ public function __construct(
*
* @return string[] The downloaded packages
*/
- public function downloadPackages(callable $progressCallback = null): array
+ public function downloadPackages(?callable $progressCallback = null): array
{
try {
$installed = $this->loadInstalled();
diff --git a/src/Symfony/Component/AssetMapper/ImportMap/Resolver/JsDelivrEsmResolver.php b/src/Symfony/Component/AssetMapper/ImportMap/Resolver/JsDelivrEsmResolver.php
index 082e790be399f..0788bbb77385c 100644
--- a/src/Symfony/Component/AssetMapper/ImportMap/Resolver/JsDelivrEsmResolver.php
+++ b/src/Symfony/Component/AssetMapper/ImportMap/Resolver/JsDelivrEsmResolver.php
@@ -35,7 +35,7 @@ final class JsDelivrEsmResolver implements PackageResolverInterface
private HttpClientInterface $httpClient;
public function __construct(
- HttpClientInterface $httpClient = null,
+ ?HttpClientInterface $httpClient = null,
) {
$this->httpClient = $httpClient ?? HttpClient::create();
}
@@ -163,7 +163,7 @@ public function resolvePackages(array $packagesToRequire): array
*
* @return array}>
*/
- public function downloadPackages(array $importMapEntries, callable $progressCallback = null): array
+ public function downloadPackages(array $importMapEntries, ?callable $progressCallback = null): array
{
$responses = [];
foreach ($importMapEntries as $package => $entry) {
@@ -336,7 +336,7 @@ private function makeImportsBare(string $content, array &$dependencies, array &$
/**
* Determine the URL pattern to be used by the HTTP Client.
*/
- private function resolveUrlPattern(string $packageName, string $path, ImportMapType $type = null): string
+ private function resolveUrlPattern(string $packageName, string $path, ?ImportMapType $type = null): string
{
// The URL for the es-module-shims polyfill package uses the CSS pattern to
// prevent a syntax error in the browser console, so check the package name
diff --git a/src/Symfony/Component/AssetMapper/ImportMap/Resolver/PackageResolverInterface.php b/src/Symfony/Component/AssetMapper/ImportMap/Resolver/PackageResolverInterface.php
index defd04716baa3..354fa9d151be7 100644
--- a/src/Symfony/Component/AssetMapper/ImportMap/Resolver/PackageResolverInterface.php
+++ b/src/Symfony/Component/AssetMapper/ImportMap/Resolver/PackageResolverInterface.php
@@ -39,5 +39,5 @@ public function resolvePackages(array $packagesToRequire): array;
*
* @return array}>
*/
- public function downloadPackages(array $importMapEntries, callable $progressCallback = null): array;
+ public function downloadPackages(array $importMapEntries, ?callable $progressCallback = null): array;
}
diff --git a/src/Symfony/Component/AssetMapper/MappedAsset.php b/src/Symfony/Component/AssetMapper/MappedAsset.php
index 0962ec1c3fb73..763e3ccc03ccc 100644
--- a/src/Symfony/Component/AssetMapper/MappedAsset.php
+++ b/src/Symfony/Component/AssetMapper/MappedAsset.php
@@ -59,12 +59,12 @@ final class MappedAsset
*/
public function __construct(
public readonly string $logicalPath,
- string $sourcePath = null,
- string $publicPathWithoutDigest = null,
- string $publicPath = null,
- string $content = null,
- string $digest = null,
- bool $isPredigested = null,
+ ?string $sourcePath = null,
+ ?string $publicPathWithoutDigest = null,
+ ?string $publicPath = null,
+ ?string $content = null,
+ ?string $digest = null,
+ ?bool $isPredigested = null,
bool $isVendor = false,
array $dependencies = [],
array $fileDependencies = [],
diff --git a/src/Symfony/Component/AssetMapper/Tests/AssetMapperDevServerSubscriberFunctionalTest.php b/src/Symfony/Component/AssetMapper/Tests/AssetMapperDevServerSubscriberFunctionalTest.php
index f83ff87f9426c..c6b2e7ecae9a6 100644
--- a/src/Symfony/Component/AssetMapper/Tests/AssetMapperDevServerSubscriberFunctionalTest.php
+++ b/src/Symfony/Component/AssetMapper/Tests/AssetMapperDevServerSubscriberFunctionalTest.php
@@ -35,6 +35,20 @@ public function testGettingAssetWorks()
$this->assertTrue($response->headers->has('X-Assets-Dev'));
}
+ public function testGettingAssetWithNonAsciiFilenameWorks()
+ {
+ $client = static::createClient();
+
+ $client->request('GET', '/assets/voilà-6344422da690fcc471f23f7a8966cd1c.css');
+ $response = $client->getResponse();
+ $this->assertSame(200, $response->getStatusCode());
+ $this->assertSame(<<getInternalResponse()->getContent());
+ }
+
public function test404OnUnknownAsset()
{
$client = static::createClient();
diff --git a/src/Symfony/Component/AssetMapper/Tests/Command/AssetMapperCompileCommandTest.php b/src/Symfony/Component/AssetMapper/Tests/Command/AssetMapperCompileCommandTest.php
index 05283f33df5d7..ec7e3835b8a86 100644
--- a/src/Symfony/Component/AssetMapper/Tests/Command/AssetMapperCompileCommandTest.php
+++ b/src/Symfony/Component/AssetMapper/Tests/Command/AssetMapperCompileCommandTest.php
@@ -69,7 +69,7 @@ public function testAssetsAreCompiled()
$finder = new Finder();
$finder->in($targetBuildDir)->files();
- $this->assertCount(12, $finder); // 9 files + manifest.json & importmap.json + entrypoint.file6.json
+ $this->assertCount(13, $finder); // 10 files + manifest.json & importmap.json + entrypoint.file6.json
$this->assertFileExists($targetBuildDir.'/manifest.json');
$this->assertSame([
@@ -82,6 +82,7 @@ public function testAssetsAreCompiled()
'subdir/file6.js',
'vendor/@hotwired/stimulus/stimulus.index.js',
'vendor/lodash/lodash.index.js',
+ 'voilà.css',
], array_keys(json_decode(file_get_contents($targetBuildDir.'/manifest.json'), true)));
$this->assertFileExists($targetBuildDir.'/importmap.json');
diff --git a/src/Symfony/Component/AssetMapper/Tests/Compiler/JavaScriptImportPathCompilerTest.php b/src/Symfony/Component/AssetMapper/Tests/Compiler/JavaScriptImportPathCompilerTest.php
index c0894825b62aa..e616211b5b9dc 100644
--- a/src/Symfony/Component/AssetMapper/Tests/Compiler/JavaScriptImportPathCompilerTest.php
+++ b/src/Symfony/Component/AssetMapper/Tests/Compiler/JavaScriptImportPathCompilerTest.php
@@ -67,6 +67,7 @@ public function testCompileFindsCorrectImports(string $input, array $expectedJav
->method('getAssetFromSourcePath')
->willReturnCallback(function ($path) {
return match ($path) {
+ '/project/assets/foo.js' => new MappedAsset('foo.js', '/can/be/anything.js', publicPathWithoutDigest: '/assets/foo.js'),
'/project/assets/other.js' => new MappedAsset('other.js', '/can/be/anything.js', publicPathWithoutDigest: '/assets/other.js'),
'/project/assets/subdir/foo.js' => new MappedAsset('subdir/foo.js', '/can/be/anything.js', publicPathWithoutDigest: '/assets/subdir/foo.js'),
'/project/assets/styles.css' => new MappedAsset('styles.css', '/can/be/anything.js', publicPathWithoutDigest: '/assets/styles.css'),
@@ -269,6 +270,63 @@ public static function provideCompileTests(): iterable
'expectedJavaScriptImports' => ['/assets/other.js' => ['lazy' => true, 'asset' => 'other.js', 'add' => true]],
];
+ yield 'import_in_double_quoted_string_is_ignored' => [
+ 'input' => << [],
+ ];
+
+ yield 'import_in_double_quoted_string_with_escaped_quote_is_ignored' => [
+ 'input' => << [],
+ ];
+
+ yield 'import_in_single_quoted_string_is_ignored' => [
+ 'input' => << [],
+ ];
+
+ yield 'import_after_a_string_is_parsed' => [
+ 'input' => << ['/assets/foo.js' => ['lazy' => true, 'asset' => 'foo.js', 'add' => true]],
+ ];
+
+ yield 'import_before_a_string_is_parsed' => [
+ 'input' => << ['/assets/other.js' => ['lazy' => true, 'asset' => 'other.js', 'add' => true]],
+ ];
+
+ yield 'import_before_and_after_a_string_is_parsed' => [
+ 'input' => << [
+ '/assets/other.js' => ['lazy' => true, 'asset' => 'other.js', 'add' => true],
+ '/assets/subdir/foo.js' => ['lazy' => true, 'asset' => 'subdir/foo.js', 'add' => true],
+ ],
+ ];
+
yield 'bare_import_not_in_importmap' => [
'input' => 'import "some_module";',
'expectedJavaScriptImports' => [],
diff --git a/src/Symfony/Component/AssetMapper/Tests/Factory/MappedAssetFactoryTest.php b/src/Symfony/Component/AssetMapper/Tests/Factory/MappedAssetFactoryTest.php
index 8127bd3d3be3a..d4e129a50ccfc 100644
--- a/src/Symfony/Component/AssetMapper/Tests/Factory/MappedAssetFactoryTest.php
+++ b/src/Symfony/Component/AssetMapper/Tests/Factory/MappedAssetFactoryTest.php
@@ -137,7 +137,7 @@ public function testCreateMappedAssetInVendor()
$this->assertTrue($asset->isVendor);
}
- private function createFactory(AssetCompilerInterface $extraCompiler = null): MappedAssetFactory
+ private function createFactory(?AssetCompilerInterface $extraCompiler = null): MappedAssetFactory
{
$compilers = [
new JavaScriptImportPathCompiler($this->createMock(ImportMapConfigReader::class)),
diff --git a/src/Symfony/Component/AssetMapper/Tests/Fixtures/AssetMapperTestAppKernel.php b/src/Symfony/Component/AssetMapper/Tests/Fixtures/AssetMapperTestAppKernel.php
index 52092b6bf6eae..d8c44a257bdc3 100644
--- a/src/Symfony/Component/AssetMapper/Tests/Fixtures/AssetMapperTestAppKernel.php
+++ b/src/Symfony/Component/AssetMapper/Tests/Fixtures/AssetMapperTestAppKernel.php
@@ -43,7 +43,7 @@ public function registerContainerConfiguration(LoaderInterface $loader): void
'http_client' => true,
'assets' => null,
'asset_mapper' => [
- 'paths' => ['dir1', 'dir2', 'assets'],
+ 'paths' => ['dir1', 'dir2', 'non_ascii', 'assets'],
],
'test' => true,
]);
diff --git "a/src/Symfony/Component/AssetMapper/Tests/Fixtures/non_ascii/voil\303\240.css" "b/src/Symfony/Component/AssetMapper/Tests/Fixtures/non_ascii/voil\303\240.css"
new file mode 100644
index 0000000000000..f9a66cb6613c8
--- /dev/null
+++ "b/src/Symfony/Component/AssetMapper/Tests/Fixtures/non_ascii/voil\303\240.css"
@@ -0,0 +1,2 @@
+/* voilà.css */
+body {}
diff --git a/src/Symfony/Component/AssetMapper/Tests/ImportMap/ImportMapGeneratorTest.php b/src/Symfony/Component/AssetMapper/Tests/ImportMap/ImportMapGeneratorTest.php
index 273e02747a24c..deafa38e2cef8 100644
--- a/src/Symfony/Component/AssetMapper/Tests/ImportMap/ImportMapGeneratorTest.php
+++ b/src/Symfony/Component/AssetMapper/Tests/ImportMap/ImportMapGeneratorTest.php
@@ -745,7 +745,7 @@ private static function createLocalEntry(string $importName, string $path, Impor
return ImportMapEntry::createLocal($importName, $type, path: $path, isEntrypoint: $isEntrypoint);
}
- private static function createRemoteEntry(string $importName, string $version, string $path = null, ImportMapType $type = ImportMapType::JS, string $packageSpecifier = null): ImportMapEntry
+ private static function createRemoteEntry(string $importName, string $version, ?string $path = null, ImportMapType $type = ImportMapType::JS, ?string $packageSpecifier = null): ImportMapEntry
{
$packageSpecifier = $packageSpecifier ?? $importName;
$path = $path ?? '/vendor/any-path.js';
diff --git a/src/Symfony/Component/AssetMapper/Tests/ImportMap/ImportMapManagerTest.php b/src/Symfony/Component/AssetMapper/Tests/ImportMap/ImportMapManagerTest.php
index 6ab4363b7fddc..3198b11ee76a6 100644
--- a/src/Symfony/Component/AssetMapper/Tests/ImportMap/ImportMapManagerTest.php
+++ b/src/Symfony/Component/AssetMapper/Tests/ImportMap/ImportMapManagerTest.php
@@ -425,7 +425,7 @@ private static function createLocalEntry(string $importName, string $path, Impor
return ImportMapEntry::createLocal($importName, $type, path: $path, isEntrypoint: $isEntrypoint);
}
- private static function createRemoteEntry(string $importName, string $version, string $path = null, ImportMapType $type = ImportMapType::JS, string $packageSpecifier = null): ImportMapEntry
+ private static function createRemoteEntry(string $importName, string $version, ?string $path = null, ImportMapType $type = ImportMapType::JS, ?string $packageSpecifier = null): ImportMapEntry
{
$packageSpecifier = $packageSpecifier ?? $importName;
$path = $path ?? '/vendor/any-path.js';
diff --git a/src/Symfony/Component/AssetMapper/Tests/ImportMap/ImportMapUpdateCheckerTest.php b/src/Symfony/Component/AssetMapper/Tests/ImportMap/ImportMapUpdateCheckerTest.php
index 7356fb758877c..e01a2362a85f0 100644
--- a/src/Symfony/Component/AssetMapper/Tests/ImportMap/ImportMapUpdateCheckerTest.php
+++ b/src/Symfony/Component/AssetMapper/Tests/ImportMap/ImportMapUpdateCheckerTest.php
@@ -205,7 +205,7 @@ private function responseFactory($method, $url): MockResponse
return $map[$url] ?? new MockResponse('Not found', ['http_code' => 404]);
}
- private static function createRemoteEntry(string $importName, string $version, ImportMapType $type = ImportMapType::JS, string $packageSpecifier = null): ImportMapEntry
+ private static function createRemoteEntry(string $importName, string $version, ImportMapType $type = ImportMapType::JS, ?string $packageSpecifier = null): ImportMapEntry
{
$packageSpecifier = $packageSpecifier ?? $importName;
diff --git a/src/Symfony/Component/AssetMapper/Tests/ImportMap/ImportMapVersionCheckerTest.php b/src/Symfony/Component/AssetMapper/Tests/ImportMap/ImportMapVersionCheckerTest.php
index 5eab19b2f6b6c..43346d3de33aa 100644
--- a/src/Symfony/Component/AssetMapper/Tests/ImportMap/ImportMapVersionCheckerTest.php
+++ b/src/Symfony/Component/AssetMapper/Tests/ImportMap/ImportMapVersionCheckerTest.php
@@ -405,7 +405,7 @@ public static function getNpmSpecificVersionConstraints()
];
}
- private static function createRemoteEntry(string $importName, string $version, string $packageModuleSpecifier = null): ImportMapEntry
+ private static function createRemoteEntry(string $importName, string $version, ?string $packageModuleSpecifier = null): ImportMapEntry
{
$packageModuleSpecifier = $packageModuleSpecifier ?? $importName;
diff --git a/src/Symfony/Component/AssetMapper/Tests/ImportMap/Resolver/JsDelivrEsmResolverTest.php b/src/Symfony/Component/AssetMapper/Tests/ImportMap/Resolver/JsDelivrEsmResolverTest.php
index 50eb55228b338..f5fb90d2c90c9 100644
--- a/src/Symfony/Component/AssetMapper/Tests/ImportMap/Resolver/JsDelivrEsmResolverTest.php
+++ b/src/Symfony/Component/AssetMapper/Tests/ImportMap/Resolver/JsDelivrEsmResolverTest.php
@@ -688,7 +688,7 @@ public static function provideImportRegex(): iterable
];
}
- private static function createRemoteEntry(string $importName, string $version, ImportMapType $type = ImportMapType::JS, string $packageSpecifier = null): ImportMapEntry
+ private static function createRemoteEntry(string $importName, string $version, ImportMapType $type = ImportMapType::JS, ?string $packageSpecifier = null): ImportMapEntry
{
$packageSpecifier = $packageSpecifier ?? $importName;
diff --git a/src/Symfony/Component/BrowserKit/AbstractBrowser.php b/src/Symfony/Component/BrowserKit/AbstractBrowser.php
index 90f55999c4c9e..d4b5a43aa68fa 100644
--- a/src/Symfony/Component/BrowserKit/AbstractBrowser.php
+++ b/src/Symfony/Component/BrowserKit/AbstractBrowser.php
@@ -54,7 +54,7 @@ abstract class AbstractBrowser
/**
* @param array $server The server parameters (equivalent of $_SERVER)
*/
- public function __construct(array $server = [], History $history = null, CookieJar $cookieJar = null)
+ public function __construct(array $server = [], ?History $history = null, ?CookieJar $cookieJar = null)
{
$this->setServerParameters($server);
$this->history = $history ?? new History();
@@ -142,7 +142,7 @@ public function getServerParameter(string $key, mixed $default = ''): mixed
return $this->server[$key] ?? $default;
}
- public function xmlHttpRequest(string $method, string $uri, array $parameters = [], array $files = [], array $server = [], string $content = null, bool $changeHistory = true): Crawler
+ public function xmlHttpRequest(string $method, string $uri, array $parameters = [], array $files = [], array $server = [], ?string $content = null, bool $changeHistory = true): Crawler
{
$this->setServerParameter('HTTP_X_REQUESTED_WITH', 'XMLHttpRequest');
@@ -323,7 +323,7 @@ public function submitForm(string $button, array $fieldValues = [], string $meth
* @param string $content The raw body data
* @param bool $changeHistory Whether to update the history or not (only used internally for back(), forward(), and reload())
*/
- public function request(string $method, string $uri, array $parameters = [], array $files = [], array $server = [], string $content = null, bool $changeHistory = true): Crawler
+ public function request(string $method, string $uri, array $parameters = [], array $files = [], array $server = [], ?string $content = null, bool $changeHistory = true): Crawler
{
if ($this->isMainRequest) {
$this->redirectCount = 0;
diff --git a/src/Symfony/Component/BrowserKit/Cookie.php b/src/Symfony/Component/BrowserKit/Cookie.php
index 992eeed7c7bbb..c3d1af3812436 100644
--- a/src/Symfony/Component/BrowserKit/Cookie.php
+++ b/src/Symfony/Component/BrowserKit/Cookie.php
@@ -56,8 +56,8 @@ class Cookie
public function __construct(
private string $name,
?string $value,
- string $expires = null,
- string $path = null,
+ ?string $expires = null,
+ ?string $path = null,
private string $domain = '',
private bool $secure = false,
private bool $httponly = true,
@@ -123,7 +123,7 @@ public function __toString(): string
*
* @throws InvalidArgumentException
*/
- public static function fromString(string $cookie, string $url = null): static
+ public static function fromString(string $cookie, ?string $url = null): static
{
$parts = explode(';', $cookie);
diff --git a/src/Symfony/Component/BrowserKit/CookieJar.php b/src/Symfony/Component/BrowserKit/CookieJar.php
index 59445d5fbea2f..bdaf65ef56052 100644
--- a/src/Symfony/Component/BrowserKit/CookieJar.php
+++ b/src/Symfony/Component/BrowserKit/CookieJar.php
@@ -35,7 +35,7 @@ public function set(Cookie $cookie): void
* (this behavior ensures a BC behavior with previous versions of
* Symfony).
*/
- public function get(string $name, string $path = '/', string $domain = null): ?Cookie
+ public function get(string $name, string $path = '/', ?string $domain = null): ?Cookie
{
$this->flushExpiredCookies();
@@ -67,7 +67,7 @@ public function get(string $name, string $path = '/', string $domain = null): ?C
* all cookies for the given name/path expire (this behavior
* ensures a BC behavior with previous versions of Symfony).
*/
- public function expire(string $name, ?string $path = '/', string $domain = null): void
+ public function expire(string $name, ?string $path = '/', ?string $domain = null): void
{
$path ??= '/';
@@ -105,7 +105,7 @@ public function clear(): void
*
* @param string[] $setCookies Set-Cookie headers from an HTTP response
*/
- public function updateFromSetCookie(array $setCookies, string $uri = null): void
+ public function updateFromSetCookie(array $setCookies, ?string $uri = null): void
{
$cookies = [];
@@ -131,7 +131,7 @@ public function updateFromSetCookie(array $setCookies, string $uri = null): void
/**
* Updates the cookie jar from a Response object.
*/
- public function updateFromResponse(Response $response, string $uri = null): void
+ public function updateFromResponse(Response $response, ?string $uri = null): void
{
$this->updateFromSetCookie($response->getHeader('Set-Cookie', false), $uri);
}
diff --git a/src/Symfony/Component/BrowserKit/HttpBrowser.php b/src/Symfony/Component/BrowserKit/HttpBrowser.php
index 4b61c86ec79e6..9d84bda751ba5 100644
--- a/src/Symfony/Component/BrowserKit/HttpBrowser.php
+++ b/src/Symfony/Component/BrowserKit/HttpBrowser.php
@@ -29,7 +29,7 @@ class HttpBrowser extends AbstractBrowser
{
private HttpClientInterface $client;
- public function __construct(HttpClientInterface $client = null, History $history = null, CookieJar $cookieJar = null)
+ public function __construct(?HttpClientInterface $client = null, ?History $history = null, ?CookieJar $cookieJar = null)
{
if (!$client && !class_exists(HttpClient::class)) {
throw new LogicException(sprintf('You cannot use "%s" as the HttpClient component is not installed. Try running "composer require symfony/http-client".', __CLASS__));
diff --git a/src/Symfony/Component/BrowserKit/Test/Constraint/BrowserCookieValueSame.php b/src/Symfony/Component/BrowserKit/Test/Constraint/BrowserCookieValueSame.php
index ef9b4a05920b8..b3aa746ee3dfa 100644
--- a/src/Symfony/Component/BrowserKit/Test/Constraint/BrowserCookieValueSame.php
+++ b/src/Symfony/Component/BrowserKit/Test/Constraint/BrowserCookieValueSame.php
@@ -22,7 +22,7 @@ final class BrowserCookieValueSame extends Constraint
private string $path;
private ?string $domain;
- public function __construct(string $name, string $value, bool $raw = false, string $path = '/', string $domain = null)
+ public function __construct(string $name, string $value, bool $raw = false, string $path = '/', ?string $domain = null)
{
$this->name = $name;
$this->path = $path;
diff --git a/src/Symfony/Component/BrowserKit/Test/Constraint/BrowserHasCookie.php b/src/Symfony/Component/BrowserKit/Test/Constraint/BrowserHasCookie.php
index e6d7ab4f48475..ae39d61d646f1 100644
--- a/src/Symfony/Component/BrowserKit/Test/Constraint/BrowserHasCookie.php
+++ b/src/Symfony/Component/BrowserKit/Test/Constraint/BrowserHasCookie.php
@@ -20,7 +20,7 @@ final class BrowserHasCookie extends Constraint
private string $path;
private ?string $domain;
- public function __construct(string $name, string $path = '/', string $domain = null)
+ public function __construct(string $name, string $path = '/', ?string $domain = null)
{
$this->name = $name;
$this->path = $path;
diff --git a/src/Symfony/Component/BrowserKit/Tests/AbstractBrowserTest.php b/src/Symfony/Component/BrowserKit/Tests/AbstractBrowserTest.php
index e136a9049d25d..2267fca448799 100644
--- a/src/Symfony/Component/BrowserKit/Tests/AbstractBrowserTest.php
+++ b/src/Symfony/Component/BrowserKit/Tests/AbstractBrowserTest.php
@@ -21,7 +21,7 @@
class AbstractBrowserTest extends TestCase
{
- public function getBrowser(array $server = [], History $history = null, CookieJar $cookieJar = null)
+ public function getBrowser(array $server = [], ?History $history = null, ?CookieJar $cookieJar = null)
{
return new TestClient($server, $history, $cookieJar);
}
diff --git a/src/Symfony/Component/BrowserKit/Tests/HttpBrowserTest.php b/src/Symfony/Component/BrowserKit/Tests/HttpBrowserTest.php
index 44f61289d8d6a..e1f19b16ce814 100644
--- a/src/Symfony/Component/BrowserKit/Tests/HttpBrowserTest.php
+++ b/src/Symfony/Component/BrowserKit/Tests/HttpBrowserTest.php
@@ -19,7 +19,7 @@
class HttpBrowserTest extends AbstractBrowserTest
{
- public function getBrowser(array $server = [], History $history = null, CookieJar $cookieJar = null)
+ public function getBrowser(array $server = [], ?History $history = null, ?CookieJar $cookieJar = null)
{
return new TestHttpClient($server, $history, $cookieJar);
}
diff --git a/src/Symfony/Component/BrowserKit/Tests/TestHttpClient.php b/src/Symfony/Component/BrowserKit/Tests/TestHttpClient.php
index c11e6831847b4..3d0a354f5b340 100644
--- a/src/Symfony/Component/BrowserKit/Tests/TestHttpClient.php
+++ b/src/Symfony/Component/BrowserKit/Tests/TestHttpClient.php
@@ -23,7 +23,7 @@ class TestHttpClient extends HttpBrowser
protected ?Response $nextResponse = null;
protected string $nextScript;
- public function __construct(array $server = [], History $history = null, CookieJar $cookieJar = null)
+ public function __construct(array $server = [], ?History $history = null, ?CookieJar $cookieJar = null)
{
$client = new MockHttpClient(function (string $method, string $url, array $options) {
if (null === $this->nextResponse) {
diff --git a/src/Symfony/Component/Cache/Adapter/AbstractAdapter.php b/src/Symfony/Component/Cache/Adapter/AbstractAdapter.php
index 68db8c16959eb..1d88fbf87ddeb 100644
--- a/src/Symfony/Component/Cache/Adapter/AbstractAdapter.php
+++ b/src/Symfony/Component/Cache/Adapter/AbstractAdapter.php
@@ -86,7 +86,7 @@ static function ($deferred, $namespace, &$expiredIds, $getId, $defaultLifetime)
*
* Using ApcuAdapter makes system caches compatible with read-only filesystems.
*/
- public static function createSystemCache(string $namespace, int $defaultLifetime, string $version, string $directory, LoggerInterface $logger = null): AdapterInterface
+ public static function createSystemCache(string $namespace, int $defaultLifetime, string $version, string $directory, ?LoggerInterface $logger = null): AdapterInterface
{
$opcache = new PhpFilesAdapter($namespace, $defaultLifetime, $directory, true);
if (null !== $logger) {
diff --git a/src/Symfony/Component/Cache/Adapter/ApcuAdapter.php b/src/Symfony/Component/Cache/Adapter/ApcuAdapter.php
index 6bd36cdb5c966..03b512f05e3f9 100644
--- a/src/Symfony/Component/Cache/Adapter/ApcuAdapter.php
+++ b/src/Symfony/Component/Cache/Adapter/ApcuAdapter.php
@@ -26,7 +26,7 @@ class ApcuAdapter extends AbstractAdapter
public function __construct(
string $namespace = '',
int $defaultLifetime = 0,
- string $version = null,
+ ?string $version = null,
private ?MarshallerInterface $marshaller = null,
) {
if (!static::isSupported()) {
diff --git a/src/Symfony/Component/Cache/Adapter/ArrayAdapter.php b/src/Symfony/Component/Cache/Adapter/ArrayAdapter.php
index f54cff4c56548..0f1c49db902aa 100644
--- a/src/Symfony/Component/Cache/Adapter/ArrayAdapter.php
+++ b/src/Symfony/Component/Cache/Adapter/ArrayAdapter.php
@@ -70,7 +70,7 @@ static function ($key, $value, $isHit, $tags) {
);
}
- public function get(string $key, callable $callback, float $beta = null, array &$metadata = null): mixed
+ public function get(string $key, callable $callback, ?float $beta = null, ?array &$metadata = null): mixed
{
$item = $this->getItem($key);
$metadata = $item->getMetadata();
diff --git a/src/Symfony/Component/Cache/Adapter/ChainAdapter.php b/src/Symfony/Component/Cache/Adapter/ChainAdapter.php
index 3d0edb60d4e45..1418cff04a635 100644
--- a/src/Symfony/Component/Cache/Adapter/ChainAdapter.php
+++ b/src/Symfony/Component/Cache/Adapter/ChainAdapter.php
@@ -88,7 +88,7 @@ static function ($sourceItem, $item, $defaultLifetime, $sourceMetadata = null) {
);
}
- public function get(string $key, callable $callback, float $beta = null, array &$metadata = null): mixed
+ public function get(string $key, callable $callback, ?float $beta = null, ?array &$metadata = null): mixed
{
$doSave = true;
$callback = static function (CacheItem $item, bool &$save) use ($callback, &$doSave) {
@@ -98,7 +98,7 @@ public function get(string $key, callable $callback, float $beta = null, array &
return $value;
};
- $wrap = function (CacheItem $item = null, bool &$save = true) use ($key, $callback, $beta, &$wrap, &$doSave, &$metadata) {
+ $wrap = function (?CacheItem $item = null, bool &$save = true) use ($key, $callback, $beta, &$wrap, &$doSave, &$metadata) {
static $lastItem;
static $i = 0;
$adapter = $this->adapters[$i];
diff --git a/src/Symfony/Component/Cache/Adapter/CouchbaseBucketAdapter.php b/src/Symfony/Component/Cache/Adapter/CouchbaseBucketAdapter.php
index 6c04859d148a1..1e5190f3d44e5 100644
--- a/src/Symfony/Component/Cache/Adapter/CouchbaseBucketAdapter.php
+++ b/src/Symfony/Component/Cache/Adapter/CouchbaseBucketAdapter.php
@@ -46,7 +46,7 @@ public function __construct(
private \CouchbaseBucket $bucket,
string $namespace = '',
int $defaultLifetime = 0,
- MarshallerInterface $marshaller = null,
+ ?MarshallerInterface $marshaller = null,
) {
if (!static::isSupported()) {
throw new CacheException('Couchbase >= 2.6.0 < 3.0.0 is required.');
diff --git a/src/Symfony/Component/Cache/Adapter/CouchbaseCollectionAdapter.php b/src/Symfony/Component/Cache/Adapter/CouchbaseCollectionAdapter.php
index 5cc4af1ad8a86..9646bc340fdef 100644
--- a/src/Symfony/Component/Cache/Adapter/CouchbaseCollectionAdapter.php
+++ b/src/Symfony/Component/Cache/Adapter/CouchbaseCollectionAdapter.php
@@ -35,7 +35,7 @@ public function __construct(
private Collection $connection,
string $namespace = '',
int $defaultLifetime = 0,
- MarshallerInterface $marshaller = null,
+ ?MarshallerInterface $marshaller = null,
) {
if (!static::isSupported()) {
throw new CacheException('Couchbase >= 3.0.5 < 4.0.0 is required.');
diff --git a/src/Symfony/Component/Cache/Adapter/DoctrineDbalAdapter.php b/src/Symfony/Component/Cache/Adapter/DoctrineDbalAdapter.php
index 5d78caec4709e..ae2bea7ed232a 100644
--- a/src/Symfony/Component/Cache/Adapter/DoctrineDbalAdapter.php
+++ b/src/Symfony/Component/Cache/Adapter/DoctrineDbalAdapter.php
@@ -60,7 +60,7 @@ public function __construct(
private string $namespace = '',
int $defaultLifetime = 0,
array $options = [],
- MarshallerInterface $marshaller = null,
+ ?MarshallerInterface $marshaller = null,
) {
if (isset($namespace[0]) && preg_match('#[^-+.A-Za-z0-9]#', $namespace, $match)) {
throw new InvalidArgumentException(sprintf('Namespace contains "%s" but only characters in [-+.A-Za-z0-9] are allowed.', $match[0]));
diff --git a/src/Symfony/Component/Cache/Adapter/FilesystemAdapter.php b/src/Symfony/Component/Cache/Adapter/FilesystemAdapter.php
index 7185dd4877e42..13daa568c7cdd 100644
--- a/src/Symfony/Component/Cache/Adapter/FilesystemAdapter.php
+++ b/src/Symfony/Component/Cache/Adapter/FilesystemAdapter.php
@@ -20,7 +20,7 @@ class FilesystemAdapter extends AbstractAdapter implements PruneableInterface
{
use FilesystemTrait;
- public function __construct(string $namespace = '', int $defaultLifetime = 0, string $directory = null, MarshallerInterface $marshaller = null)
+ public function __construct(string $namespace = '', int $defaultLifetime = 0, ?string $directory = null, ?MarshallerInterface $marshaller = null)
{
$this->marshaller = $marshaller ?? new DefaultMarshaller();
parent::__construct('', $defaultLifetime);
diff --git a/src/Symfony/Component/Cache/Adapter/FilesystemTagAwareAdapter.php b/src/Symfony/Component/Cache/Adapter/FilesystemTagAwareAdapter.php
index e78536794ede2..80edee433dba0 100644
--- a/src/Symfony/Component/Cache/Adapter/FilesystemTagAwareAdapter.php
+++ b/src/Symfony/Component/Cache/Adapter/FilesystemTagAwareAdapter.php
@@ -35,7 +35,7 @@ class FilesystemTagAwareAdapter extends AbstractTagAwareAdapter implements Prune
*/
private const TAG_FOLDER = 'tags';
- public function __construct(string $namespace = '', int $defaultLifetime = 0, string $directory = null, MarshallerInterface $marshaller = null)
+ public function __construct(string $namespace = '', int $defaultLifetime = 0, ?string $directory = null, ?MarshallerInterface $marshaller = null)
{
$this->marshaller = new TagAwareMarshaller($marshaller);
parent::__construct('', $defaultLifetime);
diff --git a/src/Symfony/Component/Cache/Adapter/MemcachedAdapter.php b/src/Symfony/Component/Cache/Adapter/MemcachedAdapter.php
index 54c87e55b7425..033d9871e6eaa 100644
--- a/src/Symfony/Component/Cache/Adapter/MemcachedAdapter.php
+++ b/src/Symfony/Component/Cache/Adapter/MemcachedAdapter.php
@@ -45,7 +45,7 @@ class MemcachedAdapter extends AbstractAdapter
*
* Using a MemcachedAdapter as a pure items store is fine.
*/
- public function __construct(\Memcached $client, string $namespace = '', int $defaultLifetime = 0, MarshallerInterface $marshaller = null)
+ public function __construct(\Memcached $client, string $namespace = '', int $defaultLifetime = 0, ?MarshallerInterface $marshaller = null)
{
if (!static::isSupported()) {
throw new CacheException('Memcached > 3.1.5 is required.');
diff --git a/src/Symfony/Component/Cache/Adapter/NullAdapter.php b/src/Symfony/Component/Cache/Adapter/NullAdapter.php
index 07c7af8162402..d5d2ef6b40d03 100644
--- a/src/Symfony/Component/Cache/Adapter/NullAdapter.php
+++ b/src/Symfony/Component/Cache/Adapter/NullAdapter.php
@@ -37,7 +37,7 @@ static function ($key) {
);
}
- public function get(string $key, callable $callback, float $beta = null, array &$metadata = null): mixed
+ public function get(string $key, callable $callback, ?float $beta = null, ?array &$metadata = null): mixed
{
$save = true;
diff --git a/src/Symfony/Component/Cache/Adapter/PdoAdapter.php b/src/Symfony/Component/Cache/Adapter/PdoAdapter.php
index 0dd1b168bbb1f..c6ec11a0a8407 100644
--- a/src/Symfony/Component/Cache/Adapter/PdoAdapter.php
+++ b/src/Symfony/Component/Cache/Adapter/PdoAdapter.php
@@ -54,7 +54,7 @@ class PdoAdapter extends AbstractAdapter implements PruneableInterface
* @throws InvalidArgumentException When PDO error mode is not PDO::ERRMODE_EXCEPTION
* @throws InvalidArgumentException When namespace contains invalid characters
*/
- public function __construct(#[\SensitiveParameter] \PDO|string $connOrDsn, string $namespace = '', int $defaultLifetime = 0, array $options = [], MarshallerInterface $marshaller = null)
+ public function __construct(#[\SensitiveParameter] \PDO|string $connOrDsn, string $namespace = '', int $defaultLifetime = 0, array $options = [], ?MarshallerInterface $marshaller = null)
{
if (\is_string($connOrDsn) && str_contains($connOrDsn, '://')) {
throw new InvalidArgumentException(sprintf('Usage of Doctrine DBAL URL with "%s" is not supported. Use a PDO DSN or "%s" instead.', __CLASS__, DoctrineDbalAdapter::class));
diff --git a/src/Symfony/Component/Cache/Adapter/PhpArrayAdapter.php b/src/Symfony/Component/Cache/Adapter/PhpArrayAdapter.php
index f7794a197ebd0..f92a2380f1e59 100644
--- a/src/Symfony/Component/Cache/Adapter/PhpArrayAdapter.php
+++ b/src/Symfony/Component/Cache/Adapter/PhpArrayAdapter.php
@@ -78,7 +78,7 @@ public static function create(string $file, CacheItemPoolInterface $fallbackPool
return new static($file, $fallbackPool);
}
- public function get(string $key, callable $callback, float $beta = null, array &$metadata = null): mixed
+ public function get(string $key, callable $callback, ?float $beta = null, ?array &$metadata = null): mixed
{
if (!isset($this->values)) {
$this->initialize();
diff --git a/src/Symfony/Component/Cache/Adapter/PhpFilesAdapter.php b/src/Symfony/Component/Cache/Adapter/PhpFilesAdapter.php
index 558199950ec61..917ff161f4742 100644
--- a/src/Symfony/Component/Cache/Adapter/PhpFilesAdapter.php
+++ b/src/Symfony/Component/Cache/Adapter/PhpFilesAdapter.php
@@ -45,7 +45,7 @@ class PhpFilesAdapter extends AbstractAdapter implements PruneableInterface
public function __construct(
string $namespace = '',
int $defaultLifetime = 0,
- string $directory = null,
+ ?string $directory = null,
private bool $appendOnly = false,
) {
self::$startTime ??= $_SERVER['REQUEST_TIME'] ?? time();
diff --git a/src/Symfony/Component/Cache/Adapter/ProxyAdapter.php b/src/Symfony/Component/Cache/Adapter/ProxyAdapter.php
index 88fccde4a6819..c022dd5fa9fc0 100644
--- a/src/Symfony/Component/Cache/Adapter/ProxyAdapter.php
+++ b/src/Symfony/Component/Cache/Adapter/ProxyAdapter.php
@@ -80,7 +80,7 @@ static function (CacheItemInterface $innerItem, CacheItem $item, $expiry = null)
);
}
- public function get(string $key, callable $callback, float $beta = null, array &$metadata = null): mixed
+ public function get(string $key, callable $callback, ?float $beta = null, ?array &$metadata = null): mixed
{
if (!$this->pool instanceof CacheInterface) {
return $this->doGet($this, $key, $callback, $beta, $metadata);
diff --git a/src/Symfony/Component/Cache/Adapter/RedisAdapter.php b/src/Symfony/Component/Cache/Adapter/RedisAdapter.php
index d8e37b1d7b2f3..e33f2f65fc927 100644
--- a/src/Symfony/Component/Cache/Adapter/RedisAdapter.php
+++ b/src/Symfony/Component/Cache/Adapter/RedisAdapter.php
@@ -18,7 +18,7 @@ class RedisAdapter extends AbstractAdapter
{
use RedisTrait;
- public function __construct(\Redis|\RedisArray|\RedisCluster|\Predis\ClientInterface|\Relay\Relay $redis, string $namespace = '', int $defaultLifetime = 0, MarshallerInterface $marshaller = null)
+ public function __construct(\Redis|\RedisArray|\RedisCluster|\Predis\ClientInterface|\Relay\Relay $redis, string $namespace = '', int $defaultLifetime = 0, ?MarshallerInterface $marshaller = null)
{
$this->init($redis, $namespace, $defaultLifetime, $marshaller);
}
diff --git a/src/Symfony/Component/Cache/Adapter/RedisTagAwareAdapter.php b/src/Symfony/Component/Cache/Adapter/RedisTagAwareAdapter.php
index 7305bb2165c77..f71622b6bc208 100644
--- a/src/Symfony/Component/Cache/Adapter/RedisTagAwareAdapter.php
+++ b/src/Symfony/Component/Cache/Adapter/RedisTagAwareAdapter.php
@@ -63,7 +63,7 @@ public function __construct(
\Redis|Relay|\RedisArray|\RedisCluster|\Predis\ClientInterface $redis,
private string $namespace = '',
int $defaultLifetime = 0,
- MarshallerInterface $marshaller = null,
+ ?MarshallerInterface $marshaller = null,
) {
if ($redis instanceof \Predis\ClientInterface && $redis->getConnection() instanceof ClusterInterface && !$redis->getConnection() instanceof PredisCluster) {
throw new InvalidArgumentException(sprintf('Unsupported Predis cluster connection: only "%s" is, "%s" given.', PredisCluster::class, get_debug_type($redis->getConnection())));
diff --git a/src/Symfony/Component/Cache/Adapter/TagAwareAdapter.php b/src/Symfony/Component/Cache/Adapter/TagAwareAdapter.php
index ce94e474074aa..1fe1cde6a5b83 100644
--- a/src/Symfony/Component/Cache/Adapter/TagAwareAdapter.php
+++ b/src/Symfony/Component/Cache/Adapter/TagAwareAdapter.php
@@ -52,7 +52,7 @@ class TagAwareAdapter implements TagAwareAdapterInterface, TagAwareCacheInterfac
public function __construct(
AdapterInterface $itemsPool,
- AdapterInterface $tagsPool = null,
+ ?AdapterInterface $tagsPool = null,
private float $knownTagVersionsTtl = 0.15,
) {
$this->pool = $itemsPool;
diff --git a/src/Symfony/Component/Cache/Adapter/TraceableAdapter.php b/src/Symfony/Component/Cache/Adapter/TraceableAdapter.php
index 784c156b48b7b..b5bce143f7218 100644
--- a/src/Symfony/Component/Cache/Adapter/TraceableAdapter.php
+++ b/src/Symfony/Component/Cache/Adapter/TraceableAdapter.php
@@ -35,7 +35,7 @@ public function __construct(AdapterInterface $pool)
$this->pool = $pool;
}
- public function get(string $key, callable $callback, float $beta = null, array &$metadata = null): mixed
+ public function get(string $key, callable $callback, ?float $beta = null, ?array &$metadata = null): mixed
{
if (!$this->pool instanceof CacheInterface) {
throw new \BadMethodCallException(sprintf('Cannot call "%s::get()": this class doesn\'t implement "%s".', get_debug_type($this->pool), CacheInterface::class));
diff --git a/src/Symfony/Component/Cache/DataCollector/CacheDataCollector.php b/src/Symfony/Component/Cache/DataCollector/CacheDataCollector.php
index 08ab8816c1687..b9bcdaf132572 100644
--- a/src/Symfony/Component/Cache/DataCollector/CacheDataCollector.php
+++ b/src/Symfony/Component/Cache/DataCollector/CacheDataCollector.php
@@ -36,7 +36,7 @@ public function addInstance(string $name, TraceableAdapter $instance): void
$this->instances[$name] = $instance;
}
- public function collect(Request $request, Response $response, \Throwable $exception = null): void
+ public function collect(Request $request, Response $response, ?\Throwable $exception = null): void
{
$empty = ['calls' => [], 'adapters' => [], 'config' => [], 'options' => [], 'statistics' => []];
$this->data = ['instances' => $empty, 'total' => $empty];
diff --git a/src/Symfony/Component/Cache/DependencyInjection/CachePoolPass.php b/src/Symfony/Component/Cache/DependencyInjection/CachePoolPass.php
index 49d0ba32b7900..081d82cd72cb2 100644
--- a/src/Symfony/Component/Cache/DependencyInjection/CachePoolPass.php
+++ b/src/Symfony/Component/Cache/DependencyInjection/CachePoolPass.php
@@ -178,11 +178,11 @@ public function process(ContainerBuilder $container): void
$container->removeDefinition('cache.early_expiration_handler');
}
- $notAliasedCacheClearerId = $aliasedCacheClearerId = 'cache.global_clearer';
- while ($container->hasAlias('cache.global_clearer')) {
- $aliasedCacheClearerId = (string) $container->getAlias('cache.global_clearer');
+ $notAliasedCacheClearerId = 'cache.global_clearer';
+ while ($container->hasAlias($notAliasedCacheClearerId)) {
+ $notAliasedCacheClearerId = (string) $container->getAlias($notAliasedCacheClearerId);
}
- if ($container->hasDefinition($aliasedCacheClearerId)) {
+ if ($container->hasDefinition($notAliasedCacheClearerId)) {
$clearers[$notAliasedCacheClearerId] = $allPools;
}
diff --git a/src/Symfony/Component/Cache/LockRegistry.php b/src/Symfony/Component/Cache/LockRegistry.php
index 4b750cb44eeac..c5c5fde898978 100644
--- a/src/Symfony/Component/Cache/LockRegistry.php
+++ b/src/Symfony/Component/Cache/LockRegistry.php
@@ -83,7 +83,7 @@ public static function setFiles(array $files): array
return $previousFiles;
}
- public static function compute(callable $callback, ItemInterface $item, bool &$save, CacheInterface $pool, \Closure $setMetadata = null, LoggerInterface $logger = null): mixed
+ public static function compute(callable $callback, ItemInterface $item, bool &$save, CacheInterface $pool, ?\Closure $setMetadata = null, ?LoggerInterface $logger = null): mixed
{
if ('\\' === \DIRECTORY_SEPARATOR && null === self::$lockedFiles) {
// disable locking on Windows by default
diff --git a/src/Symfony/Component/Cache/Marshaller/DefaultMarshaller.php b/src/Symfony/Component/Cache/Marshaller/DefaultMarshaller.php
index 973b137ae3eee..34bbeb8930078 100644
--- a/src/Symfony/Component/Cache/Marshaller/DefaultMarshaller.php
+++ b/src/Symfony/Component/Cache/Marshaller/DefaultMarshaller.php
@@ -23,7 +23,7 @@ class DefaultMarshaller implements MarshallerInterface
private bool $useIgbinarySerialize = true;
private bool $throwOnSerializationFailure = false;
- public function __construct(bool $useIgbinarySerialize = null, bool $throwOnSerializationFailure = false)
+ public function __construct(?bool $useIgbinarySerialize = null, bool $throwOnSerializationFailure = false)
{
if (null === $useIgbinarySerialize) {
$useIgbinarySerialize = \extension_loaded('igbinary') && version_compare('3.1.6', phpversion('igbinary'), '<=');
diff --git a/src/Symfony/Component/Cache/Marshaller/SodiumMarshaller.php b/src/Symfony/Component/Cache/Marshaller/SodiumMarshaller.php
index ae6d9e1c4b57d..77d16e8b878e3 100644
--- a/src/Symfony/Component/Cache/Marshaller/SodiumMarshaller.php
+++ b/src/Symfony/Component/Cache/Marshaller/SodiumMarshaller.php
@@ -30,7 +30,7 @@ class SodiumMarshaller implements MarshallerInterface
*/
public function __construct(
private array $decryptionKeys,
- MarshallerInterface $marshaller = null,
+ ?MarshallerInterface $marshaller = null,
) {
if (!self::isSupported()) {
throw new CacheException('The "sodium" PHP extension is not loaded.');
diff --git a/src/Symfony/Component/Cache/Marshaller/TagAwareMarshaller.php b/src/Symfony/Component/Cache/Marshaller/TagAwareMarshaller.php
index f5c2867af2cf8..825f32cc0e0dc 100644
--- a/src/Symfony/Component/Cache/Marshaller/TagAwareMarshaller.php
+++ b/src/Symfony/Component/Cache/Marshaller/TagAwareMarshaller.php
@@ -20,7 +20,7 @@ class TagAwareMarshaller implements MarshallerInterface
{
private MarshallerInterface $marshaller;
- public function __construct(MarshallerInterface $marshaller = null)
+ public function __construct(?MarshallerInterface $marshaller = null)
{
$this->marshaller = $marshaller ?? new DefaultMarshaller();
}
diff --git a/src/Symfony/Component/Cache/Messenger/EarlyExpirationDispatcher.php b/src/Symfony/Component/Cache/Messenger/EarlyExpirationDispatcher.php
index dee265887b900..d9726347925fc 100644
--- a/src/Symfony/Component/Cache/Messenger/EarlyExpirationDispatcher.php
+++ b/src/Symfony/Component/Cache/Messenger/EarlyExpirationDispatcher.php
@@ -28,12 +28,12 @@ class EarlyExpirationDispatcher
public function __construct(
private MessageBusInterface $bus,
private ReverseContainer $reverseContainer,
- callable $callbackWrapper = null,
+ ?callable $callbackWrapper = null,
) {
$this->callbackWrapper = null === $callbackWrapper ? null : $callbackWrapper(...);
}
- public function __invoke(callable $callback, CacheItem $item, bool &$save, AdapterInterface $pool, \Closure $setMetadata, LoggerInterface $logger = null): mixed
+ public function __invoke(callable $callback, CacheItem $item, bool &$save, AdapterInterface $pool, \Closure $setMetadata, ?LoggerInterface $logger = null): mixed
{
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
diff --git a/src/Symfony/Component/Cache/Tests/Adapter/AbstractRedisAdapterTestCase.php b/src/Symfony/Component/Cache/Tests/Adapter/AbstractRedisAdapterTestCase.php
index 52f9500da0ed7..c83365cc73f35 100644
--- a/src/Symfony/Component/Cache/Tests/Adapter/AbstractRedisAdapterTestCase.php
+++ b/src/Symfony/Component/Cache/Tests/Adapter/AbstractRedisAdapterTestCase.php
@@ -25,7 +25,7 @@ abstract class AbstractRedisAdapterTestCase extends AdapterTestCase
protected static \Redis|Relay|\RedisArray|\RedisCluster|\Predis\ClientInterface $redis;
- public function createCachePool(int $defaultLifetime = 0, string $testMethod = null): CacheItemPoolInterface
+ public function createCachePool(int $defaultLifetime = 0, ?string $testMethod = null): CacheItemPoolInterface
{
return new RedisAdapter(self::$redis, str_replace('\\', '.', __CLASS__), $defaultLifetime);
}
diff --git a/src/Symfony/Component/Cache/Tests/Adapter/AdapterTestCase.php b/src/Symfony/Component/Cache/Tests/Adapter/AdapterTestCase.php
index e48c8b4e8bcec..8c4b404853f31 100644
--- a/src/Symfony/Component/Cache/Tests/Adapter/AdapterTestCase.php
+++ b/src/Symfony/Component/Cache/Tests/Adapter/AdapterTestCase.php
@@ -234,7 +234,7 @@ public function testPrune()
/** @var PruneableInterface|CacheItemPoolInterface $cache */
$cache = $this->createCachePool();
- $doSet = function ($name, $value, \DateInterval $expiresAfter = null) use ($cache) {
+ $doSet = function ($name, $value, ?\DateInterval $expiresAfter = null) use ($cache) {
$item = $cache->getItem($name);
$item->set($value);
diff --git a/src/Symfony/Component/Cache/Tests/Adapter/ChainAdapterTest.php b/src/Symfony/Component/Cache/Tests/Adapter/ChainAdapterTest.php
index a72b783babd41..6f849a6bd08a6 100644
--- a/src/Symfony/Component/Cache/Tests/Adapter/ChainAdapterTest.php
+++ b/src/Symfony/Component/Cache/Tests/Adapter/ChainAdapterTest.php
@@ -30,7 +30,7 @@
*/
class ChainAdapterTest extends AdapterTestCase
{
- public function createCachePool(int $defaultLifetime = 0, string $testMethod = null): CacheItemPoolInterface
+ public function createCachePool(int $defaultLifetime = 0, ?string $testMethod = null): CacheItemPoolInterface
{
if ('testGetMetadata' === $testMethod) {
return new ChainAdapter([new FilesystemAdapter('a', $defaultLifetime), new FilesystemAdapter('b', $defaultLifetime)], $defaultLifetime);
diff --git a/src/Symfony/Component/Cache/Tests/Adapter/DoctrineDbalAdapterTest.php b/src/Symfony/Component/Cache/Tests/Adapter/DoctrineDbalAdapterTest.php
index 63d0045213b47..9b7c448767781 100644
--- a/src/Symfony/Component/Cache/Tests/Adapter/DoctrineDbalAdapterTest.php
+++ b/src/Symfony/Component/Cache/Tests/Adapter/DoctrineDbalAdapterTest.php
@@ -107,7 +107,7 @@ public function testConfigureSchemaTableExists()
/**
* @dataProvider provideDsnWithSQLite
*/
- public function testDsnWithSQLite(string $dsn, string $file = null)
+ public function testDsnWithSQLite(string $dsn, ?string $file = null)
{
try {
$pool = new DoctrineDbalAdapter($dsn);
diff --git a/src/Symfony/Component/Cache/Tests/Adapter/MemcachedAdapterTest.php b/src/Symfony/Component/Cache/Tests/Adapter/MemcachedAdapterTest.php
index 2534e90e94579..88950042fcde9 100644
--- a/src/Symfony/Component/Cache/Tests/Adapter/MemcachedAdapterTest.php
+++ b/src/Symfony/Component/Cache/Tests/Adapter/MemcachedAdapterTest.php
@@ -43,7 +43,7 @@ public static function setUpBeforeClass(): void
}
}
- public function createCachePool(int $defaultLifetime = 0, string $testMethod = null, string $namespace = null): CacheItemPoolInterface
+ public function createCachePool(int $defaultLifetime = 0, ?string $testMethod = null, ?string $namespace = null): CacheItemPoolInterface
{
$client = $defaultLifetime ? AbstractAdapter::createConnection('memcached://'.getenv('MEMCACHED_HOST')) : self::$client;
diff --git a/src/Symfony/Component/Cache/Tests/Adapter/NamespacedProxyAdapterTest.php b/src/Symfony/Component/Cache/Tests/Adapter/NamespacedProxyAdapterTest.php
index a4edc7a608db5..4e6ebede0a596 100644
--- a/src/Symfony/Component/Cache/Tests/Adapter/NamespacedProxyAdapterTest.php
+++ b/src/Symfony/Component/Cache/Tests/Adapter/NamespacedProxyAdapterTest.php
@@ -21,7 +21,7 @@
*/
class NamespacedProxyAdapterTest extends ProxyAdapterTest
{
- public function createCachePool(int $defaultLifetime = 0, string $testMethod = null): CacheItemPoolInterface
+ public function createCachePool(int $defaultLifetime = 0, ?string $testMethod = null): CacheItemPoolInterface
{
if ('testGetMetadata' === $testMethod) {
return new ProxyAdapter(new FilesystemAdapter(), 'foo', $defaultLifetime);
diff --git a/src/Symfony/Component/Cache/Tests/Adapter/PdoAdapterTest.php b/src/Symfony/Component/Cache/Tests/Adapter/PdoAdapterTest.php
index 48ec520debd16..f55a4ce20796a 100644
--- a/src/Symfony/Component/Cache/Tests/Adapter/PdoAdapterTest.php
+++ b/src/Symfony/Component/Cache/Tests/Adapter/PdoAdapterTest.php
@@ -79,7 +79,7 @@ public function testCleanupExpiredItems()
/**
* @dataProvider provideDsnSQLite
*/
- public function testDsnWithSQLite(string $dsn, string $file = null)
+ public function testDsnWithSQLite(string $dsn, ?string $file = null)
{
try {
$pool = new PdoAdapter($dsn);
diff --git a/src/Symfony/Component/Cache/Tests/Adapter/PhpArrayAdapterTest.php b/src/Symfony/Component/Cache/Tests/Adapter/PhpArrayAdapterTest.php
index 440352c9b63f6..5bbe4d1d7be13 100644
--- a/src/Symfony/Component/Cache/Tests/Adapter/PhpArrayAdapterTest.php
+++ b/src/Symfony/Component/Cache/Tests/Adapter/PhpArrayAdapterTest.php
@@ -75,7 +75,7 @@ protected function tearDown(): void
}
}
- public function createCachePool(int $defaultLifetime = 0, string $testMethod = null): CacheItemPoolInterface
+ public function createCachePool(int $defaultLifetime = 0, ?string $testMethod = null): CacheItemPoolInterface
{
if ('testGetMetadata' === $testMethod || 'testClearPrefix' === $testMethod) {
return new PhpArrayAdapter(self::$file, new FilesystemAdapter());
diff --git a/src/Symfony/Component/Cache/Tests/Adapter/PredisTagAwareAdapterTest.php b/src/Symfony/Component/Cache/Tests/Adapter/PredisTagAwareAdapterTest.php
index 0971f80c553e5..0468e89449729 100644
--- a/src/Symfony/Component/Cache/Tests/Adapter/PredisTagAwareAdapterTest.php
+++ b/src/Symfony/Component/Cache/Tests/Adapter/PredisTagAwareAdapterTest.php
@@ -27,7 +27,7 @@ protected function setUp(): void
$this->skippedTests['testTagItemExpiry'] = 'Testing expiration slows down the test suite';
}
- public function createCachePool(int $defaultLifetime = 0, string $testMethod = null): CacheItemPoolInterface
+ public function createCachePool(int $defaultLifetime = 0, ?string $testMethod = null): CacheItemPoolInterface
{
$this->assertInstanceOf(\Predis\Client::class, self::$redis);
$adapter = new RedisTagAwareAdapter(self::$redis, str_replace('\\', '.', __CLASS__), $defaultLifetime);
diff --git a/src/Symfony/Component/Cache/Tests/Adapter/PredisTagAwareClusterAdapterTest.php b/src/Symfony/Component/Cache/Tests/Adapter/PredisTagAwareClusterAdapterTest.php
index af25b2df52c45..3a118dc17147e 100644
--- a/src/Symfony/Component/Cache/Tests/Adapter/PredisTagAwareClusterAdapterTest.php
+++ b/src/Symfony/Component/Cache/Tests/Adapter/PredisTagAwareClusterAdapterTest.php
@@ -27,7 +27,7 @@ protected function setUp(): void
$this->skippedTests['testTagItemExpiry'] = 'Testing expiration slows down the test suite';
}
- public function createCachePool(int $defaultLifetime = 0, string $testMethod = null): CacheItemPoolInterface
+ public function createCachePool(int $defaultLifetime = 0, ?string $testMethod = null): CacheItemPoolInterface
{
$this->assertInstanceOf(\Predis\Client::class, self::$redis);
$adapter = new RedisTagAwareAdapter(self::$redis, str_replace('\\', '.', __CLASS__), $defaultLifetime);
diff --git a/src/Symfony/Component/Cache/Tests/Adapter/ProxyAdapterAndRedisAdapterTest.php b/src/Symfony/Component/Cache/Tests/Adapter/ProxyAdapterAndRedisAdapterTest.php
index ed811fb26a9c1..4bff8c33909d7 100644
--- a/src/Symfony/Component/Cache/Tests/Adapter/ProxyAdapterAndRedisAdapterTest.php
+++ b/src/Symfony/Component/Cache/Tests/Adapter/ProxyAdapterAndRedisAdapterTest.php
@@ -32,7 +32,7 @@ public static function setUpBeforeClass(): void
self::$redis = AbstractAdapter::createConnection('redis://'.getenv('REDIS_HOST'));
}
- public function createCachePool($defaultLifetime = 0, string $testMethod = null): CacheItemPoolInterface
+ public function createCachePool($defaultLifetime = 0, ?string $testMethod = null): CacheItemPoolInterface
{
return new ProxyAdapter(new RedisAdapter(self::$redis, str_replace('\\', '.', __CLASS__), 100), 'ProxyNS', $defaultLifetime);
}
diff --git a/src/Symfony/Component/Cache/Tests/Adapter/ProxyAdapterTest.php b/src/Symfony/Component/Cache/Tests/Adapter/ProxyAdapterTest.php
index 71122a98b6740..765dd7565dc76 100644
--- a/src/Symfony/Component/Cache/Tests/Adapter/ProxyAdapterTest.php
+++ b/src/Symfony/Component/Cache/Tests/Adapter/ProxyAdapterTest.php
@@ -29,7 +29,7 @@ class ProxyAdapterTest extends AdapterTestCase
'testPrune' => 'ProxyAdapter just proxies',
];
- public function createCachePool(int $defaultLifetime = 0, string $testMethod = null): CacheItemPoolInterface
+ public function createCachePool(int $defaultLifetime = 0, ?string $testMethod = null): CacheItemPoolInterface
{
if ('testGetMetadata' === $testMethod) {
return new ProxyAdapter(new FilesystemAdapter(), '', $defaultLifetime);
diff --git a/src/Symfony/Component/Cache/Tests/Adapter/RedisAdapterTest.php b/src/Symfony/Component/Cache/Tests/Adapter/RedisAdapterTest.php
index 3b44d63371e3d..7b8e11ea5faf2 100644
--- a/src/Symfony/Component/Cache/Tests/Adapter/RedisAdapterTest.php
+++ b/src/Symfony/Component/Cache/Tests/Adapter/RedisAdapterTest.php
@@ -28,7 +28,7 @@ public static function setUpBeforeClass(): void
self::$redis = AbstractAdapter::createConnection('redis://'.getenv('REDIS_HOST'), ['lazy' => true]);
}
- public function createCachePool(int $defaultLifetime = 0, string $testMethod = null): CacheItemPoolInterface
+ public function createCachePool(int $defaultLifetime = 0, ?string $testMethod = null): CacheItemPoolInterface
{
if ('testClearWithPrefix' === $testMethod && \defined('Redis::SCAN_PREFIX')) {
self::$redis->setOption(\Redis::OPT_SCAN, \Redis::SCAN_PREFIX);
diff --git a/src/Symfony/Component/Cache/Tests/Adapter/RedisClusterAdapterTest.php b/src/Symfony/Component/Cache/Tests/Adapter/RedisClusterAdapterTest.php
index ebee3200d6bce..3b7450e139254 100644
--- a/src/Symfony/Component/Cache/Tests/Adapter/RedisClusterAdapterTest.php
+++ b/src/Symfony/Component/Cache/Tests/Adapter/RedisClusterAdapterTest.php
@@ -35,7 +35,7 @@ public static function setUpBeforeClass(): void
self::$redis->setOption(\Redis::OPT_PREFIX, 'prefix_');
}
- public function createCachePool(int $defaultLifetime = 0, string $testMethod = null): CacheItemPoolInterface
+ public function createCachePool(int $defaultLifetime = 0, ?string $testMethod = null): CacheItemPoolInterface
{
if ('testClearWithPrefix' === $testMethod && \defined('Redis::SCAN_PREFIX')) {
self::$redis->setOption(\Redis::OPT_SCAN, \Redis::SCAN_PREFIX);
diff --git a/src/Symfony/Component/Cache/Tests/Adapter/RedisTagAwareAdapterTest.php b/src/Symfony/Component/Cache/Tests/Adapter/RedisTagAwareAdapterTest.php
index 12e3b6ff55365..f00eb9de8aaeb 100644
--- a/src/Symfony/Component/Cache/Tests/Adapter/RedisTagAwareAdapterTest.php
+++ b/src/Symfony/Component/Cache/Tests/Adapter/RedisTagAwareAdapterTest.php
@@ -28,7 +28,7 @@ protected function setUp(): void
$this->skippedTests['testTagItemExpiry'] = 'Testing expiration slows down the test suite';
}
- public function createCachePool(int $defaultLifetime = 0, string $testMethod = null): CacheItemPoolInterface
+ public function createCachePool(int $defaultLifetime = 0, ?string $testMethod = null): CacheItemPoolInterface
{
if ('testClearWithPrefix' === $testMethod && \defined('Redis::SCAN_PREFIX')) {
self::$redis->setOption(\Redis::OPT_SCAN, \Redis::SCAN_PREFIX);
diff --git a/src/Symfony/Component/Cache/Tests/Adapter/RedisTagAwareArrayAdapterTest.php b/src/Symfony/Component/Cache/Tests/Adapter/RedisTagAwareArrayAdapterTest.php
index b5823711dc858..860709bf7f2cb 100644
--- a/src/Symfony/Component/Cache/Tests/Adapter/RedisTagAwareArrayAdapterTest.php
+++ b/src/Symfony/Component/Cache/Tests/Adapter/RedisTagAwareArrayAdapterTest.php
@@ -27,7 +27,7 @@ protected function setUp(): void
$this->skippedTests['testTagItemExpiry'] = 'Testing expiration slows down the test suite';
}
- public function createCachePool(int $defaultLifetime = 0, string $testMethod = null): CacheItemPoolInterface
+ public function createCachePool(int $defaultLifetime = 0, ?string $testMethod = null): CacheItemPoolInterface
{
if ('testClearWithPrefix' === $testMethod && \defined('Redis::SCAN_PREFIX')) {
self::$redis->setOption(\Redis::OPT_SCAN, \Redis::SCAN_PREFIX);
diff --git a/src/Symfony/Component/Cache/Tests/Adapter/RedisTagAwareClusterAdapterTest.php b/src/Symfony/Component/Cache/Tests/Adapter/RedisTagAwareClusterAdapterTest.php
index d4a1bc97779ca..c7d143d3a35db 100644
--- a/src/Symfony/Component/Cache/Tests/Adapter/RedisTagAwareClusterAdapterTest.php
+++ b/src/Symfony/Component/Cache/Tests/Adapter/RedisTagAwareClusterAdapterTest.php
@@ -28,7 +28,7 @@ protected function setUp(): void
$this->skippedTests['testTagItemExpiry'] = 'Testing expiration slows down the test suite';
}
- public function createCachePool(int $defaultLifetime = 0, string $testMethod = null): CacheItemPoolInterface
+ public function createCachePool(int $defaultLifetime = 0, ?string $testMethod = null): CacheItemPoolInterface
{
if ('testClearWithPrefix' === $testMethod && \defined('Redis::SCAN_PREFIX')) {
self::$redis->setOption(\Redis::OPT_SCAN, \Redis::SCAN_PREFIX);
diff --git a/src/Symfony/Component/Cache/Tests/DependencyInjection/CachePoolPassTest.php b/src/Symfony/Component/Cache/Tests/DependencyInjection/CachePoolPassTest.php
index 98a093ed0222f..ef64d1932da8f 100644
--- a/src/Symfony/Component/Cache/Tests/DependencyInjection/CachePoolPassTest.php
+++ b/src/Symfony/Component/Cache/Tests/DependencyInjection/CachePoolPassTest.php
@@ -20,8 +20,10 @@
use Symfony\Component\Cache\DependencyInjection\CachePoolPass;
use Symfony\Component\DependencyInjection\ChildDefinition;
use Symfony\Component\DependencyInjection\ContainerBuilder;
+use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\DependencyInjection\Definition;
use Symfony\Component\DependencyInjection\Reference;
+use Symfony\Component\HttpKernel\CacheClearer\Psr6CacheClearer;
class CachePoolPassTest extends TestCase
{
@@ -233,4 +235,33 @@ public function testChainAdapterPool()
$this->assertInstanceOf(ChildDefinition::class, $doctrineCachePool);
$this->assertSame('cache.app', $doctrineCachePool->getParent());
}
+
+ public function testGlobalClearerAlias()
+ {
+ $container = new ContainerBuilder();
+ $container->setParameter('kernel.container_class', 'app');
+ $container->setParameter('kernel.project_dir', 'foo');
+
+ $container->register('cache.default_clearer', Psr6CacheClearer::class);
+
+ $container->setDefinition('cache.system_clearer', new ChildDefinition('cache.default_clearer'));
+
+ $container->setDefinition('cache.foo_bar_clearer', new ChildDefinition('cache.default_clearer'));
+ $container->setAlias('cache.global_clearer', 'cache.foo_bar_clearer');
+
+ $container->register('cache.adapter.array', ArrayAdapter::class)
+ ->setAbstract(true)
+ ->addTag('cache.pool');
+
+ $cachePool = new ChildDefinition('cache.adapter.array');
+ $cachePool->addTag('cache.pool', ['clearer' => 'cache.system_clearer']);
+ $container->setDefinition('app.cache_pool', $cachePool);
+
+ $this->cachePoolPass->process($container);
+
+ $definition = $container->getDefinition('cache.foo_bar_clearer');
+
+ $this->assertTrue($definition->hasTag('cache.pool.clearer'));
+ $this->assertEquals(['app.cache_pool' => new Reference('app.cache_pool', ContainerInterface::IGNORE_ON_UNINITIALIZED_REFERENCE)], $definition->getArgument(0));
+ }
}
diff --git a/src/Symfony/Component/Cache/Tests/Traits/RedisProxiesTest.php b/src/Symfony/Component/Cache/Tests/Traits/RedisProxiesTest.php
index a59b558859c3b..01d96fb9e0480 100644
--- a/src/Symfony/Component/Cache/Tests/Traits/RedisProxiesTest.php
+++ b/src/Symfony/Component/Cache/Tests/Traits/RedisProxiesTest.php
@@ -101,7 +101,17 @@ public function testRedis6Proxy($class, $stub)
continue;
}
$return = $method->getReturnType() instanceof \ReflectionNamedType && 'void' === (string) $method->getReturnType() ? '' : 'return ';
- $methods[] = "\n ".str_replace('timeout = 0.0', 'timeout = 0', ProxyHelper::exportSignature($method, false, $args))."\n".<<name) {
+ $signature = str_replace(': \Redis|array|false', ': \Redis|array', $signature);
+ }
+
+ if ('RedisCluster' === $class && 'publish' === $method->name) {
+ $signature = str_replace(': \RedisCluster|bool|int', ': \RedisCluster|bool', $signature);
+ }
+
+ $methods[] = "\n ".str_replace('timeout = 0.0', 'timeout = 0', $signature)."\n".<<lazyObjectState->realInstance ??= (\$this->lazyObjectState->initializer)())->{$method->name}({$args});
}
diff --git a/src/Symfony/Component/Cache/Traits/ContractsTrait.php b/src/Symfony/Component/Cache/Traits/ContractsTrait.php
index 083ce1f9dbd3f..8d830f0abf941 100644
--- a/src/Symfony/Component/Cache/Traits/ContractsTrait.php
+++ b/src/Symfony/Component/Cache/Traits/ContractsTrait.php
@@ -59,7 +59,7 @@ public function setCallbackWrapper(?callable $callbackWrapper): callable
return $previousWrapper;
}
- private function doGet(AdapterInterface $pool, string $key, callable $callback, ?float $beta, array &$metadata = null): mixed
+ private function doGet(AdapterInterface $pool, string $key, callable $callback, ?float $beta, ?array &$metadata = null): mixed
{
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));
diff --git a/src/Symfony/Component/Cache/Traits/FilesystemCommonTrait.php b/src/Symfony/Component/Cache/Traits/FilesystemCommonTrait.php
index cd14886ffab2e..7fa0f2e874d63 100644
--- a/src/Symfony/Component/Cache/Traits/FilesystemCommonTrait.php
+++ b/src/Symfony/Component/Cache/Traits/FilesystemCommonTrait.php
@@ -82,7 +82,7 @@ protected function doUnlink(string $file): bool
return @unlink($file);
}
- private function write(string $file, string $data, int $expiresAt = null): bool
+ private function write(string $file, string $data, ?int $expiresAt = null): bool
{
$unlink = false;
set_error_handler(static fn ($type, $message, $file, $line) => throw new \ErrorException($message, 0, $type, $file, $line));
@@ -119,7 +119,7 @@ private function write(string $file, string $data, int $expiresAt = null): bool
}
}
- private function getFile(string $id, bool $mkdir = false, string $directory = null): string
+ private function getFile(string $id, bool $mkdir = false, ?string $directory = null): string
{
// Use xxh128 to favor speed over security, which is not an issue here
$hash = str_replace('/', '-', base64_encode(hash('xxh128', static::class.$id, true)));
diff --git a/src/Symfony/Component/Cache/Traits/RedisTrait.php b/src/Symfony/Component/Cache/Traits/RedisTrait.php
index 9852484288dc8..8574c9c17e168 100644
--- a/src/Symfony/Component/Cache/Traits/RedisTrait.php
+++ b/src/Symfony/Component/Cache/Traits/RedisTrait.php
@@ -569,7 +569,7 @@ protected function doSave(array $values, int $lifetime): array|bool
return $failed;
}
- private function pipeline(\Closure $generator, object $redis = null): \Generator
+ private function pipeline(\Closure $generator, ?object $redis = null): \Generator
{
$ids = [];
$redis ??= $this->redis;
diff --git a/src/Symfony/Component/Clock/DatePoint.php b/src/Symfony/Component/Clock/DatePoint.php
index 95d23191eac05..5d8ace6374bc8 100644
--- a/src/Symfony/Component/Clock/DatePoint.php
+++ b/src/Symfony/Component/Clock/DatePoint.php
@@ -21,7 +21,7 @@ final class DatePoint extends \DateTimeImmutable
/**
* @throws \DateMalformedStringException When $datetime is invalid
*/
- public function __construct(string $datetime = 'now', \DateTimeZone $timezone = null, parent $reference = null)
+ public function __construct(string $datetime = 'now', ?\DateTimeZone $timezone = null, ?parent $reference = null)
{
$now = $reference ?? Clock::get()->now();
@@ -51,7 +51,7 @@ public function __construct(string $datetime = 'now', \DateTimeZone $timezone =
/**
* @throws \DateMalformedStringException When $format or $datetime are invalid
*/
- public static function createFromFormat(string $format, string $datetime, \DateTimeZone $timezone = null): static
+ public static function createFromFormat(string $format, string $datetime, ?\DateTimeZone $timezone = null): static
{
return parent::createFromFormat($format, $datetime, $timezone) ?: throw new \DateMalformedStringException(static::getLastErrors()['errors'][0] ?? 'Invalid date string or format.');
}
diff --git a/src/Symfony/Component/Clock/MockClock.php b/src/Symfony/Component/Clock/MockClock.php
index b742c4331e052..ab64f1cbaf86f 100644
--- a/src/Symfony/Component/Clock/MockClock.php
+++ b/src/Symfony/Component/Clock/MockClock.php
@@ -26,7 +26,7 @@ final class MockClock implements ClockInterface
* @throws \DateMalformedStringException When $now is invalid
* @throws \DateInvalidTimeZoneException When $timezone is invalid
*/
- public function __construct(\DateTimeImmutable|string $now = 'now', \DateTimeZone|string $timezone = null)
+ public function __construct(\DateTimeImmutable|string $now = 'now', \DateTimeZone|string|null $timezone = null)
{
if (\PHP_VERSION_ID >= 80300 && \is_string($timezone)) {
$timezone = new \DateTimeZone($timezone);
diff --git a/src/Symfony/Component/Clock/MonotonicClock.php b/src/Symfony/Component/Clock/MonotonicClock.php
index a834dde1dbc56..d27bf9c3134e0 100644
--- a/src/Symfony/Component/Clock/MonotonicClock.php
+++ b/src/Symfony/Component/Clock/MonotonicClock.php
@@ -25,7 +25,7 @@ final class MonotonicClock implements ClockInterface
/**
* @throws \DateInvalidTimeZoneException When $timezone is invalid
*/
- public function __construct(\DateTimeZone|string $timezone = null)
+ public function __construct(\DateTimeZone|string|null $timezone = null)
{
if (false === $offset = hrtime()) {
throw new \RuntimeException('hrtime() returned false: the runtime environment does not provide access to a monotonic timer.');
diff --git a/src/Symfony/Component/Clock/NativeClock.php b/src/Symfony/Component/Clock/NativeClock.php
index 9480dae5f6957..b580a886cf566 100644
--- a/src/Symfony/Component/Clock/NativeClock.php
+++ b/src/Symfony/Component/Clock/NativeClock.php
@@ -23,7 +23,7 @@ final class NativeClock implements ClockInterface
/**
* @throws \DateInvalidTimeZoneException When $timezone is invalid
*/
- public function __construct(\DateTimeZone|string $timezone = null)
+ public function __construct(\DateTimeZone|string|null $timezone = null)
{
$this->timezone = \is_string($timezone ??= date_default_timezone_get()) ? $this->withTimeZone($timezone)->timezone : $timezone;
}
diff --git a/src/Symfony/Component/Config/Builder/ClassBuilder.php b/src/Symfony/Component/Config/Builder/ClassBuilder.php
index 3ab8b01a8cfa2..f34ab8519b82f 100644
--- a/src/Symfony/Component/Config/Builder/ClassBuilder.php
+++ b/src/Symfony/Component/Config/Builder/ClassBuilder.php
@@ -119,7 +119,7 @@ public function addMethod(string $name, string $body, array $params = []): void
$this->methods[] = new Method(strtr($body, ['NAME' => $this->camelCase($name)] + $params));
}
- public function addProperty(string $name, string $classType = null, string $defaultValue = null): Property
+ public function addProperty(string $name, ?string $classType = null, ?string $defaultValue = null): Property
{
$property = new Property($name, '_' !== $name[0] ? $this->camelCase($name) : $name);
if (null !== $classType) {
diff --git a/src/Symfony/Component/Config/CHANGELOG.md b/src/Symfony/Component/Config/CHANGELOG.md
index 51e2d1fee567b..79709aaa78f85 100644
--- a/src/Symfony/Component/Config/CHANGELOG.md
+++ b/src/Symfony/Component/Config/CHANGELOG.md
@@ -1,6 +1,11 @@
CHANGELOG
=========
+7.1
+---
+
+ * Allow custom meta location in `ResourceCheckerConfigCache`
+
7.0
---
diff --git a/src/Symfony/Component/Config/ConfigCacheInterface.php b/src/Symfony/Component/Config/ConfigCacheInterface.php
index f3ea53bde64da..7b9d388973ba5 100644
--- a/src/Symfony/Component/Config/ConfigCacheInterface.php
+++ b/src/Symfony/Component/Config/ConfigCacheInterface.php
@@ -41,5 +41,5 @@ public function isFresh(): bool;
*
* @throws \RuntimeException When the cache file cannot be written
*/
- public function write(string $content, array $metadata = null): void;
+ public function write(string $content, ?array $metadata = null): void;
}
diff --git a/src/Symfony/Component/Config/Definition/Builder/ArrayNodeDefinition.php b/src/Symfony/Component/Config/Definition/Builder/ArrayNodeDefinition.php
index dd6c58da746c1..4596151fba054 100644
--- a/src/Symfony/Component/Config/Definition/Builder/ArrayNodeDefinition.php
+++ b/src/Symfony/Component/Config/Definition/Builder/ArrayNodeDefinition.php
@@ -33,11 +33,11 @@ class ArrayNodeDefinition extends NodeDefinition implements ParentNodeDefinition
protected ?string $key = null;
protected bool $removeKeyItem = false;
protected bool $addDefaults = false;
- protected int|string|array|null|false $addDefaultChildren = false;
+ protected int|string|array|false|null $addDefaultChildren = false;
protected NodeBuilder $nodeBuilder;
protected bool $normalizeKeys = true;
- public function __construct(?string $name, NodeParentInterface $parent = null)
+ public function __construct(?string $name, ?NodeParentInterface $parent = null)
{
parent::__construct($name, $parent);
@@ -123,7 +123,7 @@ public function addDefaultsIfNotSet(): static
*
* @return $this
*/
- public function addDefaultChildrenIfNoneSet(int|string|array $children = null): static
+ public function addDefaultChildrenIfNoneSet(int|string|array|null $children = null): static
{
$this->addDefaultChildren = $children;
@@ -166,7 +166,7 @@ public function disallowNewKeysInSubsequentConfigs(): static
*
* @return $this
*/
- public function fixXmlConfig(string $singular, string $plural = null): static
+ public function fixXmlConfig(string $singular, ?string $plural = null): static
{
$this->normalization()->remap($singular, $plural);
diff --git a/src/Symfony/Component/Config/Definition/Builder/BooleanNodeDefinition.php b/src/Symfony/Component/Config/Definition/Builder/BooleanNodeDefinition.php
index 3d8fad4d55d31..15e63961ab727 100644
--- a/src/Symfony/Component/Config/Definition/Builder/BooleanNodeDefinition.php
+++ b/src/Symfony/Component/Config/Definition/Builder/BooleanNodeDefinition.php
@@ -21,7 +21,7 @@
*/
class BooleanNodeDefinition extends ScalarNodeDefinition
{
- public function __construct(?string $name, NodeParentInterface $parent = null)
+ public function __construct(?string $name, ?NodeParentInterface $parent = null)
{
parent::__construct($name, $parent);
diff --git a/src/Symfony/Component/Config/Definition/Builder/ExprBuilder.php b/src/Symfony/Component/Config/Definition/Builder/ExprBuilder.php
index dd82e8308cc5e..f5547a6e0a405 100644
--- a/src/Symfony/Component/Config/Definition/Builder/ExprBuilder.php
+++ b/src/Symfony/Component/Config/Definition/Builder/ExprBuilder.php
@@ -40,7 +40,7 @@ public function __construct(
*
* @return $this
*/
- public function always(\Closure $then = null): static
+ public function always(?\Closure $then = null): static
{
$this->ifPart = static fn () => true;
$this->allowedTypes = self::TYPE_ANY;
@@ -59,7 +59,7 @@ public function always(\Closure $then = null): static
*
* @return $this
*/
- public function ifTrue(\Closure $closure = null): static
+ public function ifTrue(?\Closure $closure = null): static
{
$this->ifPart = $closure ?? static fn ($v) => true === $v;
$this->allowedTypes = self::TYPE_ANY;
diff --git a/src/Symfony/Component/Config/Definition/Builder/NodeDefinition.php b/src/Symfony/Component/Config/Definition/Builder/NodeDefinition.php
index cdfd1993dc86a..54e976e246ec6 100644
--- a/src/Symfony/Component/Config/Definition/Builder/NodeDefinition.php
+++ b/src/Symfony/Component/Config/Definition/Builder/NodeDefinition.php
@@ -38,7 +38,7 @@ abstract class NodeDefinition implements NodeParentInterface
protected NodeParentInterface|NodeInterface|null $parent;
protected array $attributes = [];
- public function __construct(?string $name, NodeParentInterface $parent = null)
+ public function __construct(?string $name, ?NodeParentInterface $parent = null)
{
$this->parent = $parent;
$this->name = $name;
diff --git a/src/Symfony/Component/Config/Definition/Builder/NormalizationBuilder.php b/src/Symfony/Component/Config/Definition/Builder/NormalizationBuilder.php
index a64fc76b7bf24..8a8141c19fd6b 100644
--- a/src/Symfony/Component/Config/Definition/Builder/NormalizationBuilder.php
+++ b/src/Symfony/Component/Config/Definition/Builder/NormalizationBuilder.php
@@ -35,7 +35,7 @@ public function __construct(
*
* @return $this
*/
- public function remap(string $key, string $plural = null): static
+ public function remap(string $key, ?string $plural = null): static
{
$this->remappings[] = [$key, null === $plural ? $key.'s' : $plural];
@@ -47,7 +47,7 @@ public function remap(string $key, string $plural = null): static
*
* @return ExprBuilder|$this
*/
- public function before(\Closure $closure = null): ExprBuilder|static
+ public function before(?\Closure $closure = null): ExprBuilder|static
{
if (null !== $closure) {
$this->before[] = $closure;
diff --git a/src/Symfony/Component/Config/Definition/Builder/TreeBuilder.php b/src/Symfony/Component/Config/Definition/Builder/TreeBuilder.php
index 97544b94d87df..5170e19d1e266 100644
--- a/src/Symfony/Component/Config/Definition/Builder/TreeBuilder.php
+++ b/src/Symfony/Component/Config/Definition/Builder/TreeBuilder.php
@@ -23,7 +23,7 @@ class TreeBuilder implements NodeParentInterface
protected ?NodeInterface $tree = null;
protected ?NodeDefinition $root = null;
- public function __construct(string $name, string $type = 'array', NodeBuilder $builder = null)
+ public function __construct(string $name, string $type = 'array', ?NodeBuilder $builder = null)
{
$builder ??= new NodeBuilder();
$this->root = $builder->node($name, $type)->setParent($this);
diff --git a/src/Symfony/Component/Config/Definition/Builder/ValidationBuilder.php b/src/Symfony/Component/Config/Definition/Builder/ValidationBuilder.php
index d99cbb1bcb96e..ad22393495d6a 100644
--- a/src/Symfony/Component/Config/Definition/Builder/ValidationBuilder.php
+++ b/src/Symfony/Component/Config/Definition/Builder/ValidationBuilder.php
@@ -30,7 +30,7 @@ public function __construct(
*
* @return ExprBuilder|$this
*/
- public function rule(\Closure $closure = null): ExprBuilder|static
+ public function rule(?\Closure $closure = null): ExprBuilder|static
{
if (null !== $closure) {
$this->rules[] = $closure;
diff --git a/src/Symfony/Component/Config/Definition/Configurator/DefinitionConfigurator.php b/src/Symfony/Component/Config/Definition/Configurator/DefinitionConfigurator.php
index 006a444bedcb0..13fe45ca45557 100644
--- a/src/Symfony/Component/Config/Definition/Configurator/DefinitionConfigurator.php
+++ b/src/Symfony/Component/Config/Definition/Configurator/DefinitionConfigurator.php
@@ -29,7 +29,7 @@ public function __construct(
) {
}
- public function import(string $resource, string $type = null, bool $ignoreErrors = false): void
+ public function import(string $resource, ?string $type = null, bool $ignoreErrors = false): void
{
$this->loader->setCurrentDir(\dirname($this->path));
$this->loader->import($resource, $type, $ignoreErrors, $this->file);
diff --git a/src/Symfony/Component/Config/Definition/Dumper/XmlReferenceDumper.php b/src/Symfony/Component/Config/Definition/Dumper/XmlReferenceDumper.php
index 277bf0f71f08a..34584c43b8ae1 100644
--- a/src/Symfony/Component/Config/Definition/Dumper/XmlReferenceDumper.php
+++ b/src/Symfony/Component/Config/Definition/Dumper/XmlReferenceDumper.php
@@ -31,12 +31,12 @@ class XmlReferenceDumper
{
private ?string $reference = null;
- public function dump(ConfigurationInterface $configuration, string $namespace = null): string
+ public function dump(ConfigurationInterface $configuration, ?string $namespace = null): string
{
return $this->dumpNode($configuration->getConfigTreeBuilder()->buildTree(), $namespace);
}
- public function dumpNode(NodeInterface $node, string $namespace = null): string
+ public function dumpNode(NodeInterface $node, ?string $namespace = null): string
{
$this->reference = '';
$this->writeNode($node, 0, true, $namespace);
@@ -46,7 +46,7 @@ public function dumpNode(NodeInterface $node, string $namespace = null): string
return $ref;
}
- private function writeNode(NodeInterface $node, int $depth = 0, bool $root = false, string $namespace = null): void
+ private function writeNode(NodeInterface $node, int $depth = 0, bool $root = false, ?string $namespace = null): void
{
$rootName = ($root ? 'config' : $node->getName());
$rootNamespace = ($namespace ?: ($root ? 'http://example.org/schema/dic/'.$node->getName() : null));
diff --git a/src/Symfony/Component/Config/Definition/Dumper/YamlReferenceDumper.php b/src/Symfony/Component/Config/Definition/Dumper/YamlReferenceDumper.php
index 46d6ec61eef4f..4f720aa97f9f4 100644
--- a/src/Symfony/Component/Config/Definition/Dumper/YamlReferenceDumper.php
+++ b/src/Symfony/Component/Config/Definition/Dumper/YamlReferenceDumper.php
@@ -71,7 +71,7 @@ public function dumpNode(NodeInterface $node): string
return $ref;
}
- private function writeNode(NodeInterface $node, NodeInterface $parentNode = null, int $depth = 0, bool $prototypedArray = false): void
+ private function writeNode(NodeInterface $node, ?NodeInterface $parentNode = null, int $depth = 0, bool $prototypedArray = false): void
{
$comments = [];
$default = '';
diff --git a/src/Symfony/Component/Config/Definition/EnumNode.php b/src/Symfony/Component/Config/Definition/EnumNode.php
index 6bbe6fd39e55b..29fe0bdfba8c6 100644
--- a/src/Symfony/Component/Config/Definition/EnumNode.php
+++ b/src/Symfony/Component/Config/Definition/EnumNode.php
@@ -22,7 +22,7 @@ class EnumNode extends ScalarNode
{
private array $values;
- public function __construct(?string $name, NodeInterface $parent = null, array $values = [], string $pathSeparator = BaseNode::DEFAULT_PATH_SEPARATOR)
+ public function __construct(?string $name, ?NodeInterface $parent = null, array $values = [], string $pathSeparator = BaseNode::DEFAULT_PATH_SEPARATOR)
{
if (!$values) {
throw new \InvalidArgumentException('$values must contain at least one element.');
diff --git a/src/Symfony/Component/Config/Definition/Loader/DefinitionFileLoader.php b/src/Symfony/Component/Config/Definition/Loader/DefinitionFileLoader.php
index 506f787cab4cb..940b894f77323 100644
--- a/src/Symfony/Component/Config/Definition/Loader/DefinitionFileLoader.php
+++ b/src/Symfony/Component/Config/Definition/Loader/DefinitionFileLoader.php
@@ -34,7 +34,7 @@ public function __construct(
parent::__construct($locator);
}
- public function load(mixed $resource, string $type = null): mixed
+ public function load(mixed $resource, ?string $type = null): mixed
{
// the loader variable is exposed to the included file below
$loader = $this;
@@ -57,7 +57,7 @@ public function load(mixed $resource, string $type = null): mixed
return null;
}
- public function supports(mixed $resource, string $type = null): bool
+ public function supports(mixed $resource, ?string $type = null): bool
{
if (!\is_string($resource)) {
return false;
diff --git a/src/Symfony/Component/Config/Definition/NumericNode.php b/src/Symfony/Component/Config/Definition/NumericNode.php
index 1ea84ba85f7f2..b55ee922bdb6f 100644
--- a/src/Symfony/Component/Config/Definition/NumericNode.php
+++ b/src/Symfony/Component/Config/Definition/NumericNode.php
@@ -23,7 +23,7 @@ class NumericNode extends ScalarNode
protected int|float|null $min;
protected int|float|null $max;
- public function __construct(?string $name, NodeInterface $parent = null, int|float $min = null, int|float $max = null, string $pathSeparator = BaseNode::DEFAULT_PATH_SEPARATOR)
+ public function __construct(?string $name, ?NodeInterface $parent = null, int|float|null $min = null, int|float|null $max = null, string $pathSeparator = BaseNode::DEFAULT_PATH_SEPARATOR)
{
parent::__construct($name, $parent, $pathSeparator);
$this->min = $min;
diff --git a/src/Symfony/Component/Config/Definition/Processor.php b/src/Symfony/Component/Config/Definition/Processor.php
index dc3d4c69bbe44..272ddcc447360 100644
--- a/src/Symfony/Component/Config/Definition/Processor.php
+++ b/src/Symfony/Component/Config/Definition/Processor.php
@@ -67,7 +67,7 @@ public function processConfiguration(ConfigurationInterface $configuration, arra
* @param string $key The key to normalize
* @param string|null $plural The plural form of the key if it is irregular
*/
- public static function normalizeConfig(array $config, string $key, string $plural = null): array
+ public static function normalizeConfig(array $config, string $key, ?string $plural = null): array
{
$plural ??= $key.'s';
diff --git a/src/Symfony/Component/Config/Exception/FileLoaderImportCircularReferenceException.php b/src/Symfony/Component/Config/Exception/FileLoaderImportCircularReferenceException.php
index da0b55ba8ca61..2d2a4de004945 100644
--- a/src/Symfony/Component/Config/Exception/FileLoaderImportCircularReferenceException.php
+++ b/src/Symfony/Component/Config/Exception/FileLoaderImportCircularReferenceException.php
@@ -18,7 +18,7 @@
*/
class FileLoaderImportCircularReferenceException extends LoaderLoadException
{
- public function __construct(array $resources, int $code = 0, \Throwable $previous = null)
+ public function __construct(array $resources, int $code = 0, ?\Throwable $previous = null)
{
$message = sprintf('Circular reference detected in "%s" ("%s" > "%s").', $this->varToString($resources[0]), implode('" > "', $resources), $resources[0]);
diff --git a/src/Symfony/Component/Config/Exception/FileLocatorFileNotFoundException.php b/src/Symfony/Component/Config/Exception/FileLocatorFileNotFoundException.php
index 591182e53bac5..5641a31457289 100644
--- a/src/Symfony/Component/Config/Exception/FileLocatorFileNotFoundException.php
+++ b/src/Symfony/Component/Config/Exception/FileLocatorFileNotFoundException.php
@@ -20,7 +20,7 @@ class FileLocatorFileNotFoundException extends \InvalidArgumentException
{
private array $paths;
- public function __construct(string $message = '', int $code = 0, \Throwable $previous = null, array $paths = [])
+ public function __construct(string $message = '', int $code = 0, ?\Throwable $previous = null, array $paths = [])
{
parent::__construct($message, $code, $previous);
diff --git a/src/Symfony/Component/Config/Exception/LoaderLoadException.php b/src/Symfony/Component/Config/Exception/LoaderLoadException.php
index 495e9da272ab5..a2d5e33c7392f 100644
--- a/src/Symfony/Component/Config/Exception/LoaderLoadException.php
+++ b/src/Symfony/Component/Config/Exception/LoaderLoadException.php
@@ -25,7 +25,7 @@ class LoaderLoadException extends \Exception
* @param \Throwable|null $previous A previous exception
* @param string|null $type The type of resource
*/
- public function __construct(mixed $resource, string $sourceResource = null, int $code = 0, \Throwable $previous = null, string $type = null)
+ public function __construct(mixed $resource, ?string $sourceResource = null, int $code = 0, ?\Throwable $previous = null, ?string $type = null)
{
if (!\is_string($resource)) {
try {
diff --git a/src/Symfony/Component/Config/FileLocator.php b/src/Symfony/Component/Config/FileLocator.php
index a2a35b1c7e628..bf800694b519e 100644
--- a/src/Symfony/Component/Config/FileLocator.php
+++ b/src/Symfony/Component/Config/FileLocator.php
@@ -30,7 +30,12 @@ public function __construct(string|array $paths = [])
$this->paths = (array) $paths;
}
- public function locate(string $name, string $currentPath = null, bool $first = true): string|array
+ /**
+ * @return string|string[]
+ *
+ * @psalm-return ($first is true ? string : string[])
+ */
+ public function locate(string $name, ?string $currentPath = null, bool $first = true): string|array
{
if ('' === $name) {
throw new \InvalidArgumentException('An empty file name is not valid to be located.');
diff --git a/src/Symfony/Component/Config/FileLocatorInterface.php b/src/Symfony/Component/Config/FileLocatorInterface.php
index 526d35048412e..87cecf47729bb 100644
--- a/src/Symfony/Component/Config/FileLocatorInterface.php
+++ b/src/Symfony/Component/Config/FileLocatorInterface.php
@@ -25,10 +25,12 @@ interface FileLocatorInterface
* @param string|null $currentPath The current path
* @param bool $first Whether to return the first occurrence or an array of filenames
*
- * @return string|array The full path to the file or an array of file paths
+ * @return string|string[] The full path to the file or an array of file paths
*
* @throws \InvalidArgumentException If $name is empty
* @throws FileLocatorFileNotFoundException If a file is not found
+ *
+ * @psalm-return ($first is true ? string : string[])
*/
- public function locate(string $name, string $currentPath = null, bool $first = true): string|array;
+ public function locate(string $name, ?string $currentPath = null, bool $first = true): string|array;
}
diff --git a/src/Symfony/Component/Config/Loader/DelegatingLoader.php b/src/Symfony/Component/Config/Loader/DelegatingLoader.php
index fac3724e9eac3..045a559e2bad0 100644
--- a/src/Symfony/Component/Config/Loader/DelegatingLoader.php
+++ b/src/Symfony/Component/Config/Loader/DelegatingLoader.php
@@ -28,7 +28,7 @@ public function __construct(LoaderResolverInterface $resolver)
$this->resolver = $resolver;
}
- public function load(mixed $resource, string $type = null): mixed
+ public function load(mixed $resource, ?string $type = null): mixed
{
if (false === $loader = $this->resolver->resolve($resource, $type)) {
throw new LoaderLoadException($resource, null, 0, null, $type);
@@ -37,7 +37,7 @@ public function load(mixed $resource, string $type = null): mixed
return $loader->load($resource, $type);
}
- public function supports(mixed $resource, string $type = null): bool
+ public function supports(mixed $resource, ?string $type = null): bool
{
return false !== $this->resolver->resolve($resource, $type);
}
diff --git a/src/Symfony/Component/Config/Loader/FileLoader.php b/src/Symfony/Component/Config/Loader/FileLoader.php
index af1e5e7443764..c217cd85bfedd 100644
--- a/src/Symfony/Component/Config/Loader/FileLoader.php
+++ b/src/Symfony/Component/Config/Loader/FileLoader.php
@@ -31,7 +31,7 @@ abstract class FileLoader extends Loader
private ?string $currentDir = null;
- public function __construct(FileLocatorInterface $locator, string $env = null)
+ public function __construct(FileLocatorInterface $locator, ?string $env = null)
{
$this->locator = $locator;
parent::__construct($env);
@@ -66,7 +66,7 @@ public function getLocator(): FileLocatorInterface
* @throws FileLoaderImportCircularReferenceException
* @throws FileLocatorFileNotFoundException
*/
- public function import(mixed $resource, string $type = null, bool $ignoreErrors = false, string $sourceResource = null, string|array $exclude = null): mixed
+ public function import(mixed $resource, ?string $type = null, bool $ignoreErrors = false, ?string $sourceResource = null, string|array|null $exclude = null): mixed
{
if (\is_string($resource) && \strlen($resource) !== ($i = strcspn($resource, '*?{[')) && !str_contains($resource, "\n")) {
$excluded = [];
@@ -97,7 +97,7 @@ public function import(mixed $resource, string $type = null, bool $ignoreErrors
/**
* @internal
*/
- protected function glob(string $pattern, bool $recursive, array|GlobResource &$resource = null, bool $ignoreErrors = false, bool $forExclusion = false, array $excluded = []): iterable
+ protected function glob(string $pattern, bool $recursive, array|GlobResource|null &$resource = null, bool $ignoreErrors = false, bool $forExclusion = false, array $excluded = []): iterable
{
if (\strlen($pattern) === $i = strcspn($pattern, '*?{[')) {
$prefix = $pattern;
@@ -129,7 +129,7 @@ protected function glob(string $pattern, bool $recursive, array|GlobResource &$r
yield from $resource;
}
- private function doImport(mixed $resource, string $type = null, bool $ignoreErrors = false, string $sourceResource = null): mixed
+ private function doImport(mixed $resource, ?string $type = null, bool $ignoreErrors = false, ?string $sourceResource = null): mixed
{
try {
$loader = $this->resolve($resource, $type);
diff --git a/src/Symfony/Component/Config/Loader/GlobFileLoader.php b/src/Symfony/Component/Config/Loader/GlobFileLoader.php
index f921ec555a654..31eebf69d8b15 100644
--- a/src/Symfony/Component/Config/Loader/GlobFileLoader.php
+++ b/src/Symfony/Component/Config/Loader/GlobFileLoader.php
@@ -18,12 +18,12 @@
*/
class GlobFileLoader extends FileLoader
{
- public function load(mixed $resource, string $type = null): mixed
+ public function load(mixed $resource, ?string $type = null): mixed
{
return $this->import($resource);
}
- public function supports(mixed $resource, string $type = null): bool
+ public function supports(mixed $resource, ?string $type = null): bool
{
return 'glob' === $type;
}
diff --git a/src/Symfony/Component/Config/Loader/Loader.php b/src/Symfony/Component/Config/Loader/Loader.php
index df94e9777777b..dc65ecb528be4 100644
--- a/src/Symfony/Component/Config/Loader/Loader.php
+++ b/src/Symfony/Component/Config/Loader/Loader.php
@@ -40,7 +40,7 @@ public function setResolver(LoaderResolverInterface $resolver): void
/**
* Imports a resource.
*/
- public function import(mixed $resource, string $type = null): mixed
+ public function import(mixed $resource, ?string $type = null): mixed
{
return $this->resolve($resource, $type)->load($resource, $type);
}
@@ -50,7 +50,7 @@ public function import(mixed $resource, string $type = null): mixed
*
* @throws LoaderLoadException If no loader is found
*/
- public function resolve(mixed $resource, string $type = null): LoaderInterface
+ public function resolve(mixed $resource, ?string $type = null): LoaderInterface
{
if ($this->supports($resource, $type)) {
return $this;
diff --git a/src/Symfony/Component/Config/Loader/LoaderInterface.php b/src/Symfony/Component/Config/Loader/LoaderInterface.php
index 0de7c8bb8fbcf..6ed1893a53ae4 100644
--- a/src/Symfony/Component/Config/Loader/LoaderInterface.php
+++ b/src/Symfony/Component/Config/Loader/LoaderInterface.php
@@ -23,14 +23,14 @@ interface LoaderInterface
*
* @throws \Exception If something went wrong
*/
- public function load(mixed $resource, string $type = null): mixed;
+ public function load(mixed $resource, ?string $type = null): mixed;
/**
* Returns whether this class supports the given resource.
*
* @param mixed $resource A resource
*/
- public function supports(mixed $resource, string $type = null): bool;
+ public function supports(mixed $resource, ?string $type = null): bool;
/**
* Gets the loader resolver.
diff --git a/src/Symfony/Component/Config/Loader/LoaderResolver.php b/src/Symfony/Component/Config/Loader/LoaderResolver.php
index 50bcc7fe90684..8308d7e895c0b 100644
--- a/src/Symfony/Component/Config/Loader/LoaderResolver.php
+++ b/src/Symfony/Component/Config/Loader/LoaderResolver.php
@@ -36,7 +36,7 @@ public function __construct(array $loaders = [])
}
}
- public function resolve(mixed $resource, string $type = null): LoaderInterface|false
+ public function resolve(mixed $resource, ?string $type = null): LoaderInterface|false
{
foreach ($this->loaders as $loader) {
if ($loader->supports($resource, $type)) {
diff --git a/src/Symfony/Component/Config/Loader/LoaderResolverInterface.php b/src/Symfony/Component/Config/Loader/LoaderResolverInterface.php
index 076c5207c9c16..a8bb3a43766f4 100644
--- a/src/Symfony/Component/Config/Loader/LoaderResolverInterface.php
+++ b/src/Symfony/Component/Config/Loader/LoaderResolverInterface.php
@@ -23,5 +23,5 @@ interface LoaderResolverInterface
*
* @param string|null $type The resource type or null if unknown
*/
- public function resolve(mixed $resource, string $type = null): LoaderInterface|false;
+ public function resolve(mixed $resource, ?string $type = null): LoaderInterface|false;
}
diff --git a/src/Symfony/Component/Config/Resource/ClassExistenceResource.php b/src/Symfony/Component/Config/Resource/ClassExistenceResource.php
index 72932c969a12f..e2175b9ba7b48 100644
--- a/src/Symfony/Component/Config/Resource/ClassExistenceResource.php
+++ b/src/Symfony/Component/Config/Resource/ClassExistenceResource.php
@@ -35,7 +35,7 @@ class ClassExistenceResource implements SelfCheckingResourceInterface
*/
public function __construct(
private string $resource,
- bool $exists = null,
+ ?bool $exists = null,
) {
if (null !== $exists) {
$this->exists = [$exists, null];
@@ -139,7 +139,7 @@ public function __wakeup(): void
*
* @internal
*/
- public static function throwOnRequiredClass(string $class, \Exception $previous = null): void
+ public static function throwOnRequiredClass(string $class, ?\Exception $previous = null): void
{
// If the passed class is the resource being checked, we shouldn't throw.
if (null === $previous && self::$autoloadedClass === $class) {
diff --git a/src/Symfony/Component/Config/ResourceCheckerConfigCache.php b/src/Symfony/Component/Config/ResourceCheckerConfigCache.php
index 5634f1ecfa9d0..8704bc91e311a 100644
--- a/src/Symfony/Component/Config/ResourceCheckerConfigCache.php
+++ b/src/Symfony/Component/Config/ResourceCheckerConfigCache.php
@@ -23,14 +23,19 @@
*/
class ResourceCheckerConfigCache implements ConfigCacheInterface
{
+ private string $metaFile;
+
/**
* @param string $file The absolute cache path
* @param iterable $resourceCheckers The ResourceCheckers to use for the freshness check
+ * @param string|null $metaFile The absolute path to the meta file, defaults to $file.meta if null
*/
public function __construct(
private string $file,
private iterable $resourceCheckers = [],
+ ?string $metaFile = null,
) {
+ $this->metaFile = $metaFile ?? $file.'.meta';
}
public function getPath(): string
@@ -61,7 +66,7 @@ public function isFresh(): bool
return true; // shortcut - if we don't have any checkers we don't need to bother with the meta file at all
}
- $metadata = $this->getMetaFile();
+ $metadata = $this->metaFile;
if (!is_file($metadata)) {
return false;
@@ -100,7 +105,7 @@ public function isFresh(): bool
*
* @throws \RuntimeException When cache file can't be written
*/
- public function write(string $content, array $metadata = null): void
+ public function write(string $content, ?array $metadata = null): void
{
$mode = 0666;
$umask = umask();
@@ -113,9 +118,9 @@ public function write(string $content, array $metadata = null): void
}
if (null !== $metadata) {
- $filesystem->dumpFile($this->getMetaFile(), serialize($metadata));
+ $filesystem->dumpFile($this->metaFile, serialize($metadata));
try {
- $filesystem->chmod($this->getMetaFile(), $mode, $umask);
+ $filesystem->chmod($this->metaFile, $mode, $umask);
} catch (IOException) {
// discard chmod failure (some filesystem may not support it)
}
@@ -126,14 +131,6 @@ public function write(string $content, array $metadata = null): void
}
}
- /**
- * Gets the meta file path.
- */
- private function getMetaFile(): string
- {
- return $this->file.'.meta';
- }
-
private function safelyUnserialize(string $file): mixed
{
$meta = false;
diff --git a/src/Symfony/Component/Config/Tests/Builder/GeneratedConfigTest.php b/src/Symfony/Component/Config/Tests/Builder/GeneratedConfigTest.php
index db2ade6ffa204..722df54cbcf26 100644
--- a/src/Symfony/Component/Config/Tests/Builder/GeneratedConfigTest.php
+++ b/src/Symfony/Component/Config/Tests/Builder/GeneratedConfigTest.php
@@ -162,7 +162,7 @@ public function testSetExtraKeyMethodIsNotGeneratedWhenAllowExtraKeysIsFalse()
/**
* Generate the ConfigBuilder or return an already generated instance.
*/
- private function generateConfigBuilder(string $configurationClass, string $outputDir = null)
+ private function generateConfigBuilder(string $configurationClass, ?string $outputDir = null)
{
$outputDir ??= sys_get_temp_dir().\DIRECTORY_SEPARATOR.uniqid('sf_config_builder', true);
if (!str_contains($outputDir, __DIR__)) {
diff --git a/src/Symfony/Component/Config/Tests/Definition/Builder/ExprBuilderTest.php b/src/Symfony/Component/Config/Tests/Definition/Builder/ExprBuilderTest.php
index 873ffb4051e96..656919e65f617 100644
--- a/src/Symfony/Component/Config/Tests/Definition/Builder/ExprBuilderTest.php
+++ b/src/Symfony/Component/Config/Tests/Definition/Builder/ExprBuilderTest.php
@@ -223,7 +223,7 @@ protected function getTestBuilder(): ExprBuilder
* @param array|null $config The config you want to use for the finalization, if nothing provided
* a simple ['key'=>'value'] will be used
*/
- protected function finalizeTestBuilder(NodeDefinition $nodeDefinition, array $config = null): array
+ protected function finalizeTestBuilder(NodeDefinition $nodeDefinition, ?array $config = null): array
{
return $nodeDefinition
->end()
diff --git a/src/Symfony/Component/Config/Tests/Loader/FileLoaderTest.php b/src/Symfony/Component/Config/Tests/Loader/FileLoaderTest.php
index 4b7464a3cd977..185213964753b 100644
--- a/src/Symfony/Component/Config/Tests/Loader/FileLoaderTest.php
+++ b/src/Symfony/Component/Config/Tests/Loader/FileLoaderTest.php
@@ -155,12 +155,12 @@ class TestFileLoader extends FileLoader
{
private bool $supports = true;
- public function load(mixed $resource, string $type = null): mixed
+ public function load(mixed $resource, ?string $type = null): mixed
{
return $resource;
}
- public function supports(mixed $resource, string $type = null): bool
+ public function supports(mixed $resource, ?string $type = null): bool
{
return $this->supports;
}
diff --git a/src/Symfony/Component/Config/Tests/Loader/LoaderTest.php b/src/Symfony/Component/Config/Tests/Loader/LoaderTest.php
index 385103cebe2ec..70bfb8fc15005 100644
--- a/src/Symfony/Component/Config/Tests/Loader/LoaderTest.php
+++ b/src/Symfony/Component/Config/Tests/Loader/LoaderTest.php
@@ -105,11 +105,11 @@ public function testImportWithType()
class ProjectLoader1 extends Loader
{
- public function load(mixed $resource, string $type = null): mixed
+ public function load(mixed $resource, ?string $type = null): mixed
{
}
- public function supports(mixed $resource, string $type = null): bool
+ public function supports(mixed $resource, ?string $type = null): bool
{
return \is_string($resource) && 'foo' === pathinfo($resource, \PATHINFO_EXTENSION);
}
diff --git a/src/Symfony/Component/Config/Tests/Resource/ReflectionClassResourceTest.php b/src/Symfony/Component/Config/Tests/Resource/ReflectionClassResourceTest.php
index 10e4e169d3f7f..07741556b1950 100644
--- a/src/Symfony/Component/Config/Tests/Resource/ReflectionClassResourceTest.php
+++ b/src/Symfony/Component/Config/Tests/Resource/ReflectionClassResourceTest.php
@@ -63,7 +63,7 @@ public function testIsFreshForDeletedResources()
/**
* @dataProvider provideHashedSignature
*/
- public function testHashedSignature(bool $changeExpected, int $changedLine, ?string $changedCode, \Closure $setContext = null)
+ public function testHashedSignature(bool $changeExpected, int $changedLine, ?string $changedCode, ?\Closure $setContext = null)
{
if ($setContext) {
$setContext();
diff --git a/src/Symfony/Component/Config/Tests/ResourceCheckerConfigCacheTest.php b/src/Symfony/Component/Config/Tests/ResourceCheckerConfigCacheTest.php
index 37f30a49d4ec0..53b66b88e447f 100644
--- a/src/Symfony/Component/Config/Tests/ResourceCheckerConfigCacheTest.php
+++ b/src/Symfony/Component/Config/Tests/ResourceCheckerConfigCacheTest.php
@@ -21,14 +21,17 @@ class ResourceCheckerConfigCacheTest extends TestCase
{
private string $cacheFile;
+ private string $metaFile;
+
protected function setUp(): void
{
$this->cacheFile = tempnam(sys_get_temp_dir(), 'config_');
+ $this->metaFile = tempnam(sys_get_temp_dir(), 'config_');
}
protected function tearDown(): void
{
- $files = [$this->cacheFile, "{$this->cacheFile}.meta"];
+ $files = [$this->cacheFile, "{$this->cacheFile}.meta", $this->metaFile];
foreach ($files as $file) {
if (file_exists($file)) {
@@ -148,4 +151,15 @@ public function testCacheIsNotFreshIfNotExistsMetaFile()
$this->assertFalse($cache->isFresh());
}
+
+ public function testCacheWithCustomMetaFile()
+ {
+ $this->assertStringEqualsFile($this->metaFile, '');
+
+ $checker = $this->createMock(ResourceCheckerInterface::class);
+ $cache = new ResourceCheckerConfigCache($this->cacheFile, [$checker], $this->metaFile);
+ $cache->write('foo', [new FileResource(__FILE__)]);
+
+ $this->assertStringNotEqualsFile($this->metaFile, '');
+ }
}
diff --git a/src/Symfony/Component/Config/Util/XmlUtils.php b/src/Symfony/Component/Config/Util/XmlUtils.php
index a21d261a248c7..d86a5823ad994 100644
--- a/src/Symfony/Component/Config/Util/XmlUtils.php
+++ b/src/Symfony/Component/Config/Util/XmlUtils.php
@@ -42,7 +42,7 @@ private function __construct()
* @throws InvalidXmlException When parsing of XML with schema or callable produces any errors unrelated to the XML parsing itself
* @throws \RuntimeException When DOM extension is missing
*/
- public static function parse(string $content, string|callable $schemaOrCallable = null): \DOMDocument
+ public static function parse(string $content, string|callable|null $schemaOrCallable = null): \DOMDocument
{
if (!\extension_loaded('dom')) {
throw new \LogicException('Extension DOM is required.');
@@ -112,7 +112,7 @@ public static function parse(string $content, string|callable $schemaOrCallable
* @throws XmlParsingException When XML parsing returns any errors
* @throws \RuntimeException When DOM extension is missing
*/
- public static function loadFile(string $file, string|callable $schemaOrCallable = null): \DOMDocument
+ public static function loadFile(string $file, string|callable|null $schemaOrCallable = null): \DOMDocument
{
if (!is_file($file)) {
throw new \InvalidArgumentException(sprintf('Resource "%s" is not a file.', $file));
diff --git a/src/Symfony/Component/Console/Application.php b/src/Symfony/Component/Console/Application.php
index 00acef1dd1df0..9c301471c6581 100644
--- a/src/Symfony/Component/Console/Application.php
+++ b/src/Symfony/Component/Console/Application.php
@@ -135,7 +135,7 @@ public function setSignalsToDispatchEvent(int ...$signalsToDispatchEvent): void
*
* @throws \Exception When running fails. Bypass this when {@link setCatchExceptions()}.
*/
- public function run(InputInterface $input = null, OutputInterface $output = null): int
+ public function run(?InputInterface $input = null, ?OutputInterface $output = null): int
{
if (\function_exists('putenv')) {
@putenv('LINES='.$this->terminal->getHeight());
@@ -760,7 +760,7 @@ public function find(string $name): Command
*
* @return Command[]
*/
- public function all(string $namespace = null): array
+ public function all(?string $namespace = null): array
{
$this->init();
@@ -1128,7 +1128,7 @@ private function getAbbreviationSuggestions(array $abbrevs): string
*
* This method is not part of public API and should not be used directly.
*/
- public function extractNamespace(string $name, int $limit = null): string
+ public function extractNamespace(string $name, ?int $limit = null): string
{
$parts = explode(':', $name, -1);
diff --git a/src/Symfony/Component/Console/CI/GithubActionReporter.php b/src/Symfony/Component/Console/CI/GithubActionReporter.php
index 7e5565469a954..2cae6fd8ba34c 100644
--- a/src/Symfony/Component/Console/CI/GithubActionReporter.php
+++ b/src/Symfony/Component/Console/CI/GithubActionReporter.php
@@ -57,7 +57,7 @@ public static function isGithubActionEnvironment(): bool
*
* @see https://docs.github.com/en/free-pro-team@latest/actions/reference/workflow-commands-for-github-actions#setting-an-error-message
*/
- public function error(string $message, string $file = null, int $line = null, int $col = null): void
+ public function error(string $message, ?string $file = null, ?int $line = null, ?int $col = null): void
{
$this->log('error', $message, $file, $line, $col);
}
@@ -67,7 +67,7 @@ public function error(string $message, string $file = null, int $line = null, in
*
* @see https://docs.github.com/en/free-pro-team@latest/actions/reference/workflow-commands-for-github-actions#setting-a-warning-message
*/
- public function warning(string $message, string $file = null, int $line = null, int $col = null): void
+ public function warning(string $message, ?string $file = null, ?int $line = null, ?int $col = null): void
{
$this->log('warning', $message, $file, $line, $col);
}
@@ -77,12 +77,12 @@ public function warning(string $message, string $file = null, int $line = null,
*
* @see https://docs.github.com/en/free-pro-team@latest/actions/reference/workflow-commands-for-github-actions#setting-a-debug-message
*/
- public function debug(string $message, string $file = null, int $line = null, int $col = null): void
+ public function debug(string $message, ?string $file = null, ?int $line = null, ?int $col = null): void
{
$this->log('debug', $message, $file, $line, $col);
}
- private function log(string $type, string $message, string $file = null, int $line = null, int $col = null): void
+ private function log(string $type, string $message, ?string $file = null, ?int $line = null, ?int $col = null): void
{
// Some values must be encoded.
$message = strtr($message, self::ESCAPED_DATA);
diff --git a/src/Symfony/Component/Console/Command/Command.php b/src/Symfony/Component/Console/Command/Command.php
index ef1e7c31e9087..03da6db43f335 100644
--- a/src/Symfony/Component/Console/Command/Command.php
+++ b/src/Symfony/Component/Console/Command/Command.php
@@ -77,7 +77,7 @@ public static function getDefaultDescription(): ?string
*
* @throws LogicException When the command name is empty
*/
- public function __construct(string $name = null)
+ public function __construct(?string $name = null)
{
$this->definition = new InputDefinition();
@@ -283,7 +283,7 @@ public function run(InputInterface $input, OutputInterface $output): int
}
/**
- * Adds suggestions to $suggestions for the current completion input (e.g. option or argument).
+ * Supplies suggestions when resolving possible completion options for input (e.g. option or argument).
*/
public function complete(CompletionInput $input, CompletionSuggestions $suggestions): void
{
@@ -401,15 +401,15 @@ public function getNativeDefinition(): InputDefinition
/**
* Adds an argument.
*
- * @param $mode The argument mode: InputArgument::REQUIRED or InputArgument::OPTIONAL
- * @param $default The default value (for InputArgument::OPTIONAL mode only)
+ * @param $mode The argument mode: InputArgument::REQUIRED or InputArgument::OPTIONAL
+ * @param $default The default value (for InputArgument::OPTIONAL mode only)
* @param array|\Closure(CompletionInput,CompletionSuggestions):list $suggestedValues The values used for input completion
*
* @return $this
*
* @throws InvalidArgumentException When argument mode is not valid
*/
- public function addArgument(string $name, int $mode = null, string $description = '', mixed $default = null, array|\Closure $suggestedValues = []): static
+ public function addArgument(string $name, ?int $mode = null, string $description = '', mixed $default = null, array|\Closure $suggestedValues = []): static
{
$this->definition->addArgument(new InputArgument($name, $mode, $description, $default, $suggestedValues));
$this->fullDefinition?->addArgument(new InputArgument($name, $mode, $description, $default, $suggestedValues));
@@ -420,16 +420,16 @@ public function addArgument(string $name, int $mode = null, string $description
/**
* Adds an option.
*
- * @param $shortcut The shortcuts, can be null, a string of shortcuts delimited by | or an array of shortcuts
- * @param $mode The option mode: One of the InputOption::VALUE_* constants
- * @param $default The default value (must be null for InputOption::VALUE_NONE)
+ * @param $shortcut The shortcuts, can be null, a string of shortcuts delimited by | or an array of shortcuts
+ * @param $mode The option mode: One of the InputOption::VALUE_* constants
+ * @param $default The default value (must be null for InputOption::VALUE_NONE)
* @param array|\Closure(CompletionInput,CompletionSuggestions):list $suggestedValues The values used for input completion
*
* @return $this
*
* @throws InvalidArgumentException If option mode is invalid or incompatible
*/
- public function addOption(string $name, string|array $shortcut = null, int $mode = null, string $description = '', mixed $default = null, array|\Closure $suggestedValues = []): static
+ public function addOption(string $name, string|array|null $shortcut = null, ?int $mode = null, string $description = '', mixed $default = null, array|\Closure $suggestedValues = []): static
{
$this->definition->addOption(new InputOption($name, $shortcut, $mode, $description, $default, $suggestedValues));
$this->fullDefinition?->addOption(new InputOption($name, $shortcut, $mode, $description, $default, $suggestedValues));
diff --git a/src/Symfony/Component/Console/Command/LazyCommand.php b/src/Symfony/Component/Console/Command/LazyCommand.php
index df44b3d01d8ec..fd2c300d7fb90 100644
--- a/src/Symfony/Component/Console/Command/LazyCommand.php
+++ b/src/Symfony/Component/Console/Command/LazyCommand.php
@@ -117,7 +117,7 @@ public function getNativeDefinition(): InputDefinition
/**
* @param array|\Closure(CompletionInput,CompletionSuggestions):list $suggestedValues The values used for input completion
*/
- public function addArgument(string $name, int $mode = null, string $description = '', mixed $default = null, array|\Closure $suggestedValues = []): static
+ public function addArgument(string $name, ?int $mode = null, string $description = '', mixed $default = null, array|\Closure $suggestedValues = []): static
{
$this->getCommand()->addArgument($name, $mode, $description, $default, $suggestedValues);
@@ -127,7 +127,7 @@ public function addArgument(string $name, int $mode = null, string $description
/**
* @param array|\Closure(CompletionInput,CompletionSuggestions):list $suggestedValues The values used for input completion
*/
- public function addOption(string $name, string|array $shortcut = null, int $mode = null, string $description = '', mixed $default = null, array|\Closure $suggestedValues = []): static
+ public function addOption(string $name, string|array|null $shortcut = null, ?int $mode = null, string $description = '', mixed $default = null, array|\Closure $suggestedValues = []): static
{
$this->getCommand()->addOption($name, $shortcut, $mode, $description, $default, $suggestedValues);
diff --git a/src/Symfony/Component/Console/Command/LockableTrait.php b/src/Symfony/Component/Console/Command/LockableTrait.php
index c1006a65c0aff..cd7548f02f9e9 100644
--- a/src/Symfony/Component/Console/Command/LockableTrait.php
+++ b/src/Symfony/Component/Console/Command/LockableTrait.php
@@ -29,7 +29,7 @@ trait LockableTrait
/**
* Locks a command.
*/
- private function lock(string $name = null, bool $blocking = false): bool
+ private function lock(?string $name = null, bool $blocking = false): bool
{
if (!class_exists(SemaphoreStore::class)) {
throw new LogicException('To enable the locking feature you must install the symfony/lock component. Try running "composer require symfony/lock".');
diff --git a/src/Symfony/Component/Console/Command/TraceableCommand.php b/src/Symfony/Component/Console/Command/TraceableCommand.php
index d8c46b7faa1ed..9ffb68da39766 100644
--- a/src/Symfony/Component/Console/Command/TraceableCommand.php
+++ b/src/Symfony/Component/Console/Command/TraceableCommand.php
@@ -134,7 +134,7 @@ public function ignoreValidationErrors(): void
parent::ignoreValidationErrors();
}
- public function setApplication(Application $application = null): void
+ public function setApplication(?Application $application = null): void
{
$this->command->setApplication($application);
}
@@ -209,14 +209,14 @@ public function getNativeDefinition(): InputDefinition
return $this->command->getNativeDefinition();
}
- public function addArgument(string $name, int $mode = null, string $description = '', mixed $default = null, array|\Closure $suggestedValues = []): static
+ public function addArgument(string $name, ?int $mode = null, string $description = '', mixed $default = null, array|\Closure $suggestedValues = []): static
{
$this->command->addArgument($name, $mode, $description, $default, $suggestedValues);
return $this;
}
- public function addOption(string $name, string|array $shortcut = null, int $mode = null, string $description = '', mixed $default = null, array|\Closure $suggestedValues = []): static
+ public function addOption(string $name, string|array|null $shortcut = null, ?int $mode = null, string $description = '', mixed $default = null, array|\Closure $suggestedValues = []): static
{
$this->command->addOption($name, $shortcut, $mode, $description, $default, $suggestedValues);
diff --git a/src/Symfony/Component/Console/DataCollector/CommandDataCollector.php b/src/Symfony/Component/Console/DataCollector/CommandDataCollector.php
index 16a0eadf4802f..45138c7dc0f86 100644
--- a/src/Symfony/Component/Console/DataCollector/CommandDataCollector.php
+++ b/src/Symfony/Component/Console/DataCollector/CommandDataCollector.php
@@ -27,7 +27,7 @@
*/
final class CommandDataCollector extends DataCollector
{
- public function collect(Request $request, Response $response, \Throwable $exception = null): void
+ public function collect(Request $request, Response $response, ?\Throwable $exception = null): void
{
if (!$request instanceof CliRequest) {
return;
diff --git a/src/Symfony/Component/Console/Descriptor/XmlDescriptor.php b/src/Symfony/Component/Console/Descriptor/XmlDescriptor.php
index 72580fd9852b4..866c718566fec 100644
--- a/src/Symfony/Component/Console/Descriptor/XmlDescriptor.php
+++ b/src/Symfony/Component/Console/Descriptor/XmlDescriptor.php
@@ -79,7 +79,7 @@ public function getCommandDocument(Command $command, bool $short = false): \DOMD
return $dom;
}
- public function getApplicationDocument(Application $application, string $namespace = null, bool $short = false): \DOMDocument
+ public function getApplicationDocument(Application $application, ?string $namespace = null, bool $short = false): \DOMDocument
{
$dom = new \DOMDocument('1.0', 'UTF-8');
$dom->appendChild($rootXml = $dom->createElement('symfony'));
diff --git a/src/Symfony/Component/Console/Event/ConsoleErrorEvent.php b/src/Symfony/Component/Console/Event/ConsoleErrorEvent.php
index f469fbcee0653..1c0d62652d913 100644
--- a/src/Symfony/Component/Console/Event/ConsoleErrorEvent.php
+++ b/src/Symfony/Component/Console/Event/ConsoleErrorEvent.php
@@ -28,7 +28,7 @@ public function __construct(
InputInterface $input,
OutputInterface $output,
private \Throwable $error,
- Command $command = null,
+ ?Command $command = null,
) {
parent::__construct($command, $input, $output);
}
diff --git a/src/Symfony/Component/Console/Exception/CommandNotFoundException.php b/src/Symfony/Component/Console/Exception/CommandNotFoundException.php
index 47750d5f94131..246f04fa20e31 100644
--- a/src/Symfony/Component/Console/Exception/CommandNotFoundException.php
+++ b/src/Symfony/Component/Console/Exception/CommandNotFoundException.php
@@ -28,7 +28,7 @@ public function __construct(
string $message,
private array $alternatives = [],
int $code = 0,
- \Throwable $previous = null,
+ ?\Throwable $previous = null,
) {
parent::__construct($message, $code, $previous);
}
diff --git a/src/Symfony/Component/Console/Formatter/OutputFormatterStyle.php b/src/Symfony/Component/Console/Formatter/OutputFormatterStyle.php
index 4582ccd051116..20a65b517c568 100644
--- a/src/Symfony/Component/Console/Formatter/OutputFormatterStyle.php
+++ b/src/Symfony/Component/Console/Formatter/OutputFormatterStyle.php
@@ -33,7 +33,7 @@ class OutputFormatterStyle implements OutputFormatterStyleInterface
* @param string|null $foreground The style foreground color name
* @param string|null $background The style background color name
*/
- public function __construct(string $foreground = null, string $background = null, array $options = [])
+ public function __construct(?string $foreground = null, ?string $background = null, array $options = [])
{
$this->color = new Color($this->foreground = $foreground ?: '', $this->background = $background ?: '', $this->options = $options);
}
diff --git a/src/Symfony/Component/Console/Formatter/OutputFormatterStyleStack.php b/src/Symfony/Component/Console/Formatter/OutputFormatterStyleStack.php
index c3726a35d840a..4985213abc075 100644
--- a/src/Symfony/Component/Console/Formatter/OutputFormatterStyleStack.php
+++ b/src/Symfony/Component/Console/Formatter/OutputFormatterStyleStack.php
@@ -26,7 +26,7 @@ class OutputFormatterStyleStack implements ResetInterface
private OutputFormatterStyleInterface $emptyStyle;
- public function __construct(OutputFormatterStyleInterface $emptyStyle = null)
+ public function __construct(?OutputFormatterStyleInterface $emptyStyle = null)
{
$this->emptyStyle = $emptyStyle ?? new OutputFormatterStyle();
$this->reset();
@@ -53,7 +53,7 @@ public function push(OutputFormatterStyleInterface $style): void
*
* @throws InvalidArgumentException When style tags incorrectly nested
*/
- public function pop(OutputFormatterStyleInterface $style = null): OutputFormatterStyleInterface
+ public function pop(?OutputFormatterStyleInterface $style = null): OutputFormatterStyleInterface
{
if (!$this->styles) {
return $this->emptyStyle;
diff --git a/src/Symfony/Component/Console/Helper/Helper.php b/src/Symfony/Component/Console/Helper/Helper.php
index afb20ad50377a..de090063a1380 100644
--- a/src/Symfony/Component/Console/Helper/Helper.php
+++ b/src/Symfony/Component/Console/Helper/Helper.php
@@ -74,7 +74,7 @@ public static function length(?string $string): int
/**
* Returns the subset of a string, using mb_substr if it is available.
*/
- public static function substr(?string $string, int $from, int $length = null): string
+ public static function substr(?string $string, int $from, ?int $length = null): string
{
$string ??= '';
diff --git a/src/Symfony/Component/Console/Helper/HelperSet.php b/src/Symfony/Component/Console/Helper/HelperSet.php
index 42153b68d01c0..30df9f9582cc1 100644
--- a/src/Symfony/Component/Console/Helper/HelperSet.php
+++ b/src/Symfony/Component/Console/Helper/HelperSet.php
@@ -35,7 +35,7 @@ public function __construct(array $helpers = [])
}
}
- public function set(HelperInterface $helper, string $alias = null): void
+ public function set(HelperInterface $helper, ?string $alias = null): void
{
$this->helpers[$helper->getName()] = $helper;
if (null !== $alias) {
diff --git a/src/Symfony/Component/Console/Helper/ProcessHelper.php b/src/Symfony/Component/Console/Helper/ProcessHelper.php
index 26d35a1a89d12..3ef6f71f753aa 100644
--- a/src/Symfony/Component/Console/Helper/ProcessHelper.php
+++ b/src/Symfony/Component/Console/Helper/ProcessHelper.php
@@ -32,7 +32,7 @@ class ProcessHelper extends Helper
* @param callable|null $callback A PHP callback to run whenever there is some
* output available on STDOUT or STDERR
*/
- public function run(OutputInterface $output, array|Process $cmd, string $error = null, callable $callback = null, int $verbosity = OutputInterface::VERBOSITY_VERY_VERBOSE): Process
+ public function run(OutputInterface $output, array|Process $cmd, ?string $error = null, ?callable $callback = null, int $verbosity = OutputInterface::VERBOSITY_VERY_VERBOSE): Process
{
if (!class_exists(Process::class)) {
throw new \LogicException('The ProcessHelper cannot be run as the Process component is not installed. Try running "compose require symfony/process".');
@@ -94,7 +94,7 @@ public function run(OutputInterface $output, array|Process $cmd, string $error =
*
* @see run()
*/
- public function mustRun(OutputInterface $output, array|Process $cmd, string $error = null, callable $callback = null): Process
+ public function mustRun(OutputInterface $output, array|Process $cmd, ?string $error = null, ?callable $callback = null): Process
{
$process = $this->run($output, $cmd, $error, $callback);
@@ -108,7 +108,7 @@ public function mustRun(OutputInterface $output, array|Process $cmd, string $err
/**
* Wraps a Process callback to add debugging output.
*/
- public function wrapCallback(OutputInterface $output, Process $process, callable $callback = null): callable
+ public function wrapCallback(OutputInterface $output, Process $process, ?callable $callback = null): callable
{
if ($output instanceof ConsoleOutputInterface) {
$output = $output->getErrorOutput();
diff --git a/src/Symfony/Component/Console/Helper/ProgressBar.php b/src/Symfony/Component/Console/Helper/ProgressBar.php
index a1f806d5f3113..70fe50ee4970f 100644
--- a/src/Symfony/Component/Console/Helper/ProgressBar.php
+++ b/src/Symfony/Component/Console/Helper/ProgressBar.php
@@ -313,7 +313,7 @@ public function maxSecondsBetweenRedraws(float $seconds): void
*
* @return iterable
*/
- public function iterate(iterable $iterable, int $max = null): iterable
+ public function iterate(iterable $iterable, ?int $max = null): iterable
{
if (0 === $max) {
$max = null;
@@ -346,7 +346,7 @@ public function iterate(iterable $iterable, int $max = null): iterable
* @param int|null $max Number of steps to complete the bar (0 if indeterminate), null to leave unchanged
* @param int $startAt The starting point of the bar (useful e.g. when resuming a previously started bar)
*/
- public function start(int $max = null, int $startAt = 0): void
+ public function start(?int $max = null, int $startAt = 0): void
{
$this->startTime = time();
$this->step = $startAt;
diff --git a/src/Symfony/Component/Console/Helper/ProgressIndicator.php b/src/Symfony/Component/Console/Helper/ProgressIndicator.php
index 8ebf991458f26..969d83539d8e2 100644
--- a/src/Symfony/Component/Console/Helper/ProgressIndicator.php
+++ b/src/Symfony/Component/Console/Helper/ProgressIndicator.php
@@ -50,9 +50,9 @@ class ProgressIndicator
*/
public function __construct(
private OutputInterface $output,
- string $format = null,
+ ?string $format = null,
private int $indicatorChangeInterval = 100,
- array $indicatorValues = null,
+ ?array $indicatorValues = null,
) {
$format ??= $this->determineBestFormat();
diff --git a/src/Symfony/Component/Console/Helper/QuestionHelper.php b/src/Symfony/Component/Console/Helper/QuestionHelper.php
index cb75ac914cb06..0967156cae04d 100644
--- a/src/Symfony/Component/Console/Helper/QuestionHelper.php
+++ b/src/Symfony/Component/Console/Helper/QuestionHelper.php
@@ -34,11 +34,6 @@
*/
class QuestionHelper extends Helper
{
- /**
- * @var resource|null
- */
- private $inputStream;
-
private static bool $stty = true;
private static bool $stdinIsInteractive;
@@ -59,16 +54,15 @@ public function ask(InputInterface $input, OutputInterface $output, Question $qu
return $this->getDefaultAnswer($question);
}
- if ($input instanceof StreamableInputInterface && $stream = $input->getStream()) {
- $this->inputStream = $stream;
- }
+ $inputStream = $input instanceof StreamableInputInterface ? $input->getStream() : null;
+ $inputStream ??= STDIN;
try {
if (!$question->getValidator()) {
- return $this->doAsk($output, $question);
+ return $this->doAsk($inputStream, $output, $question);
}
- $interviewer = fn () => $this->doAsk($output, $question);
+ $interviewer = fn () => $this->doAsk($inputStream, $output, $question);
return $this->validateAttempts($interviewer, $output, $question);
} catch (MissingInputException $exception) {
@@ -98,13 +92,14 @@ public static function disableStty(): void
/**
* Asks the question to the user.
*
+ * @param resource $inputStream
+ *
* @throws RuntimeException In case the fallback is deactivated and the response cannot be hidden
*/
- private function doAsk(OutputInterface $output, Question $question): mixed
+ private function doAsk($inputStream, OutputInterface $output, Question $question): mixed
{
$this->writePrompt($output, $question);
- $inputStream = $this->inputStream ?: \STDIN;
$autocomplete = $question->getAutocompleterCallback();
if (null === $autocomplete || !self::$stty || !Terminal::hasSttyAvailable()) {
diff --git a/src/Symfony/Component/Console/Helper/Table.php b/src/Symfony/Component/Console/Helper/Table.php
index 87cea7f77b621..1b32ae39fdbeb 100644
--- a/src/Symfony/Component/Console/Helper/Table.php
+++ b/src/Symfony/Component/Console/Helper/Table.php
@@ -460,7 +460,7 @@ public function render(): void
*
* +-----+-----------+-------+
*/
- private function renderRowSeparator(int $type = self::SEPARATOR_MID, string $title = null, string $titleFormat = null): void
+ private function renderRowSeparator(int $type = self::SEPARATOR_MID, ?string $title = null, ?string $titleFormat = null): void
{
if (!$count = $this->numberOfColumns) {
return;
@@ -525,7 +525,7 @@ private function renderColumnSeparator(int $type = self::BORDER_OUTSIDE): string
*
* | 9971-5-0210-0 | A Tale of Two Cities | Charles Dickens |
*/
- private function renderRow(array $row, string $cellFormat, string $firstCellFormat = null): void
+ private function renderRow(array $row, string $cellFormat, ?string $firstCellFormat = null): void
{
$rowContent = $this->renderColumnSeparator(self::BORDER_OUTSIDE);
$columns = $this->getRowColumns($row);
diff --git a/src/Symfony/Component/Console/Helper/TableStyle.php b/src/Symfony/Component/Console/Helper/TableStyle.php
index bbad98e73ccd7..be956c109edf5 100644
--- a/src/Symfony/Component/Console/Helper/TableStyle.php
+++ b/src/Symfony/Component/Console/Helper/TableStyle.php
@@ -88,7 +88,7 @@ public function getPaddingChar(): string
*
* @return $this
*/
- public function setHorizontalBorderChars(string $outside, string $inside = null): static
+ public function setHorizontalBorderChars(string $outside, ?string $inside = null): static
{
$this->horizontalOutsideBorderChar = $outside;
$this->horizontalInsideBorderChar = $inside ?? $outside;
@@ -113,7 +113,7 @@ public function setHorizontalBorderChars(string $outside, string $inside = null)
*
* @return $this
*/
- public function setVerticalBorderChars(string $outside, string $inside = null): static
+ public function setVerticalBorderChars(string $outside, ?string $inside = null): static
{
$this->verticalOutsideBorderChar = $outside;
$this->verticalInsideBorderChar = $inside ?? $outside;
@@ -167,7 +167,7 @@ public function getBorderChars(): array
*
* @return $this
*/
- public function setCrossingChars(string $cross, string $topLeft, string $topMid, string $topRight, string $midRight, string $bottomRight, string $bottomMid, string $bottomLeft, string $midLeft, string $topLeftBottom = null, string $topMidBottom = null, string $topRightBottom = null): static
+ public function setCrossingChars(string $cross, string $topLeft, string $topMid, string $topRight, string $midRight, string $bottomRight, string $bottomMid, string $bottomLeft, string $midLeft, ?string $topLeftBottom = null, ?string $topMidBottom = null, ?string $topRightBottom = null): static
{
$this->crossingChar = $cross;
$this->crossingTopLeftChar = $topLeft;
diff --git a/src/Symfony/Component/Console/Input/ArgvInput.php b/src/Symfony/Component/Console/Input/ArgvInput.php
index 9ae2f54f572b0..8621d62cf7121 100644
--- a/src/Symfony/Component/Console/Input/ArgvInput.php
+++ b/src/Symfony/Component/Console/Input/ArgvInput.php
@@ -43,7 +43,7 @@ class ArgvInput extends Input
private array $tokens;
private array $parsed;
- public function __construct(array $argv = null, InputDefinition $definition = null)
+ public function __construct(?array $argv = null, ?InputDefinition $definition = null)
{
$argv ??= $_SERVER['argv'] ?? [];
diff --git a/src/Symfony/Component/Console/Input/ArrayInput.php b/src/Symfony/Component/Console/Input/ArrayInput.php
index 2697e3721a681..d27ff411ee620 100644
--- a/src/Symfony/Component/Console/Input/ArrayInput.php
+++ b/src/Symfony/Component/Console/Input/ArrayInput.php
@@ -27,7 +27,7 @@ class ArrayInput extends Input
{
public function __construct(
private array $parameters,
- InputDefinition $definition = null,
+ ?InputDefinition $definition = null,
) {
parent::__construct($definition);
}
diff --git a/src/Symfony/Component/Console/Input/Input.php b/src/Symfony/Component/Console/Input/Input.php
index 6a9248b7aa8df..5a8b9a27a2b58 100644
--- a/src/Symfony/Component/Console/Input/Input.php
+++ b/src/Symfony/Component/Console/Input/Input.php
@@ -34,7 +34,7 @@ abstract class Input implements InputInterface, StreamableInputInterface
protected array $arguments = [];
protected bool $interactive = true;
- public function __construct(InputDefinition $definition = null)
+ public function __construct(?InputDefinition $definition = null)
{
if (null === $definition) {
$this->definition = new InputDefinition();
diff --git a/src/Symfony/Component/Console/Input/InputArgument.php b/src/Symfony/Component/Console/Input/InputArgument.php
index 9d6c17fa3c2c4..a5d949277748e 100644
--- a/src/Symfony/Component/Console/Input/InputArgument.php
+++ b/src/Symfony/Component/Console/Input/InputArgument.php
@@ -25,16 +25,27 @@
*/
class InputArgument
{
+ /**
+ * Providing an argument is required (e.g. just 'app:foo' is not allowed).
+ */
public const REQUIRED = 1;
+
+ /**
+ * Providing an argument is optional (e.g. 'app:foo' and 'app:foo bar' are both allowed). This is the default behavior of arguments.
+ */
public const OPTIONAL = 2;
+
+ /**
+ * The argument accepts multiple values and turn them into an array (e.g. 'app:foo bar baz' will result in value ['bar', 'baz']).
+ */
public const IS_ARRAY = 4;
private int $mode;
- private string|int|bool|array|null|float $default;
+ private string|int|bool|array|float|null $default;
/**
* @param string $name The argument name
- * @param int|null $mode The argument mode: a bit mask of self::REQUIRED, self::OPTIONAL and self::IS_ARRAY
+ * @param int-mask-of|null $mode The argument mode: a bit mask of self::REQUIRED, self::OPTIONAL and self::IS_ARRAY
* @param string $description A description text
* @param string|bool|int|float|array|null $default The default value (for self::OPTIONAL mode only)
* @param array|\Closure(CompletionInput,CompletionSuggestions):list $suggestedValues The values used for input completion
@@ -43,14 +54,14 @@ class InputArgument
*/
public function __construct(
private string $name,
- int $mode = null,
+ ?int $mode = null,
private string $description = '',
- string|bool|int|float|array $default = null,
+ string|bool|int|float|array|null $default = null,
private \Closure|array $suggestedValues = [],
) {
if (null === $mode) {
$mode = self::OPTIONAL;
- } elseif ($mode > 7 || $mode < 1) {
+ } elseif ($mode >= (self::IS_ARRAY << 1) || $mode < 1) {
throw new InvalidArgumentException(sprintf('Argument mode "%s" is not valid.', $mode));
}
@@ -89,8 +100,6 @@ public function isArray(): bool
/**
* Sets the default value.
- *
- * @throws LogicException When incorrect default value is given
*/
public function setDefault(string|bool|int|float|array|null $default): void
{
@@ -117,13 +126,16 @@ public function getDefault(): string|bool|int|float|array|null
return $this->default;
}
+ /**
+ * Returns true if the argument has values for input completion.
+ */
public function hasCompletion(): bool
{
return [] !== $this->suggestedValues;
}
/**
- * Adds suggestions to $suggestions for the current completion input.
+ * Supplies suggestions when command resolves possible completion options for input.
*
* @see Command::complete()
*/
diff --git a/src/Symfony/Component/Console/Input/InputOption.php b/src/Symfony/Component/Console/Input/InputOption.php
index 5d305518a4c4c..50851c44c6531 100644
--- a/src/Symfony/Component/Console/Input/InputOption.php
+++ b/src/Symfony/Component/Console/Input/InputOption.php
@@ -46,18 +46,18 @@ class InputOption
public const VALUE_IS_ARRAY = 8;
/**
- * The option may have either positive or negative value (e.g. --ansi or --no-ansi).
+ * The option allows passing a negated variant (e.g. --ansi or --no-ansi).
*/
public const VALUE_NEGATABLE = 16;
private string $name;
- private string|array|null $shortcut;
+ private ?string $shortcut;
private int $mode;
- private string|int|bool|array|null|float $default;
+ private string|int|bool|array|float|null $default;
/**
* @param string|array|null $shortcut The shortcuts, can be null, a string of shortcuts delimited by | or an array of shortcuts
- * @param int|null $mode The option mode: One of the VALUE_* constants
+ * @param int-mask-of|null $mode The option mode: One of the VALUE_* constants
* @param string|bool|int|float|array|null $default The default value (must be null for self::VALUE_NONE)
* @param array|\Closure(CompletionInput,CompletionSuggestions):list $suggestedValues The values used for input completion
*
@@ -65,10 +65,10 @@ class InputOption
*/
public function __construct(
string $name,
- string|array $shortcut = null,
- int $mode = null,
+ string|array|null $shortcut = null,
+ ?int $mode = null,
private string $description = '',
- string|bool|int|float|array $default = null,
+ string|bool|int|float|array|null $default = null,
private array|\Closure $suggestedValues = [],
) {
if (str_starts_with($name, '--')) {
@@ -79,7 +79,7 @@ public function __construct(
throw new InvalidArgumentException('An option name cannot be empty.');
}
- if (empty($shortcut)) {
+ if ('' === $shortcut || [] === $shortcut || false === $shortcut) {
$shortcut = null;
}
@@ -88,10 +88,10 @@ public function __construct(
$shortcut = implode('|', $shortcut);
}
$shortcuts = preg_split('{(\|)-?}', ltrim($shortcut, '-'));
- $shortcuts = array_filter($shortcuts);
+ $shortcuts = array_filter($shortcuts, 'strlen');
$shortcut = implode('|', $shortcuts);
- if (empty($shortcut)) {
+ if ('' === $shortcut) {
throw new InvalidArgumentException('An option shortcut cannot be empty.');
}
}
@@ -175,11 +175,19 @@ public function isArray(): bool
return self::VALUE_IS_ARRAY === (self::VALUE_IS_ARRAY & $this->mode);
}
+ /**
+ * Returns true if the option allows passing a negated variant.
+ *
+ * @return bool true if mode is self::VALUE_NEGATABLE, false otherwise
+ */
public function isNegatable(): bool
{
return self::VALUE_NEGATABLE === (self::VALUE_NEGATABLE & $this->mode);
}
+ /**
+ * Sets the default value.
+ */
public function setDefault(string|bool|int|float|array|null $default): void
{
if (self::VALUE_NONE === (self::VALUE_NONE & $this->mode) && null !== $default) {
@@ -213,13 +221,16 @@ public function getDescription(): string
return $this->description;
}
+ /**
+ * Returns true if the option has values for input completion.
+ */
public function hasCompletion(): bool
{
return [] !== $this->suggestedValues;
}
/**
- * Adds suggestions to $suggestions for the current completion input.
+ * Supplies suggestions when command resolves possible completion options for input.
*
* @see Command::complete()
*/
diff --git a/src/Symfony/Component/Console/Output/ConsoleOutput.php b/src/Symfony/Component/Console/Output/ConsoleOutput.php
index f9e6c77109078..2ad3dbcf384a3 100644
--- a/src/Symfony/Component/Console/Output/ConsoleOutput.php
+++ b/src/Symfony/Component/Console/Output/ConsoleOutput.php
@@ -37,7 +37,7 @@ class ConsoleOutput extends StreamOutput implements ConsoleOutputInterface
* @param bool|null $decorated Whether to decorate messages (null for auto-guessing)
* @param OutputFormatterInterface|null $formatter Output formatter instance (null to use default OutputFormatter)
*/
- public function __construct(int $verbosity = self::VERBOSITY_NORMAL, bool $decorated = null, OutputFormatterInterface $formatter = null)
+ public function __construct(int $verbosity = self::VERBOSITY_NORMAL, ?bool $decorated = null, ?OutputFormatterInterface $formatter = null)
{
parent::__construct($this->openOutputStream(), $verbosity, $decorated, $formatter);
diff --git a/src/Symfony/Component/Console/Output/ConsoleSectionOutput.php b/src/Symfony/Component/Console/Output/ConsoleSectionOutput.php
index d5b5aff766849..ded97c70e01d6 100644
--- a/src/Symfony/Component/Console/Output/ConsoleSectionOutput.php
+++ b/src/Symfony/Component/Console/Output/ConsoleSectionOutput.php
@@ -61,7 +61,7 @@ public function setMaxHeight(int $maxHeight): void
*
* @param int $lines Number of lines to clear. If null, then the entire output of this section is cleared
*/
- public function clear(int $lines = null): void
+ public function clear(?int $lines = null): void
{
if (empty($this->content) || !$this->isDecorated()) {
return;
diff --git a/src/Symfony/Component/Console/Output/Output.php b/src/Symfony/Component/Console/Output/Output.php
index fe8564bb9b4ed..2bb105748b8f8 100644
--- a/src/Symfony/Component/Console/Output/Output.php
+++ b/src/Symfony/Component/Console/Output/Output.php
@@ -37,7 +37,7 @@ abstract class Output implements OutputInterface
* @param bool $decorated Whether to decorate messages
* @param OutputFormatterInterface|null $formatter Output formatter instance (null to use default OutputFormatter)
*/
- public function __construct(?int $verbosity = self::VERBOSITY_NORMAL, bool $decorated = false, OutputFormatterInterface $formatter = null)
+ public function __construct(?int $verbosity = self::VERBOSITY_NORMAL, bool $decorated = false, ?OutputFormatterInterface $formatter = null)
{
$this->verbosity = $verbosity ?? self::VERBOSITY_NORMAL;
$this->formatter = $formatter ?? new OutputFormatter();
diff --git a/src/Symfony/Component/Console/Output/StreamOutput.php b/src/Symfony/Component/Console/Output/StreamOutput.php
index 55e403d3351a7..aa3fe8b5d2ced 100644
--- a/src/Symfony/Component/Console/Output/StreamOutput.php
+++ b/src/Symfony/Component/Console/Output/StreamOutput.php
@@ -40,7 +40,7 @@ class StreamOutput extends Output
*
* @throws InvalidArgumentException When first argument is not a real stream
*/
- public function __construct($stream, int $verbosity = self::VERBOSITY_NORMAL, bool $decorated = null, OutputFormatterInterface $formatter = null)
+ public function __construct($stream, int $verbosity = self::VERBOSITY_NORMAL, ?bool $decorated = null, ?OutputFormatterInterface $formatter = null)
{
if (!\is_resource($stream) || 'stream' !== get_resource_type($stream)) {
throw new InvalidArgumentException('The StreamOutput class needs a stream as its first argument.');
@@ -94,6 +94,10 @@ protected function hasColorSupport(): bool
return false;
}
+ if (!$this->isTty()) {
+ return false;
+ }
+
if (\DIRECTORY_SEPARATOR === '\\'
&& \function_exists('sapi_windows_vt100_support')
&& @sapi_windows_vt100_support($this->stream)
@@ -101,10 +105,51 @@ protected function hasColorSupport(): bool
return true;
}
- return 'Hyper' === getenv('TERM_PROGRAM')
+ if ('Hyper' === getenv('TERM_PROGRAM')
+ || false !== getenv('COLORTERM')
|| false !== getenv('ANSICON')
|| 'ON' === getenv('ConEmuANSI')
- || str_starts_with((string) getenv('TERM'), 'xterm')
- || stream_isatty($this->stream);
+ ) {
+ return true;
+ }
+
+ $term = (string) getenv('TERM');
+
+ if ('dumb' === $term) {
+ return false;
+ }
+
+ // See https://github.com/chalk/supports-color/blob/d4f413efaf8da045c5ab440ed418ef02dbb28bf1/index.js#L157
+ return 1 === @preg_match('/^((screen|xterm|vt100|vt220|putty|rxvt|ansi|cygwin|linux).*)|(.*-256(color)?(-bce)?)$/', $term);
+ }
+
+ /**
+ * Checks if the stream is a TTY, i.e; whether the output stream is connected to a terminal.
+ *
+ * Reference: Composer\Util\Platform::isTty
+ * https://github.com/composer/composer
+ */
+ private function isTty(): bool
+ {
+ // Detect msysgit/mingw and assume this is a tty because detection
+ // does not work correctly, see https://github.com/composer/composer/issues/9690
+ if (\in_array(strtoupper((string) getenv('MSYSTEM')), ['MINGW32', 'MINGW64'], true)) {
+ return true;
+ }
+
+ // Modern cross-platform function, includes the fstat fallback so if it is present we trust it
+ if (\function_exists('stream_isatty')) {
+ return stream_isatty($this->stream);
+ }
+
+ // Only trusting this if it is positive, otherwise prefer fstat fallback.
+ if (\function_exists('posix_isatty') && posix_isatty($this->stream)) {
+ return true;
+ }
+
+ $stat = @fstat($this->stream);
+
+ // Check if formatted mode is S_IFCHR
+ return $stat ? 0020000 === ($stat['mode'] & 0170000) : false;
}
}
diff --git a/src/Symfony/Component/Console/Output/TrimmedBufferOutput.php b/src/Symfony/Component/Console/Output/TrimmedBufferOutput.php
index 5655e7bc814ae..c1862a2bd7ffa 100644
--- a/src/Symfony/Component/Console/Output/TrimmedBufferOutput.php
+++ b/src/Symfony/Component/Console/Output/TrimmedBufferOutput.php
@@ -24,7 +24,7 @@ class TrimmedBufferOutput extends Output
private int $maxLength;
private string $buffer = '';
- public function __construct(int $maxLength, ?int $verbosity = self::VERBOSITY_NORMAL, bool $decorated = false, OutputFormatterInterface $formatter = null)
+ public function __construct(int $maxLength, ?int $verbosity = self::VERBOSITY_NORMAL, bool $decorated = false, ?OutputFormatterInterface $formatter = null)
{
if ($maxLength <= 0) {
throw new InvalidArgumentException(sprintf('"%s()" expects a strictly positive maxLength. Got %d.', __METHOD__, $maxLength));
diff --git a/src/Symfony/Component/Console/Question/Question.php b/src/Symfony/Component/Console/Question/Question.php
index a82125c91e87f..46a60c798b0ba 100644
--- a/src/Symfony/Component/Console/Question/Question.php
+++ b/src/Symfony/Component/Console/Question/Question.php
@@ -36,7 +36,7 @@ class Question
*/
public function __construct(
private string $question,
- private null|string|bool|int|float $default = null,
+ private string|bool|int|float|null $default = null,
) {
}
diff --git a/src/Symfony/Component/Console/SingleCommandApplication.php b/src/Symfony/Component/Console/SingleCommandApplication.php
index 4f0b5ba3cc6e6..ff1c17247fc4f 100644
--- a/src/Symfony/Component/Console/SingleCommandApplication.php
+++ b/src/Symfony/Component/Console/SingleCommandApplication.php
@@ -46,7 +46,7 @@ public function setAutoExit(bool $autoExit): static
return $this;
}
- public function run(InputInterface $input = null, OutputInterface $output = null): int
+ public function run(?InputInterface $input = null, ?OutputInterface $output = null): int
{
if ($this->running) {
return parent::run($input, $output);
diff --git a/src/Symfony/Component/Console/Style/StyleInterface.php b/src/Symfony/Component/Console/Style/StyleInterface.php
index 869b160902790..fcc5bc775f8a9 100644
--- a/src/Symfony/Component/Console/Style/StyleInterface.php
+++ b/src/Symfony/Component/Console/Style/StyleInterface.php
@@ -71,12 +71,12 @@ public function table(array $headers, array $rows): void;
/**
* Asks a question.
*/
- public function ask(string $question, string $default = null, callable $validator = null): mixed;
+ public function ask(string $question, ?string $default = null, ?callable $validator = null): mixed;
/**
* Asks a question with the user input hidden.
*/
- public function askHidden(string $question, callable $validator = null): mixed;
+ public function askHidden(string $question, ?callable $validator = null): mixed;
/**
* Asks for confirmation.
diff --git a/src/Symfony/Component/Console/Style/SymfonyStyle.php b/src/Symfony/Component/Console/Style/SymfonyStyle.php
index 3fd531d981fe0..19ad892efba3c 100644
--- a/src/Symfony/Component/Console/Style/SymfonyStyle.php
+++ b/src/Symfony/Component/Console/Style/SymfonyStyle.php
@@ -60,7 +60,7 @@ public function __construct(
/**
* 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): void
+ public function block(string|array $messages, ?string $type = null, ?string $style = null, string $prefix = ' ', bool $padding = false, bool $escape = true): void
{
$messages = \is_array($messages) ? array_values($messages) : [$messages];
@@ -208,7 +208,7 @@ public function definitionList(string|array|TableSeparator ...$list): void
$this->horizontalTable($headers, [$row]);
}
- public function ask(string $question, string $default = null, callable $validator = null): mixed
+ public function ask(string $question, ?string $default = null, ?callable $validator = null): mixed
{
$question = new Question($question, $default);
$question->setValidator($validator);
@@ -216,7 +216,7 @@ public function ask(string $question, string $default = null, callable $validato
return $this->askQuestion($question);
}
- public function askHidden(string $question, callable $validator = null): mixed
+ public function askHidden(string $question, ?callable $validator = null): mixed
{
$question = new Question($question);
@@ -286,7 +286,7 @@ public function createProgressBar(int $max = 0): ProgressBar
*
* @return iterable
*/
- public function progressIterate(iterable $iterable, int $max = null): iterable
+ public function progressIterate(iterable $iterable, ?int $max = null): iterable
{
yield from $this->createProgressBar()->iterate($iterable, $max);
@@ -397,7 +397,7 @@ private function writeBuffer(string $message, bool $newLine, int $type): void
$this->bufferedOutput->write($message, $newLine, $type);
}
- private function createBlock(iterable $messages, string $type = null, string $style = null, string $prefix = ' ', bool $padding = false, bool $escape = false): array
+ private function createBlock(iterable $messages, ?string $type = null, ?string $style = null, string $prefix = ' ', bool $padding = false, bool $escape = false): array
{
$indentLength = 0;
$prefixLength = Helper::width(Helper::removeDecoration($this->getFormatter(), $prefix));
diff --git a/src/Symfony/Component/Console/Tests/Formatter/OutputFormatterTest.php b/src/Symfony/Component/Console/Tests/Formatter/OutputFormatterTest.php
index 610522a7e8088..f62fa088907d3 100644
--- a/src/Symfony/Component/Console/Tests/Formatter/OutputFormatterTest.php
+++ b/src/Symfony/Component/Console/Tests/Formatter/OutputFormatterTest.php
@@ -162,7 +162,7 @@ public function testInlineStyle()
/**
* @dataProvider provideInlineStyleOptionsCases
*/
- public function testInlineStyleOptions(string $tag, string $expected = null, string $input = null, bool $truecolor = false)
+ public function testInlineStyleOptions(string $tag, ?string $expected = null, ?string $input = null, bool $truecolor = false)
{
if ($truecolor && 'truecolor' !== getenv('COLORTERM')) {
$this->markTestSkipped('The terminal does not support true colors.');
diff --git a/src/Symfony/Component/Console/Tests/Helper/HelperSetTest.php b/src/Symfony/Component/Console/Tests/Helper/HelperSetTest.php
index 9fbb9afca9e48..389ee0ed31425 100644
--- a/src/Symfony/Component/Console/Tests/Helper/HelperSetTest.php
+++ b/src/Symfony/Component/Console/Tests/Helper/HelperSetTest.php
@@ -87,7 +87,7 @@ public function testIteration()
}
}
- private function getGenericMockHelper($name, HelperSet $helperset = null)
+ private function getGenericMockHelper($name, ?HelperSet $helperset = null)
{
$mock_helper = $this->createMock(HelperInterface::class);
$mock_helper->expects($this->any())
diff --git a/src/Symfony/Component/Console/Tests/Input/InputOptionTest.php b/src/Symfony/Component/Console/Tests/Input/InputOptionTest.php
index 74bf69586fa89..7e3fb16da1fe9 100644
--- a/src/Symfony/Component/Console/Tests/Input/InputOptionTest.php
+++ b/src/Symfony/Component/Console/Tests/Input/InputOptionTest.php
@@ -59,6 +59,22 @@ public function testShortcut()
$this->assertEquals('f|ff|fff', $option->getShortcut(), '__construct() removes the leading - of the shortcuts');
$option = new InputOption('foo');
$this->assertNull($option->getShortcut(), '__construct() makes the shortcut null by default');
+ $option = new InputOption('foo', '');
+ $this->assertNull($option->getShortcut(), '__construct() makes the shortcut null when given an empty string');
+ $option = new InputOption('foo', []);
+ $this->assertNull($option->getShortcut(), '__construct() makes the shortcut null when given an empty array');
+ $option = new InputOption('foo', ['f', '', 'fff']);
+ $this->assertEquals('f|fff', $option->getShortcut(), '__construct() removes empty shortcuts');
+ $option = new InputOption('foo', 'f||fff');
+ $this->assertEquals('f|fff', $option->getShortcut(), '__construct() removes empty shortcuts');
+ $option = new InputOption('foo', '0');
+ $this->assertEquals('0', $option->getShortcut(), '-0 is an acceptable shortcut value');
+ $option = new InputOption('foo', ['0', 'z']);
+ $this->assertEquals('0|z', $option->getShortcut(), '-0 is an acceptable shortcut value when embedded in an array');
+ $option = new InputOption('foo', '0|z');
+ $this->assertEquals('0|z', $option->getShortcut(), '-0 is an acceptable shortcut value when embedded in a string-list');
+ $option = new InputOption('foo', false);
+ $this->assertNull($option->getShortcut(), '__construct() makes the shortcut null when given a false as value');
}
public function testModes()
diff --git a/src/Symfony/Component/CssSelector/CHANGELOG.md b/src/Symfony/Component/CssSelector/CHANGELOG.md
index c035d6b3db49e..d2b7fb1d62acf 100644
--- a/src/Symfony/Component/CssSelector/CHANGELOG.md
+++ b/src/Symfony/Component/CssSelector/CHANGELOG.md
@@ -1,8 +1,14 @@
CHANGELOG
=========
+7.1
+---
+
+ * Add support for `:is()`
+ * Add support for `:where()`
+
6.3
------
+---
* Add support for `:scope`
diff --git a/src/Symfony/Component/CssSelector/Node/MatchingNode.php b/src/Symfony/Component/CssSelector/Node/MatchingNode.php
new file mode 100644
index 0000000000000..381ac4585d03a
--- /dev/null
+++ b/src/Symfony/Component/CssSelector/Node/MatchingNode.php
@@ -0,0 +1,55 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\CssSelector\Node;
+
+/**
+ * Represents a ":is()" node.
+ *
+ * This component is a port of the Python cssselect library,
+ * which is copyright Ian Bicking, @see https://github.com/SimonSapin/cssselect.
+ *
+ * @author Hubert Lenoir
+ *
+ * @internal
+ */
+class MatchingNode extends AbstractNode
+{
+ /**
+ * @param array $arguments
+ */
+ public function __construct(
+ public readonly NodeInterface $selector,
+ public readonly array $arguments = [],
+ ) {
+ }
+
+ public function getSpecificity(): Specificity
+ {
+ $argumentsSpecificity = array_reduce(
+ $this->arguments,
+ fn ($c, $n) => 1 === $n->getSpecificity()->compareTo($c) ? $n->getSpecificity() : $c,
+ new Specificity(0, 0, 0),
+ );
+
+ return $this->selector->getSpecificity()->plus($argumentsSpecificity);
+ }
+
+ public function __toString(): string
+ {
+ $selectorArguments = array_map(
+ fn ($n): string => ltrim((string) $n, '*'),
+ $this->arguments,
+ );
+
+ return sprintf('%s[%s:is(%s)]', $this->getNodeName(), $this->selector, implode(', ', $selectorArguments));
+ }
+}
diff --git a/src/Symfony/Component/CssSelector/Node/SelectorNode.php b/src/Symfony/Component/CssSelector/Node/SelectorNode.php
index 72c90235f009b..aebe50251e460 100644
--- a/src/Symfony/Component/CssSelector/Node/SelectorNode.php
+++ b/src/Symfony/Component/CssSelector/Node/SelectorNode.php
@@ -27,7 +27,7 @@ class SelectorNode extends AbstractNode
public function __construct(
private NodeInterface $tree,
- string $pseudoElement = null,
+ ?string $pseudoElement = null,
) {
$this->pseudoElement = $pseudoElement ? strtolower($pseudoElement) : null;
}
diff --git a/src/Symfony/Component/CssSelector/Node/SpecificityAdjustmentNode.php b/src/Symfony/Component/CssSelector/Node/SpecificityAdjustmentNode.php
new file mode 100644
index 0000000000000..d49ed4c5f90e6
--- /dev/null
+++ b/src/Symfony/Component/CssSelector/Node/SpecificityAdjustmentNode.php
@@ -0,0 +1,49 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\CssSelector\Node;
+
+/**
+ * Represents a ":where()" node.
+ *
+ * This component is a port of the Python cssselect library,
+ * which is copyright Ian Bicking, @see https://github.com/SimonSapin/cssselect.
+ *
+ * @author Hubert Lenoir
+ *
+ * @internal
+ */
+class SpecificityAdjustmentNode extends AbstractNode
+{
+ /**
+ * @param array $arguments
+ */
+ public function __construct(
+ public readonly NodeInterface $selector,
+ public readonly array $arguments = [],
+ ) {
+ }
+
+ public function getSpecificity(): Specificity
+ {
+ return $this->selector->getSpecificity();
+ }
+
+ public function __toString(): string
+ {
+ $selectorArguments = array_map(
+ fn ($n) => ltrim((string) $n, '*'),
+ $this->arguments,
+ );
+
+ return sprintf('%s[%s:where(%s)]', $this->getNodeName(), $this->selector, implode(', ', $selectorArguments));
+ }
+}
diff --git a/src/Symfony/Component/CssSelector/Parser/Parser.php b/src/Symfony/Component/CssSelector/Parser/Parser.php
index 5313d3435ba9c..f7eea2f828fc3 100644
--- a/src/Symfony/Component/CssSelector/Parser/Parser.php
+++ b/src/Symfony/Component/CssSelector/Parser/Parser.php
@@ -29,7 +29,7 @@ class Parser implements ParserInterface
{
private Tokenizer $tokenizer;
- public function __construct(Tokenizer $tokenizer = null)
+ public function __construct(?Tokenizer $tokenizer = null)
{
$this->tokenizer = $tokenizer ?? new Tokenizer();
}
@@ -87,13 +87,17 @@ public static function parseSeries(array $tokens): array
];
}
- private function parseSelectorList(TokenStream $stream): array
+ private function parseSelectorList(TokenStream $stream, bool $isArgument = false): array
{
$stream->skipWhitespace();
$selectors = [];
while (true) {
- $selectors[] = $this->parserSelectorNode($stream);
+ if ($isArgument && $stream->getPeek()->isDelimiter([')'])) {
+ break;
+ }
+
+ $selectors[] = $this->parserSelectorNode($stream, $isArgument);
if ($stream->getPeek()->isDelimiter([','])) {
$stream->getNext();
@@ -106,15 +110,19 @@ private function parseSelectorList(TokenStream $stream): array
return $selectors;
}
- private function parserSelectorNode(TokenStream $stream): Node\SelectorNode
+ private function parserSelectorNode(TokenStream $stream, bool $isArgument = false): Node\SelectorNode
{
- [$result, $pseudoElement] = $this->parseSimpleSelector($stream);
+ [$result, $pseudoElement] = $this->parseSimpleSelector($stream, false, $isArgument);
while (true) {
$stream->skipWhitespace();
$peek = $stream->getPeek();
- if ($peek->isFileEnd() || $peek->isDelimiter([','])) {
+ if (
+ $peek->isFileEnd()
+ || $peek->isDelimiter([','])
+ || ($isArgument && $peek->isDelimiter([')']))
+ ) {
break;
}
@@ -129,7 +137,7 @@ private function parserSelectorNode(TokenStream $stream): Node\SelectorNode
$combinator = ' ';
}
- [$nextSelector, $pseudoElement] = $this->parseSimpleSelector($stream);
+ [$nextSelector, $pseudoElement] = $this->parseSimpleSelector($stream, false, $isArgument);
$result = new Node\CombinedSelectorNode($result, $combinator, $nextSelector);
}
@@ -141,7 +149,7 @@ private function parserSelectorNode(TokenStream $stream): Node\SelectorNode
*
* @throws SyntaxErrorException
*/
- private function parseSimpleSelector(TokenStream $stream, bool $insideNegation = false): array
+ private function parseSimpleSelector(TokenStream $stream, bool $insideNegation = false, bool $isArgument = false): array
{
$stream->skipWhitespace();
@@ -154,7 +162,7 @@ private function parseSimpleSelector(TokenStream $stream, bool $insideNegation =
if ($peek->isWhitespace()
|| $peek->isFileEnd()
|| $peek->isDelimiter([',', '+', '>', '~'])
- || ($insideNegation && $peek->isDelimiter([')']))
+ || ($isArgument && $peek->isDelimiter([')']))
) {
break;
}
@@ -215,7 +223,7 @@ private function parseSimpleSelector(TokenStream $stream, bool $insideNegation =
throw SyntaxErrorException::nestedNot();
}
- [$argument, $argumentPseudoElement] = $this->parseSimpleSelector($stream, true);
+ [$argument, $argumentPseudoElement] = $this->parseSimpleSelector($stream, true, true);
$next = $stream->getNext();
if (null !== $argumentPseudoElement) {
@@ -227,6 +235,24 @@ private function parseSimpleSelector(TokenStream $stream, bool $insideNegation =
}
$result = new Node\NegationNode($result, $argument);
+ } elseif ('is' === strtolower($identifier)) {
+ $selectors = $this->parseSelectorList($stream, true);
+
+ $next = $stream->getNext();
+ if (!$next->isDelimiter([')'])) {
+ throw SyntaxErrorException::unexpectedToken('")"', $next);
+ }
+
+ $result = new Node\MatchingNode($result, $selectors);
+ } elseif ('where' === strtolower($identifier)) {
+ $selectors = $this->parseSelectorList($stream, true);
+
+ $next = $stream->getNext();
+ if (!$next->isDelimiter([')'])) {
+ throw SyntaxErrorException::unexpectedToken('")"', $next);
+ }
+
+ $result = new Node\SpecificityAdjustmentNode($result, $selectors);
} else {
$arguments = [];
$next = null;
diff --git a/src/Symfony/Component/CssSelector/Tests/Node/MatchingNodeTest.php b/src/Symfony/Component/CssSelector/Tests/Node/MatchingNodeTest.php
new file mode 100644
index 0000000000000..0bc718c4c6d49
--- /dev/null
+++ b/src/Symfony/Component/CssSelector/Tests/Node/MatchingNodeTest.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\Component\CssSelector\Tests\Node;
+
+use Symfony\Component\CssSelector\Node\ClassNode;
+use Symfony\Component\CssSelector\Node\ElementNode;
+use Symfony\Component\CssSelector\Node\HashNode;
+use Symfony\Component\CssSelector\Node\MatchingNode;
+
+class MatchingNodeTest extends AbstractNodeTestCase
+{
+ public static function getToStringConversionTestData()
+ {
+ return [
+ [new MatchingNode(new ElementNode(), [
+ new ClassNode(new ElementNode(), 'class'),
+ new HashNode(new ElementNode(), 'id'),
+ ]), 'Matching[Element[*]:is(Class[Element[*].class], Hash[Element[*]#id])]'],
+ ];
+ }
+
+ public static function getSpecificityValueTestData()
+ {
+ return [
+ [new MatchingNode(new ElementNode(), [
+ new ClassNode(new ElementNode(), 'class'),
+ new HashNode(new ElementNode(), 'id'),
+ ]), 100],
+ [new MatchingNode(new ClassNode(new ElementNode(), 'class'), [
+ new ClassNode(new ElementNode(), 'class'),
+ new HashNode(new ElementNode(), 'id'),
+ ]), 110],
+ [new MatchingNode(new HashNode(new ElementNode(), 'id'), [
+ new ClassNode(new ElementNode(), 'class'),
+ new HashNode(new ElementNode(), 'id'),
+ ]), 200],
+ ];
+ }
+}
diff --git a/src/Symfony/Component/CssSelector/Tests/Node/SpecificityAdjustmentNodeTest.php b/src/Symfony/Component/CssSelector/Tests/Node/SpecificityAdjustmentNodeTest.php
new file mode 100644
index 0000000000000..5c830571e5437
--- /dev/null
+++ b/src/Symfony/Component/CssSelector/Tests/Node/SpecificityAdjustmentNodeTest.php
@@ -0,0 +1,44 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\CssSelector\Tests\Node;
+
+use Symfony\Component\CssSelector\Node\ClassNode;
+use Symfony\Component\CssSelector\Node\ElementNode;
+use Symfony\Component\CssSelector\Node\HashNode;
+use Symfony\Component\CssSelector\Node\SpecificityAdjustmentNode;
+
+class SpecificityAdjustmentNodeTest extends AbstractNodeTestCase
+{
+ public static function getToStringConversionTestData()
+ {
+ return [
+ [new SpecificityAdjustmentNode(new ElementNode(), [
+ new ClassNode(new ElementNode(), 'class'),
+ new HashNode(new ElementNode(), 'id'),
+ ]), 'SpecificityAdjustment[Element[*]:where(Class[Element[*].class], Hash[Element[*]#id])]'],
+ ];
+ }
+
+ public static function getSpecificityValueTestData()
+ {
+ return [
+ [new SpecificityAdjustmentNode(new ElementNode(), [
+ new ClassNode(new ElementNode(), 'class'),
+ new HashNode(new ElementNode(), 'id'),
+ ]), 0],
+ [new SpecificityAdjustmentNode(new ClassNode(new ElementNode(), 'class'), [
+ new ClassNode(new ElementNode(), 'class'),
+ new HashNode(new ElementNode(), 'id'),
+ ]), 10],
+ ];
+ }
+}
diff --git a/src/Symfony/Component/CssSelector/Tests/Parser/ParserTest.php b/src/Symfony/Component/CssSelector/Tests/Parser/ParserTest.php
index a8708ce47282e..509f6e35930e9 100644
--- a/src/Symfony/Component/CssSelector/Tests/Parser/ParserTest.php
+++ b/src/Symfony/Component/CssSelector/Tests/Parser/ParserTest.php
@@ -152,6 +152,10 @@ public static function getParserTestData()
[':scope', ['Pseudo[Element[*]:scope]']],
['foo bar, :scope > div', ['CombinedSelector[Element[foo] Element[bar]]', 'CombinedSelector[Pseudo[Element[*]:scope] > Element[div]]']],
['foo bar,:scope > div', ['CombinedSelector[Element[foo] Element[bar]]', 'CombinedSelector[Pseudo[Element[*]:scope] > Element[div]]']],
+ ['div:is(.foo, #bar)', ['Matching[Element[div]:is(Selector[Class[Element[*].foo]], Selector[Hash[Element[*]#bar]])]']],
+ [':is(:hover, :visited)', ['Matching[Element[*]:is(Selector[Pseudo[Element[*]:hover]], Selector[Pseudo[Element[*]:visited]])]']],
+ ['div:where(.foo, #bar)', ['SpecificityAdjustment[Element[div]:where(Selector[Class[Element[*].foo]], Selector[Hash[Element[*]#bar]])]']],
+ [':where(:hover, :visited)', ['SpecificityAdjustment[Element[*]:where(Selector[Pseudo[Element[*]:hover]], Selector[Pseudo[Element[*]:visited]])]']],
];
}
@@ -183,6 +187,7 @@ public static function getParserExceptionTestData()
[':contains("foo', SyntaxErrorException::unclosedString(10)->getMessage()],
['foo!', SyntaxErrorException::unexpectedToken('selector', new Token(Token::TYPE_DELIMITER, '!', 3))->getMessage()],
[':scope > div :scope header', SyntaxErrorException::notAtTheStartOfASelector('scope')->getMessage()],
+ [':not(:not(a))', SyntaxErrorException::nestedNot()->getMessage()],
];
}
@@ -233,6 +238,18 @@ public static function getSpecificityTestData()
['foo::before', 2],
['foo:empty::before', 12],
['#lorem + foo#ipsum:first-child > bar:first-line', 213],
+ [':is(*)', 0],
+ [':is(foo)', 1],
+ [':is(.foo)', 10],
+ [':is(#foo)', 100],
+ [':is(#foo, :empty, foo)', 100],
+ ['#foo:is(#bar:empty)', 210],
+ [':where(*)', 0],
+ [':where(foo)', 0],
+ [':where(.foo)', 0],
+ [':where(#foo)', 0],
+ [':where(#foo, :empty, foo)', 0],
+ ['#foo:where(#bar:empty)', 100],
];
}
diff --git a/src/Symfony/Component/CssSelector/Tests/XPath/TranslatorTest.php b/src/Symfony/Component/CssSelector/Tests/XPath/TranslatorTest.php
index de15384382652..f521a94708423 100644
--- a/src/Symfony/Component/CssSelector/Tests/XPath/TranslatorTest.php
+++ b/src/Symfony/Component/CssSelector/Tests/XPath/TranslatorTest.php
@@ -233,6 +233,8 @@ public static function getCssToXPathTestData()
['div#container p', "div[@id = 'container']/descendant-or-self::*/p"],
[':scope > div[dataimg=""]', "*[1]/div[@dataimg = '']"],
[':scope', '*[1]'],
+ ['e:is(section, article) h1', "e[(name() = 'section') or (name() = 'article')]/descendant-or-self::*/h1"],
+ ['e:where(section, article) h1', "e[(name() = 'section') or (name() = 'article')]/descendant-or-self::*/h1"],
];
}
@@ -367,6 +369,17 @@ public static function getHtmlIdsTestData()
[':not(*)', []],
['a:not([href])', ['name-anchor']],
['ol :Not(li[class])', ['first-li', 'second-li', 'li-div', 'fifth-li', 'sixth-li', 'seventh-li']],
+ [':is(#first-li, #second-li)', ['first-li', 'second-li']],
+ ['a:is(#name-anchor, #tag-anchor)', ['name-anchor', 'tag-anchor']],
+ [':is(.c)', ['first-ol', 'third-li', 'fourth-li']],
+ ['a:is(:not(#name-anchor))', ['tag-anchor', 'nofollow-anchor']],
+ ['a:not(:is(#name-anchor))', ['tag-anchor', 'nofollow-anchor']],
+ [':where(#first-li, #second-li)', ['first-li', 'second-li']],
+ ['a:where(#name-anchor, #tag-anchor)', ['name-anchor', 'tag-anchor']],
+ [':where(.c)', ['first-ol', 'third-li', 'fourth-li']],
+ ['a:where(:not(#name-anchor))', ['tag-anchor', 'nofollow-anchor']],
+ ['a:not(:where(#name-anchor))', ['tag-anchor', 'nofollow-anchor']],
+ ['a:where(:is(#name-anchor), :where(#tag-anchor))', ['name-anchor', 'tag-anchor']],
// HTML-specific
[':link', ['link-href', 'tag-anchor', 'nofollow-anchor', 'area-href']],
[':visited', []],
@@ -428,6 +441,7 @@ public static function getHtmlShakespearTestData()
[':scope > div', 1],
[':scope > div > div[class=dialog]', 1],
[':scope > div div', 242],
+ ['div:is(div#test .dialog) .direction', 4],
];
}
}
diff --git a/src/Symfony/Component/CssSelector/XPath/Extension/NodeExtension.php b/src/Symfony/Component/CssSelector/XPath/Extension/NodeExtension.php
index f2cd617ac4cc8..87b70dfef9224 100644
--- a/src/Symfony/Component/CssSelector/XPath/Extension/NodeExtension.php
+++ b/src/Symfony/Component/CssSelector/XPath/Extension/NodeExtension.php
@@ -63,6 +63,8 @@ public function getNodeTranslators(): array
'Selector' => $this->translateSelector(...),
'CombinedSelector' => $this->translateCombinedSelector(...),
'Negation' => $this->translateNegation(...),
+ 'Matching' => $this->translateMatching(...),
+ 'SpecificityAdjustment' => $this->translateSpecificityAdjustment(...),
'Function' => $this->translateFunction(...),
'Pseudo' => $this->translatePseudo(...),
'Attribute' => $this->translateAttribute(...),
@@ -95,6 +97,36 @@ public function translateNegation(Node\NegationNode $node, Translator $translato
return $xpath->addCondition('0');
}
+ public function translateMatching(Node\MatchingNode $node, Translator $translator): XPathExpr
+ {
+ $xpath = $translator->nodeToXPath($node->selector);
+
+ foreach ($node->arguments as $argument) {
+ $expr = $translator->nodeToXPath($argument);
+ $expr->addNameTest();
+ if ($condition = $expr->getCondition()) {
+ $xpath->addCondition($condition, 'or');
+ }
+ }
+
+ return $xpath;
+ }
+
+ public function translateSpecificityAdjustment(Node\SpecificityAdjustmentNode $node, Translator $translator): XPathExpr
+ {
+ $xpath = $translator->nodeToXPath($node->selector);
+
+ foreach ($node->arguments as $argument) {
+ $expr = $translator->nodeToXPath($argument);
+ $expr->addNameTest();
+ if ($condition = $expr->getCondition()) {
+ $xpath->addCondition($condition, 'or');
+ }
+ }
+
+ return $xpath;
+ }
+
public function translateFunction(Node\FunctionNode $node, Translator $translator): XPathExpr
{
$xpath = $translator->nodeToXPath($node->getSelector());
diff --git a/src/Symfony/Component/CssSelector/XPath/Translator.php b/src/Symfony/Component/CssSelector/XPath/Translator.php
index 83e855b5c4158..9e66ce7ddbd08 100644
--- a/src/Symfony/Component/CssSelector/XPath/Translator.php
+++ b/src/Symfony/Component/CssSelector/XPath/Translator.php
@@ -48,7 +48,7 @@ class Translator implements TranslatorInterface
private array $pseudoClassTranslators = [];
private array $attributeMatchingTranslators = [];
- public function __construct(ParserInterface $parser = null)
+ public function __construct(?ParserInterface $parser = null)
{
$this->mainParser = $parser ?? new Parser();
diff --git a/src/Symfony/Component/CssSelector/XPath/XPathExpr.php b/src/Symfony/Component/CssSelector/XPath/XPathExpr.php
index 14f63ef978930..ceccab619cfe2 100644
--- a/src/Symfony/Component/CssSelector/XPath/XPathExpr.php
+++ b/src/Symfony/Component/CssSelector/XPath/XPathExpr.php
@@ -42,9 +42,9 @@ public function getElement(): string
/**
* @return $this
*/
- public function addCondition(string $condition): static
+ public function addCondition(string $condition, string $operator = 'and'): static
{
- $this->condition = $this->condition ? sprintf('(%s) and (%s)', $this->condition, $condition) : $condition;
+ $this->condition = $this->condition ? sprintf('(%s) %s (%s)', $this->condition, $operator, $condition) : $condition;
return $this;
}
diff --git a/src/Symfony/Component/DependencyInjection/Argument/BoundArgument.php b/src/Symfony/Component/DependencyInjection/Argument/BoundArgument.php
index be24e20af8345..22d94140a49ad 100644
--- a/src/Symfony/Component/DependencyInjection/Argument/BoundArgument.php
+++ b/src/Symfony/Component/DependencyInjection/Argument/BoundArgument.php
@@ -28,7 +28,7 @@ final class BoundArgument implements ArgumentInterface
private int $type;
private ?string $file;
- public function __construct(mixed $value, bool $trackUsage = true, int $type = 0, string $file = null)
+ public function __construct(mixed $value, bool $trackUsage = true, int $type = 0, ?string $file = null)
{
$this->value = $value;
if ($trackUsage) {
diff --git a/src/Symfony/Component/DependencyInjection/Argument/ServiceLocator.php b/src/Symfony/Component/DependencyInjection/Argument/ServiceLocator.php
index e58293489d419..8276f6a39485b 100644
--- a/src/Symfony/Component/DependencyInjection/Argument/ServiceLocator.php
+++ b/src/Symfony/Component/DependencyInjection/Argument/ServiceLocator.php
@@ -24,7 +24,7 @@ class ServiceLocator extends BaseServiceLocator
private array $serviceMap;
private ?array $serviceTypes;
- public function __construct(\Closure $factory, array $serviceMap, array $serviceTypes = null)
+ public function __construct(\Closure $factory, array $serviceMap, ?array $serviceTypes = null)
{
$this->factory = $factory;
$this->serviceMap = $serviceMap;
diff --git a/src/Symfony/Component/DependencyInjection/Argument/TaggedIteratorArgument.php b/src/Symfony/Component/DependencyInjection/Argument/TaggedIteratorArgument.php
index 86ab0b9020dcd..2e0a1fea8df1e 100644
--- a/src/Symfony/Component/DependencyInjection/Argument/TaggedIteratorArgument.php
+++ b/src/Symfony/Component/DependencyInjection/Argument/TaggedIteratorArgument.php
@@ -35,7 +35,7 @@ class TaggedIteratorArgument extends IteratorArgument
* @param array $exclude Services to exclude from the iterator
* @param bool $excludeSelf Whether to automatically exclude the referencing service from the iterator
*/
- public function __construct(string $tag, string $indexAttribute = null, string $defaultIndexMethod = null, bool $needsIndexes = false, string $defaultPriorityMethod = null, array $exclude = [], bool $excludeSelf = true)
+ public function __construct(string $tag, ?string $indexAttribute = null, ?string $defaultIndexMethod = null, bool $needsIndexes = false, ?string $defaultPriorityMethod = null, array $exclude = [], bool $excludeSelf = true)
{
parent::__construct([]);
diff --git a/src/Symfony/Component/DependencyInjection/Attribute/AutoconfigureTag.php b/src/Symfony/Component/DependencyInjection/Attribute/AutoconfigureTag.php
index ea738342c5bd3..dab5595618e28 100644
--- a/src/Symfony/Component/DependencyInjection/Attribute/AutoconfigureTag.php
+++ b/src/Symfony/Component/DependencyInjection/Attribute/AutoconfigureTag.php
@@ -23,7 +23,7 @@ class AutoconfigureTag extends Autoconfigure
* @param string|null $name The tag name to add
* @param array $attributes The tag attributes to attach to the tag
*/
- public function __construct(string $name = null, array $attributes = [])
+ public function __construct(?string $name = null, array $attributes = [])
{
parent::__construct(
tags: [
diff --git a/src/Symfony/Component/DependencyInjection/Attribute/Autowire.php b/src/Symfony/Component/DependencyInjection/Attribute/Autowire.php
index c17eb13702492..874092657883d 100644
--- a/src/Symfony/Component/DependencyInjection/Attribute/Autowire.php
+++ b/src/Symfony/Component/DependencyInjection/Attribute/Autowire.php
@@ -38,11 +38,11 @@ class Autowire
* @param bool|class-string|class-string[] $lazy Whether to use lazy-loading for this argument
*/
public function __construct(
- string|array|ArgumentInterface $value = null,
- string $service = null,
- string $expression = null,
- string $env = null,
- string $param = null,
+ string|array|ArgumentInterface|null $value = null,
+ ?string $service = null,
+ ?string $expression = null,
+ ?string $env = null,
+ ?string $param = null,
bool|string|array $lazy = false,
) {
if ($this->lazy = \is_string($lazy) ? [$lazy] : $lazy) {
diff --git a/src/Symfony/Component/DependencyInjection/Attribute/AutowireCallable.php b/src/Symfony/Component/DependencyInjection/Attribute/AutowireCallable.php
index 1fdc160e724c5..869e96e1ab93e 100644
--- a/src/Symfony/Component/DependencyInjection/Attribute/AutowireCallable.php
+++ b/src/Symfony/Component/DependencyInjection/Attribute/AutowireCallable.php
@@ -28,9 +28,9 @@ class AutowireCallable extends Autowire
* @param bool|class-string $lazy Whether to use lazy-loading for this argument
*/
public function __construct(
- string|array $callable = null,
- string $service = null,
- string $method = null,
+ string|array|null $callable = null,
+ ?string $service = null,
+ ?string $method = null,
bool|string $lazy = false,
) {
if (!(null !== $callable xor null !== $service)) {
diff --git a/src/Symfony/Component/DependencyInjection/Attribute/AutowireIterator.php b/src/Symfony/Component/DependencyInjection/Attribute/AutowireIterator.php
index 92e5f02d7ecb4..2f845c86aaaeb 100644
--- a/src/Symfony/Component/DependencyInjection/Attribute/AutowireIterator.php
+++ b/src/Symfony/Component/DependencyInjection/Attribute/AutowireIterator.php
@@ -31,9 +31,9 @@ class AutowireIterator extends Autowire
*/
public function __construct(
string $tag,
- string $indexAttribute = null,
- string $defaultIndexMethod = null,
- string $defaultPriorityMethod = null,
+ ?string $indexAttribute = null,
+ ?string $defaultIndexMethod = null,
+ ?string $defaultPriorityMethod = null,
string|array $exclude = [],
bool $excludeSelf = true,
) {
diff --git a/src/Symfony/Component/DependencyInjection/Attribute/AutowireLocator.php b/src/Symfony/Component/DependencyInjection/Attribute/AutowireLocator.php
index bd5c912697f17..3bf4d57575c0f 100644
--- a/src/Symfony/Component/DependencyInjection/Attribute/AutowireLocator.php
+++ b/src/Symfony/Component/DependencyInjection/Attribute/AutowireLocator.php
@@ -37,9 +37,9 @@ class AutowireLocator extends Autowire
*/
public function __construct(
string|array $services,
- string $indexAttribute = null,
- string $defaultIndexMethod = null,
- string $defaultPriorityMethod = null,
+ ?string $indexAttribute = null,
+ ?string $defaultIndexMethod = null,
+ ?string $defaultPriorityMethod = null,
string|array $exclude = [],
bool $excludeSelf = true,
) {
diff --git a/src/Symfony/Component/DependencyInjection/Attribute/Lazy.php b/src/Symfony/Component/DependencyInjection/Attribute/Lazy.php
new file mode 100644
index 0000000000000..54de2fed138a5
--- /dev/null
+++ b/src/Symfony/Component/DependencyInjection/Attribute/Lazy.php
@@ -0,0 +1,21 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\DependencyInjection\Attribute;
+
+#[\Attribute(\Attribute::TARGET_CLASS | \Attribute::TARGET_PARAMETER)]
+class Lazy
+{
+ public function __construct(
+ public bool|string|null $lazy = true,
+ ) {
+ }
+}
diff --git a/src/Symfony/Component/DependencyInjection/Attribute/Target.php b/src/Symfony/Component/DependencyInjection/Attribute/Target.php
index 57c0a7dbd5667..8255315a99613 100644
--- a/src/Symfony/Component/DependencyInjection/Attribute/Target.php
+++ b/src/Symfony/Component/DependencyInjection/Attribute/Target.php
@@ -38,7 +38,7 @@ public function getParsedName(): string
return lcfirst(str_replace(' ', '', ucwords(preg_replace('/[^a-zA-Z0-9\x7f-\xff]++/', ' ', $this->name))));
}
- public static function parseName(\ReflectionParameter $parameter, self &$attribute = null, string &$parsedName = null): string
+ public static function parseName(\ReflectionParameter $parameter, ?self &$attribute = null, ?string &$parsedName = null): string
{
$attribute = null;
if (!$target = $parameter->getAttributes(self::class)[0] ?? null) {
diff --git a/src/Symfony/Component/DependencyInjection/CHANGELOG.md b/src/Symfony/Component/DependencyInjection/CHANGELOG.md
index ace4f5056cf8b..96ca110562db9 100644
--- a/src/Symfony/Component/DependencyInjection/CHANGELOG.md
+++ b/src/Symfony/Component/DependencyInjection/CHANGELOG.md
@@ -6,6 +6,7 @@ CHANGELOG
* Add argument `$prepend` to `ContainerConfigurator::extension()` to prepend the configuration instead of appending it
* Have `ServiceLocator` implement `ServiceCollectionInterface`
+ * Add `#[Lazy]` attribute as shortcut for `#[Autowire(lazy: [bool|string])]` and `#[Autoconfigure(lazy: [bool|string])]`
7.0
---
diff --git a/src/Symfony/Component/DependencyInjection/Compiler/AutowirePass.php b/src/Symfony/Component/DependencyInjection/Compiler/AutowirePass.php
index d6564d409fc7c..41fa5052393f1 100644
--- a/src/Symfony/Component/DependencyInjection/Compiler/AutowirePass.php
+++ b/src/Symfony/Component/DependencyInjection/Compiler/AutowirePass.php
@@ -15,6 +15,7 @@
use Symfony\Component\DependencyInjection\Attribute\Autowire;
use Symfony\Component\DependencyInjection\Attribute\AutowireCallable;
use Symfony\Component\DependencyInjection\Attribute\AutowireDecorated;
+use Symfony\Component\DependencyInjection\Attribute\Lazy;
use Symfony\Component\DependencyInjection\Attribute\Target;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\ContainerInterface;
@@ -299,7 +300,13 @@ private function autowireMethod(\ReflectionFunctionAbstract $reflectionMethod, a
};
if ($checkAttributes) {
- foreach ($parameter->getAttributes(Autowire::class, \ReflectionAttribute::IS_INSTANCEOF) as $attribute) {
+ $attributes = array_merge($parameter->getAttributes(Autowire::class, \ReflectionAttribute::IS_INSTANCEOF), $parameter->getAttributes(Lazy::class, \ReflectionAttribute::IS_INSTANCEOF));
+
+ if (1 < \count($attributes)) {
+ throw new AutowiringFailedException($this->currentId, 'Using both attributes #[Lazy] and #[Autowire] on an argument is not allowed; use the "lazy" parameter of #[Autowire] instead.');
+ }
+
+ foreach ($attributes as $attribute) {
$attribute = $attribute->newInstance();
$invalidBehavior = $parameter->allowsNull() ? ContainerInterface::NULL_ON_INVALID_REFERENCE : ContainerBuilder::EXCEPTION_ON_INVALID_REFERENCE;
@@ -686,7 +693,7 @@ private function getAliasesSuggestionForType(ContainerBuilder $container, string
return null;
}
- private function populateAutowiringAlias(string $id, string $target = null): void
+ private function populateAutowiringAlias(string $id, ?string $target = null): void
{
if (!preg_match('/(?(DEFINE)(?[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*+))^((?&V)(?:\\\\(?&V))*+)(?: \$((?&V)))?$/', $id, $m)) {
return;
@@ -706,7 +713,7 @@ private function populateAutowiringAlias(string $id, string $target = null): voi
}
}
- private function getCombinedAlias(string $type, string $name = null): ?string
+ private function getCombinedAlias(string $type, ?string $name = null): ?string
{
if (str_contains($type, '&')) {
$types = explode('&', $type);
diff --git a/src/Symfony/Component/DependencyInjection/Compiler/CheckTypeDeclarationsPass.php b/src/Symfony/Component/DependencyInjection/Compiler/CheckTypeDeclarationsPass.php
index 4830bad1a5385..074d899900915 100644
--- a/src/Symfony/Component/DependencyInjection/Compiler/CheckTypeDeclarationsPass.php
+++ b/src/Symfony/Component/DependencyInjection/Compiler/CheckTypeDeclarationsPass.php
@@ -163,7 +163,7 @@ private function checkTypeDeclarations(Definition $checkedDefinition, \Reflectio
/**
* @throws InvalidParameterTypeException When a parameter is not compatible with the declared type
*/
- private function checkType(Definition $checkedDefinition, mixed $value, \ReflectionParameter $parameter, ?string $envPlaceholderUniquePrefix, \ReflectionType $reflectionType = null): void
+ private function checkType(Definition $checkedDefinition, mixed $value, \ReflectionParameter $parameter, ?string $envPlaceholderUniquePrefix, ?\ReflectionType $reflectionType = null): void
{
$reflectionType ??= $parameter->getType();
diff --git a/src/Symfony/Component/DependencyInjection/Compiler/InlineServiceDefinitionsPass.php b/src/Symfony/Component/DependencyInjection/Compiler/InlineServiceDefinitionsPass.php
index 737049d489a77..b87ad69b0d536 100644
--- a/src/Symfony/Component/DependencyInjection/Compiler/InlineServiceDefinitionsPass.php
+++ b/src/Symfony/Component/DependencyInjection/Compiler/InlineServiceDefinitionsPass.php
@@ -34,7 +34,7 @@ class InlineServiceDefinitionsPass extends AbstractRecursivePass
private array $notInlinableIds = [];
private ?ServiceReferenceGraph $graph = null;
- public function __construct(AnalyzeServiceReferencesPass $analyzingPass = null)
+ public function __construct(?AnalyzeServiceReferencesPass $analyzingPass = null)
{
$this->analyzingPass = $analyzingPass;
}
diff --git a/src/Symfony/Component/DependencyInjection/Compiler/MergeExtensionConfigurationPass.php b/src/Symfony/Component/DependencyInjection/Compiler/MergeExtensionConfigurationPass.php
index b49f4ed4ee910..6b19df1f71343 100644
--- a/src/Symfony/Component/DependencyInjection/Compiler/MergeExtensionConfigurationPass.php
+++ b/src/Symfony/Component/DependencyInjection/Compiler/MergeExtensionConfigurationPass.php
@@ -153,7 +153,7 @@ class MergeExtensionConfigurationContainerBuilder extends ContainerBuilder
{
private string $extensionClass;
- public function __construct(ExtensionInterface $extension, ParameterBagInterface $parameterBag = null)
+ public function __construct(ExtensionInterface $extension, ?ParameterBagInterface $parameterBag = null)
{
parent::__construct($parameterBag);
@@ -175,7 +175,7 @@ public function compile(bool $resolveEnvPlaceholders = false): void
throw new LogicException(sprintf('Cannot compile the container in extension "%s".', $this->extensionClass));
}
- public function resolveEnvPlaceholders(mixed $value, string|bool $format = null, array &$usedEnvs = null): mixed
+ public function resolveEnvPlaceholders(mixed $value, string|bool|null $format = null, ?array &$usedEnvs = null): mixed
{
if (true !== $format || !\is_string($value)) {
return parent::resolveEnvPlaceholders($value, $format, $usedEnvs);
diff --git a/src/Symfony/Component/DependencyInjection/Compiler/RegisterAutoconfigureAttributesPass.php b/src/Symfony/Component/DependencyInjection/Compiler/RegisterAutoconfigureAttributesPass.php
index d479743ecd301..ec40eee2d3872 100644
--- a/src/Symfony/Component/DependencyInjection/Compiler/RegisterAutoconfigureAttributesPass.php
+++ b/src/Symfony/Component/DependencyInjection/Compiler/RegisterAutoconfigureAttributesPass.php
@@ -12,8 +12,10 @@
namespace Symfony\Component\DependencyInjection\Compiler;
use Symfony\Component\DependencyInjection\Attribute\Autoconfigure;
+use Symfony\Component\DependencyInjection\Attribute\Lazy;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Definition;
+use Symfony\Component\DependencyInjection\Exception\AutoconfigureFailedException;
use Symfony\Component\DependencyInjection\Loader\YamlFileLoader;
/**
@@ -42,7 +44,16 @@ public function accept(Definition $definition): bool
public function processClass(ContainerBuilder $container, \ReflectionClass $class): void
{
- foreach ($class->getAttributes(Autoconfigure::class, \ReflectionAttribute::IS_INSTANCEOF) as $attribute) {
+ $autoconfigure = $class->getAttributes(Autoconfigure::class, \ReflectionAttribute::IS_INSTANCEOF);
+ $lazy = $class->getAttributes(Lazy::class, \ReflectionAttribute::IS_INSTANCEOF);
+
+ if ($autoconfigure && $lazy) {
+ throw new AutoconfigureFailedException($class->name, 'Using both attributes #[Lazy] and #[Autoconfigure] on an argument is not allowed; use the "lazy" parameter of #[Autoconfigure] instead.');
+ }
+
+ $attributes = array_merge($autoconfigure, $lazy);
+
+ foreach ($attributes as $attribute) {
self::registerForAutoconfiguration($container, $class, $attribute);
}
}
diff --git a/src/Symfony/Component/DependencyInjection/Compiler/ResolveBindingsPass.php b/src/Symfony/Component/DependencyInjection/Compiler/ResolveBindingsPass.php
index 50e34335e9966..e00eb44b94b8d 100644
--- a/src/Symfony/Component/DependencyInjection/Compiler/ResolveBindingsPass.php
+++ b/src/Symfony/Component/DependencyInjection/Compiler/ResolveBindingsPass.php
@@ -14,6 +14,7 @@
use Symfony\Component\DependencyInjection\Argument\BoundArgument;
use Symfony\Component\DependencyInjection\Argument\ServiceLocatorArgument;
use Symfony\Component\DependencyInjection\Argument\TaggedIteratorArgument;
+use Symfony\Component\DependencyInjection\Attribute\Autowire;
use Symfony\Component\DependencyInjection\Attribute\Target;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Definition;
@@ -184,6 +185,13 @@ protected function processValue(mixed $value, bool $isRoot = false): mixed
if (\array_key_exists($parameter->name, $arguments) && '' !== $arguments[$parameter->name]) {
continue;
}
+ if (
+ $value->isAutowired()
+ && !$value->hasTag('container.ignore_attributes')
+ && $parameter->getAttributes(Autowire::class, \ReflectionAttribute::IS_INSTANCEOF)
+ ) {
+ continue;
+ }
$typeHint = ltrim(ProxyHelper::exportType($parameter) ?? '', '?');
diff --git a/src/Symfony/Component/DependencyInjection/Compiler/ServiceLocatorTagPass.php b/src/Symfony/Component/DependencyInjection/Compiler/ServiceLocatorTagPass.php
index cf35855f9230e..728feb0bd732f 100644
--- a/src/Symfony/Component/DependencyInjection/Compiler/ServiceLocatorTagPass.php
+++ b/src/Symfony/Component/DependencyInjection/Compiler/ServiceLocatorTagPass.php
@@ -81,7 +81,7 @@ protected function processValue(mixed $value, bool $isRoot = false): mixed
return new Reference($id);
}
- public static function register(ContainerBuilder $container, array $map, string $callerId = null): Reference
+ public static function register(ContainerBuilder $container, array $map, ?string $callerId = null): Reference
{
$locator = (new Definition(ServiceLocator::class))
->addArgument(self::map($map))
diff --git a/src/Symfony/Component/DependencyInjection/Compiler/ServiceReferenceGraph.php b/src/Symfony/Component/DependencyInjection/Compiler/ServiceReferenceGraph.php
index c90fc7ac5618d..8310fb2412b54 100644
--- a/src/Symfony/Component/DependencyInjection/Compiler/ServiceReferenceGraph.php
+++ b/src/Symfony/Component/DependencyInjection/Compiler/ServiceReferenceGraph.php
@@ -74,7 +74,7 @@ public function clear(): void
/**
* Connects 2 nodes together in the Graph.
*/
- public function connect(?string $sourceId, mixed $sourceValue, ?string $destId, mixed $destValue = null, Reference $reference = null, bool $lazy = false, bool $weak = false, bool $byConstructor = false): void
+ public function connect(?string $sourceId, mixed $sourceValue, ?string $destId, mixed $destValue = null, ?Reference $reference = null, bool $lazy = false, bool $weak = false, bool $byConstructor = false): void
{
if (null === $sourceId || null === $destId) {
return;
diff --git a/src/Symfony/Component/DependencyInjection/Container.php b/src/Symfony/Component/DependencyInjection/Container.php
index 8a570df9ecfb8..4e37fe9e43573 100644
--- a/src/Symfony/Component/DependencyInjection/Container.php
+++ b/src/Symfony/Component/DependencyInjection/Container.php
@@ -67,7 +67,7 @@ class Container implements ContainerInterface, ResetInterface
private static \Closure $make;
- public function __construct(ParameterBagInterface $parameterBag = null)
+ public function __construct(?ParameterBagInterface $parameterBag = null)
{
$this->parameterBag = $parameterBag ?? new EnvPlaceholderParameterBag();
}
diff --git a/src/Symfony/Component/DependencyInjection/ContainerBuilder.php b/src/Symfony/Component/DependencyInjection/ContainerBuilder.php
index a5942a0b8effc..3f8aa599185fd 100644
--- a/src/Symfony/Component/DependencyInjection/ContainerBuilder.php
+++ b/src/Symfony/Component/DependencyInjection/ContainerBuilder.php
@@ -155,7 +155,7 @@ class ContainerBuilder extends Container implements TaggedContainerInterface
'mixed' => true,
];
- public function __construct(ParameterBagInterface $parameterBag = null)
+ public function __construct(?ParameterBagInterface $parameterBag = null)
{
parent::__construct($parameterBag);
@@ -424,7 +424,7 @@ public function fileExists(string $path, bool|string $trackContents = true): boo
* @throws BadMethodCallException When this ContainerBuilder is compiled
* @throws \LogicException if the extension is not registered
*/
- public function loadFromExtension(string $extension, array $values = null): static
+ public function loadFromExtension(string $extension, ?array $values = null): static
{
if ($this->isCompiled()) {
throw new BadMethodCallException('Cannot load from an extension on a compiled container.');
@@ -520,7 +520,7 @@ public function get(string $id, int $invalidBehavior = ContainerInterface::EXCEP
return $this->doGet($id, $invalidBehavior);
}
- private function doGet(string $id, int $invalidBehavior = ContainerInterface::EXCEPTION_ON_INVALID_REFERENCE, array &$inlineServices = null, bool $isConstructorArgument = false): mixed
+ private function doGet(string $id, int $invalidBehavior = ContainerInterface::EXCEPTION_ON_INVALID_REFERENCE, ?array &$inlineServices = null, bool $isConstructorArgument = false): mixed
{
if (isset($inlineServices[$id])) {
return $inlineServices[$id];
@@ -876,7 +876,7 @@ public function getAlias(string $id): Alias
* This methods allows for simple registration of service definition
* with a fluid interface.
*/
- public function register(string $id, string $class = null): Definition
+ public function register(string $id, ?string $class = null): Definition
{
return $this->setDefinition($id, new Definition($class));
}
@@ -887,7 +887,7 @@ public function register(string $id, string $class = null): Definition
* This method implements a shortcut for using setDefinition() with
* an autowired definition.
*/
- public function autowire(string $id, string $class = null): Definition
+ public function autowire(string $id, ?string $class = null): Definition
{
return $this->setDefinition($id, (new Definition($class))->setAutowired(true));
}
@@ -1001,7 +1001,7 @@ public function findDefinition(string $id): Definition
* @throws RuntimeException When the service is a synthetic service
* @throws InvalidArgumentException When configure callable is not callable
*/
- private function createService(Definition $definition, array &$inlineServices, bool $isConstructorArgument = false, string $id = null, bool|object $tryProxy = true): mixed
+ private function createService(Definition $definition, array &$inlineServices, bool $isConstructorArgument = false, ?string $id = null, bool|object $tryProxy = true): mixed
{
if (null === $id && isset($inlineServices[$h = spl_object_hash($definition)])) {
return $inlineServices[$h];
@@ -1349,7 +1349,7 @@ public function registerAttributeForAutoconfiguration(string $attributeClass, ca
* "$fooBar"-named arguments with $type as type-hint. Such arguments will
* receive the service $id when autowiring is used.
*/
- public function registerAliasForArgument(string $id, string $type, string $name = null): Alias
+ public function registerAliasForArgument(string $id, string $type, ?string $name = null): Alias
{
$parsedName = (new Target($name ??= $id))->getParsedName();
@@ -1396,7 +1396,7 @@ public function getAutoconfiguredAttributes(): array
*
* @return mixed The value with env parameters resolved if a string or an array is passed
*/
- public function resolveEnvPlaceholders(mixed $value, string|bool $format = null, array &$usedEnvs = null): mixed
+ public function resolveEnvPlaceholders(mixed $value, string|bool|null $format = null, ?array &$usedEnvs = null): mixed
{
$bag = $this->getParameterBag();
if (true === $format ??= '%%env(%s)%%') {
diff --git a/src/Symfony/Component/DependencyInjection/Definition.php b/src/Symfony/Component/DependencyInjection/Definition.php
index 6c79ce59efa88..97b6728929d3a 100644
--- a/src/Symfony/Component/DependencyInjection/Definition.php
+++ b/src/Symfony/Component/DependencyInjection/Definition.php
@@ -61,7 +61,7 @@ class Definition
*/
public ?int $decorationOnInvalid = null;
- public function __construct(string $class = null, array $arguments = [])
+ public function __construct(?string $class = null, array $arguments = [])
{
if (null !== $class) {
$this->setClass($class);
@@ -133,7 +133,7 @@ public function getFactory(): string|array|null
*
* @throws InvalidArgumentException in case the decorated service id and the new decorated service id are equals
*/
- public function setDecoratedService(?string $id, string $renamedId = null, int $priority = 0, int $invalidBehavior = ContainerInterface::EXCEPTION_ON_INVALID_REFERENCE): static
+ public function setDecoratedService(?string $id, ?string $renamedId = null, int $priority = 0, int $invalidBehavior = ContainerInterface::EXCEPTION_ON_INVALID_REFERENCE): static
{
if ($renamedId && $id === $renamedId) {
throw new InvalidArgumentException(sprintf('The decorated service inner name for "%s" must be different than the service name itself.', $id));
@@ -257,10 +257,6 @@ public function replaceArgument(int|string $index, mixed $argument): static
throw new OutOfBoundsException(sprintf('Cannot replace arguments for class "%s" if none have been configured yet.', $this->class));
}
- if (\is_int($index) && ($index < 0 || $index > \count($this->arguments) - 1)) {
- throw new OutOfBoundsException(sprintf('The index "%d" is not in the range [0, %d] of the arguments of class "%s".', $index, \count($this->arguments) - 1, $this->class));
- }
-
if (!\array_key_exists($index, $this->arguments)) {
throw new OutOfBoundsException(sprintf('The argument "%s" doesn\'t exist in class "%s".', $index, $this->class));
}
diff --git a/src/Symfony/Component/DependencyInjection/Dumper/PhpDumper.php b/src/Symfony/Component/DependencyInjection/Dumper/PhpDumper.php
index 6b92b77dff794..55db19552568e 100644
--- a/src/Symfony/Component/DependencyInjection/Dumper/PhpDumper.php
+++ b/src/Symfony/Component/DependencyInjection/Dumper/PhpDumper.php
@@ -1033,7 +1033,7 @@ private function addInlineReference(string $id, Definition $definition, string $
return $code;
}
- private function addInlineService(string $id, Definition $definition, Definition $inlineDef = null, bool $forConstructor = true): string
+ private function addInlineService(string $id, Definition $definition, ?Definition $inlineDef = null, bool $forConstructor = true): string
{
$code = '';
@@ -1093,7 +1093,7 @@ private function addInlineService(string $id, Definition $definition, Definition
return $code."\n return \$instance;\n";
}
- private function addServices(array &$services = null): string
+ private function addServices(?array &$services = null): string
{
$publicServices = $privateServices = '';
$definitions = $this->container->getDefinitions();
@@ -1135,7 +1135,7 @@ private function generateServiceFiles(array $services): iterable
}
}
- private function addNewInstance(Definition $definition, string $return = '', string $id = null, bool $asGhostObject = false): string
+ private function addNewInstance(Definition $definition, string $return = '', ?string $id = null, bool $asGhostObject = false): string
{
$tail = $return ? str_repeat(')', substr_count($return, '(') - substr_count($return, ')')).";\n" : '';
@@ -1764,7 +1764,7 @@ private function getServiceConditionals(mixed $value): string
return implode(' && ', $conditions);
}
- private function getDefinitionsFromArguments(array $arguments, \SplObjectStorage $definitions = null, array &$calls = [], bool $byConstructor = null): \SplObjectStorage
+ private function getDefinitionsFromArguments(array $arguments, ?\SplObjectStorage $definitions = null, array &$calls = [], ?bool $byConstructor = null): \SplObjectStorage
{
$definitions ??= new \SplObjectStorage();
@@ -1995,7 +1995,7 @@ private function dumpParameter(string $name): string
return sprintf('$container->parameters[%s]', $this->doExport($name));
}
- private function getServiceCall(string $id, Reference $reference = null): string
+ private function getServiceCall(string $id, ?Reference $reference = null): string
{
while ($this->container->hasAlias($id)) {
$id = (string) $this->container->getAlias($id);
diff --git a/src/Symfony/Component/DependencyInjection/Dumper/YamlDumper.php b/src/Symfony/Component/DependencyInjection/Dumper/YamlDumper.php
index 5c96e3b328ecd..fac33bc6792d1 100644
--- a/src/Symfony/Component/DependencyInjection/Dumper/YamlDumper.php
+++ b/src/Symfony/Component/DependencyInjection/Dumper/YamlDumper.php
@@ -312,7 +312,7 @@ private function dumpValue(mixed $value): mixed
} elseif ($value instanceof Definition) {
return new TaggedValue('service', (new Parser())->parse("_:\n".$this->addService('_', $value), Yaml::PARSE_CUSTOM_TAGS)['_']['_']);
} elseif ($value instanceof \UnitEnum) {
- return new TaggedValue('php/const', sprintf('%s::%s', $value::class, $value->name));
+ return new TaggedValue('php/enum', sprintf('%s::%s', $value::class, $value->name));
} elseif ($value instanceof AbstractArgument) {
return new TaggedValue('abstract', $value->getText());
} elseif (\is_object($value) || \is_resource($value)) {
@@ -322,7 +322,7 @@ private function dumpValue(mixed $value): mixed
return $value;
}
- private function getServiceCall(string $id, Reference $reference = null): string
+ private function getServiceCall(string $id, ?Reference $reference = null): string
{
if (null !== $reference) {
switch ($reference->getInvalidBehavior()) {
diff --git a/src/Symfony/Component/DependencyInjection/EnvVarLoaderInterface.php b/src/Symfony/Component/DependencyInjection/EnvVarLoaderInterface.php
index 0c547f8a5fae2..803156be2364b 100644
--- a/src/Symfony/Component/DependencyInjection/EnvVarLoaderInterface.php
+++ b/src/Symfony/Component/DependencyInjection/EnvVarLoaderInterface.php
@@ -19,7 +19,7 @@
interface EnvVarLoaderInterface
{
/**
- * @return string[] Key/value pairs that can be accessed using the regular "%env()%" syntax
+ * @return array Key/value pairs that can be accessed using the regular "%env()%" syntax
*/
public function loadEnvVars(): array;
}
diff --git a/src/Symfony/Component/DependencyInjection/EnvVarProcessor.php b/src/Symfony/Component/DependencyInjection/EnvVarProcessor.php
index 0e730978d3b5a..57392807f75ab 100644
--- a/src/Symfony/Component/DependencyInjection/EnvVarProcessor.php
+++ b/src/Symfony/Component/DependencyInjection/EnvVarProcessor.php
@@ -28,7 +28,7 @@ class EnvVarProcessor implements EnvVarProcessorInterface
/**
* @param \Traversable|null $loaders
*/
- public function __construct(ContainerInterface $container, \Traversable $loaders = null)
+ public function __construct(ContainerInterface $container, ?\Traversable $loaders = null)
{
$this->container = $container;
$this->loaders = $loaders ?? new \ArrayIterator();
@@ -165,10 +165,16 @@ public function getEnv(string $prefix, string $name, \Closure $getEnv): mixed
if (false !== $i || 'string' !== $prefix) {
$env = $getEnv($name);
} elseif ('' === ($env = $_ENV[$name] ?? (str_starts_with($name, 'HTTP_') ? null : ($_SERVER[$name] ?? null)))
- || (false !== $env && false === ($env = $env ?? getenv($name) ?? false)) // null is a possible value because of thread safety issues
+ || (false !== $env && false === $env ??= getenv($name) ?? false) // null is a possible value because of thread safety issues
) {
- foreach ($this->loadedVars as $vars) {
- if (false !== ($env = ($vars[$name] ?? $env)) && '' !== $env) {
+ foreach ($this->loadedVars as $i => $vars) {
+ if (false === $env = $vars[$name] ?? $env) {
+ continue;
+ }
+ if ($env instanceof \Stringable) {
+ $this->loadedVars[$i][$name] = $env = (string) $env;
+ }
+ if ('' !== ($env ?? '')) {
break;
}
}
@@ -186,7 +192,13 @@ public function getEnv(string $prefix, string $name, \Closure $getEnv): mixed
continue;
}
$this->loadedVars[] = $vars = $loader->loadEnvVars();
- if (false !== ($env = ($vars[$name] ?? $env)) && '' !== $env) {
+ if (false === $env = $vars[$name] ?? $env) {
+ continue;
+ }
+ if ($env instanceof \Stringable) {
+ $this->loadedVars[array_key_last($this->loadedVars)][$name] = $env = (string) $env;
+ }
+ if ('' !== ($env ?? '')) {
$ended = false;
break;
}
diff --git a/src/Symfony/Component/DependencyInjection/Exception/AutoconfigureFailedException.php b/src/Symfony/Component/DependencyInjection/Exception/AutoconfigureFailedException.php
new file mode 100644
index 0000000000000..f7ce978599cf2
--- /dev/null
+++ b/src/Symfony/Component/DependencyInjection/Exception/AutoconfigureFailedException.php
@@ -0,0 +1,16 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\DependencyInjection\Exception;
+
+class AutoconfigureFailedException extends AutowiringFailedException
+{
+}
diff --git a/src/Symfony/Component/DependencyInjection/Exception/AutowiringFailedException.php b/src/Symfony/Component/DependencyInjection/Exception/AutowiringFailedException.php
index 9304f1fdca542..53e05ceae9e4a 100644
--- a/src/Symfony/Component/DependencyInjection/Exception/AutowiringFailedException.php
+++ b/src/Symfony/Component/DependencyInjection/Exception/AutowiringFailedException.php
@@ -19,13 +19,11 @@ class AutowiringFailedException extends RuntimeException
private string $serviceId;
private ?\Closure $messageCallback = null;
- public function __construct(string $serviceId, string|\Closure $message = '', int $code = 0, \Throwable $previous = null)
+ public function __construct(string $serviceId, string|\Closure $message = '', int $code = 0, ?\Throwable $previous = null)
{
$this->serviceId = $serviceId;
- if ($message instanceof \Closure
- && (\function_exists('xdebug_is_enabled') ? xdebug_is_enabled() : \function_exists('xdebug_info'))
- ) {
+ if ($message instanceof \Closure && \function_exists('xdebug_is_enabled') && xdebug_is_enabled()) {
$message = $message();
}
diff --git a/src/Symfony/Component/DependencyInjection/Exception/EnvParameterException.php b/src/Symfony/Component/DependencyInjection/Exception/EnvParameterException.php
index 48b5e486ae71d..6cd53c9f738ba 100644
--- a/src/Symfony/Component/DependencyInjection/Exception/EnvParameterException.php
+++ b/src/Symfony/Component/DependencyInjection/Exception/EnvParameterException.php
@@ -18,7 +18,7 @@
*/
class EnvParameterException extends InvalidArgumentException
{
- public function __construct(array $envs, \Throwable $previous = null, string $message = 'Incompatible use of dynamic environment variables "%s" found in parameters.')
+ public function __construct(array $envs, ?\Throwable $previous = null, string $message = 'Incompatible use of dynamic environment variables "%s" found in parameters.')
{
parent::__construct(sprintf($message, implode('", "', $envs)), 0, $previous);
}
diff --git a/src/Symfony/Component/DependencyInjection/Exception/ParameterCircularReferenceException.php b/src/Symfony/Component/DependencyInjection/Exception/ParameterCircularReferenceException.php
index c8029d08ac0c6..408801f43f594 100644
--- a/src/Symfony/Component/DependencyInjection/Exception/ParameterCircularReferenceException.php
+++ b/src/Symfony/Component/DependencyInjection/Exception/ParameterCircularReferenceException.php
@@ -20,7 +20,7 @@ class ParameterCircularReferenceException extends RuntimeException
{
private array $parameters;
- public function __construct(array $parameters, \Throwable $previous = null)
+ public function __construct(array $parameters, ?\Throwable $previous = null)
{
parent::__construct(sprintf('Circular reference detected for parameter "%s" ("%s" > "%s").', $parameters[0], implode('" > "', $parameters), $parameters[0]), 0, $previous);
diff --git a/src/Symfony/Component/DependencyInjection/Exception/ParameterNotFoundException.php b/src/Symfony/Component/DependencyInjection/Exception/ParameterNotFoundException.php
index 55df87ee10752..37876e4cabc1e 100644
--- a/src/Symfony/Component/DependencyInjection/Exception/ParameterNotFoundException.php
+++ b/src/Symfony/Component/DependencyInjection/Exception/ParameterNotFoundException.php
@@ -34,7 +34,7 @@ class ParameterNotFoundException extends InvalidArgumentException implements Not
* @param string[] $alternatives Some parameter name alternatives
* @param string|null $nonNestedAlternative The alternative parameter name when the user expected dot notation for nested parameters
*/
- public function __construct(string $key, string $sourceId = null, string $sourceKey = null, \Throwable $previous = null, array $alternatives = [], string $nonNestedAlternative = null)
+ public function __construct(string $key, ?string $sourceId = null, ?string $sourceKey = null, ?\Throwable $previous = null, array $alternatives = [], ?string $nonNestedAlternative = null)
{
$this->key = $key;
$this->sourceId = $sourceId;
diff --git a/src/Symfony/Component/DependencyInjection/Exception/ServiceCircularReferenceException.php b/src/Symfony/Component/DependencyInjection/Exception/ServiceCircularReferenceException.php
index 0d8609bd57ecb..f7a85bd251b45 100644
--- a/src/Symfony/Component/DependencyInjection/Exception/ServiceCircularReferenceException.php
+++ b/src/Symfony/Component/DependencyInjection/Exception/ServiceCircularReferenceException.php
@@ -21,7 +21,7 @@ class ServiceCircularReferenceException extends RuntimeException
private string $serviceId;
private array $path;
- public function __construct(string $serviceId, array $path, \Throwable $previous = null)
+ public function __construct(string $serviceId, array $path, ?\Throwable $previous = null)
{
parent::__construct(sprintf('Circular reference detected for service "%s", path: "%s".', $serviceId, implode(' -> ', $path)), 0, $previous);
diff --git a/src/Symfony/Component/DependencyInjection/Exception/ServiceNotFoundException.php b/src/Symfony/Component/DependencyInjection/Exception/ServiceNotFoundException.php
index 2b0943c783cfa..a7f82ffd1b405 100644
--- a/src/Symfony/Component/DependencyInjection/Exception/ServiceNotFoundException.php
+++ b/src/Symfony/Component/DependencyInjection/Exception/ServiceNotFoundException.php
@@ -24,7 +24,7 @@ class ServiceNotFoundException extends InvalidArgumentException implements NotFo
private ?string $sourceId;
private array $alternatives;
- public function __construct(string $id, string $sourceId = null, \Throwable $previous = null, array $alternatives = [], string $msg = null)
+ public function __construct(string $id, ?string $sourceId = null, ?\Throwable $previous = null, array $alternatives = [], ?string $msg = null)
{
if (null !== $msg) {
// no-op
diff --git a/src/Symfony/Component/DependencyInjection/ExpressionLanguage.php b/src/Symfony/Component/DependencyInjection/ExpressionLanguage.php
index 1a7f5fd38efb0..84d45dbdd70c1 100644
--- a/src/Symfony/Component/DependencyInjection/ExpressionLanguage.php
+++ b/src/Symfony/Component/DependencyInjection/ExpressionLanguage.php
@@ -27,7 +27,7 @@
*/
class ExpressionLanguage extends BaseExpressionLanguage
{
- public function __construct(CacheItemPoolInterface $cache = null, array $providers = [], callable $serviceCompiler = null, \Closure $getEnv = null)
+ public function __construct(?CacheItemPoolInterface $cache = null, array $providers = [], ?callable $serviceCompiler = null, ?\Closure $getEnv = null)
{
// prepend the default provider to let users override it easily
array_unshift($providers, new ExpressionLanguageProvider($serviceCompiler, $getEnv));
diff --git a/src/Symfony/Component/DependencyInjection/ExpressionLanguageProvider.php b/src/Symfony/Component/DependencyInjection/ExpressionLanguageProvider.php
index d0cc1f70b5939..6ae797d864ecc 100644
--- a/src/Symfony/Component/DependencyInjection/ExpressionLanguageProvider.php
+++ b/src/Symfony/Component/DependencyInjection/ExpressionLanguageProvider.php
@@ -30,7 +30,7 @@ class ExpressionLanguageProvider implements ExpressionFunctionProviderInterface
private ?\Closure $getEnv;
- public function __construct(callable $serviceCompiler = null, \Closure $getEnv = null)
+ public function __construct(?callable $serviceCompiler = null, ?\Closure $getEnv = null)
{
$this->serviceCompiler = null === $serviceCompiler ? null : $serviceCompiler(...);
$this->getEnv = $getEnv;
diff --git a/src/Symfony/Component/DependencyInjection/LazyProxy/PhpDumper/DumperInterface.php b/src/Symfony/Component/DependencyInjection/LazyProxy/PhpDumper/DumperInterface.php
index 6f6cc3fcc4508..05f2fbfb50dc2 100644
--- a/src/Symfony/Component/DependencyInjection/LazyProxy/PhpDumper/DumperInterface.php
+++ b/src/Symfony/Component/DependencyInjection/LazyProxy/PhpDumper/DumperInterface.php
@@ -25,7 +25,7 @@ interface DumperInterface
*
* @param bool|null &$asGhostObject Set to true after the call if the proxy is a ghost object
*/
- public function isProxyCandidate(Definition $definition, bool &$asGhostObject = null, string $id = null): bool;
+ public function isProxyCandidate(Definition $definition, ?bool &$asGhostObject = null, ?string $id = null): bool;
/**
* Generates the code to be used to instantiate a proxy in the dumped factory code.
@@ -35,5 +35,5 @@ public function getProxyFactoryCode(Definition $definition, string $id, string $
/**
* Generates the code for the lazy proxy.
*/
- public function getProxyCode(Definition $definition, string $id = null): string;
+ public function getProxyCode(Definition $definition, ?string $id = null): string;
}
diff --git a/src/Symfony/Component/DependencyInjection/LazyProxy/PhpDumper/LazyServiceDumper.php b/src/Symfony/Component/DependencyInjection/LazyProxy/PhpDumper/LazyServiceDumper.php
index 282353916a970..7e8d7db84c041 100644
--- a/src/Symfony/Component/DependencyInjection/LazyProxy/PhpDumper/LazyServiceDumper.php
+++ b/src/Symfony/Component/DependencyInjection/LazyProxy/PhpDumper/LazyServiceDumper.php
@@ -26,7 +26,7 @@ public function __construct(
) {
}
- public function isProxyCandidate(Definition $definition, bool &$asGhostObject = null, string $id = null): bool
+ public function isProxyCandidate(Definition $definition, ?bool &$asGhostObject = null, ?string $id = null): bool
{
$asGhostObject = false;
@@ -96,7 +96,7 @@ public function getProxyFactoryCode(Definition $definition, string $id, string $
EOF;
}
- public function getProxyCode(Definition $definition, string $id = null): string
+ public function getProxyCode(Definition $definition, ?string $id = null): string
{
if (!$this->isProxyCandidate($definition, $asGhostObject, $id)) {
throw new InvalidArgumentException(sprintf('Cannot instantiate lazy proxy for service "%s".', $id ?? $definition->getClass()));
@@ -139,7 +139,7 @@ public function getProxyCode(Definition $definition, string $id = null): string
}
}
- public function getProxyClass(Definition $definition, bool $asGhostObject, \ReflectionClass &$class = null): string
+ public function getProxyClass(Definition $definition, bool $asGhostObject, ?\ReflectionClass &$class = null): string
{
$class = 'object' !== $definition->getClass() ? $definition->getClass() : 'stdClass';
$class = new \ReflectionClass($class);
diff --git a/src/Symfony/Component/DependencyInjection/LazyProxy/PhpDumper/NullDumper.php b/src/Symfony/Component/DependencyInjection/LazyProxy/PhpDumper/NullDumper.php
index daa6fed79fdb3..c987b19d4c632 100644
--- a/src/Symfony/Component/DependencyInjection/LazyProxy/PhpDumper/NullDumper.php
+++ b/src/Symfony/Component/DependencyInjection/LazyProxy/PhpDumper/NullDumper.php
@@ -22,7 +22,7 @@
*/
class NullDumper implements DumperInterface
{
- public function isProxyCandidate(Definition $definition, bool &$asGhostObject = null, string $id = null): bool
+ public function isProxyCandidate(Definition $definition, ?bool &$asGhostObject = null, ?string $id = null): bool
{
return $asGhostObject = false;
}
@@ -32,7 +32,7 @@ public function getProxyFactoryCode(Definition $definition, string $id, string $
return '';
}
- public function getProxyCode(Definition $definition, string $id = null): string
+ public function getProxyCode(Definition $definition, ?string $id = null): string
{
return '';
}
diff --git a/src/Symfony/Component/DependencyInjection/Loader/ClosureLoader.php b/src/Symfony/Component/DependencyInjection/Loader/ClosureLoader.php
index 94305ae9438b2..1e3061d4fd45e 100644
--- a/src/Symfony/Component/DependencyInjection/Loader/ClosureLoader.php
+++ b/src/Symfony/Component/DependencyInjection/Loader/ClosureLoader.php
@@ -25,18 +25,18 @@ class ClosureLoader extends Loader
{
private ContainerBuilder $container;
- public function __construct(ContainerBuilder $container, string $env = null)
+ public function __construct(ContainerBuilder $container, ?string $env = null)
{
$this->container = $container;
parent::__construct($env);
}
- public function load(mixed $resource, string $type = null): mixed
+ public function load(mixed $resource, ?string $type = null): mixed
{
return $resource($this->container, $this->env);
}
- public function supports(mixed $resource, string $type = null): bool
+ public function supports(mixed $resource, ?string $type = null): bool
{
return $resource instanceof \Closure;
}
diff --git a/src/Symfony/Component/DependencyInjection/Loader/Configurator/AbstractServiceConfigurator.php b/src/Symfony/Component/DependencyInjection/Loader/Configurator/AbstractServiceConfigurator.php
index fcb37fc287fd5..295a35109be72 100644
--- a/src/Symfony/Component/DependencyInjection/Loader/Configurator/AbstractServiceConfigurator.php
+++ b/src/Symfony/Component/DependencyInjection/Loader/Configurator/AbstractServiceConfigurator.php
@@ -20,7 +20,7 @@ abstract class AbstractServiceConfigurator extends AbstractConfigurator
protected ?string $id;
private array $defaultTags = [];
- public function __construct(ServicesConfigurator $parent, Definition $definition, string $id = null, array $defaultTags = [])
+ public function __construct(ServicesConfigurator $parent, Definition $definition, ?string $id = null, array $defaultTags = [])
{
$this->parent = $parent;
$this->definition = $definition;
@@ -42,7 +42,7 @@ public function __destruct()
/**
* Registers a service.
*/
- final public function set(?string $id, string $class = null): ServiceConfigurator
+ final public function set(?string $id, ?string $class = null): ServiceConfigurator
{
$this->__destruct();
@@ -106,7 +106,7 @@ final public function stack(string $id, array $services): AliasConfigurator
/**
* Registers a service.
*/
- final public function __invoke(string $id, string $class = null): ServiceConfigurator
+ final public function __invoke(string $id, ?string $class = null): ServiceConfigurator
{
$this->__destruct();
diff --git a/src/Symfony/Component/DependencyInjection/Loader/Configurator/ContainerConfigurator.php b/src/Symfony/Component/DependencyInjection/Loader/Configurator/ContainerConfigurator.php
index ad1110e17442a..aed608053a5c2 100644
--- a/src/Symfony/Component/DependencyInjection/Loader/Configurator/ContainerConfigurator.php
+++ b/src/Symfony/Component/DependencyInjection/Loader/Configurator/ContainerConfigurator.php
@@ -38,7 +38,7 @@ class ContainerConfigurator extends AbstractConfigurator
private int $anonymousCount = 0;
private ?string $env;
- public function __construct(ContainerBuilder $container, PhpFileLoader $loader, array &$instanceof, string $path, string $file, string $env = null)
+ public function __construct(ContainerBuilder $container, PhpFileLoader $loader, array &$instanceof, string $path, string $file, ?string $env = null)
{
$this->container = $container;
$this->loader = $loader;
@@ -64,7 +64,7 @@ final public function extension(string $namespace, array $config, bool $prepend
$this->container->loadFromExtension($namespace, static::processValue($config));
}
- final public function import(string $resource, string $type = null, bool|string $ignoreErrors = false): void
+ final public function import(string $resource, ?string $type = null, bool|string $ignoreErrors = false): void
{
$this->loader->setCurrentDir(\dirname($this->path));
$this->loader->import($resource, $type, $ignoreErrors, $this->file);
@@ -117,7 +117,7 @@ function service(string $serviceId): ReferenceConfigurator
/**
* Creates an inline service.
*/
-function inline_service(string $class = null): InlineServiceConfigurator
+function inline_service(?string $class = null): InlineServiceConfigurator
{
return new InlineServiceConfigurator(new Definition($class));
}
@@ -147,7 +147,7 @@ function iterator(array $values): IteratorArgument
/**
* Creates a lazy iterator by tag name.
*/
-function tagged_iterator(string $tag, string $indexAttribute = null, string $defaultIndexMethod = null, string $defaultPriorityMethod = null, string|array $exclude = [], bool $excludeSelf = true): TaggedIteratorArgument
+function tagged_iterator(string $tag, ?string $indexAttribute = null, ?string $defaultIndexMethod = null, ?string $defaultPriorityMethod = null, string|array $exclude = [], bool $excludeSelf = true): TaggedIteratorArgument
{
return new TaggedIteratorArgument($tag, $indexAttribute, $defaultIndexMethod, false, $defaultPriorityMethod, (array) $exclude, $excludeSelf);
}
@@ -155,7 +155,7 @@ function tagged_iterator(string $tag, string $indexAttribute = null, string $def
/**
* Creates a service locator by tag name.
*/
-function tagged_locator(string $tag, string $indexAttribute = null, string $defaultIndexMethod = null, string $defaultPriorityMethod = null, string|array $exclude = [], bool $excludeSelf = true): ServiceLocatorArgument
+function tagged_locator(string $tag, ?string $indexAttribute = null, ?string $defaultIndexMethod = null, ?string $defaultPriorityMethod = null, string|array $exclude = [], bool $excludeSelf = true): ServiceLocatorArgument
{
return new ServiceLocatorArgument(new TaggedIteratorArgument($tag, $indexAttribute, $defaultIndexMethod, true, $defaultPriorityMethod, (array) $exclude, $excludeSelf));
}
diff --git a/src/Symfony/Component/DependencyInjection/Loader/Configurator/DefaultsConfigurator.php b/src/Symfony/Component/DependencyInjection/Loader/Configurator/DefaultsConfigurator.php
index 2236cd77a8802..1f26c978858da 100644
--- a/src/Symfony/Component/DependencyInjection/Loader/Configurator/DefaultsConfigurator.php
+++ b/src/Symfony/Component/DependencyInjection/Loader/Configurator/DefaultsConfigurator.php
@@ -28,7 +28,7 @@ class DefaultsConfigurator extends AbstractServiceConfigurator
private ?string $path;
- public function __construct(ServicesConfigurator $parent, Definition $definition, string $path = null)
+ public function __construct(ServicesConfigurator $parent, Definition $definition, ?string $path = null)
{
parent::__construct($parent, $definition, null, []);
diff --git a/src/Symfony/Component/DependencyInjection/Loader/Configurator/InstanceofConfigurator.php b/src/Symfony/Component/DependencyInjection/Loader/Configurator/InstanceofConfigurator.php
index 2db004051e5e2..9de0baa4cb13e 100644
--- a/src/Symfony/Component/DependencyInjection/Loader/Configurator/InstanceofConfigurator.php
+++ b/src/Symfony/Component/DependencyInjection/Loader/Configurator/InstanceofConfigurator.php
@@ -33,7 +33,7 @@ class InstanceofConfigurator extends AbstractServiceConfigurator
private ?string $path;
- public function __construct(ServicesConfigurator $parent, Definition $definition, string $id, string $path = null)
+ public function __construct(ServicesConfigurator $parent, Definition $definition, string $id, ?string $path = null)
{
parent::__construct($parent, $definition, $id, []);
diff --git a/src/Symfony/Component/DependencyInjection/Loader/Configurator/PrototypeConfigurator.php b/src/Symfony/Component/DependencyInjection/Loader/Configurator/PrototypeConfigurator.php
index 4ab957a85ce30..5d844722d6f0c 100644
--- a/src/Symfony/Component/DependencyInjection/Loader/Configurator/PrototypeConfigurator.php
+++ b/src/Symfony/Component/DependencyInjection/Loader/Configurator/PrototypeConfigurator.php
@@ -44,7 +44,7 @@ class PrototypeConfigurator extends AbstractServiceConfigurator
private bool $allowParent;
private ?string $path;
- public function __construct(ServicesConfigurator $parent, PhpFileLoader $loader, Definition $defaults, string $namespace, string $resource, bool $allowParent, string $path = null)
+ public function __construct(ServicesConfigurator $parent, PhpFileLoader $loader, Definition $defaults, string $namespace, string $resource, bool $allowParent, ?string $path = null)
{
$definition = new Definition();
if (!$defaults->isPublic() || !$defaults->isPrivate()) {
diff --git a/src/Symfony/Component/DependencyInjection/Loader/Configurator/ServiceConfigurator.php b/src/Symfony/Component/DependencyInjection/Loader/Configurator/ServiceConfigurator.php
index 9042ed1d6b494..57f498acf6662 100644
--- a/src/Symfony/Component/DependencyInjection/Loader/Configurator/ServiceConfigurator.php
+++ b/src/Symfony/Component/DependencyInjection/Loader/Configurator/ServiceConfigurator.php
@@ -49,7 +49,7 @@ class ServiceConfigurator extends AbstractServiceConfigurator
private ?string $path;
private bool $destructed = false;
- public function __construct(ContainerBuilder $container, array $instanceof, bool $allowParent, ServicesConfigurator $parent, Definition $definition, ?string $id, array $defaultTags, string $path = null)
+ public function __construct(ContainerBuilder $container, array $instanceof, bool $allowParent, ServicesConfigurator $parent, Definition $definition, ?string $id, array $defaultTags, ?string $path = null)
{
$this->container = $container;
$this->instanceof = $instanceof;
diff --git a/src/Symfony/Component/DependencyInjection/Loader/Configurator/ServicesConfigurator.php b/src/Symfony/Component/DependencyInjection/Loader/Configurator/ServicesConfigurator.php
index ee4d1ad16039d..0c2e5a461f953 100644
--- a/src/Symfony/Component/DependencyInjection/Loader/Configurator/ServicesConfigurator.php
+++ b/src/Symfony/Component/DependencyInjection/Loader/Configurator/ServicesConfigurator.php
@@ -34,7 +34,7 @@ class ServicesConfigurator extends AbstractConfigurator
private string $anonymousHash;
private int $anonymousCount;
- public function __construct(ContainerBuilder $container, PhpFileLoader $loader, array &$instanceof, string $path = null, int &$anonymousCount = 0)
+ public function __construct(ContainerBuilder $container, PhpFileLoader $loader, array &$instanceof, ?string $path = null, int &$anonymousCount = 0)
{
$this->defaults = new Definition();
$this->container = $container;
@@ -70,7 +70,7 @@ final public function instanceof(string $fqcn): InstanceofConfigurator
* @param string|null $id The service id, or null to create an anonymous service
* @param string|null $class The class of the service, or null when $id is also the class name
*/
- final public function set(?string $id, string $class = null): ServiceConfigurator
+ final public function set(?string $id, ?string $class = null): ServiceConfigurator
{
$defaults = $this->defaults;
$definition = new Definition();
@@ -180,7 +180,7 @@ final public function stack(string $id, array $services): AliasConfigurator
/**
* Registers a service.
*/
- final public function __invoke(string $id, string $class = null): ServiceConfigurator
+ final public function __invoke(string $id, ?string $class = null): ServiceConfigurator
{
return $this->set($id, $class);
}
diff --git a/src/Symfony/Component/DependencyInjection/Loader/Configurator/Traits/DecorateTrait.php b/src/Symfony/Component/DependencyInjection/Loader/Configurator/Traits/DecorateTrait.php
index ae6d3c9487382..afb56ae3d1907 100644
--- a/src/Symfony/Component/DependencyInjection/Loader/Configurator/Traits/DecorateTrait.php
+++ b/src/Symfony/Component/DependencyInjection/Loader/Configurator/Traits/DecorateTrait.php
@@ -25,7 +25,7 @@ trait DecorateTrait
*
* @throws InvalidArgumentException in case the decorated service id and the new decorated service id are equals
*/
- final public function decorate(?string $id, string $renamedId = null, int $priority = 0, int $invalidBehavior = ContainerInterface::EXCEPTION_ON_INVALID_REFERENCE): static
+ final public function decorate(?string $id, ?string $renamedId = null, int $priority = 0, int $invalidBehavior = ContainerInterface::EXCEPTION_ON_INVALID_REFERENCE): static
{
$this->definition->setDecoratedService($id, $renamedId, $priority, $invalidBehavior);
diff --git a/src/Symfony/Component/DependencyInjection/Loader/DirectoryLoader.php b/src/Symfony/Component/DependencyInjection/Loader/DirectoryLoader.php
index 1b5e81d1981c0..d435366f05ee6 100644
--- a/src/Symfony/Component/DependencyInjection/Loader/DirectoryLoader.php
+++ b/src/Symfony/Component/DependencyInjection/Loader/DirectoryLoader.php
@@ -18,7 +18,7 @@
*/
class DirectoryLoader extends FileLoader
{
- public function load(mixed $file, string $type = null): mixed
+ public function load(mixed $file, ?string $type = null): mixed
{
$file = rtrim($file, '/');
$path = $this->locator->locate($file);
@@ -39,7 +39,7 @@ public function load(mixed $file, string $type = null): mixed
return null;
}
- public function supports(mixed $resource, string $type = null): bool
+ public function supports(mixed $resource, ?string $type = null): bool
{
if ('directory' === $type) {
return true;
diff --git a/src/Symfony/Component/DependencyInjection/Loader/FileLoader.php b/src/Symfony/Component/DependencyInjection/Loader/FileLoader.php
index 185fb33d9f77b..76432ad360861 100644
--- a/src/Symfony/Component/DependencyInjection/Loader/FileLoader.php
+++ b/src/Symfony/Component/DependencyInjection/Loader/FileLoader.php
@@ -46,7 +46,7 @@ abstract class FileLoader extends BaseFileLoader
protected array $aliases = [];
protected bool $autoRegisterAliasesForSinglyImplementedInterfaces = true;
- public function __construct(ContainerBuilder $container, FileLocatorInterface $locator, string $env = null)
+ public function __construct(ContainerBuilder $container, FileLocatorInterface $locator, ?string $env = null)
{
$this->container = $container;
@@ -56,7 +56,7 @@ public function __construct(ContainerBuilder $container, FileLocatorInterface $l
/**
* @param bool|string $ignoreErrors Whether errors should be ignored; pass "not_found" to ignore only when the loaded resource is not found
*/
- public function import(mixed $resource, string $type = null, bool|string $ignoreErrors = false, string $sourceResource = null, $exclude = null): mixed
+ public function import(mixed $resource, ?string $type = null, bool|string $ignoreErrors = false, ?string $sourceResource = null, $exclude = null): mixed
{
$args = \func_get_args();
@@ -96,7 +96,7 @@ public function import(mixed $resource, string $type = null, bool|string $ignore
* @param string|string[]|null $exclude A globbed path of files to exclude or an array of globbed paths of files to exclude
* @param string|null $source The path to the file that defines the auto-discovery rule
*/
- public function registerClasses(Definition $prototype, string $namespace, string $resource, string|array $exclude = null, string $source = null): void
+ public function registerClasses(Definition $prototype, string $namespace, string $resource, string|array|null $exclude = null, ?string $source = null): void
{
if (!str_ends_with($namespace, '\\')) {
throw new InvalidArgumentException(sprintf('Namespace prefix must end with a "\\": "%s".', $namespace));
diff --git a/src/Symfony/Component/DependencyInjection/Loader/GlobFileLoader.php b/src/Symfony/Component/DependencyInjection/Loader/GlobFileLoader.php
index 50349b25793d0..4716f11a7f8c3 100644
--- a/src/Symfony/Component/DependencyInjection/Loader/GlobFileLoader.php
+++ b/src/Symfony/Component/DependencyInjection/Loader/GlobFileLoader.php
@@ -18,7 +18,7 @@
*/
class GlobFileLoader extends FileLoader
{
- public function load(mixed $resource, string $type = null): mixed
+ public function load(mixed $resource, ?string $type = null): mixed
{
foreach ($this->glob($resource, false, $globResource) as $path => $info) {
$this->import($path);
@@ -29,7 +29,7 @@ public function load(mixed $resource, string $type = null): mixed
return null;
}
- public function supports(mixed $resource, string $type = null): bool
+ public function supports(mixed $resource, ?string $type = null): bool
{
return 'glob' === $type;
}
diff --git a/src/Symfony/Component/DependencyInjection/Loader/IniFileLoader.php b/src/Symfony/Component/DependencyInjection/Loader/IniFileLoader.php
index c177790e37c91..424fbdd51a2b3 100644
--- a/src/Symfony/Component/DependencyInjection/Loader/IniFileLoader.php
+++ b/src/Symfony/Component/DependencyInjection/Loader/IniFileLoader.php
@@ -21,7 +21,7 @@
*/
class IniFileLoader extends FileLoader
{
- public function load(mixed $resource, string $type = null): mixed
+ public function load(mixed $resource, ?string $type = null): mixed
{
$path = $this->locator->locate($resource);
@@ -55,7 +55,7 @@ public function load(mixed $resource, string $type = null): mixed
return null;
}
- public function supports(mixed $resource, string $type = null): bool
+ public function supports(mixed $resource, ?string $type = null): bool
{
if (!\is_string($resource)) {
return false;
diff --git a/src/Symfony/Component/DependencyInjection/Loader/PhpFileLoader.php b/src/Symfony/Component/DependencyInjection/Loader/PhpFileLoader.php
index 13021f2f00a2e..9acaa8cffbfbc 100644
--- a/src/Symfony/Component/DependencyInjection/Loader/PhpFileLoader.php
+++ b/src/Symfony/Component/DependencyInjection/Loader/PhpFileLoader.php
@@ -36,13 +36,13 @@ class PhpFileLoader extends FileLoader
protected bool $autoRegisterAliasesForSinglyImplementedInterfaces = false;
private ?ConfigBuilderGeneratorInterface $generator;
- public function __construct(ContainerBuilder $container, FileLocatorInterface $locator, string $env = null, ConfigBuilderGeneratorInterface $generator = null)
+ public function __construct(ContainerBuilder $container, FileLocatorInterface $locator, ?string $env = null, ?ConfigBuilderGeneratorInterface $generator = null)
{
parent::__construct($container, $locator, $env);
$this->generator = $generator;
}
- public function load(mixed $resource, string $type = null): mixed
+ public function load(mixed $resource, ?string $type = null): mixed
{
// the container and loader variables are exposed to the included file below
$container = $this->container;
@@ -71,7 +71,7 @@ public function load(mixed $resource, string $type = null): mixed
return null;
}
- public function supports(mixed $resource, string $type = null): bool
+ public function supports(mixed $resource, ?string $type = null): bool
{
if (!\is_string($resource)) {
return false;
diff --git a/src/Symfony/Component/DependencyInjection/Loader/XmlFileLoader.php b/src/Symfony/Component/DependencyInjection/Loader/XmlFileLoader.php
index d26833828e147..6fedd9821acee 100644
--- a/src/Symfony/Component/DependencyInjection/Loader/XmlFileLoader.php
+++ b/src/Symfony/Component/DependencyInjection/Loader/XmlFileLoader.php
@@ -41,7 +41,7 @@ class XmlFileLoader extends FileLoader
protected bool $autoRegisterAliasesForSinglyImplementedInterfaces = false;
- public function load(mixed $resource, string $type = null): mixed
+ public function load(mixed $resource, ?string $type = null): mixed
{
$path = $this->locator->locate($resource);
@@ -68,7 +68,7 @@ public function load(mixed $resource, string $type = null): mixed
return null;
}
- private function loadXml(\DOMDocument $xml, string $path, \DOMNode $root = null): void
+ private function loadXml(\DOMDocument $xml, string $path, ?\DOMNode $root = null): void
{
$defaults = $this->getServiceDefaults($xml, $path, $root);
@@ -93,7 +93,7 @@ private function loadXml(\DOMDocument $xml, string $path, \DOMNode $root = null)
}
}
- public function supports(mixed $resource, string $type = null): bool
+ public function supports(mixed $resource, ?string $type = null): bool
{
if (!\is_string($resource)) {
return false;
@@ -106,14 +106,14 @@ public function supports(mixed $resource, string $type = null): bool
return 'xml' === $type;
}
- private function parseParameters(\DOMDocument $xml, string $file, \DOMNode $root = null): void
+ private function parseParameters(\DOMDocument $xml, string $file, ?\DOMNode $root = null): void
{
if ($parameters = $this->getChildren($root ?? $xml->documentElement, 'parameters')) {
$this->container->getParameterBag()->add($this->getArgumentsAsPhp($parameters[0], 'parameter', $file));
}
}
- private function parseImports(\DOMDocument $xml, string $file, \DOMNode $root = null): void
+ private function parseImports(\DOMDocument $xml, string $file, ?\DOMNode $root = null): void
{
$xpath = new \DOMXPath($xml);
$xpath->registerNamespace('container', self::NS);
@@ -129,7 +129,7 @@ private function parseImports(\DOMDocument $xml, string $file, \DOMNode $root =
}
}
- private function parseDefinitions(\DOMDocument $xml, string $file, Definition $defaults, \DOMNode $root = null): void
+ private function parseDefinitions(\DOMDocument $xml, string $file, Definition $defaults, ?\DOMNode $root = null): void
{
$xpath = new \DOMXPath($xml);
$xpath->registerNamespace('container', self::NS);
@@ -187,7 +187,7 @@ private function parseDefinitions(\DOMDocument $xml, string $file, Definition $d
}
}
- private function getServiceDefaults(\DOMDocument $xml, string $file, \DOMNode $root = null): Definition
+ private function getServiceDefaults(\DOMDocument $xml, string $file, ?\DOMNode $root = null): Definition
{
$xpath = new \DOMXPath($xml);
$xpath->registerNamespace('container', self::NS);
@@ -469,7 +469,7 @@ private function parseFileToDOM(string $file): \DOMDocument
/**
* Processes anonymous services.
*/
- private function processAnonymousServices(\DOMDocument $xml, string $file, \DOMNode $root = null): void
+ private function processAnonymousServices(\DOMDocument $xml, string $file, ?\DOMNode $root = null): void
{
$definitions = [];
$count = 0;
diff --git a/src/Symfony/Component/DependencyInjection/Loader/YamlFileLoader.php b/src/Symfony/Component/DependencyInjection/Loader/YamlFileLoader.php
index eb399b8652bdc..c74e606be3831 100644
--- a/src/Symfony/Component/DependencyInjection/Loader/YamlFileLoader.php
+++ b/src/Symfony/Component/DependencyInjection/Loader/YamlFileLoader.php
@@ -116,7 +116,7 @@ class YamlFileLoader extends FileLoader
private int $anonymousServicesCount;
private string $anonymousServicesSuffix;
- public function load(mixed $resource, string $type = null): mixed
+ public function load(mixed $resource, ?string $type = null): mixed
{
$path = $this->locator->locate($resource);
@@ -180,7 +180,7 @@ private function loadContent(array $content, string $path): void
}
}
- public function supports(mixed $resource, string $type = null): bool
+ public function supports(mixed $resource, ?string $type = null): bool
{
if (!\is_string($resource)) {
return false;
diff --git a/src/Symfony/Component/DependencyInjection/ServiceLocator.php b/src/Symfony/Component/DependencyInjection/ServiceLocator.php
index 74b03da6a1dbc..fbf76690f2720 100644
--- a/src/Symfony/Component/DependencyInjection/ServiceLocator.php
+++ b/src/Symfony/Component/DependencyInjection/ServiceLocator.php
@@ -142,7 +142,7 @@ private function createCircularReferenceException(string $id, array $path): Cont
return new ServiceCircularReferenceException($id, $path);
}
- private function formatAlternatives(array $alternatives = null, string $separator = 'and'): string
+ private function formatAlternatives(?array $alternatives = null, string $separator = 'and'): string
{
$format = '"%s"%s';
if (null === $alternatives) {
diff --git a/src/Symfony/Component/DependencyInjection/Tests/Compiler/AutowirePassTest.php b/src/Symfony/Component/DependencyInjection/Tests/Compiler/AutowirePassTest.php
index 3045367aad1a4..62ed73a767cf9 100644
--- a/src/Symfony/Component/DependencyInjection/Tests/Compiler/AutowirePassTest.php
+++ b/src/Symfony/Component/DependencyInjection/Tests/Compiler/AutowirePassTest.php
@@ -1368,4 +1368,29 @@ public function testNestedAttributes()
];
$this->assertEquals($expected, $container->getDefinition(AutowireNestedAttributes::class)->getArgument(0));
}
+
+ public function testLazyServiceAttribute()
+ {
+ $container = new ContainerBuilder();
+ $container->register('a', A::class)->setAutowired(true);
+ $container->register('foo', LazyServiceAttributeAutowiring::class)->setAutowired(true);
+
+ (new AutowirePass())->process($container);
+
+ $expected = new Reference('.lazy.'.A::class);
+ $this->assertEquals($expected, $container->getDefinition('foo')->getArgument(0));
+ }
+
+ public function testLazyNotCompatibleWithAutowire()
+ {
+ $container = new ContainerBuilder();
+ $container->register('a', A::class)->setAutowired(true);
+ $container->register('foo', LazyAutowireServiceAttributesAutowiring::class)->setAutowired(true);
+
+ try {
+ (new AutowirePass())->process($container);
+ } catch (AutowiringFailedException $e) {
+ $this->assertSame('Using both attributes #[Lazy] and #[Autowire] on an argument is not allowed; use the "lazy" parameter of #[Autowire] instead.', $e->getMessage());
+ }
+ }
}
diff --git a/src/Symfony/Component/DependencyInjection/Tests/Compiler/IntegrationTest.php b/src/Symfony/Component/DependencyInjection/Tests/Compiler/IntegrationTest.php
index a2896d1492a6a..cd0ac69738674 100644
--- a/src/Symfony/Component/DependencyInjection/Tests/Compiler/IntegrationTest.php
+++ b/src/Symfony/Component/DependencyInjection/Tests/Compiler/IntegrationTest.php
@@ -15,6 +15,7 @@
use Psr\Container\ContainerInterface;
use Symfony\Component\Config\FileLocator;
use Symfony\Component\DependencyInjection\Alias;
+use Symfony\Component\DependencyInjection\Argument\BoundArgument;
use Symfony\Component\DependencyInjection\Argument\ServiceLocatorArgument;
use Symfony\Component\DependencyInjection\Argument\TaggedIteratorArgument;
use Symfony\Component\DependencyInjection\ChildDefinition;
@@ -50,6 +51,7 @@
use Symfony\Component\DependencyInjection\Tests\Fixtures\TaggedLocatorConsumerWithDefaultIndexMethodAndWithDefaultPriorityMethod;
use Symfony\Component\DependencyInjection\Tests\Fixtures\TaggedLocatorConsumerWithDefaultPriorityMethod;
use Symfony\Component\DependencyInjection\Tests\Fixtures\TaggedLocatorConsumerWithoutIndex;
+use Symfony\Component\DependencyInjection\Tests\Fixtures\TaggedLocatorConsumerWithServiceSubscriber;
use Symfony\Component\DependencyInjection\Tests\Fixtures\TaggedService1;
use Symfony\Component\DependencyInjection\Tests\Fixtures\TaggedService2;
use Symfony\Component\DependencyInjection\Tests\Fixtures\TaggedService3;
@@ -246,7 +248,7 @@ public function testAliasDecoratedService()
/**
* @dataProvider getYamlCompileTests
*/
- public function testYamlContainerCompiles($directory, $actualServiceId, $expectedServiceId, ContainerBuilder $mainContainer = null)
+ public function testYamlContainerCompiles($directory, $actualServiceId, $expectedServiceId, ?ContainerBuilder $mainContainer = null)
{
// allow a container to be passed in, which might have autoconfigure settings
$container = $mainContainer ?? new ContainerBuilder();
@@ -1118,6 +1120,66 @@ public function testTaggedIteratorAndLocatorWithExclude()
$this->assertTrue($locator->has(AutoconfiguredService2::class));
$this->assertFalse($locator->has(TaggedConsumerWithExclude::class));
}
+
+ public function testAutowireAttributeHasPriorityOverBindings()
+ {
+ $container = new ContainerBuilder();
+ $container->register(FooTagClass::class)
+ ->setPublic(true)
+ ->addTag('foo_bar', ['key' => 'tagged_service'])
+ ;
+ $container->register(TaggedLocatorConsumerWithServiceSubscriber::class)
+ ->setBindings([
+ '$locator' => new BoundArgument(new Reference('service_container'), false),
+ ])
+ ->setPublic(true)
+ ->setAutowired(true)
+ ->addTag('container.service_subscriber')
+ ;
+ $container->register('subscribed_service', \stdClass::class)
+ ->setPublic(true)
+ ;
+
+ $container->compile();
+
+ /** @var TaggedLocatorConsumerWithServiceSubscriber $s */
+ $s = $container->get(TaggedLocatorConsumerWithServiceSubscriber::class);
+
+ self::assertInstanceOf(ContainerInterface::class, $subscriberLocator = $s->getContainer());
+ self::assertTrue($subscriberLocator->has('subscribed_service'));
+ self::assertNotSame($subscriberLocator, $taggedLocator = $s->getLocator());
+ self::assertInstanceOf(ContainerInterface::class, $taggedLocator);
+ self::assertTrue($taggedLocator->has('tagged_service'));
+ }
+
+ public function testBindingsWithAutowireAttributeAndAutowireFalse()
+ {
+ $container = new ContainerBuilder();
+ $container->register(FooTagClass::class)
+ ->setPublic(true)
+ ->addTag('foo_bar', ['key' => 'tagged_service'])
+ ;
+ $container->register(TaggedLocatorConsumerWithServiceSubscriber::class)
+ ->setBindings([
+ '$locator' => new BoundArgument(new Reference('service_container'), false),
+ ])
+ ->setPublic(true)
+ ->setAutowired(false)
+ ->addTag('container.service_subscriber')
+ ;
+ $container->register('subscribed_service', \stdClass::class)
+ ->setPublic(true)
+ ;
+
+ $container->compile();
+
+ /** @var TaggedLocatorConsumerWithServiceSubscriber $s */
+ $s = $container->get(TaggedLocatorConsumerWithServiceSubscriber::class);
+
+ self::assertNull($s->getContainer());
+ self::assertInstanceOf(ContainerInterface::class, $taggedLocator = $s->getLocator());
+ self::assertSame($container, $taggedLocator);
+ }
}
class ServiceSubscriberStub implements ServiceSubscriberInterface
diff --git a/src/Symfony/Component/DependencyInjection/Tests/Compiler/RegisterAutoconfigureAttributesPassTest.php b/src/Symfony/Component/DependencyInjection/Tests/Compiler/RegisterAutoconfigureAttributesPassTest.php
index 877c50f027fa2..f1f70ed30cd9a 100644
--- a/src/Symfony/Component/DependencyInjection/Tests/Compiler/RegisterAutoconfigureAttributesPassTest.php
+++ b/src/Symfony/Component/DependencyInjection/Tests/Compiler/RegisterAutoconfigureAttributesPassTest.php
@@ -16,9 +16,13 @@
use Symfony\Component\DependencyInjection\ChildDefinition;
use Symfony\Component\DependencyInjection\Compiler\RegisterAutoconfigureAttributesPass;
use Symfony\Component\DependencyInjection\ContainerBuilder;
+use Symfony\Component\DependencyInjection\Exception\AutoconfigureFailedException;
use Symfony\Component\DependencyInjection\Reference;
use Symfony\Component\DependencyInjection\Tests\Fixtures\AutoconfigureAttributed;
use Symfony\Component\DependencyInjection\Tests\Fixtures\AutoconfiguredInterface;
+use Symfony\Component\DependencyInjection\Tests\Fixtures\LazyAutoconfigured;
+use Symfony\Component\DependencyInjection\Tests\Fixtures\LazyLoaded;
+use Symfony\Component\DependencyInjection\Tests\Fixtures\MultipleAutoconfigureAttributed;
use Symfony\Component\DependencyInjection\Tests\Fixtures\ParentNotExists;
use Symfony\Component\DependencyInjection\Tests\Fixtures\StaticConstructorAutoconfigure;
@@ -104,4 +108,46 @@ public function testStaticConstructor()
;
$this->assertEquals([StaticConstructorAutoconfigure::class => $expected], $container->getAutoconfiguredInstanceof());
}
+
+ public function testLazyServiceAttribute()
+ {
+ $container = new ContainerBuilder();
+ $container->register('foo', LazyLoaded::class)
+ ->setAutoconfigured(true);
+
+ (new RegisterAutoconfigureAttributesPass())->process($container);
+
+ $expected = (new ChildDefinition(''))
+ ->setLazy(true)
+ ;
+ $this->assertEquals([LazyLoaded::class => $expected], $container->getAutoconfiguredInstanceof());
+ }
+
+ public function testLazyNotCompatibleWithAutoconfigureAttribute()
+ {
+ $container = new ContainerBuilder();
+ $container->register('foo', LazyAutoconfigured::class)
+ ->setAutoconfigured(true);
+
+ try {
+ (new RegisterAutoconfigureAttributesPass())->process($container);
+ } catch (AutoconfigureFailedException $e) {
+ $this->assertSame('Using both attributes #[Lazy] and #[Autoconfigure] on an argument is not allowed; use the "lazy" parameter of #[Autoconfigure] instead.', $e->getMessage());
+ }
+ }
+
+ public function testMultipleAutoconfigureAllowed()
+ {
+ $container = new ContainerBuilder();
+ $container->register('foo', MultipleAutoconfigureAttributed::class)
+ ->setAutoconfigured(true);
+
+ (new RegisterAutoconfigureAttributesPass())->process($container);
+
+ $expected = (new ChildDefinition(''))
+ ->addTag('foo')
+ ->addTag('bar')
+ ;
+ $this->assertEquals([MultipleAutoconfigureAttributed::class => $expected], $container->getAutoconfiguredInstanceof());
+ }
}
diff --git a/src/Symfony/Component/DependencyInjection/Tests/Compiler/ValidateEnvPlaceholdersPassTest.php b/src/Symfony/Component/DependencyInjection/Tests/Compiler/ValidateEnvPlaceholdersPassTest.php
index cdaa1e2cd8c5d..8c5c4cc32323e 100644
--- a/src/Symfony/Component/DependencyInjection/Tests/Compiler/ValidateEnvPlaceholdersPassTest.php
+++ b/src/Symfony/Component/DependencyInjection/Tests/Compiler/ValidateEnvPlaceholdersPassTest.php
@@ -374,7 +374,7 @@ class EnvExtension extends Extension
private ConfigurationInterface $configuration;
private array $config;
- public function __construct(ConfigurationInterface $configuration = null)
+ public function __construct(?ConfigurationInterface $configuration = null)
{
$this->configuration = $configuration ?? new EnvConfiguration();
}
diff --git a/src/Symfony/Component/DependencyInjection/Tests/Config/ContainerParametersResourceCheckerTest.php b/src/Symfony/Component/DependencyInjection/Tests/Config/ContainerParametersResourceCheckerTest.php
index 9fefdd49e01e3..dfd6be81432a4 100644
--- a/src/Symfony/Component/DependencyInjection/Tests/Config/ContainerParametersResourceCheckerTest.php
+++ b/src/Symfony/Component/DependencyInjection/Tests/Config/ContainerParametersResourceCheckerTest.php
@@ -11,22 +11,21 @@
namespace Symfony\Component\DependencyInjection\Tests\Config;
-use PHPUnit\Framework\MockObject\MockObject;
use PHPUnit\Framework\TestCase;
use Symfony\Component\DependencyInjection\Config\ContainerParametersResource;
use Symfony\Component\DependencyInjection\Config\ContainerParametersResourceChecker;
-use Symfony\Component\DependencyInjection\ContainerInterface;
+use Symfony\Component\DependencyInjection\Container;
class ContainerParametersResourceCheckerTest extends TestCase
{
private ContainerParametersResource $resource;
private ContainerParametersResourceChecker $resourceChecker;
- private MockObject&ContainerInterface $container;
+ private Container $container;
protected function setUp(): void
{
$this->resource = new ContainerParametersResource(['locales' => ['fr', 'en'], 'default_locale' => 'fr']);
- $this->container = $this->createMock(ContainerInterface::class);
+ $this->container = new Container();
$this->resourceChecker = new ContainerParametersResourceChecker($this->container);
}
@@ -47,29 +46,16 @@ public function testIsFresh(callable $mockContainer, $expected)
public static function isFreshProvider()
{
- yield 'not fresh on missing parameter' => [function (MockObject $container) {
- $container->method('hasParameter')->with('locales')->willReturn(false);
+ yield 'not fresh on missing parameter' => [function (Container $container) {
}, false];
- yield 'not fresh on different value' => [function (MockObject $container) {
- $container->method('getParameter')->with('locales')->willReturn(['nl', 'es']);
+ yield 'not fresh on different value' => [function (Container $container) {
+ $container->setParameter('locales', ['nl', 'es']);
}, false];
- yield 'fresh on every identical parameters' => [function (MockObject $container) {
- $container->expects(self::exactly(2))->method('hasParameter')->willReturn(true);
- $container->expects(self::exactly(2))->method('getParameter')
- ->willReturnCallback(function (...$args) {
- static $series = [
- [['locales'], ['fr', 'en']],
- [['default_locale'], 'fr'],
- ];
-
- [$expectedArgs, $return] = array_shift($series);
- self::assertSame($expectedArgs, $args);
-
- return $return;
- })
- ;
+ yield 'fresh on every identical parameters' => [function (Container $container) {
+ $container->setParameter('locales', ['fr', 'en']);
+ $container->setParameter('default_locale', 'fr');
}, true];
}
}
diff --git a/src/Symfony/Component/DependencyInjection/Tests/DefinitionTest.php b/src/Symfony/Component/DependencyInjection/Tests/DefinitionTest.php
index 8f33418671f63..3a7c3a98002ca 100644
--- a/src/Symfony/Component/DependencyInjection/Tests/DefinitionTest.php
+++ b/src/Symfony/Component/DependencyInjection/Tests/DefinitionTest.php
@@ -292,7 +292,7 @@ public function testReplaceArgumentShouldCheckBounds()
$def->addArgument('foo');
$this->expectException(\OutOfBoundsException::class);
- $this->expectExceptionMessage('The index "1" is not in the range [0, 0] of the arguments of class "stdClass".');
+ $this->expectExceptionMessage('The argument "1" doesn\'t exist in class "stdClass".');
$def->replaceArgument(1, 'bar');
}
@@ -307,6 +307,17 @@ public function testReplaceArgumentWithoutExistingArgumentsShouldCheckBounds()
$def->replaceArgument(0, 'bar');
}
+ public function testReplaceArgumentWithNonConsecutiveIntIndex()
+ {
+ $def = new Definition('stdClass');
+
+ $def->setArguments([1 => 'foo']);
+ $this->assertSame([1 => 'foo'], $def->getArguments());
+
+ $def->replaceArgument(1, 'bar');
+ $this->assertSame([1 => 'bar'], $def->getArguments());
+ }
+
public function testSetGetProperties()
{
$def = new Definition('stdClass');
diff --git a/src/Symfony/Component/DependencyInjection/Tests/Dumper/YamlDumperTest.php b/src/Symfony/Component/DependencyInjection/Tests/Dumper/YamlDumperTest.php
index 68931050b2182..f9ff3fff786a3 100644
--- a/src/Symfony/Component/DependencyInjection/Tests/Dumper/YamlDumperTest.php
+++ b/src/Symfony/Component/DependencyInjection/Tests/Dumper/YamlDumperTest.php
@@ -163,7 +163,11 @@ public function testDumpHandlesEnumeration()
$container->compile();
$dumper = new YamlDumper($container);
- $this->assertEquals(file_get_contents(self::$fixturesPath.'/yaml/services_with_enumeration.yml'), $dumper->dump());
+ if (str_starts_with(Yaml::dump(FooUnitEnum::BAR), '!php/enum')) {
+ $this->assertEquals(file_get_contents(self::$fixturesPath.'/yaml/services_with_enumeration_enum_tag.yml'), $dumper->dump());
+ } else {
+ $this->assertEquals(file_get_contents(self::$fixturesPath.'/yaml/services_with_enumeration.yml'), $dumper->dump());
+ }
}
/**
diff --git a/src/Symfony/Component/DependencyInjection/Tests/EnvVarProcessorTest.php b/src/Symfony/Component/DependencyInjection/Tests/EnvVarProcessorTest.php
index acda307a16702..54b036d80f053 100644
--- a/src/Symfony/Component/DependencyInjection/Tests/EnvVarProcessorTest.php
+++ b/src/Symfony/Component/DependencyInjection/Tests/EnvVarProcessorTest.php
@@ -808,6 +808,12 @@ public function loadEnvVars(): array
return [
'FOO_ENV_LOADER' => '123',
'BAZ_ENV_LOADER' => '',
+ 'LAZY_ENV_LOADER' => new class() {
+ public function __toString()
+ {
+ return '';
+ }
+ },
];
}
};
@@ -819,6 +825,12 @@ public function loadEnvVars(): array
'FOO_ENV_LOADER' => '234',
'BAR_ENV_LOADER' => '456',
'BAZ_ENV_LOADER' => '567',
+ 'LAZY_ENV_LOADER' => new class() {
+ public function __toString()
+ {
+ return '678';
+ }
+ },
];
}
};
@@ -841,6 +853,9 @@ public function loadEnvVars(): array
$result = $processor->getEnv('string', 'FOO_ENV_LOADER', function () {});
$this->assertSame('123', $result); // check twice
+ $result = $processor->getEnv('string', 'LAZY_ENV_LOADER', function () {});
+ $this->assertSame('678', $result);
+
unset($_ENV['BAZ_ENV_LOADER']);
unset($_ENV['BUZ_ENV_LOADER']);
}
diff --git a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/LazyAutoconfigured.php b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/LazyAutoconfigured.php
new file mode 100644
index 0000000000000..7145e18ee9f6a
--- /dev/null
+++ b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/LazyAutoconfigured.php
@@ -0,0 +1,11 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\DependencyInjection\Tests\Fixtures;
+
+use Psr\Container\ContainerInterface;
+use Symfony\Component\DependencyInjection\Attribute\TaggedLocator;
+use Symfony\Contracts\Service\Attribute\Required;
+use Symfony\Contracts\Service\ServiceSubscriberInterface;
+
+final class TaggedLocatorConsumerWithServiceSubscriber implements ServiceSubscriberInterface
+{
+ private ?ContainerInterface $container = null;
+
+ public function __construct(
+ #[TaggedLocator('foo_bar', indexAttribute: 'key')]
+ private ContainerInterface $locator,
+ ) {
+ }
+
+ public function getLocator(): ContainerInterface
+ {
+ return $this->locator;
+ }
+
+ public function getContainer(): ?ContainerInterface
+ {
+ return $this->container;
+ }
+
+ #[Required]
+ public function setContainer(ContainerInterface $container): void
+ {
+ $this->container = $container;
+ }
+
+ public static function getSubscribedServices(): array
+ {
+ return [
+ 'subscribed_service',
+ ];
+ }
+}
diff --git a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/includes/autowiring_classes_80.php b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/includes/autowiring_classes_80.php
index 69ca09218812c..ed4cc2994d657 100644
--- a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/includes/autowiring_classes_80.php
+++ b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/includes/autowiring_classes_80.php
@@ -5,6 +5,7 @@
use Symfony\Component\DependencyInjection\Attribute\AsDecorator;
use Symfony\Component\DependencyInjection\Attribute\Autowire;
use Symfony\Component\DependencyInjection\Attribute\AutowireDecorated;
+use Symfony\Component\DependencyInjection\Attribute\Lazy;
use Symfony\Component\DependencyInjection\Attribute\TaggedIterator;
use Symfony\Component\DependencyInjection\Attribute\TaggedLocator;
use Symfony\Component\DependencyInjection\ContainerInterface;
@@ -125,3 +126,17 @@ public function __construct(
{
}
}
+
+class LazyServiceAttributeAutowiring
+{
+ public function __construct(#[Lazy] A $a)
+ {
+ }
+}
+
+class LazyAutowireServiceAttributesAutowiring
+{
+ public function __construct(#[Lazy, Autowire(lazy: true)] A $a)
+ {
+ }
+}
diff --git a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/yaml/services_with_enumeration.yml b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/yaml/services_with_enumeration.yml
index 0d335703383bc..992a83b14515c 100644
--- a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/yaml/services_with_enumeration.yml
+++ b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/yaml/services_with_enumeration.yml
@@ -10,4 +10,4 @@ services:
Symfony\Component\DependencyInjection\Tests\Fixtures\FooClassWithEnumAttribute:
class: Symfony\Component\DependencyInjection\Tests\Fixtures\FooClassWithEnumAttribute
public: true
- arguments: [!php/const 'Symfony\Component\DependencyInjection\Tests\Fixtures\FooUnitEnum::BAR']
+ arguments: [!php/enum 'Symfony\Component\DependencyInjection\Tests\Fixtures\FooUnitEnum::BAR']
diff --git a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/yaml/services_with_enumeration_enum_tag.yml b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/yaml/services_with_enumeration_enum_tag.yml
new file mode 100644
index 0000000000000..f166e2809cacd
--- /dev/null
+++ b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/yaml/services_with_enumeration_enum_tag.yml
@@ -0,0 +1,13 @@
+parameters:
+ unit_enum: !php/enum Symfony\Component\DependencyInjection\Tests\Fixtures\FooUnitEnum::BAR
+ enum_array: [!php/enum Symfony\Component\DependencyInjection\Tests\Fixtures\FooUnitEnum::BAR, !php/enum Symfony\Component\DependencyInjection\Tests\Fixtures\FooUnitEnum::FOO]
+
+services:
+ service_container:
+ class: Symfony\Component\DependencyInjection\ContainerInterface
+ public: true
+ synthetic: true
+ Symfony\Component\DependencyInjection\Tests\Fixtures\FooClassWithEnumAttribute:
+ class: Symfony\Component\DependencyInjection\Tests\Fixtures\FooClassWithEnumAttribute
+ public: true
+ arguments: [!php/enum 'Symfony\Component\DependencyInjection\Tests\Fixtures\FooUnitEnum::BAR']
diff --git a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/yaml/services_with_invalid_enumeration.yml b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/yaml/services_with_invalid_enumeration.yml
index b9f74e0f468ab..9676a70dd3c1b 100644
--- a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/yaml/services_with_invalid_enumeration.yml
+++ b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/yaml/services_with_invalid_enumeration.yml
@@ -7,4 +7,4 @@ services:
Symfony\Component\DependencyInjection\Tests\Fixtures\FooClassWithEnumAttribute:
class: Symfony\Component\DependencyInjection\Tests\Fixtures\FooClassWithEnumAttribute
public: true
- arguments: [!php/const 'Symfony\Component\DependencyInjection\Tests\Fixtures\FooUnitEnum::BAZ']
+ arguments: [!php/enum 'Symfony\Component\DependencyInjection\Tests\Fixtures\FooUnitEnum::BAZ']
diff --git a/src/Symfony/Component/DependencyInjection/Tests/LazyProxy/Instantiator/RealServiceInstantiatorTest.php b/src/Symfony/Component/DependencyInjection/Tests/LazyProxy/Instantiator/RealServiceInstantiatorTest.php
index 544c046d0097b..dadc9737a9c45 100644
--- a/src/Symfony/Component/DependencyInjection/Tests/LazyProxy/Instantiator/RealServiceInstantiatorTest.php
+++ b/src/Symfony/Component/DependencyInjection/Tests/LazyProxy/Instantiator/RealServiceInstantiatorTest.php
@@ -12,7 +12,7 @@
namespace Symfony\Component\DependencyInjection\Tests\LazyProxy\Instantiator;
use PHPUnit\Framework\TestCase;
-use Symfony\Component\DependencyInjection\ContainerInterface;
+use Symfony\Component\DependencyInjection\Container;
use Symfony\Component\DependencyInjection\Definition;
use Symfony\Component\DependencyInjection\LazyProxy\Instantiator\RealServiceInstantiator;
@@ -27,9 +27,8 @@ public function testInstantiateProxy()
{
$instantiator = new RealServiceInstantiator();
$instance = new \stdClass();
- $container = $this->createMock(ContainerInterface::class);
$callback = fn () => $instance;
- $this->assertSame($instance, $instantiator->instantiateProxy($container, new Definition(), 'foo', $callback));
+ $this->assertSame($instance, $instantiator->instantiateProxy(new Container(), new Definition(), 'foo', $callback));
}
}
diff --git a/src/Symfony/Component/DependencyInjection/Tests/Loader/FileLoaderTest.php b/src/Symfony/Component/DependencyInjection/Tests/Loader/FileLoaderTest.php
index 2dd904428d086..406e51eba789a 100644
--- a/src/Symfony/Component/DependencyInjection/Tests/Loader/FileLoaderTest.php
+++ b/src/Symfony/Component/DependencyInjection/Tests/Loader/FileLoaderTest.php
@@ -377,12 +377,12 @@ public function noAutoRegisterAliasesForSinglyImplementedInterfaces()
$this->autoRegisterAliasesForSinglyImplementedInterfaces = false;
}
- public function load(mixed $resource, string $type = null): mixed
+ public function load(mixed $resource, ?string $type = null): mixed
{
return $resource;
}
- public function supports(mixed $resource, string $type = null): bool
+ public function supports(mixed $resource, ?string $type = null): bool
{
return false;
}
diff --git a/src/Symfony/Component/DependencyInjection/Tests/Loader/GlobFileLoaderTest.php b/src/Symfony/Component/DependencyInjection/Tests/Loader/GlobFileLoaderTest.php
index f7f003b132ccb..0cf48dcb34e88 100644
--- a/src/Symfony/Component/DependencyInjection/Tests/Loader/GlobFileLoaderTest.php
+++ b/src/Symfony/Component/DependencyInjection/Tests/Loader/GlobFileLoaderTest.php
@@ -38,7 +38,7 @@ public function testLoadAddsTheGlobResourceToTheContainer()
class GlobFileLoaderWithoutImport extends GlobFileLoader
{
- public function import(mixed $resource, string $type = null, bool|string $ignoreErrors = false, string $sourceResource = null, $exclude = null): mixed
+ public function import(mixed $resource, ?string $type = null, bool|string $ignoreErrors = false, ?string $sourceResource = null, $exclude = null): mixed
{
return null;
}
diff --git a/src/Symfony/Component/DependencyInjection/Tests/Loader/YamlFileLoaderTest.php b/src/Symfony/Component/DependencyInjection/Tests/Loader/YamlFileLoaderTest.php
index 6b8512684d66d..5be7ed74ad7f6 100644
--- a/src/Symfony/Component/DependencyInjection/Tests/Loader/YamlFileLoaderTest.php
+++ b/src/Symfony/Component/DependencyInjection/Tests/Loader/YamlFileLoaderTest.php
@@ -43,6 +43,7 @@
use Symfony\Component\DependencyInjection\Tests\Fixtures\NamedArgumentsDummy;
use Symfony\Component\DependencyInjection\Tests\Fixtures\Prototype;
use Symfony\Component\ExpressionLanguage\Expression;
+use Symfony\Component\Yaml\Yaml;
class YamlFileLoaderTest extends TestCase
{
@@ -1020,7 +1021,13 @@ public function testInvalidEnumeration()
$loader = new YamlFileLoader($container, new FileLocator(self::$fixturesPath.'/yaml'));
$this->expectException(InvalidArgumentException::class);
- $this->expectExceptionMessage('The constant "Symfony\Component\DependencyInjection\Tests\Fixtures\FooUnitEnum::BAZ" is not defined');
+
+ if (str_starts_with(Yaml::dump(FooUnitEnum::BAR), '!php/enum')) {
+ $this->expectExceptionMessage('The string "Symfony\Component\DependencyInjection\Tests\Fixtures\FooUnitEnum::BAZ" is not the name of a valid enum');
+ } else {
+ $this->expectExceptionMessage('The enum "Symfony\Component\DependencyInjection\Tests\Fixtures\FooUnitEnum::BAZ" is not defined');
+ }
+
$loader->load('services_with_invalid_enumeration.yml');
}
diff --git a/src/Symfony/Component/DependencyInjection/TypedReference.php b/src/Symfony/Component/DependencyInjection/TypedReference.php
index fd1008a64eaa4..acdd3b89fc70a 100644
--- a/src/Symfony/Component/DependencyInjection/TypedReference.php
+++ b/src/Symfony/Component/DependencyInjection/TypedReference.php
@@ -29,7 +29,7 @@ class TypedReference extends Reference
* @param string|null $name The name of the argument targeting the service
* @param array $attributes The attributes to be used
*/
- public function __construct(string $id, string $type, int $invalidBehavior = ContainerInterface::EXCEPTION_ON_INVALID_REFERENCE, string $name = null, array $attributes = [])
+ public function __construct(string $id, string $type, int $invalidBehavior = ContainerInterface::EXCEPTION_ON_INVALID_REFERENCE, ?string $name = null, array $attributes = [])
{
$this->name = $type === $id ? $name : null;
parent::__construct($id, $invalidBehavior);
diff --git a/src/Symfony/Component/DomCrawler/AbstractUriElement.php b/src/Symfony/Component/DomCrawler/AbstractUriElement.php
index 9a3712bb2da5f..d75dcd219405d 100644
--- a/src/Symfony/Component/DomCrawler/AbstractUriElement.php
+++ b/src/Symfony/Component/DomCrawler/AbstractUriElement.php
@@ -29,7 +29,7 @@ abstract class AbstractUriElement
*
* @throws \InvalidArgumentException if the node is not a link
*/
- public function __construct(\DOMElement $node, string $currentUri = null, ?string $method = 'GET')
+ public function __construct(\DOMElement $node, ?string $currentUri = null, ?string $method = 'GET')
{
$this->setNode($node);
$this->method = $method ? strtoupper($method) : null;
diff --git a/src/Symfony/Component/DomCrawler/Crawler.php b/src/Symfony/Component/DomCrawler/Crawler.php
index 315e225035251..85d9c1eb36c7e 100644
--- a/src/Symfony/Component/DomCrawler/Crawler.php
+++ b/src/Symfony/Component/DomCrawler/Crawler.php
@@ -60,7 +60,7 @@ class Crawler implements \Countable, \IteratorAggregate
/**
* @param \DOMNodeList|\DOMNode|\DOMNode[]|string|null $node A Node to use as the base for the crawling
*/
- public function __construct(\DOMNodeList|\DOMNode|array|string $node = null, string $uri = null, string $baseHref = null, bool $useHtml5Parser = true)
+ public function __construct(\DOMNodeList|\DOMNode|array|string|null $node = null, ?string $uri = null, ?string $baseHref = null, bool $useHtml5Parser = true)
{
$this->uri = $uri;
$this->baseHref = $baseHref ?: $uri;
@@ -128,7 +128,7 @@ public function add(\DOMNodeList|\DOMNode|array|string|null $node): void
* or ISO-8859-1 as a fallback, which is the default charset defined by the
* HTTP 1.1 specification.
*/
- public function addContent(string $content, string $type = null): void
+ public function addContent(string $content, ?string $type = null): void
{
if (empty($type)) {
$type = str_starts_with($content, 'createSubCrawler(\array_slice($this->nodes, $offset, $length));
}
@@ -479,7 +479,7 @@ public function ancestors(): static
* @throws \InvalidArgumentException When current node is empty
* @throws \RuntimeException If the CssSelector Component is not available and $selector is provided
*/
- public function children(string $selector = null): static
+ public function children(?string $selector = null): static
{
if (!$this->nodes) {
throw new \InvalidArgumentException('The current node list is empty.');
@@ -504,7 +504,7 @@ public function children(string $selector = null): static
*
* @throws \InvalidArgumentException When current node is empty
*/
- public function attr(string $attribute, string $default = null): ?string
+ public function attr(string $attribute, ?string $default = null): ?string
{
if (!$this->nodes) {
if (null !== $default) {
@@ -543,7 +543,7 @@ public function nodeName(): string
*
* @throws \InvalidArgumentException When current node is empty
*/
- public function text(string $default = null, bool $normalizeWhitespace = true): string
+ public function text(?string $default = null, bool $normalizeWhitespace = true): string
{
if (!$this->nodes) {
if (null !== $default) {
@@ -591,7 +591,7 @@ public function innerText(bool $normalizeWhitespace = true): string
*
* @throws \InvalidArgumentException When current node is empty
*/
- public function html(string $default = null): string
+ public function html(?string $default = null): string
{
if (!$this->nodes) {
if (null !== $default) {
@@ -840,7 +840,7 @@ public function images(): array
*
* @throws \InvalidArgumentException If the current node list is empty or the selected node is not instance of DOMElement
*/
- public function form(array $values = null, string $method = null): Form
+ public function form(?array $values = null, ?string $method = null): Form
{
if (!$this->nodes) {
throw new \InvalidArgumentException('The current node list is empty.');
diff --git a/src/Symfony/Component/DomCrawler/Form.php b/src/Symfony/Component/DomCrawler/Form.php
index 1747bf9f02d43..fc2849e8b3087 100644
--- a/src/Symfony/Component/DomCrawler/Form.php
+++ b/src/Symfony/Component/DomCrawler/Form.php
@@ -33,7 +33,7 @@ class Form extends Link implements \ArrayAccess
*
* @throws \LogicException if the node is not a button inside a form tag
*/
- public function __construct(\DOMElement $node, string $currentUri = null, string $method = null, string $baseHref = null)
+ public function __construct(\DOMElement $node, ?string $currentUri = null, ?string $method = null, ?string $baseHref = null)
{
parent::__construct($node, $currentUri, $method);
$this->baseHref = $baseHref;
diff --git a/src/Symfony/Component/DomCrawler/Image.php b/src/Symfony/Component/DomCrawler/Image.php
index 5573928446f18..dc7c0b42b0032 100644
--- a/src/Symfony/Component/DomCrawler/Image.php
+++ b/src/Symfony/Component/DomCrawler/Image.php
@@ -16,7 +16,7 @@
*/
class Image extends AbstractUriElement
{
- public function __construct(\DOMElement $node, string $currentUri = null)
+ public function __construct(\DOMElement $node, ?string $currentUri = null)
{
parent::__construct($node, $currentUri, 'GET');
}
diff --git a/src/Symfony/Component/DomCrawler/Tests/AbstractCrawlerTestCase.php b/src/Symfony/Component/DomCrawler/Tests/AbstractCrawlerTestCase.php
index 2169a49a4379a..90c97e7452ce7 100644
--- a/src/Symfony/Component/DomCrawler/Tests/AbstractCrawlerTestCase.php
+++ b/src/Symfony/Component/DomCrawler/Tests/AbstractCrawlerTestCase.php
@@ -21,7 +21,7 @@ abstract class AbstractCrawlerTestCase extends TestCase
{
abstract public static function getDoctype(): string;
- protected function createCrawler($node = null, string $uri = null, string $baseHref = null, bool $useHtml5Parser = true)
+ protected function createCrawler($node = null, ?string $uri = null, ?string $baseHref = null, bool $useHtml5Parser = true)
{
return new Crawler($node, $uri, $baseHref, $useHtml5Parser);
}
diff --git a/src/Symfony/Component/Dotenv/Dotenv.php b/src/Symfony/Component/Dotenv/Dotenv.php
index 9908d63ca2ec4..e29051e06db24 100644
--- a/src/Symfony/Component/Dotenv/Dotenv.php
+++ b/src/Symfony/Component/Dotenv/Dotenv.php
@@ -96,7 +96,7 @@ public function load(string $path, string ...$extraPaths): void
* @throws FormatException when a file has a syntax error
* @throws PathException when a file does not exist or is not readable
*/
- public function loadEnv(string $path, string $envKey = null, string $defaultEnv = 'dev', array $testEnvs = ['test'], bool $overrideExistingVars = false): void
+ public function loadEnv(string $path, ?string $envKey = null, string $defaultEnv = 'dev', array $testEnvs = ['test'], bool $overrideExistingVars = false): void
{
$this->populatePath($path);
diff --git a/src/Symfony/Component/Dotenv/Exception/FormatException.php b/src/Symfony/Component/Dotenv/Exception/FormatException.php
index 7d8ec8f21270e..81c00bb3aa2a3 100644
--- a/src/Symfony/Component/Dotenv/Exception/FormatException.php
+++ b/src/Symfony/Component/Dotenv/Exception/FormatException.php
@@ -22,7 +22,7 @@ public function __construct(
string $message,
private FormatExceptionContext $context,
int $code = 0,
- \Throwable $previous = null,
+ ?\Throwable $previous = null,
) {
parent::__construct(sprintf("%s in \"%s\" at line %d.\n%s", $message, $context->getPath(), $context->getLineno(), $context->getDetails()), $code, $previous);
}
diff --git a/src/Symfony/Component/Dotenv/Exception/PathException.php b/src/Symfony/Component/Dotenv/Exception/PathException.php
index 4a4d71722223d..e432b2e33a8bf 100644
--- a/src/Symfony/Component/Dotenv/Exception/PathException.php
+++ b/src/Symfony/Component/Dotenv/Exception/PathException.php
@@ -18,7 +18,7 @@
*/
final class PathException extends \RuntimeException implements ExceptionInterface
{
- public function __construct(string $path, int $code = 0, \Throwable $previous = null)
+ public function __construct(string $path, int $code = 0, ?\Throwable $previous = null)
{
parent::__construct(sprintf('Unable to read the "%s" environment file.', $path), $code, $previous);
}
diff --git a/src/Symfony/Component/Dotenv/Tests/Command/DebugCommandTest.php b/src/Symfony/Component/Dotenv/Tests/Command/DebugCommandTest.php
index 5760bf1c80095..c2f698108cdfb 100644
--- a/src/Symfony/Component/Dotenv/Tests/Command/DebugCommandTest.php
+++ b/src/Symfony/Component/Dotenv/Tests/Command/DebugCommandTest.php
@@ -290,7 +290,7 @@ public function testCompletion()
$this->assertSame(['FOO', 'TEST'], $tester->complete(['']));
}
- private function executeCommand(string $projectDirectory, string $env, array $input = [], string $dotenvPath = null): string
+ private function executeCommand(string $projectDirectory, string $env, array $input = [], ?string $dotenvPath = null): string
{
$_SERVER['TEST_ENV_KEY'] = $env;
(new Dotenv('TEST_ENV_KEY'))->bootEnv($dotenvPath ?? $projectDirectory.'/.env');
diff --git a/src/Symfony/Component/Emoji/.gitattributes b/src/Symfony/Component/Emoji/.gitattributes
new file mode 100644
index 0000000000000..9e72316d442f0
--- /dev/null
+++ b/src/Symfony/Component/Emoji/.gitattributes
@@ -0,0 +1,8 @@
+/Resources/bin/build.php export-ignore
+/Resources/bin/composer.json export-ignore
+/Resources/bin/Makefile export-ignore
+/Resources/bin/README.md export-ignore
+/Tests export-ignore
+/phpunit.xml.dist export-ignore
+/.gitattributes export-ignore
+/.gitignore export-ignore
diff --git a/src/Symfony/Component/Emoji/.gitignore b/src/Symfony/Component/Emoji/.gitignore
new file mode 100644
index 0000000000000..c49a5d8df5c65
--- /dev/null
+++ b/src/Symfony/Component/Emoji/.gitignore
@@ -0,0 +1,3 @@
+vendor/
+composer.lock
+phpunit.xml
diff --git a/src/Symfony/Component/Emoji/CHANGELOG.md b/src/Symfony/Component/Emoji/CHANGELOG.md
new file mode 100644
index 0000000000000..5f941ae21a99a
--- /dev/null
+++ b/src/Symfony/Component/Emoji/CHANGELOG.md
@@ -0,0 +1,7 @@
+CHANGELOG
+=========
+
+7.1
+---
+
+ * Add the component
diff --git a/src/Symfony/Component/Emoji/EmojiTransliterator.php b/src/Symfony/Component/Emoji/EmojiTransliterator.php
new file mode 100644
index 0000000000000..2a19f89cfc548
--- /dev/null
+++ b/src/Symfony/Component/Emoji/EmojiTransliterator.php
@@ -0,0 +1,141 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Emoji;
+
+use Symfony\Component\Emoji\Util\GzipStreamWrapper;
+
+if (!class_exists(\Transliterator::class)) {
+ throw new \LogicException(sprintf('You cannot use the "%s\EmojiTransliterator" class as the "intl" extension is not installed. See https://php.net/intl.', __NAMESPACE__));
+}
+
+final class EmojiTransliterator extends \Transliterator
+{
+ private const QUICK_CHECK = "\xA9\xAE\xE2\xE3\xF0";
+ private const REVERSEABLE_IDS = [
+ 'emoji-github' => 'github-emoji',
+ 'emoji-slack' => 'slack-emoji',
+ 'github-emoji' => 'emoji-github',
+ 'slack-emoji' => 'emoji-slack',
+ ];
+
+ public readonly string $id;
+
+ private array $map;
+
+ private string $quickCheck;
+
+ private \Transliterator $transliterator;
+
+ public static function create(string $id, int $direction = self::FORWARD): self
+ {
+ $id = strtolower($id);
+
+ if (!isset(self::REVERSEABLE_IDS[$id]) && !str_starts_with($id, 'emoji-')) {
+ $id = 'emoji-'.$id;
+ }
+
+ if (self::REVERSE === $direction) {
+ if (!isset(self::REVERSEABLE_IDS[$id])) {
+ // Create a failing reverse-transliterator to populate intl_get_error_*()
+ \Transliterator::createFromRules('A > B')->createInverse();
+
+ throw new \IntlException(intl_get_error_message(), intl_get_error_code());
+ }
+ $id = self::REVERSEABLE_IDS[$id];
+ }
+
+ $file = __DIR__."/Resources/data/{$id}.php";
+ if (!preg_match('/^[a-z0-9@_\\.\\-]*$/', $id) || !is_file($file) && !is_file($file .= '.gz')) {
+ \Transliterator::create($id); // Populate intl_get_error_*()
+
+ throw new \IntlException(intl_get_error_message(), intl_get_error_code());
+ }
+
+ /**
+ * @var array $maps
+ */
+ static $maps;
+
+ // Create an instance of \Transliterator with a custom id; that's the only way
+ static $newInstance;
+ $instance = ($newInstance ??= (new \ReflectionClass(self::class))->newInstanceWithoutConstructor(...))();
+ $instance->id = $id;
+ $instance->map = $maps[$id] ??= str_ends_with($file, '.gz') ? GzipStreamWrapper::require($file) : require $file;
+
+ return $instance;
+ }
+
+ public function createInverse(): self
+ {
+ return self::create($this->id, \Transliterator::REVERSE);
+ }
+
+ public function getErrorCode(): int|false
+ {
+ return $this->transliterator?->getErrorCode() ?? 0;
+ }
+
+ public function getErrorMessage(): string|false
+ {
+ return $this->transliterator?->getErrorMessage() ?? false;
+ }
+
+ public static function listIDs(): array
+ {
+ static $ids = [];
+
+ if ($ids) {
+ return $ids;
+ }
+
+ foreach (scandir(__DIR__.'/Resources/data/') as $file) {
+ if (str_ends_with($file, '.php.gz')) {
+ $ids[] = substr($file, 0, -7);
+ } elseif (str_ends_with($file, '.php')) {
+ $ids[] = substr($file, 0, -4);
+ }
+ }
+
+ return $ids;
+ }
+
+ public function transliterate(string $string, int $start = 0, int $end = -1): string|false
+ {
+ $this->quickCheck ??= str_starts_with(array_key_first($this->map), ':') ? ':' : self::QUICK_CHECK;
+
+ if (0 === $start && -1 === $end && preg_match('//u', $string)) {
+ return \strlen($string) === strcspn($string, $this->quickCheck) ? $string : strtr($string, $this->map);
+ }
+
+ // Here we rely on intl to validate the $string, $start and $end arguments
+ // and to slice the string. Slicing is done by replacing the part if $string
+ // between $start and $end by a unique cookie that can be reliably used to
+ // identify which part of $string should be transliterated.
+
+ static $cookie;
+ static $transliterator;
+
+ $cookie ??= hash('xxh128', random_bytes(8));
+ $this->transliterator ??= clone $transliterator ??= \Transliterator::createFromRules('[:any:]* > '.$cookie);
+
+ if (false === $result = $this->transliterator->transliterate($string, $start, $end)) {
+ return false;
+ }
+
+ $parts = explode($cookie, $result);
+ $start = \strlen($parts[0]);
+ $length = -\strlen($parts[1]) ?: null;
+ $string = substr($string, $start, $length);
+
+ return $parts[0].(\strlen($string) === strcspn($string, $this->quickCheck) ? $string : strtr($string, $this->map)).$parts[1];
+ }
+}
diff --git a/src/Symfony/Component/Emoji/LICENSE b/src/Symfony/Component/Emoji/LICENSE
new file mode 100644
index 0000000000000..e374a5c8339d3
--- /dev/null
+++ b/src/Symfony/Component/Emoji/LICENSE
@@ -0,0 +1,19 @@
+Copyright (c) 2024-present Fabien Potencier
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is furnished
+to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
diff --git a/src/Symfony/Component/Emoji/README.md b/src/Symfony/Component/Emoji/README.md
new file mode 100644
index 0000000000000..b5027369514d6
--- /dev/null
+++ b/src/Symfony/Component/Emoji/README.md
@@ -0,0 +1,18 @@
+Emoji Component
+===============
+
+The Emoji component provides access to emoji characters and sequences from
+the [Unicode CLDR](https://cldr.unicode.org/index).
+
+If you have the zlib extension enabled, you can compress the data by running:
+
+ php vendor/symfony/emoji/Resources/bin/compress
+
+Resources
+---------
+
+ * [Documentation](https://symfony.com/doc/current/components/emoji.html)
+ * [Contributing](https://symfony.com/doc/current/contributing/index.html)
+ * [Report issues](https://github.com/symfony/symfony/issues) and
+ [send Pull Requests](https://github.com/symfony/symfony/pulls)
+ in the [main Symfony repository](https://github.com/symfony/symfony)
diff --git a/src/Symfony/Component/Intl/Resources/emoji/Makefile b/src/Symfony/Component/Emoji/Resources/bin/Makefile
similarity index 100%
rename from src/Symfony/Component/Intl/Resources/emoji/Makefile
rename to src/Symfony/Component/Emoji/Resources/bin/Makefile
diff --git a/src/Symfony/Component/Intl/Resources/emoji/README.md b/src/Symfony/Component/Emoji/Resources/bin/README.md
similarity index 100%
rename from src/Symfony/Component/Intl/Resources/emoji/README.md
rename to src/Symfony/Component/Emoji/Resources/bin/README.md
diff --git a/src/Symfony/Component/Intl/Resources/emoji/build.php b/src/Symfony/Component/Emoji/Resources/bin/build.php
similarity index 98%
rename from src/Symfony/Component/Intl/Resources/emoji/build.php
rename to src/Symfony/Component/Emoji/Resources/bin/build.php
index a3546815865cf..088838cdd0466 100755
--- a/src/Symfony/Component/Intl/Resources/emoji/build.php
+++ b/src/Symfony/Component/Emoji/Resources/bin/build.php
@@ -25,7 +25,7 @@
final class Builder
{
- private const TARGET_DIR = __DIR__.'/../data/transliterator/emoji/';
+ private const TARGET_DIR = __DIR__.'/../data/';
public static function getEmojisCodePoints(): array
{
@@ -233,7 +233,7 @@ public static function saveRules(iterable $rulesByLocale): void
sort($firstChars);
$quickCheck = '"'.str_replace('%', '\\x', rawurlencode(implode('', $firstChars))).'"';
- $file = dirname(__DIR__, 2).'/Transliterator/EmojiTransliterator.php';
+ $file = dirname(__DIR__, 2).'/EmojiTransliterator.php';
file_put_contents($file, preg_replace('/QUICK_CHECK = .*;/m', "QUICK_CHECK = {$quickCheck};", file_get_contents($file)));
}
diff --git a/src/Symfony/Component/Intl/Resources/emoji/composer.json b/src/Symfony/Component/Emoji/Resources/bin/composer.json
similarity index 100%
rename from src/Symfony/Component/Intl/Resources/emoji/composer.json
rename to src/Symfony/Component/Emoji/Resources/bin/composer.json
diff --git a/src/Symfony/Component/Emoji/Resources/bin/compress b/src/Symfony/Component/Emoji/Resources/bin/compress
new file mode 100755
index 0000000000000..174cbca59b041
--- /dev/null
+++ b/src/Symfony/Component/Emoji/Resources/bin/compress
@@ -0,0 +1,36 @@
+#!/usr/bin/env php
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+if ('cli' !== PHP_SAPI) {
+ throw new Exception('This script must be run from the command line.');
+}
+if (!extension_loaded('zlib')) {
+ throw new Exception('This script requires the zlib extension.');
+}
+
+$iterator = new RecursiveIteratorIterator(
+ new RecursiveDirectoryIterator(
+ dirname(__DIR__).'/data',
+ FilesystemIterator::CURRENT_AS_FILEINFO | FilesystemIterator::SKIP_DOTS
+ )
+);
+
+foreach ($iterator as $file) {
+ if ('php' !== $file->getExtension()) {
+ continue;
+ }
+
+ $data = file_get_contents($file);
+ file_put_contents('compress.zlib://'.$file.'.gz', $data);
+
+ unlink($file.(filesize($file.'.gz') >= strlen($data) ? '.gz' : ''));
+}
diff --git a/src/Symfony/Component/Intl/Resources/data/transliterator/emoji/emoji-af.php b/src/Symfony/Component/Emoji/Resources/data/emoji-af.php
similarity index 100%
rename from src/Symfony/Component/Intl/Resources/data/transliterator/emoji/emoji-af.php
rename to src/Symfony/Component/Emoji/Resources/data/emoji-af.php
diff --git a/src/Symfony/Component/Intl/Resources/data/transliterator/emoji/emoji-am.php b/src/Symfony/Component/Emoji/Resources/data/emoji-am.php
similarity index 100%
rename from src/Symfony/Component/Intl/Resources/data/transliterator/emoji/emoji-am.php
rename to src/Symfony/Component/Emoji/Resources/data/emoji-am.php
diff --git a/src/Symfony/Component/Intl/Resources/data/transliterator/emoji/emoji-ar.php b/src/Symfony/Component/Emoji/Resources/data/emoji-ar.php
similarity index 100%
rename from src/Symfony/Component/Intl/Resources/data/transliterator/emoji/emoji-ar.php
rename to src/Symfony/Component/Emoji/Resources/data/emoji-ar.php
diff --git a/src/Symfony/Component/Intl/Resources/data/transliterator/emoji/emoji-ar_sa.php b/src/Symfony/Component/Emoji/Resources/data/emoji-ar_sa.php
similarity index 100%
rename from src/Symfony/Component/Intl/Resources/data/transliterator/emoji/emoji-ar_sa.php
rename to src/Symfony/Component/Emoji/Resources/data/emoji-ar_sa.php
diff --git a/src/Symfony/Component/Intl/Resources/data/transliterator/emoji/emoji-as.php b/src/Symfony/Component/Emoji/Resources/data/emoji-as.php
similarity index 100%
rename from src/Symfony/Component/Intl/Resources/data/transliterator/emoji/emoji-as.php
rename to src/Symfony/Component/Emoji/Resources/data/emoji-as.php
diff --git a/src/Symfony/Component/Intl/Resources/data/transliterator/emoji/emoji-ast.php b/src/Symfony/Component/Emoji/Resources/data/emoji-ast.php
similarity index 100%
rename from src/Symfony/Component/Intl/Resources/data/transliterator/emoji/emoji-ast.php
rename to src/Symfony/Component/Emoji/Resources/data/emoji-ast.php
diff --git a/src/Symfony/Component/Intl/Resources/data/transliterator/emoji/emoji-az.php b/src/Symfony/Component/Emoji/Resources/data/emoji-az.php
similarity index 100%
rename from src/Symfony/Component/Intl/Resources/data/transliterator/emoji/emoji-az.php
rename to src/Symfony/Component/Emoji/Resources/data/emoji-az.php
diff --git a/src/Symfony/Component/Intl/Resources/data/transliterator/emoji/emoji-be.php b/src/Symfony/Component/Emoji/Resources/data/emoji-be.php
similarity index 100%
rename from src/Symfony/Component/Intl/Resources/data/transliterator/emoji/emoji-be.php
rename to src/Symfony/Component/Emoji/Resources/data/emoji-be.php
diff --git a/src/Symfony/Component/Intl/Resources/data/transliterator/emoji/emoji-bew.php b/src/Symfony/Component/Emoji/Resources/data/emoji-bew.php
similarity index 100%
rename from src/Symfony/Component/Intl/Resources/data/transliterator/emoji/emoji-bew.php
rename to src/Symfony/Component/Emoji/Resources/data/emoji-bew.php
diff --git a/src/Symfony/Component/Intl/Resources/data/transliterator/emoji/emoji-bg.php b/src/Symfony/Component/Emoji/Resources/data/emoji-bg.php
similarity index 100%
rename from src/Symfony/Component/Intl/Resources/data/transliterator/emoji/emoji-bg.php
rename to src/Symfony/Component/Emoji/Resources/data/emoji-bg.php
diff --git a/src/Symfony/Component/Intl/Resources/data/transliterator/emoji/emoji-bgn.php b/src/Symfony/Component/Emoji/Resources/data/emoji-bgn.php
similarity index 100%
rename from src/Symfony/Component/Intl/Resources/data/transliterator/emoji/emoji-bgn.php
rename to src/Symfony/Component/Emoji/Resources/data/emoji-bgn.php
diff --git a/src/Symfony/Component/Intl/Resources/data/transliterator/emoji/emoji-bn.php b/src/Symfony/Component/Emoji/Resources/data/emoji-bn.php
similarity index 100%
rename from src/Symfony/Component/Intl/Resources/data/transliterator/emoji/emoji-bn.php
rename to src/Symfony/Component/Emoji/Resources/data/emoji-bn.php
diff --git a/src/Symfony/Component/Intl/Resources/data/transliterator/emoji/emoji-br.php b/src/Symfony/Component/Emoji/Resources/data/emoji-br.php
similarity index 100%
rename from src/Symfony/Component/Intl/Resources/data/transliterator/emoji/emoji-br.php
rename to src/Symfony/Component/Emoji/Resources/data/emoji-br.php
diff --git a/src/Symfony/Component/Intl/Resources/data/transliterator/emoji/emoji-bs.php b/src/Symfony/Component/Emoji/Resources/data/emoji-bs.php
similarity index 100%
rename from src/Symfony/Component/Intl/Resources/data/transliterator/emoji/emoji-bs.php
rename to src/Symfony/Component/Emoji/Resources/data/emoji-bs.php
diff --git a/src/Symfony/Component/Intl/Resources/data/transliterator/emoji/emoji-ca.php b/src/Symfony/Component/Emoji/Resources/data/emoji-ca.php
similarity index 100%
rename from src/Symfony/Component/Intl/Resources/data/transliterator/emoji/emoji-ca.php
rename to src/Symfony/Component/Emoji/Resources/data/emoji-ca.php
diff --git a/src/Symfony/Component/Intl/Resources/data/transliterator/emoji/emoji-ccp.php b/src/Symfony/Component/Emoji/Resources/data/emoji-ccp.php
similarity index 100%
rename from src/Symfony/Component/Intl/Resources/data/transliterator/emoji/emoji-ccp.php
rename to src/Symfony/Component/Emoji/Resources/data/emoji-ccp.php
diff --git a/src/Symfony/Component/Intl/Resources/data/transliterator/emoji/emoji-ceb.php b/src/Symfony/Component/Emoji/Resources/data/emoji-ceb.php
similarity index 100%
rename from src/Symfony/Component/Intl/Resources/data/transliterator/emoji/emoji-ceb.php
rename to src/Symfony/Component/Emoji/Resources/data/emoji-ceb.php
diff --git a/src/Symfony/Component/Intl/Resources/data/transliterator/emoji/emoji-chr.php b/src/Symfony/Component/Emoji/Resources/data/emoji-chr.php
similarity index 100%
rename from src/Symfony/Component/Intl/Resources/data/transliterator/emoji/emoji-chr.php
rename to src/Symfony/Component/Emoji/Resources/data/emoji-chr.php
diff --git a/src/Symfony/Component/Intl/Resources/data/transliterator/emoji/emoji-ckb.php b/src/Symfony/Component/Emoji/Resources/data/emoji-ckb.php
similarity index 100%
rename from src/Symfony/Component/Intl/Resources/data/transliterator/emoji/emoji-ckb.php
rename to src/Symfony/Component/Emoji/Resources/data/emoji-ckb.php
diff --git a/src/Symfony/Component/Intl/Resources/data/transliterator/emoji/emoji-cs.php b/src/Symfony/Component/Emoji/Resources/data/emoji-cs.php
similarity index 100%
rename from src/Symfony/Component/Intl/Resources/data/transliterator/emoji/emoji-cs.php
rename to src/Symfony/Component/Emoji/Resources/data/emoji-cs.php
diff --git a/src/Symfony/Component/Intl/Resources/data/transliterator/emoji/emoji-cv.php b/src/Symfony/Component/Emoji/Resources/data/emoji-cv.php
similarity index 100%
rename from src/Symfony/Component/Intl/Resources/data/transliterator/emoji/emoji-cv.php
rename to src/Symfony/Component/Emoji/Resources/data/emoji-cv.php
diff --git a/src/Symfony/Component/Intl/Resources/data/transliterator/emoji/emoji-cy.php b/src/Symfony/Component/Emoji/Resources/data/emoji-cy.php
similarity index 100%
rename from src/Symfony/Component/Intl/Resources/data/transliterator/emoji/emoji-cy.php
rename to src/Symfony/Component/Emoji/Resources/data/emoji-cy.php
diff --git a/src/Symfony/Component/Intl/Resources/data/transliterator/emoji/emoji-da.php b/src/Symfony/Component/Emoji/Resources/data/emoji-da.php
similarity index 100%
rename from src/Symfony/Component/Intl/Resources/data/transliterator/emoji/emoji-da.php
rename to src/Symfony/Component/Emoji/Resources/data/emoji-da.php
diff --git a/src/Symfony/Component/Intl/Resources/data/transliterator/emoji/emoji-de.php b/src/Symfony/Component/Emoji/Resources/data/emoji-de.php
similarity index 100%
rename from src/Symfony/Component/Intl/Resources/data/transliterator/emoji/emoji-de.php
rename to src/Symfony/Component/Emoji/Resources/data/emoji-de.php
diff --git a/src/Symfony/Component/Intl/Resources/data/transliterator/emoji/emoji-de_ch.php b/src/Symfony/Component/Emoji/Resources/data/emoji-de_ch.php
similarity index 100%
rename from src/Symfony/Component/Intl/Resources/data/transliterator/emoji/emoji-de_ch.php
rename to src/Symfony/Component/Emoji/Resources/data/emoji-de_ch.php
diff --git a/src/Symfony/Component/Intl/Resources/data/transliterator/emoji/emoji-dsb.php b/src/Symfony/Component/Emoji/Resources/data/emoji-dsb.php
similarity index 100%
rename from src/Symfony/Component/Intl/Resources/data/transliterator/emoji/emoji-dsb.php
rename to src/Symfony/Component/Emoji/Resources/data/emoji-dsb.php
diff --git a/src/Symfony/Component/Intl/Resources/data/transliterator/emoji/emoji-el.php b/src/Symfony/Component/Emoji/Resources/data/emoji-el.php
similarity index 100%
rename from src/Symfony/Component/Intl/Resources/data/transliterator/emoji/emoji-el.php
rename to src/Symfony/Component/Emoji/Resources/data/emoji-el.php
diff --git a/src/Symfony/Component/Intl/Resources/data/transliterator/emoji/emoji-en.php b/src/Symfony/Component/Emoji/Resources/data/emoji-en.php
similarity index 100%
rename from src/Symfony/Component/Intl/Resources/data/transliterator/emoji/emoji-en.php
rename to src/Symfony/Component/Emoji/Resources/data/emoji-en.php
diff --git a/src/Symfony/Component/Intl/Resources/data/transliterator/emoji/emoji-en_001.php b/src/Symfony/Component/Emoji/Resources/data/emoji-en_001.php
similarity index 100%
rename from src/Symfony/Component/Intl/Resources/data/transliterator/emoji/emoji-en_001.php
rename to src/Symfony/Component/Emoji/Resources/data/emoji-en_001.php
diff --git a/src/Symfony/Component/Intl/Resources/data/transliterator/emoji/emoji-en_au.php b/src/Symfony/Component/Emoji/Resources/data/emoji-en_au.php
similarity index 100%
rename from src/Symfony/Component/Intl/Resources/data/transliterator/emoji/emoji-en_au.php
rename to src/Symfony/Component/Emoji/Resources/data/emoji-en_au.php
diff --git a/src/Symfony/Component/Intl/Resources/data/transliterator/emoji/emoji-en_ca.php b/src/Symfony/Component/Emoji/Resources/data/emoji-en_ca.php
similarity index 100%
rename from src/Symfony/Component/Intl/Resources/data/transliterator/emoji/emoji-en_ca.php
rename to src/Symfony/Component/Emoji/Resources/data/emoji-en_ca.php
diff --git a/src/Symfony/Component/Intl/Resources/data/transliterator/emoji/emoji-en_gb.php b/src/Symfony/Component/Emoji/Resources/data/emoji-en_gb.php
similarity index 100%
rename from src/Symfony/Component/Intl/Resources/data/transliterator/emoji/emoji-en_gb.php
rename to src/Symfony/Component/Emoji/Resources/data/emoji-en_gb.php
diff --git a/src/Symfony/Component/Intl/Resources/data/transliterator/emoji/emoji-en_in.php b/src/Symfony/Component/Emoji/Resources/data/emoji-en_in.php
similarity index 100%
rename from src/Symfony/Component/Intl/Resources/data/transliterator/emoji/emoji-en_in.php
rename to src/Symfony/Component/Emoji/Resources/data/emoji-en_in.php
diff --git a/src/Symfony/Component/Intl/Resources/data/transliterator/emoji/emoji-es.php b/src/Symfony/Component/Emoji/Resources/data/emoji-es.php
similarity index 100%
rename from src/Symfony/Component/Intl/Resources/data/transliterator/emoji/emoji-es.php
rename to src/Symfony/Component/Emoji/Resources/data/emoji-es.php
diff --git a/src/Symfony/Component/Intl/Resources/data/transliterator/emoji/emoji-es_419.php b/src/Symfony/Component/Emoji/Resources/data/emoji-es_419.php
similarity index 100%
rename from src/Symfony/Component/Intl/Resources/data/transliterator/emoji/emoji-es_419.php
rename to src/Symfony/Component/Emoji/Resources/data/emoji-es_419.php
diff --git a/src/Symfony/Component/Intl/Resources/data/transliterator/emoji/emoji-es_mx.php b/src/Symfony/Component/Emoji/Resources/data/emoji-es_mx.php
similarity index 100%
rename from src/Symfony/Component/Intl/Resources/data/transliterator/emoji/emoji-es_mx.php
rename to src/Symfony/Component/Emoji/Resources/data/emoji-es_mx.php
diff --git a/src/Symfony/Component/Intl/Resources/data/transliterator/emoji/emoji-es_us.php b/src/Symfony/Component/Emoji/Resources/data/emoji-es_us.php
similarity index 100%
rename from src/Symfony/Component/Intl/Resources/data/transliterator/emoji/emoji-es_us.php
rename to src/Symfony/Component/Emoji/Resources/data/emoji-es_us.php
diff --git a/src/Symfony/Component/Intl/Resources/data/transliterator/emoji/emoji-et.php b/src/Symfony/Component/Emoji/Resources/data/emoji-et.php
similarity index 100%
rename from src/Symfony/Component/Intl/Resources/data/transliterator/emoji/emoji-et.php
rename to src/Symfony/Component/Emoji/Resources/data/emoji-et.php
diff --git a/src/Symfony/Component/Intl/Resources/data/transliterator/emoji/emoji-eu.php b/src/Symfony/Component/Emoji/Resources/data/emoji-eu.php
similarity index 100%
rename from src/Symfony/Component/Intl/Resources/data/transliterator/emoji/emoji-eu.php
rename to src/Symfony/Component/Emoji/Resources/data/emoji-eu.php
diff --git a/src/Symfony/Component/Intl/Resources/data/transliterator/emoji/emoji-fa.php b/src/Symfony/Component/Emoji/Resources/data/emoji-fa.php
similarity index 100%
rename from src/Symfony/Component/Intl/Resources/data/transliterator/emoji/emoji-fa.php
rename to src/Symfony/Component/Emoji/Resources/data/emoji-fa.php
diff --git a/src/Symfony/Component/Intl/Resources/data/transliterator/emoji/emoji-ff_adlm.php b/src/Symfony/Component/Emoji/Resources/data/emoji-ff_adlm.php
similarity index 100%
rename from src/Symfony/Component/Intl/Resources/data/transliterator/emoji/emoji-ff_adlm.php
rename to src/Symfony/Component/Emoji/Resources/data/emoji-ff_adlm.php
diff --git a/src/Symfony/Component/Intl/Resources/data/transliterator/emoji/emoji-fi.php b/src/Symfony/Component/Emoji/Resources/data/emoji-fi.php
similarity index 100%
rename from src/Symfony/Component/Intl/Resources/data/transliterator/emoji/emoji-fi.php
rename to src/Symfony/Component/Emoji/Resources/data/emoji-fi.php
diff --git a/src/Symfony/Component/Intl/Resources/data/transliterator/emoji/emoji-fil.php b/src/Symfony/Component/Emoji/Resources/data/emoji-fil.php
similarity index 100%
rename from src/Symfony/Component/Intl/Resources/data/transliterator/emoji/emoji-fil.php
rename to src/Symfony/Component/Emoji/Resources/data/emoji-fil.php
diff --git a/src/Symfony/Component/Intl/Resources/data/transliterator/emoji/emoji-fo.php b/src/Symfony/Component/Emoji/Resources/data/emoji-fo.php
similarity index 100%
rename from src/Symfony/Component/Intl/Resources/data/transliterator/emoji/emoji-fo.php
rename to src/Symfony/Component/Emoji/Resources/data/emoji-fo.php
diff --git a/src/Symfony/Component/Intl/Resources/data/transliterator/emoji/emoji-fr.php b/src/Symfony/Component/Emoji/Resources/data/emoji-fr.php
similarity index 100%
rename from src/Symfony/Component/Intl/Resources/data/transliterator/emoji/emoji-fr.php
rename to src/Symfony/Component/Emoji/Resources/data/emoji-fr.php
diff --git a/src/Symfony/Component/Intl/Resources/data/transliterator/emoji/emoji-fr_ca.php b/src/Symfony/Component/Emoji/Resources/data/emoji-fr_ca.php
similarity index 100%
rename from src/Symfony/Component/Intl/Resources/data/transliterator/emoji/emoji-fr_ca.php
rename to src/Symfony/Component/Emoji/Resources/data/emoji-fr_ca.php
diff --git a/src/Symfony/Component/Intl/Resources/data/transliterator/emoji/emoji-ga.php b/src/Symfony/Component/Emoji/Resources/data/emoji-ga.php
similarity index 100%
rename from src/Symfony/Component/Intl/Resources/data/transliterator/emoji/emoji-ga.php
rename to src/Symfony/Component/Emoji/Resources/data/emoji-ga.php
diff --git a/src/Symfony/Component/Intl/Resources/data/transliterator/emoji/emoji-gd.php b/src/Symfony/Component/Emoji/Resources/data/emoji-gd.php
similarity index 100%
rename from src/Symfony/Component/Intl/Resources/data/transliterator/emoji/emoji-gd.php
rename to src/Symfony/Component/Emoji/Resources/data/emoji-gd.php
diff --git a/src/Symfony/Component/Intl/Resources/data/transliterator/emoji/emoji-github.php b/src/Symfony/Component/Emoji/Resources/data/emoji-github.php
similarity index 100%
rename from src/Symfony/Component/Intl/Resources/data/transliterator/emoji/emoji-github.php
rename to src/Symfony/Component/Emoji/Resources/data/emoji-github.php
diff --git a/src/Symfony/Component/Intl/Resources/data/transliterator/emoji/emoji-gl.php b/src/Symfony/Component/Emoji/Resources/data/emoji-gl.php
similarity index 100%
rename from src/Symfony/Component/Intl/Resources/data/transliterator/emoji/emoji-gl.php
rename to src/Symfony/Component/Emoji/Resources/data/emoji-gl.php
diff --git a/src/Symfony/Component/Intl/Resources/data/transliterator/emoji/emoji-gu.php b/src/Symfony/Component/Emoji/Resources/data/emoji-gu.php
similarity index 100%
rename from src/Symfony/Component/Intl/Resources/data/transliterator/emoji/emoji-gu.php
rename to src/Symfony/Component/Emoji/Resources/data/emoji-gu.php
diff --git a/src/Symfony/Component/Intl/Resources/data/transliterator/emoji/emoji-ha.php b/src/Symfony/Component/Emoji/Resources/data/emoji-ha.php
similarity index 100%
rename from src/Symfony/Component/Intl/Resources/data/transliterator/emoji/emoji-ha.php
rename to src/Symfony/Component/Emoji/Resources/data/emoji-ha.php
diff --git a/src/Symfony/Component/Intl/Resources/data/transliterator/emoji/emoji-ha_ne.php b/src/Symfony/Component/Emoji/Resources/data/emoji-ha_ne.php
similarity index 100%
rename from src/Symfony/Component/Intl/Resources/data/transliterator/emoji/emoji-ha_ne.php
rename to src/Symfony/Component/Emoji/Resources/data/emoji-ha_ne.php
diff --git a/src/Symfony/Component/Intl/Resources/data/transliterator/emoji/emoji-he.php b/src/Symfony/Component/Emoji/Resources/data/emoji-he.php
similarity index 100%
rename from src/Symfony/Component/Intl/Resources/data/transliterator/emoji/emoji-he.php
rename to src/Symfony/Component/Emoji/Resources/data/emoji-he.php
diff --git a/src/Symfony/Component/Intl/Resources/data/transliterator/emoji/emoji-hi.php b/src/Symfony/Component/Emoji/Resources/data/emoji-hi.php
similarity index 100%
rename from src/Symfony/Component/Intl/Resources/data/transliterator/emoji/emoji-hi.php
rename to src/Symfony/Component/Emoji/Resources/data/emoji-hi.php
diff --git a/src/Symfony/Component/Intl/Resources/data/transliterator/emoji/emoji-hi_latn.php b/src/Symfony/Component/Emoji/Resources/data/emoji-hi_latn.php
similarity index 100%
rename from src/Symfony/Component/Intl/Resources/data/transliterator/emoji/emoji-hi_latn.php
rename to src/Symfony/Component/Emoji/Resources/data/emoji-hi_latn.php
diff --git a/src/Symfony/Component/Intl/Resources/data/transliterator/emoji/emoji-hr.php b/src/Symfony/Component/Emoji/Resources/data/emoji-hr.php
similarity index 100%
rename from src/Symfony/Component/Intl/Resources/data/transliterator/emoji/emoji-hr.php
rename to src/Symfony/Component/Emoji/Resources/data/emoji-hr.php
diff --git a/src/Symfony/Component/Intl/Resources/data/transliterator/emoji/emoji-hsb.php b/src/Symfony/Component/Emoji/Resources/data/emoji-hsb.php
similarity index 100%
rename from src/Symfony/Component/Intl/Resources/data/transliterator/emoji/emoji-hsb.php
rename to src/Symfony/Component/Emoji/Resources/data/emoji-hsb.php
diff --git a/src/Symfony/Component/Intl/Resources/data/transliterator/emoji/emoji-hu.php b/src/Symfony/Component/Emoji/Resources/data/emoji-hu.php
similarity index 100%
rename from src/Symfony/Component/Intl/Resources/data/transliterator/emoji/emoji-hu.php
rename to src/Symfony/Component/Emoji/Resources/data/emoji-hu.php
diff --git a/src/Symfony/Component/Intl/Resources/data/transliterator/emoji/emoji-hy.php b/src/Symfony/Component/Emoji/Resources/data/emoji-hy.php
similarity index 100%
rename from src/Symfony/Component/Intl/Resources/data/transliterator/emoji/emoji-hy.php
rename to src/Symfony/Component/Emoji/Resources/data/emoji-hy.php
diff --git a/src/Symfony/Component/Intl/Resources/data/transliterator/emoji/emoji-ia.php b/src/Symfony/Component/Emoji/Resources/data/emoji-ia.php
similarity index 100%
rename from src/Symfony/Component/Intl/Resources/data/transliterator/emoji/emoji-ia.php
rename to src/Symfony/Component/Emoji/Resources/data/emoji-ia.php
diff --git a/src/Symfony/Component/Intl/Resources/data/transliterator/emoji/emoji-id.php b/src/Symfony/Component/Emoji/Resources/data/emoji-id.php
similarity index 100%
rename from src/Symfony/Component/Intl/Resources/data/transliterator/emoji/emoji-id.php
rename to src/Symfony/Component/Emoji/Resources/data/emoji-id.php
diff --git a/src/Symfony/Component/Intl/Resources/data/transliterator/emoji/emoji-ig.php b/src/Symfony/Component/Emoji/Resources/data/emoji-ig.php
similarity index 100%
rename from src/Symfony/Component/Intl/Resources/data/transliterator/emoji/emoji-ig.php
rename to src/Symfony/Component/Emoji/Resources/data/emoji-ig.php
diff --git a/src/Symfony/Component/Intl/Resources/data/transliterator/emoji/emoji-is.php b/src/Symfony/Component/Emoji/Resources/data/emoji-is.php
similarity index 100%
rename from src/Symfony/Component/Intl/Resources/data/transliterator/emoji/emoji-is.php
rename to src/Symfony/Component/Emoji/Resources/data/emoji-is.php
diff --git a/src/Symfony/Component/Intl/Resources/data/transliterator/emoji/emoji-it.php b/src/Symfony/Component/Emoji/Resources/data/emoji-it.php
similarity index 100%
rename from src/Symfony/Component/Intl/Resources/data/transliterator/emoji/emoji-it.php
rename to src/Symfony/Component/Emoji/Resources/data/emoji-it.php
diff --git a/src/Symfony/Component/Intl/Resources/data/transliterator/emoji/emoji-ja.php b/src/Symfony/Component/Emoji/Resources/data/emoji-ja.php
similarity index 100%
rename from src/Symfony/Component/Intl/Resources/data/transliterator/emoji/emoji-ja.php
rename to src/Symfony/Component/Emoji/Resources/data/emoji-ja.php
diff --git a/src/Symfony/Component/Intl/Resources/data/transliterator/emoji/emoji-jv.php b/src/Symfony/Component/Emoji/Resources/data/emoji-jv.php
similarity index 100%
rename from src/Symfony/Component/Intl/Resources/data/transliterator/emoji/emoji-jv.php
rename to src/Symfony/Component/Emoji/Resources/data/emoji-jv.php
diff --git a/src/Symfony/Component/Intl/Resources/data/transliterator/emoji/emoji-ka.php b/src/Symfony/Component/Emoji/Resources/data/emoji-ka.php
similarity index 100%
rename from src/Symfony/Component/Intl/Resources/data/transliterator/emoji/emoji-ka.php
rename to src/Symfony/Component/Emoji/Resources/data/emoji-ka.php
diff --git a/src/Symfony/Component/Intl/Resources/data/transliterator/emoji/emoji-kab.php b/src/Symfony/Component/Emoji/Resources/data/emoji-kab.php
similarity index 100%
rename from src/Symfony/Component/Intl/Resources/data/transliterator/emoji/emoji-kab.php
rename to src/Symfony/Component/Emoji/Resources/data/emoji-kab.php
diff --git a/src/Symfony/Component/Intl/Resources/data/transliterator/emoji/emoji-kk.php b/src/Symfony/Component/Emoji/Resources/data/emoji-kk.php
similarity index 100%
rename from src/Symfony/Component/Intl/Resources/data/transliterator/emoji/emoji-kk.php
rename to src/Symfony/Component/Emoji/Resources/data/emoji-kk.php
diff --git a/src/Symfony/Component/Intl/Resources/data/transliterator/emoji/emoji-kl.php b/src/Symfony/Component/Emoji/Resources/data/emoji-kl.php
similarity index 100%
rename from src/Symfony/Component/Intl/Resources/data/transliterator/emoji/emoji-kl.php
rename to src/Symfony/Component/Emoji/Resources/data/emoji-kl.php
diff --git a/src/Symfony/Component/Intl/Resources/data/transliterator/emoji/emoji-km.php b/src/Symfony/Component/Emoji/Resources/data/emoji-km.php
similarity index 100%
rename from src/Symfony/Component/Intl/Resources/data/transliterator/emoji/emoji-km.php
rename to src/Symfony/Component/Emoji/Resources/data/emoji-km.php
diff --git a/src/Symfony/Component/Intl/Resources/data/transliterator/emoji/emoji-kn.php b/src/Symfony/Component/Emoji/Resources/data/emoji-kn.php
similarity index 100%
rename from src/Symfony/Component/Intl/Resources/data/transliterator/emoji/emoji-kn.php
rename to src/Symfony/Component/Emoji/Resources/data/emoji-kn.php
diff --git a/src/Symfony/Component/Intl/Resources/data/transliterator/emoji/emoji-ko.php b/src/Symfony/Component/Emoji/Resources/data/emoji-ko.php
similarity index 100%
rename from src/Symfony/Component/Intl/Resources/data/transliterator/emoji/emoji-ko.php
rename to src/Symfony/Component/Emoji/Resources/data/emoji-ko.php
diff --git a/src/Symfony/Component/Intl/Resources/data/transliterator/emoji/emoji-kok.php b/src/Symfony/Component/Emoji/Resources/data/emoji-kok.php
similarity index 100%
rename from src/Symfony/Component/Intl/Resources/data/transliterator/emoji/emoji-kok.php
rename to src/Symfony/Component/Emoji/Resources/data/emoji-kok.php
diff --git a/src/Symfony/Component/Intl/Resources/data/transliterator/emoji/emoji-ku.php b/src/Symfony/Component/Emoji/Resources/data/emoji-ku.php
similarity index 100%
rename from src/Symfony/Component/Intl/Resources/data/transliterator/emoji/emoji-ku.php
rename to src/Symfony/Component/Emoji/Resources/data/emoji-ku.php
diff --git a/src/Symfony/Component/Intl/Resources/data/transliterator/emoji/emoji-ky.php b/src/Symfony/Component/Emoji/Resources/data/emoji-ky.php
similarity index 100%
rename from src/Symfony/Component/Intl/Resources/data/transliterator/emoji/emoji-ky.php
rename to src/Symfony/Component/Emoji/Resources/data/emoji-ky.php
diff --git a/src/Symfony/Component/Intl/Resources/data/transliterator/emoji/emoji-lb.php b/src/Symfony/Component/Emoji/Resources/data/emoji-lb.php
similarity index 100%
rename from src/Symfony/Component/Intl/Resources/data/transliterator/emoji/emoji-lb.php
rename to src/Symfony/Component/Emoji/Resources/data/emoji-lb.php
diff --git a/src/Symfony/Component/Intl/Resources/data/transliterator/emoji/emoji-lij.php b/src/Symfony/Component/Emoji/Resources/data/emoji-lij.php
similarity index 100%
rename from src/Symfony/Component/Intl/Resources/data/transliterator/emoji/emoji-lij.php
rename to src/Symfony/Component/Emoji/Resources/data/emoji-lij.php
diff --git a/src/Symfony/Component/Intl/Resources/data/transliterator/emoji/emoji-lo.php b/src/Symfony/Component/Emoji/Resources/data/emoji-lo.php
similarity index 100%
rename from src/Symfony/Component/Intl/Resources/data/transliterator/emoji/emoji-lo.php
rename to src/Symfony/Component/Emoji/Resources/data/emoji-lo.php
diff --git a/src/Symfony/Component/Intl/Resources/data/transliterator/emoji/emoji-lt.php b/src/Symfony/Component/Emoji/Resources/data/emoji-lt.php
similarity index 100%
rename from src/Symfony/Component/Intl/Resources/data/transliterator/emoji/emoji-lt.php
rename to src/Symfony/Component/Emoji/Resources/data/emoji-lt.php
diff --git a/src/Symfony/Component/Intl/Resources/data/transliterator/emoji/emoji-lv.php b/src/Symfony/Component/Emoji/Resources/data/emoji-lv.php
similarity index 100%
rename from src/Symfony/Component/Intl/Resources/data/transliterator/emoji/emoji-lv.php
rename to src/Symfony/Component/Emoji/Resources/data/emoji-lv.php
diff --git a/src/Symfony/Component/Intl/Resources/data/transliterator/emoji/emoji-mi.php b/src/Symfony/Component/Emoji/Resources/data/emoji-mi.php
similarity index 100%
rename from src/Symfony/Component/Intl/Resources/data/transliterator/emoji/emoji-mi.php
rename to src/Symfony/Component/Emoji/Resources/data/emoji-mi.php
diff --git a/src/Symfony/Component/Intl/Resources/data/transliterator/emoji/emoji-mk.php b/src/Symfony/Component/Emoji/Resources/data/emoji-mk.php
similarity index 100%
rename from src/Symfony/Component/Intl/Resources/data/transliterator/emoji/emoji-mk.php
rename to src/Symfony/Component/Emoji/Resources/data/emoji-mk.php
diff --git a/src/Symfony/Component/Intl/Resources/data/transliterator/emoji/emoji-ml.php b/src/Symfony/Component/Emoji/Resources/data/emoji-ml.php
similarity index 100%
rename from src/Symfony/Component/Intl/Resources/data/transliterator/emoji/emoji-ml.php
rename to src/Symfony/Component/Emoji/Resources/data/emoji-ml.php
diff --git a/src/Symfony/Component/Intl/Resources/data/transliterator/emoji/emoji-mn.php b/src/Symfony/Component/Emoji/Resources/data/emoji-mn.php
similarity index 100%
rename from src/Symfony/Component/Intl/Resources/data/transliterator/emoji/emoji-mn.php
rename to src/Symfony/Component/Emoji/Resources/data/emoji-mn.php
diff --git a/src/Symfony/Component/Intl/Resources/data/transliterator/emoji/emoji-mni.php b/src/Symfony/Component/Emoji/Resources/data/emoji-mni.php
similarity index 100%
rename from src/Symfony/Component/Intl/Resources/data/transliterator/emoji/emoji-mni.php
rename to src/Symfony/Component/Emoji/Resources/data/emoji-mni.php
diff --git a/src/Symfony/Component/Intl/Resources/data/transliterator/emoji/emoji-mr.php b/src/Symfony/Component/Emoji/Resources/data/emoji-mr.php
similarity index 100%
rename from src/Symfony/Component/Intl/Resources/data/transliterator/emoji/emoji-mr.php
rename to src/Symfony/Component/Emoji/Resources/data/emoji-mr.php
diff --git a/src/Symfony/Component/Intl/Resources/data/transliterator/emoji/emoji-ms.php b/src/Symfony/Component/Emoji/Resources/data/emoji-ms.php
similarity index 100%
rename from src/Symfony/Component/Intl/Resources/data/transliterator/emoji/emoji-ms.php
rename to src/Symfony/Component/Emoji/Resources/data/emoji-ms.php
diff --git a/src/Symfony/Component/Intl/Resources/data/transliterator/emoji/emoji-mt.php b/src/Symfony/Component/Emoji/Resources/data/emoji-mt.php
similarity index 100%
rename from src/Symfony/Component/Intl/Resources/data/transliterator/emoji/emoji-mt.php
rename to src/Symfony/Component/Emoji/Resources/data/emoji-mt.php
diff --git a/src/Symfony/Component/Intl/Resources/data/transliterator/emoji/emoji-my.php b/src/Symfony/Component/Emoji/Resources/data/emoji-my.php
similarity index 100%
rename from src/Symfony/Component/Intl/Resources/data/transliterator/emoji/emoji-my.php
rename to src/Symfony/Component/Emoji/Resources/data/emoji-my.php
diff --git a/src/Symfony/Component/Intl/Resources/data/transliterator/emoji/emoji-ne.php b/src/Symfony/Component/Emoji/Resources/data/emoji-ne.php
similarity index 100%
rename from src/Symfony/Component/Intl/Resources/data/transliterator/emoji/emoji-ne.php
rename to src/Symfony/Component/Emoji/Resources/data/emoji-ne.php
diff --git a/src/Symfony/Component/Intl/Resources/data/transliterator/emoji/emoji-nl.php b/src/Symfony/Component/Emoji/Resources/data/emoji-nl.php
similarity index 100%
rename from src/Symfony/Component/Intl/Resources/data/transliterator/emoji/emoji-nl.php
rename to src/Symfony/Component/Emoji/Resources/data/emoji-nl.php
diff --git a/src/Symfony/Component/Intl/Resources/data/transliterator/emoji/emoji-nn.php b/src/Symfony/Component/Emoji/Resources/data/emoji-nn.php
similarity index 100%
rename from src/Symfony/Component/Intl/Resources/data/transliterator/emoji/emoji-nn.php
rename to src/Symfony/Component/Emoji/Resources/data/emoji-nn.php
diff --git a/src/Symfony/Component/Intl/Resources/data/transliterator/emoji/emoji-no.php b/src/Symfony/Component/Emoji/Resources/data/emoji-no.php
similarity index 100%
rename from src/Symfony/Component/Intl/Resources/data/transliterator/emoji/emoji-no.php
rename to src/Symfony/Component/Emoji/Resources/data/emoji-no.php
diff --git a/src/Symfony/Component/Intl/Resources/data/transliterator/emoji/emoji-nso.php b/src/Symfony/Component/Emoji/Resources/data/emoji-nso.php
similarity index 100%
rename from src/Symfony/Component/Intl/Resources/data/transliterator/emoji/emoji-nso.php
rename to src/Symfony/Component/Emoji/Resources/data/emoji-nso.php
diff --git a/src/Symfony/Component/Intl/Resources/data/transliterator/emoji/emoji-oc.php b/src/Symfony/Component/Emoji/Resources/data/emoji-oc.php
similarity index 100%
rename from src/Symfony/Component/Intl/Resources/data/transliterator/emoji/emoji-oc.php
rename to src/Symfony/Component/Emoji/Resources/data/emoji-oc.php
diff --git a/src/Symfony/Component/Intl/Resources/data/transliterator/emoji/emoji-or.php b/src/Symfony/Component/Emoji/Resources/data/emoji-or.php
similarity index 100%
rename from src/Symfony/Component/Intl/Resources/data/transliterator/emoji/emoji-or.php
rename to src/Symfony/Component/Emoji/Resources/data/emoji-or.php
diff --git a/src/Symfony/Component/Intl/Resources/data/transliterator/emoji/emoji-pa.php b/src/Symfony/Component/Emoji/Resources/data/emoji-pa.php
similarity index 100%
rename from src/Symfony/Component/Intl/Resources/data/transliterator/emoji/emoji-pa.php
rename to src/Symfony/Component/Emoji/Resources/data/emoji-pa.php
diff --git a/src/Symfony/Component/Intl/Resources/data/transliterator/emoji/emoji-pa_arab.php b/src/Symfony/Component/Emoji/Resources/data/emoji-pa_arab.php
similarity index 100%
rename from src/Symfony/Component/Intl/Resources/data/transliterator/emoji/emoji-pa_arab.php
rename to src/Symfony/Component/Emoji/Resources/data/emoji-pa_arab.php
diff --git a/src/Symfony/Component/Intl/Resources/data/transliterator/emoji/emoji-pcm.php b/src/Symfony/Component/Emoji/Resources/data/emoji-pcm.php
similarity index 100%
rename from src/Symfony/Component/Intl/Resources/data/transliterator/emoji/emoji-pcm.php
rename to src/Symfony/Component/Emoji/Resources/data/emoji-pcm.php
diff --git a/src/Symfony/Component/Intl/Resources/data/transliterator/emoji/emoji-pl.php b/src/Symfony/Component/Emoji/Resources/data/emoji-pl.php
similarity index 100%
rename from src/Symfony/Component/Intl/Resources/data/transliterator/emoji/emoji-pl.php
rename to src/Symfony/Component/Emoji/Resources/data/emoji-pl.php
diff --git a/src/Symfony/Component/Intl/Resources/data/transliterator/emoji/emoji-ps.php b/src/Symfony/Component/Emoji/Resources/data/emoji-ps.php
similarity index 100%
rename from src/Symfony/Component/Intl/Resources/data/transliterator/emoji/emoji-ps.php
rename to src/Symfony/Component/Emoji/Resources/data/emoji-ps.php
diff --git a/src/Symfony/Component/Intl/Resources/data/transliterator/emoji/emoji-pt.php b/src/Symfony/Component/Emoji/Resources/data/emoji-pt.php
similarity index 100%
rename from src/Symfony/Component/Intl/Resources/data/transliterator/emoji/emoji-pt.php
rename to src/Symfony/Component/Emoji/Resources/data/emoji-pt.php
diff --git a/src/Symfony/Component/Intl/Resources/data/transliterator/emoji/emoji-pt_pt.php b/src/Symfony/Component/Emoji/Resources/data/emoji-pt_pt.php
similarity index 100%
rename from src/Symfony/Component/Intl/Resources/data/transliterator/emoji/emoji-pt_pt.php
rename to src/Symfony/Component/Emoji/Resources/data/emoji-pt_pt.php
diff --git a/src/Symfony/Component/Intl/Resources/data/transliterator/emoji/emoji-qu.php b/src/Symfony/Component/Emoji/Resources/data/emoji-qu.php
similarity index 100%
rename from src/Symfony/Component/Intl/Resources/data/transliterator/emoji/emoji-qu.php
rename to src/Symfony/Component/Emoji/Resources/data/emoji-qu.php
diff --git a/src/Symfony/Component/Intl/Resources/data/transliterator/emoji/emoji-quc.php b/src/Symfony/Component/Emoji/Resources/data/emoji-quc.php
similarity index 100%
rename from src/Symfony/Component/Intl/Resources/data/transliterator/emoji/emoji-quc.php
rename to src/Symfony/Component/Emoji/Resources/data/emoji-quc.php
diff --git a/src/Symfony/Component/Intl/Resources/data/transliterator/emoji/emoji-rhg.php b/src/Symfony/Component/Emoji/Resources/data/emoji-rhg.php
similarity index 100%
rename from src/Symfony/Component/Intl/Resources/data/transliterator/emoji/emoji-rhg.php
rename to src/Symfony/Component/Emoji/Resources/data/emoji-rhg.php
diff --git a/src/Symfony/Component/Intl/Resources/data/transliterator/emoji/emoji-rm.php b/src/Symfony/Component/Emoji/Resources/data/emoji-rm.php
similarity index 100%
rename from src/Symfony/Component/Intl/Resources/data/transliterator/emoji/emoji-rm.php
rename to src/Symfony/Component/Emoji/Resources/data/emoji-rm.php
diff --git a/src/Symfony/Component/Intl/Resources/data/transliterator/emoji/emoji-ro.php b/src/Symfony/Component/Emoji/Resources/data/emoji-ro.php
similarity index 100%
rename from src/Symfony/Component/Intl/Resources/data/transliterator/emoji/emoji-ro.php
rename to src/Symfony/Component/Emoji/Resources/data/emoji-ro.php
diff --git a/src/Symfony/Component/Intl/Resources/data/transliterator/emoji/emoji-root.php b/src/Symfony/Component/Emoji/Resources/data/emoji-root.php
similarity index 100%
rename from src/Symfony/Component/Intl/Resources/data/transliterator/emoji/emoji-root.php
rename to src/Symfony/Component/Emoji/Resources/data/emoji-root.php
diff --git a/src/Symfony/Component/Intl/Resources/data/transliterator/emoji/emoji-ru.php b/src/Symfony/Component/Emoji/Resources/data/emoji-ru.php
similarity index 100%
rename from src/Symfony/Component/Intl/Resources/data/transliterator/emoji/emoji-ru.php
rename to src/Symfony/Component/Emoji/Resources/data/emoji-ru.php
diff --git a/src/Symfony/Component/Intl/Resources/data/transliterator/emoji/emoji-rw.php b/src/Symfony/Component/Emoji/Resources/data/emoji-rw.php
similarity index 100%
rename from src/Symfony/Component/Intl/Resources/data/transliterator/emoji/emoji-rw.php
rename to src/Symfony/Component/Emoji/Resources/data/emoji-rw.php
diff --git a/src/Symfony/Component/Intl/Resources/data/transliterator/emoji/emoji-sat.php b/src/Symfony/Component/Emoji/Resources/data/emoji-sat.php
similarity index 100%
rename from src/Symfony/Component/Intl/Resources/data/transliterator/emoji/emoji-sat.php
rename to src/Symfony/Component/Emoji/Resources/data/emoji-sat.php
diff --git a/src/Symfony/Component/Intl/Resources/data/transliterator/emoji/emoji-sc.php b/src/Symfony/Component/Emoji/Resources/data/emoji-sc.php
similarity index 100%
rename from src/Symfony/Component/Intl/Resources/data/transliterator/emoji/emoji-sc.php
rename to src/Symfony/Component/Emoji/Resources/data/emoji-sc.php
diff --git a/src/Symfony/Component/Intl/Resources/data/transliterator/emoji/emoji-sd.php b/src/Symfony/Component/Emoji/Resources/data/emoji-sd.php
similarity index 100%
rename from src/Symfony/Component/Intl/Resources/data/transliterator/emoji/emoji-sd.php
rename to src/Symfony/Component/Emoji/Resources/data/emoji-sd.php
diff --git a/src/Symfony/Component/Intl/Resources/data/transliterator/emoji/emoji-si.php b/src/Symfony/Component/Emoji/Resources/data/emoji-si.php
similarity index 100%
rename from src/Symfony/Component/Intl/Resources/data/transliterator/emoji/emoji-si.php
rename to src/Symfony/Component/Emoji/Resources/data/emoji-si.php
diff --git a/src/Symfony/Component/Intl/Resources/data/transliterator/emoji/emoji-sk.php b/src/Symfony/Component/Emoji/Resources/data/emoji-sk.php
similarity index 100%
rename from src/Symfony/Component/Intl/Resources/data/transliterator/emoji/emoji-sk.php
rename to src/Symfony/Component/Emoji/Resources/data/emoji-sk.php
diff --git a/src/Symfony/Component/Intl/Resources/data/transliterator/emoji/emoji-sl.php b/src/Symfony/Component/Emoji/Resources/data/emoji-sl.php
similarity index 100%
rename from src/Symfony/Component/Intl/Resources/data/transliterator/emoji/emoji-sl.php
rename to src/Symfony/Component/Emoji/Resources/data/emoji-sl.php
diff --git a/src/Symfony/Component/Intl/Resources/data/transliterator/emoji/emoji-slack.php b/src/Symfony/Component/Emoji/Resources/data/emoji-slack.php
similarity index 100%
rename from src/Symfony/Component/Intl/Resources/data/transliterator/emoji/emoji-slack.php
rename to src/Symfony/Component/Emoji/Resources/data/emoji-slack.php
diff --git a/src/Symfony/Component/Intl/Resources/data/transliterator/emoji/emoji-so.php b/src/Symfony/Component/Emoji/Resources/data/emoji-so.php
similarity index 100%
rename from src/Symfony/Component/Intl/Resources/data/transliterator/emoji/emoji-so.php
rename to src/Symfony/Component/Emoji/Resources/data/emoji-so.php
diff --git a/src/Symfony/Component/Intl/Resources/data/transliterator/emoji/emoji-sq.php b/src/Symfony/Component/Emoji/Resources/data/emoji-sq.php
similarity index 100%
rename from src/Symfony/Component/Intl/Resources/data/transliterator/emoji/emoji-sq.php
rename to src/Symfony/Component/Emoji/Resources/data/emoji-sq.php
diff --git a/src/Symfony/Component/Intl/Resources/data/transliterator/emoji/emoji-sr.php b/src/Symfony/Component/Emoji/Resources/data/emoji-sr.php
similarity index 100%
rename from src/Symfony/Component/Intl/Resources/data/transliterator/emoji/emoji-sr.php
rename to src/Symfony/Component/Emoji/Resources/data/emoji-sr.php
diff --git a/src/Symfony/Component/Intl/Resources/data/transliterator/emoji/emoji-sr_cyrl.php b/src/Symfony/Component/Emoji/Resources/data/emoji-sr_cyrl.php
similarity index 100%
rename from src/Symfony/Component/Intl/Resources/data/transliterator/emoji/emoji-sr_cyrl.php
rename to src/Symfony/Component/Emoji/Resources/data/emoji-sr_cyrl.php
diff --git a/src/Symfony/Component/Intl/Resources/data/transliterator/emoji/emoji-sr_cyrl_ba.php b/src/Symfony/Component/Emoji/Resources/data/emoji-sr_cyrl_ba.php
similarity index 100%
rename from src/Symfony/Component/Intl/Resources/data/transliterator/emoji/emoji-sr_cyrl_ba.php
rename to src/Symfony/Component/Emoji/Resources/data/emoji-sr_cyrl_ba.php
diff --git a/src/Symfony/Component/Intl/Resources/data/transliterator/emoji/emoji-sr_latn.php b/src/Symfony/Component/Emoji/Resources/data/emoji-sr_latn.php
similarity index 100%
rename from src/Symfony/Component/Intl/Resources/data/transliterator/emoji/emoji-sr_latn.php
rename to src/Symfony/Component/Emoji/Resources/data/emoji-sr_latn.php
diff --git a/src/Symfony/Component/Intl/Resources/data/transliterator/emoji/emoji-sr_latn_ba.php b/src/Symfony/Component/Emoji/Resources/data/emoji-sr_latn_ba.php
similarity index 100%
rename from src/Symfony/Component/Intl/Resources/data/transliterator/emoji/emoji-sr_latn_ba.php
rename to src/Symfony/Component/Emoji/Resources/data/emoji-sr_latn_ba.php
diff --git a/src/Symfony/Component/Intl/Resources/data/transliterator/emoji/emoji-strip.php b/src/Symfony/Component/Emoji/Resources/data/emoji-strip.php
similarity index 100%
rename from src/Symfony/Component/Intl/Resources/data/transliterator/emoji/emoji-strip.php
rename to src/Symfony/Component/Emoji/Resources/data/emoji-strip.php
diff --git a/src/Symfony/Component/Intl/Resources/data/transliterator/emoji/emoji-sv.php b/src/Symfony/Component/Emoji/Resources/data/emoji-sv.php
similarity index 100%
rename from src/Symfony/Component/Intl/Resources/data/transliterator/emoji/emoji-sv.php
rename to src/Symfony/Component/Emoji/Resources/data/emoji-sv.php
diff --git a/src/Symfony/Component/Intl/Resources/data/transliterator/emoji/emoji-sw.php b/src/Symfony/Component/Emoji/Resources/data/emoji-sw.php
similarity index 100%
rename from src/Symfony/Component/Intl/Resources/data/transliterator/emoji/emoji-sw.php
rename to src/Symfony/Component/Emoji/Resources/data/emoji-sw.php
diff --git a/src/Symfony/Component/Intl/Resources/data/transliterator/emoji/emoji-sw_ke.php b/src/Symfony/Component/Emoji/Resources/data/emoji-sw_ke.php
similarity index 100%
rename from src/Symfony/Component/Intl/Resources/data/transliterator/emoji/emoji-sw_ke.php
rename to src/Symfony/Component/Emoji/Resources/data/emoji-sw_ke.php
diff --git a/src/Symfony/Component/Intl/Resources/data/transliterator/emoji/emoji-ta.php b/src/Symfony/Component/Emoji/Resources/data/emoji-ta.php
similarity index 100%
rename from src/Symfony/Component/Intl/Resources/data/transliterator/emoji/emoji-ta.php
rename to src/Symfony/Component/Emoji/Resources/data/emoji-ta.php
diff --git a/src/Symfony/Component/Intl/Resources/data/transliterator/emoji/emoji-te.php b/src/Symfony/Component/Emoji/Resources/data/emoji-te.php
similarity index 100%
rename from src/Symfony/Component/Intl/Resources/data/transliterator/emoji/emoji-te.php
rename to src/Symfony/Component/Emoji/Resources/data/emoji-te.php
diff --git a/src/Symfony/Component/Intl/Resources/data/transliterator/emoji/emoji-tg.php b/src/Symfony/Component/Emoji/Resources/data/emoji-tg.php
similarity index 100%
rename from src/Symfony/Component/Intl/Resources/data/transliterator/emoji/emoji-tg.php
rename to src/Symfony/Component/Emoji/Resources/data/emoji-tg.php
diff --git a/src/Symfony/Component/Intl/Resources/data/transliterator/emoji/emoji-th.php b/src/Symfony/Component/Emoji/Resources/data/emoji-th.php
similarity index 100%
rename from src/Symfony/Component/Intl/Resources/data/transliterator/emoji/emoji-th.php
rename to src/Symfony/Component/Emoji/Resources/data/emoji-th.php
diff --git a/src/Symfony/Component/Intl/Resources/data/transliterator/emoji/emoji-ti.php b/src/Symfony/Component/Emoji/Resources/data/emoji-ti.php
similarity index 100%
rename from src/Symfony/Component/Intl/Resources/data/transliterator/emoji/emoji-ti.php
rename to src/Symfony/Component/Emoji/Resources/data/emoji-ti.php
diff --git a/src/Symfony/Component/Intl/Resources/data/transliterator/emoji/emoji-tk.php b/src/Symfony/Component/Emoji/Resources/data/emoji-tk.php
similarity index 100%
rename from src/Symfony/Component/Intl/Resources/data/transliterator/emoji/emoji-tk.php
rename to src/Symfony/Component/Emoji/Resources/data/emoji-tk.php
diff --git a/src/Symfony/Component/Intl/Resources/data/transliterator/emoji/emoji-tn.php b/src/Symfony/Component/Emoji/Resources/data/emoji-tn.php
similarity index 100%
rename from src/Symfony/Component/Intl/Resources/data/transliterator/emoji/emoji-tn.php
rename to src/Symfony/Component/Emoji/Resources/data/emoji-tn.php
diff --git a/src/Symfony/Component/Intl/Resources/data/transliterator/emoji/emoji-to.php b/src/Symfony/Component/Emoji/Resources/data/emoji-to.php
similarity index 100%
rename from src/Symfony/Component/Intl/Resources/data/transliterator/emoji/emoji-to.php
rename to src/Symfony/Component/Emoji/Resources/data/emoji-to.php
diff --git a/src/Symfony/Component/Intl/Resources/data/transliterator/emoji/emoji-tr.php b/src/Symfony/Component/Emoji/Resources/data/emoji-tr.php
similarity index 100%
rename from src/Symfony/Component/Intl/Resources/data/transliterator/emoji/emoji-tr.php
rename to src/Symfony/Component/Emoji/Resources/data/emoji-tr.php
diff --git a/src/Symfony/Component/Intl/Resources/data/transliterator/emoji/emoji-ug.php b/src/Symfony/Component/Emoji/Resources/data/emoji-ug.php
similarity index 100%
rename from src/Symfony/Component/Intl/Resources/data/transliterator/emoji/emoji-ug.php
rename to src/Symfony/Component/Emoji/Resources/data/emoji-ug.php
diff --git a/src/Symfony/Component/Intl/Resources/data/transliterator/emoji/emoji-uk.php b/src/Symfony/Component/Emoji/Resources/data/emoji-uk.php
similarity index 100%
rename from src/Symfony/Component/Intl/Resources/data/transliterator/emoji/emoji-uk.php
rename to src/Symfony/Component/Emoji/Resources/data/emoji-uk.php
diff --git a/src/Symfony/Component/Intl/Resources/data/transliterator/emoji/emoji-ur.php b/src/Symfony/Component/Emoji/Resources/data/emoji-ur.php
similarity index 100%
rename from src/Symfony/Component/Intl/Resources/data/transliterator/emoji/emoji-ur.php
rename to src/Symfony/Component/Emoji/Resources/data/emoji-ur.php
diff --git a/src/Symfony/Component/Intl/Resources/data/transliterator/emoji/emoji-uz.php b/src/Symfony/Component/Emoji/Resources/data/emoji-uz.php
similarity index 100%
rename from src/Symfony/Component/Intl/Resources/data/transliterator/emoji/emoji-uz.php
rename to src/Symfony/Component/Emoji/Resources/data/emoji-uz.php
diff --git a/src/Symfony/Component/Intl/Resources/data/transliterator/emoji/emoji-vi.php b/src/Symfony/Component/Emoji/Resources/data/emoji-vi.php
similarity index 100%
rename from src/Symfony/Component/Intl/Resources/data/transliterator/emoji/emoji-vi.php
rename to src/Symfony/Component/Emoji/Resources/data/emoji-vi.php
diff --git a/src/Symfony/Component/Intl/Resources/data/transliterator/emoji/emoji-wo.php b/src/Symfony/Component/Emoji/Resources/data/emoji-wo.php
similarity index 100%
rename from src/Symfony/Component/Intl/Resources/data/transliterator/emoji/emoji-wo.php
rename to src/Symfony/Component/Emoji/Resources/data/emoji-wo.php
diff --git a/src/Symfony/Component/Intl/Resources/data/transliterator/emoji/emoji-xh.php b/src/Symfony/Component/Emoji/Resources/data/emoji-xh.php
similarity index 100%
rename from src/Symfony/Component/Intl/Resources/data/transliterator/emoji/emoji-xh.php
rename to src/Symfony/Component/Emoji/Resources/data/emoji-xh.php
diff --git a/src/Symfony/Component/Intl/Resources/data/transliterator/emoji/emoji-yo.php b/src/Symfony/Component/Emoji/Resources/data/emoji-yo.php
similarity index 100%
rename from src/Symfony/Component/Intl/Resources/data/transliterator/emoji/emoji-yo.php
rename to src/Symfony/Component/Emoji/Resources/data/emoji-yo.php
diff --git a/src/Symfony/Component/Intl/Resources/data/transliterator/emoji/emoji-yo_bj.php b/src/Symfony/Component/Emoji/Resources/data/emoji-yo_bj.php
similarity index 100%
rename from src/Symfony/Component/Intl/Resources/data/transliterator/emoji/emoji-yo_bj.php
rename to src/Symfony/Component/Emoji/Resources/data/emoji-yo_bj.php
diff --git a/src/Symfony/Component/Intl/Resources/data/transliterator/emoji/emoji-yue.php b/src/Symfony/Component/Emoji/Resources/data/emoji-yue.php
similarity index 100%
rename from src/Symfony/Component/Intl/Resources/data/transliterator/emoji/emoji-yue.php
rename to src/Symfony/Component/Emoji/Resources/data/emoji-yue.php
diff --git a/src/Symfony/Component/Intl/Resources/data/transliterator/emoji/emoji-yue_hans.php b/src/Symfony/Component/Emoji/Resources/data/emoji-yue_hans.php
similarity index 100%
rename from src/Symfony/Component/Intl/Resources/data/transliterator/emoji/emoji-yue_hans.php
rename to src/Symfony/Component/Emoji/Resources/data/emoji-yue_hans.php
diff --git a/src/Symfony/Component/Intl/Resources/data/transliterator/emoji/emoji-zh.php b/src/Symfony/Component/Emoji/Resources/data/emoji-zh.php
similarity index 100%
rename from src/Symfony/Component/Intl/Resources/data/transliterator/emoji/emoji-zh.php
rename to src/Symfony/Component/Emoji/Resources/data/emoji-zh.php
diff --git a/src/Symfony/Component/Intl/Resources/data/transliterator/emoji/emoji-zh_hant.php b/src/Symfony/Component/Emoji/Resources/data/emoji-zh_hant.php
similarity index 100%
rename from src/Symfony/Component/Intl/Resources/data/transliterator/emoji/emoji-zh_hant.php
rename to src/Symfony/Component/Emoji/Resources/data/emoji-zh_hant.php
diff --git a/src/Symfony/Component/Intl/Resources/data/transliterator/emoji/emoji-zh_hant_hk.php b/src/Symfony/Component/Emoji/Resources/data/emoji-zh_hant_hk.php
similarity index 100%
rename from src/Symfony/Component/Intl/Resources/data/transliterator/emoji/emoji-zh_hant_hk.php
rename to src/Symfony/Component/Emoji/Resources/data/emoji-zh_hant_hk.php
diff --git a/src/Symfony/Component/Intl/Resources/data/transliterator/emoji/emoji-zu.php b/src/Symfony/Component/Emoji/Resources/data/emoji-zu.php
similarity index 100%
rename from src/Symfony/Component/Intl/Resources/data/transliterator/emoji/emoji-zu.php
rename to src/Symfony/Component/Emoji/Resources/data/emoji-zu.php
diff --git a/src/Symfony/Component/Intl/Resources/data/transliterator/emoji/github-emoji.php b/src/Symfony/Component/Emoji/Resources/data/github-emoji.php
similarity index 100%
rename from src/Symfony/Component/Intl/Resources/data/transliterator/emoji/github-emoji.php
rename to src/Symfony/Component/Emoji/Resources/data/github-emoji.php
diff --git a/src/Symfony/Component/Intl/Resources/data/transliterator/emoji/slack-emoji.php b/src/Symfony/Component/Emoji/Resources/data/slack-emoji.php
similarity index 100%
rename from src/Symfony/Component/Intl/Resources/data/transliterator/emoji/slack-emoji.php
rename to src/Symfony/Component/Emoji/Resources/data/slack-emoji.php
diff --git a/src/Symfony/Component/Intl/Tests/Transliterator/EmojiTransliteratorTest.php b/src/Symfony/Component/Emoji/Tests/EmojiTransliteratorTest.php
similarity index 96%
rename from src/Symfony/Component/Intl/Tests/Transliterator/EmojiTransliteratorTest.php
rename to src/Symfony/Component/Emoji/Tests/EmojiTransliteratorTest.php
index ccc379b09ac2d..12a3682b16769 100644
--- a/src/Symfony/Component/Intl/Tests/Transliterator/EmojiTransliteratorTest.php
+++ b/src/Symfony/Component/Emoji/Tests/EmojiTransliteratorTest.php
@@ -9,11 +9,11 @@
* file that was distributed with this source code.
*/
-namespace Symfony\Component\Intl\Tests\Transliterator;
+namespace Symfony\Component\Emoji\Tests;
use PHPUnit\Framework\TestCase;
+use Symfony\Component\Emoji\EmojiTransliterator;
use Symfony\Component\Finder\Finder;
-use Symfony\Component\Intl\Transliterator\EmojiTransliterator;
/**
* @requires extension intl
@@ -95,7 +95,7 @@ public function testAllTransliterator(string $locale)
public static function provideLocaleTest(): iterable
{
$file = (new Finder())
- ->in(__DIR__.'/../../Resources/data/transliterator/emoji')
+ ->in(__DIR__.'/../Resources/data')
->name('*.php')
->notName('emoji-strip.php')
->files()
diff --git a/src/Symfony/Component/Emoji/Util/GzipStreamWrapper.php b/src/Symfony/Component/Emoji/Util/GzipStreamWrapper.php
new file mode 100644
index 0000000000000..1ae158dd9cc38
--- /dev/null
+++ b/src/Symfony/Component/Emoji/Util/GzipStreamWrapper.php
@@ -0,0 +1,83 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Emoji\Util;
+
+/**
+ * @internal
+ */
+class GzipStreamWrapper
+{
+ /** @var resource|null */
+ public $context;
+
+ /** @var resource */
+ private $handle;
+ private string $path;
+
+ public static function require(string $path): array
+ {
+ if (!\extension_loaded('zlib')) {
+ throw new \LogicException(sprintf('The "zlib" extension is required to load the "%s/%s" map, please enable it in your php.ini file.', basename(\dirname($path)), basename($path)));
+ }
+
+ if (!\function_exists('opcache_is_script_cached') || !@opcache_is_script_cached($path)) {
+ stream_wrapper_unregister('file');
+ stream_wrapper_register('file', self::class);
+ }
+
+ return require $path;
+ }
+
+ public function stream_open(string $path, string $mode): bool
+ {
+ stream_wrapper_restore('file');
+ $this->path = $path;
+
+ return false !== $this->handle = fopen('compress.zlib://'.$path, $mode);
+ }
+
+ public function stream_read(int $count): string|false
+ {
+ return fread($this->handle, $count);
+ }
+
+ public function stream_eof(): bool
+ {
+ return feof($this->handle);
+ }
+
+ public function stream_set_option(int $option, int $arg1, int $arg2): bool
+ {
+ return match ($option) {
+ \STREAM_OPTION_BLOCKING => stream_set_blocking($this->handle, $arg1),
+ \STREAM_OPTION_READ_TIMEOUT => stream_set_timeout($this->handle, $arg1, $arg2),
+ \STREAM_OPTION_WRITE_BUFFER => 0 === stream_set_write_buffer($this->handle, $arg2),
+ default => false,
+ };
+ }
+
+ public function stream_stat(): array|false
+ {
+ if (!$stat = stat($this->path)) {
+ return false;
+ }
+
+ $h = fopen($this->path, 'r');
+ fseek($h, -4, \SEEK_END);
+ $size = unpack('V', fread($h, 4));
+ fclose($h);
+
+ $stat[7] = $stat['size'] = end($size);
+
+ return $stat;
+ }
+}
diff --git a/src/Symfony/Component/Emoji/composer.json b/src/Symfony/Component/Emoji/composer.json
new file mode 100644
index 0000000000000..c4997c1b32b92
--- /dev/null
+++ b/src/Symfony/Component/Emoji/composer.json
@@ -0,0 +1,34 @@
+{
+ "name": "symfony/emoji",
+ "type": "library",
+ "description": "Provides access to emoji characters and sequences from the Unicode CLDR",
+ "keywords": ["cldr", "emoji", "intl", "transliterator", "unicode"],
+ "homepage": "https://symfony.com",
+ "license": "MIT",
+ "authors": [
+ {
+ "name": "Grégoire Pineau",
+ "email": "lyrixx@lyrixx.info"
+ },
+ {
+ "name": "Symfony Community",
+ "homepage": "https://symfony.com/contributors"
+ }
+ ],
+ "require": {
+ "php": ">=8.2",
+ "ext-intl": "*"
+ },
+ "require-dev": {
+ "symfony/filesystem": "^6.4|^7.0",
+ "symfony/finder": "^6.4|^7.0",
+ "symfony/var-exporter": "^6.4|^7.0"
+ },
+ "autoload": {
+ "psr-4": { "Symfony\\Component\\Emoji\\": "" },
+ "exclude-from-classmap": [
+ "/Tests/"
+ ]
+ },
+ "minimum-stability": "dev"
+}
diff --git a/src/Symfony/Component/Emoji/phpunit.xml.dist b/src/Symfony/Component/Emoji/phpunit.xml.dist
new file mode 100644
index 0000000000000..5c74dab50b3ca
--- /dev/null
+++ b/src/Symfony/Component/Emoji/phpunit.xml.dist
@@ -0,0 +1,31 @@
+
+
+
+
+
+
+
+
+
+ ./Tests/
+
+
+
+
+
+ ./
+
+
+ ./Resources
+ ./Tests
+ ./vendor
+
+
+
diff --git a/src/Symfony/Component/ErrorHandler/DebugClassLoader.php b/src/Symfony/Component/ErrorHandler/DebugClassLoader.php
index b7ed7296bfeee..db5d37bb40c75 100644
--- a/src/Symfony/Component/ErrorHandler/DebugClassLoader.php
+++ b/src/Symfony/Component/ErrorHandler/DebugClassLoader.php
@@ -311,7 +311,7 @@ public function loadClass(string $class): void
$this->checkClass($class, $file);
}
- private function checkClass(string $class, string $file = null): void
+ private function checkClass(string $class, ?string $file = null): void
{
$exists = null === $file || class_exists($class, false) || interface_exists($class, false) || trait_exists($class, false);
@@ -796,7 +796,7 @@ private function getOwnInterfaces(string $class, ?string $parent): array
return $ownInterfaces;
}
- private function setReturnType(string $types, string $class, string $method, string $filename, ?string $parent, \ReflectionType $returnType = null): void
+ private function setReturnType(string $types, string $class, string $method, string $filename, ?string $parent, ?\ReflectionType $returnType = null): void
{
if ('__construct' === $method) {
return;
diff --git a/src/Symfony/Component/ErrorHandler/Error/FatalError.php b/src/Symfony/Component/ErrorHandler/Error/FatalError.php
index e0cf2f505a229..d96543ae6bc59 100644
--- a/src/Symfony/Component/ErrorHandler/Error/FatalError.php
+++ b/src/Symfony/Component/ErrorHandler/Error/FatalError.php
@@ -20,9 +20,9 @@ public function __construct(
string $message,
int $code,
private array $error,
- int $traceOffset = null,
+ ?int $traceOffset = null,
bool $traceArgs = true,
- array $trace = null,
+ ?array $trace = null,
) {
parent::__construct($message, $code);
diff --git a/src/Symfony/Component/ErrorHandler/ErrorEnhancer/ClassNotFoundErrorEnhancer.php b/src/Symfony/Component/ErrorHandler/ErrorEnhancer/ClassNotFoundErrorEnhancer.php
index a98075fe45ef4..b4623cf17cdf7 100644
--- a/src/Symfony/Component/ErrorHandler/ErrorEnhancer/ClassNotFoundErrorEnhancer.php
+++ b/src/Symfony/Component/ErrorHandler/ErrorEnhancer/ClassNotFoundErrorEnhancer.php
@@ -107,7 +107,8 @@ private function getClassCandidates(string $class): array
private function findClassInPath(string $path, string $class, string $prefix): array
{
- if (!$path = realpath($path.'/'.strtr($prefix, '\\_', '//')) ?: realpath($path.'/'.\dirname(strtr($prefix, '\\_', '//'))) ?: realpath($path)) {
+ $path = realpath($path.'/'.strtr($prefix, '\\_', '//')) ?: realpath($path.'/'.\dirname(strtr($prefix, '\\_', '//'))) ?: realpath($path);
+ if (!$path || !is_dir($path)) {
return [];
}
diff --git a/src/Symfony/Component/ErrorHandler/ErrorHandler.php b/src/Symfony/Component/ErrorHandler/ErrorHandler.php
index 1ee29e1b8e71a..5bf05431ea080 100644
--- a/src/Symfony/Component/ErrorHandler/ErrorHandler.php
+++ b/src/Symfony/Component/ErrorHandler/ErrorHandler.php
@@ -108,7 +108,7 @@ class ErrorHandler
/**
* Registers the error handler.
*/
- public static function register(self $handler = null, bool $replace = true): self
+ public static function register(?self $handler = null, bool $replace = true): self
{
if (null === self::$reservedMemory) {
self::$reservedMemory = str_repeat('x', 32768);
@@ -179,7 +179,7 @@ public static function call(callable $function, mixed ...$arguments): mixed
}
}
- public function __construct(BufferingLogger $bootstrappingLogger = null, bool $debug = false)
+ public function __construct(?BufferingLogger $bootstrappingLogger = null, bool $debug = false)
{
if ($bootstrappingLogger) {
$this->bootstrappingLogger = $bootstrappingLogger;
@@ -559,7 +559,7 @@ public function handleException(\Throwable $exception): void
*
* @internal
*/
- public static function handleFatalError(array $error = null): void
+ public static function handleFatalError(?array $error = null): void
{
if (null === self::$reservedMemory) {
return;
diff --git a/src/Symfony/Component/ErrorHandler/ErrorRenderer/FileLinkFormatter.php b/src/Symfony/Component/ErrorHandler/ErrorRenderer/FileLinkFormatter.php
index 570debb8afa53..e82082457ce10 100644
--- a/src/Symfony/Component/ErrorHandler/ErrorRenderer/FileLinkFormatter.php
+++ b/src/Symfony/Component/ErrorHandler/ErrorRenderer/FileLinkFormatter.php
@@ -30,10 +30,10 @@ class FileLinkFormatter
* @param string|\Closure $urlFormat the URL format, or a closure that returns it on-demand
*/
public function __construct(
- string|array $fileLinkFormat = null,
+ string|array|null $fileLinkFormat = null,
private ?RequestStack $requestStack = null,
private ?string $baseDir = null,
- private null|string|\Closure $urlFormat = null,
+ private string|\Closure|null $urlFormat = null,
) {
$fileLinkFormat ??= $_ENV['SYMFONY_IDE'] ?? $_SERVER['SYMFONY_IDE'] ?? '';
diff --git a/src/Symfony/Component/ErrorHandler/ErrorRenderer/HtmlErrorRenderer.php b/src/Symfony/Component/ErrorHandler/ErrorRenderer/HtmlErrorRenderer.php
index 9a60da3e3e431..cfb6b194f53f4 100644
--- a/src/Symfony/Component/ErrorHandler/ErrorRenderer/HtmlErrorRenderer.php
+++ b/src/Symfony/Component/ErrorHandler/ErrorRenderer/HtmlErrorRenderer.php
@@ -47,8 +47,8 @@ class HtmlErrorRenderer implements ErrorRendererInterface
*/
public function __construct(
bool|callable $debug = false,
- string $charset = null,
- string|FileLinkFormatter $fileLinkFormat = null,
+ ?string $charset = null,
+ string|FileLinkFormatter|null $fileLinkFormat = null,
private ?string $projectDir = null,
string|callable $outputBuffer = '',
private ?LoggerInterface $logger = null,
@@ -217,7 +217,7 @@ private function getFileRelative(string $file): ?string
* @param int $line The line number
* @param string $text Use this text for the link rather than the file path
*/
- private function formatFile(string $file, int $line, string $text = null): string
+ private function formatFile(string $file, int $line, ?string $text = null): string
{
$file = trim($file);
diff --git a/src/Symfony/Component/ErrorHandler/ErrorRenderer/SerializerErrorRenderer.php b/src/Symfony/Component/ErrorHandler/ErrorRenderer/SerializerErrorRenderer.php
index 88d4c9037085d..c5d918026ad88 100644
--- a/src/Symfony/Component/ErrorHandler/ErrorRenderer/SerializerErrorRenderer.php
+++ b/src/Symfony/Component/ErrorHandler/ErrorRenderer/SerializerErrorRenderer.php
@@ -36,7 +36,7 @@ class SerializerErrorRenderer implements ErrorRendererInterface
public function __construct(
private SerializerInterface $serializer,
string|callable $format,
- ErrorRendererInterface $fallbackErrorRenderer = null,
+ ?ErrorRendererInterface $fallbackErrorRenderer = null,
bool|callable $debug = false,
) {
$this->format = \is_string($format) ? $format : $format(...);
diff --git a/src/Symfony/Component/ErrorHandler/Exception/FlattenException.php b/src/Symfony/Component/ErrorHandler/Exception/FlattenException.php
index ab62b1be367f8..39473151db194 100644
--- a/src/Symfony/Component/ErrorHandler/Exception/FlattenException.php
+++ b/src/Symfony/Component/ErrorHandler/Exception/FlattenException.php
@@ -42,12 +42,12 @@ class FlattenException
private ?string $asString = null;
private Data $dataRepresentation;
- public static function create(\Exception $exception, int $statusCode = null, array $headers = []): static
+ public static function create(\Exception $exception, ?int $statusCode = null, array $headers = []): static
{
return static::createFromThrowable($exception, $statusCode, $headers);
}
- public static function createFromThrowable(\Throwable $exception, int $statusCode = null, array $headers = []): static
+ public static function createFromThrowable(\Throwable $exception, ?int $statusCode = null, array $headers = []): static
{
$e = new static();
$e->setMessage($exception->getMessage());
@@ -85,7 +85,7 @@ public static function createFromThrowable(\Throwable $exception, int $statusCod
return $e;
}
- public static function createWithDataRepresentation(\Throwable $throwable, int $statusCode = null, array $headers = [], VarCloner $cloner = null): static
+ public static function createWithDataRepresentation(\Throwable $throwable, ?int $statusCode = null, array $headers = [], ?VarCloner $cloner = null): static
{
$e = static::createFromThrowable($throwable, $statusCode, $headers);
diff --git a/src/Symfony/Component/ErrorHandler/Resources/views/error.html.php b/src/Symfony/Component/ErrorHandler/Resources/views/error.html.php
index 1085a5adb2821..3fbf28f60b262 100644
--- a/src/Symfony/Component/ErrorHandler/Resources/views/error.html.php
+++ b/src/Symfony/Component/ErrorHandler/Resources/views/error.html.php
@@ -1,10 +1,10 @@
-
-
+
+
An Error Occurred: = $statusText; ?>
-
+
diff --git a/src/Symfony/Component/ErrorHandler/Resources/views/exception_full.html.php b/src/Symfony/Component/ErrorHandler/Resources/views/exception_full.html.php
index 9d5f6e3366adc..af04db1bd2c97 100644
--- a/src/Symfony/Component/ErrorHandler/Resources/views/exception_full.html.php
+++ b/src/Symfony/Component/ErrorHandler/Resources/views/exception_full.html.php
@@ -2,11 +2,11 @@
-
-
-
+
+
+
= $_message; ?>
-
+
diff --git a/src/Symfony/Component/ErrorHandler/Tests/ErrorHandlerTest.php b/src/Symfony/Component/ErrorHandler/Tests/ErrorHandlerTest.php
index 1e48e8a910b6b..f216a8fba63e1 100644
--- a/src/Symfony/Component/ErrorHandler/Tests/ErrorHandlerTest.php
+++ b/src/Symfony/Component/ErrorHandler/Tests/ErrorHandlerTest.php
@@ -363,7 +363,7 @@ public function testHandleDeprecation()
/**
* @dataProvider handleExceptionProvider
*/
- public function testHandleException(string $expectedMessage, \Throwable $exception, string $enhancedMessage = null)
+ public function testHandleException(string $expectedMessage, \Throwable $exception, ?string $enhancedMessage = null)
{
try {
$logger = $this->createMock(LoggerInterface::class);
diff --git a/src/Symfony/Component/EventDispatcher/Debug/TraceableEventDispatcher.php b/src/Symfony/Component/EventDispatcher/Debug/TraceableEventDispatcher.php
index f6b96bf69e352..72ce526586584 100644
--- a/src/Symfony/Component/EventDispatcher/Debug/TraceableEventDispatcher.php
+++ b/src/Symfony/Component/EventDispatcher/Debug/TraceableEventDispatcher.php
@@ -76,7 +76,7 @@ public function removeSubscriber(EventSubscriberInterface $subscriber): void
$this->dispatcher->removeSubscriber($subscriber);
}
- public function getListeners(string $eventName = null): array
+ public function getListeners(?string $eventName = null): array
{
return $this->dispatcher->getListeners($eventName);
}
@@ -96,12 +96,12 @@ public function getListenerPriority(string $eventName, callable|array $listener)
return $this->dispatcher->getListenerPriority($eventName, $listener);
}
- public function hasListeners(string $eventName = null): bool
+ public function hasListeners(?string $eventName = null): bool
{
return $this->dispatcher->hasListeners($eventName);
}
- public function dispatch(object $event, string $eventName = null): object
+ public function dispatch(object $event, ?string $eventName = null): object
{
$eventName ??= $event::class;
@@ -136,7 +136,7 @@ public function dispatch(object $event, string $eventName = null): object
return $event;
}
- public function getCalledListeners(Request $request = null): array
+ public function getCalledListeners(?Request $request = null): array
{
if (null === $this->callStack) {
return [];
@@ -154,7 +154,7 @@ public function getCalledListeners(Request $request = null): array
return $called;
}
- public function getNotCalledListeners(Request $request = null): array
+ public function getNotCalledListeners(?Request $request = null): array
{
try {
$allListeners = $this->dispatcher instanceof EventDispatcher ? $this->getListenersWithPriority() : $this->getListenersWithoutPriority();
@@ -196,7 +196,7 @@ public function getNotCalledListeners(Request $request = null): array
return $notCalled;
}
- public function getOrphanedEvents(Request $request = null): array
+ public function getOrphanedEvents(?Request $request = null): array
{
if ($request) {
return $this->orphanedEvents[spl_object_hash($request)] ?? [];
diff --git a/src/Symfony/Component/EventDispatcher/EventDispatcher.php b/src/Symfony/Component/EventDispatcher/EventDispatcher.php
index 65d862637423c..43bc16b85b4e5 100644
--- a/src/Symfony/Component/EventDispatcher/EventDispatcher.php
+++ b/src/Symfony/Component/EventDispatcher/EventDispatcher.php
@@ -42,7 +42,7 @@ public function __construct()
}
}
- public function dispatch(object $event, string $eventName = null): object
+ public function dispatch(object $event, ?string $eventName = null): object
{
$eventName ??= $event::class;
@@ -59,7 +59,7 @@ public function dispatch(object $event, string $eventName = null): object
return $event;
}
- public function getListeners(string $eventName = null): array
+ public function getListeners(?string $eventName = null): array
{
if (null !== $eventName) {
if (empty($this->listeners[$eventName])) {
@@ -108,7 +108,7 @@ public function getListenerPriority(string $eventName, callable|array $listener)
return null;
}
- public function hasListeners(string $eventName = null): bool
+ public function hasListeners(?string $eventName = null): bool
{
if (null !== $eventName) {
return !empty($this->listeners[$eventName]);
diff --git a/src/Symfony/Component/EventDispatcher/EventDispatcherInterface.php b/src/Symfony/Component/EventDispatcher/EventDispatcherInterface.php
index 6d4a5b4d9557b..99f8b1a03a93c 100644
--- a/src/Symfony/Component/EventDispatcher/EventDispatcherInterface.php
+++ b/src/Symfony/Component/EventDispatcher/EventDispatcherInterface.php
@@ -50,7 +50,7 @@ public function removeSubscriber(EventSubscriberInterface $subscriber): void;
*
* @return array
*/
- public function getListeners(string $eventName = null): array;
+ public function getListeners(?string $eventName = null): array;
/**
* Gets the listener priority for a specific event.
@@ -62,5 +62,5 @@ public function getListenerPriority(string $eventName, callable $listener): ?int
/**
* Checks whether an event has any registered listeners.
*/
- public function hasListeners(string $eventName = null): bool;
+ public function hasListeners(?string $eventName = null): bool;
}
diff --git a/src/Symfony/Component/EventDispatcher/ImmutableEventDispatcher.php b/src/Symfony/Component/EventDispatcher/ImmutableEventDispatcher.php
index f715ecba3519d..a6d078e9b699d 100644
--- a/src/Symfony/Component/EventDispatcher/ImmutableEventDispatcher.php
+++ b/src/Symfony/Component/EventDispatcher/ImmutableEventDispatcher.php
@@ -23,7 +23,7 @@ public function __construct(
) {
}
- public function dispatch(object $event, string $eventName = null): object
+ public function dispatch(object $event, ?string $eventName = null): object
{
return $this->dispatcher->dispatch($event, $eventName);
}
@@ -48,7 +48,7 @@ public function removeSubscriber(EventSubscriberInterface $subscriber): never
throw new \BadMethodCallException('Unmodifiable event dispatchers must not be modified.');
}
- public function getListeners(string $eventName = null): array
+ public function getListeners(?string $eventName = null): array
{
return $this->dispatcher->getListeners($eventName);
}
@@ -58,7 +58,7 @@ public function getListenerPriority(string $eventName, callable|array $listener)
return $this->dispatcher->getListenerPriority($eventName, $listener);
}
- public function hasListeners(string $eventName = null): bool
+ public function hasListeners(?string $eventName = null): bool
{
return $this->dispatcher->hasListeners($eventName);
}
diff --git a/src/Symfony/Component/ExpressionLanguage/CHANGELOG.md b/src/Symfony/Component/ExpressionLanguage/CHANGELOG.md
index f54f943ac15de..f5c26e6905370 100644
--- a/src/Symfony/Component/ExpressionLanguage/CHANGELOG.md
+++ b/src/Symfony/Component/ExpressionLanguage/CHANGELOG.md
@@ -1,6 +1,11 @@
CHANGELOG
=========
+7.1
+---
+
+ * Add support for PHP `min` and `max` functions
+
7.0
---
diff --git a/src/Symfony/Component/ExpressionLanguage/ExpressionFunction.php b/src/Symfony/Component/ExpressionLanguage/ExpressionFunction.php
index 5bd857ddb41c4..8950e2148a274 100644
--- a/src/Symfony/Component/ExpressionLanguage/ExpressionFunction.php
+++ b/src/Symfony/Component/ExpressionLanguage/ExpressionFunction.php
@@ -71,7 +71,7 @@ public function getEvaluator(): \Closure
* @throws \InvalidArgumentException if given PHP function name is in namespace
* and expression function name is not defined
*/
- public static function fromPhp(string $phpFunctionName, string $expressionFunctionName = null): self
+ public static function fromPhp(string $phpFunctionName, ?string $expressionFunctionName = null): self
{
$phpFunctionName = ltrim($phpFunctionName, '\\');
if (!\function_exists($phpFunctionName)) {
diff --git a/src/Symfony/Component/ExpressionLanguage/ExpressionLanguage.php b/src/Symfony/Component/ExpressionLanguage/ExpressionLanguage.php
index e8200d9b64b25..bd9dbfcc1944c 100644
--- a/src/Symfony/Component/ExpressionLanguage/ExpressionLanguage.php
+++ b/src/Symfony/Component/ExpressionLanguage/ExpressionLanguage.php
@@ -34,7 +34,7 @@ class ExpressionLanguage
/**
* @param ExpressionFunctionProviderInterface[] $providers
*/
- public function __construct(CacheItemPoolInterface $cache = null, array $providers = [])
+ public function __construct(?CacheItemPoolInterface $cache = null, array $providers = [])
{
$this->cache = $cache ?? new ArrayAdapter();
$this->registerFunctions();
@@ -140,7 +140,10 @@ public function registerProvider(ExpressionFunctionProviderInterface $provider):
*/
protected function registerFunctions()
{
- $this->addFunction(ExpressionFunction::fromPhp('constant'));
+ $basicPhpFunctions = ['constant', 'min', 'max'];
+ foreach ($basicPhpFunctions as $function) {
+ $this->addFunction(ExpressionFunction::fromPhp($function));
+ }
$this->addFunction(new ExpressionFunction('enum',
static fn ($str): string => sprintf("(\constant(\$v = (%s))) instanceof \UnitEnum ? \constant(\$v) : throw new \TypeError(\sprintf('The string \"%%s\" is not the name of a valid enum case.', \$v))", $str),
diff --git a/src/Symfony/Component/ExpressionLanguage/Node/ArrayNode.php b/src/Symfony/Component/ExpressionLanguage/Node/ArrayNode.php
index 993af3633d9a2..79eade29ca52d 100644
--- a/src/Symfony/Component/ExpressionLanguage/Node/ArrayNode.php
+++ b/src/Symfony/Component/ExpressionLanguage/Node/ArrayNode.php
@@ -27,7 +27,7 @@ public function __construct()
$this->index = -1;
}
- public function addElement(Node $value, Node $key = null): void
+ public function addElement(Node $value, ?Node $key = null): void
{
$key ??= new ConstantNode(++$this->index);
diff --git a/src/Symfony/Component/ExpressionLanguage/SyntaxError.php b/src/Symfony/Component/ExpressionLanguage/SyntaxError.php
index 0bfd7e9977727..e165dc22a0d72 100644
--- a/src/Symfony/Component/ExpressionLanguage/SyntaxError.php
+++ b/src/Symfony/Component/ExpressionLanguage/SyntaxError.php
@@ -13,7 +13,7 @@
class SyntaxError extends \LogicException
{
- public function __construct(string $message, int $cursor = 0, string $expression = '', string $subject = null, array $proposals = null)
+ public function __construct(string $message, int $cursor = 0, string $expression = '', ?string $subject = null, ?array $proposals = null)
{
$message = sprintf('%s around position %d', rtrim($message, '.'), $cursor);
if ($expression) {
diff --git a/src/Symfony/Component/ExpressionLanguage/Tests/ExpressionLanguageTest.php b/src/Symfony/Component/ExpressionLanguage/Tests/ExpressionLanguageTest.php
index ed926ffd35073..f7f712d8c5d46 100644
--- a/src/Symfony/Component/ExpressionLanguage/Tests/ExpressionLanguageTest.php
+++ b/src/Symfony/Component/ExpressionLanguage/Tests/ExpressionLanguageTest.php
@@ -71,13 +71,23 @@ public function testCachedParse()
$this->assertSame($savedParsedExpression, $parsedExpression);
}
- public function testConstantFunction()
+ /**
+ * @dataProvider basicPhpFunctionProvider
+ */
+ public function testBasicPhpFunction($expression, $expected, $compiled)
{
$expressionLanguage = new ExpressionLanguage();
- $this->assertEquals(\PHP_VERSION, $expressionLanguage->evaluate('constant("PHP_VERSION")'));
+ $this->assertEquals($expected, $expressionLanguage->evaluate($expression));
+ $this->assertEquals($compiled, $expressionLanguage->compile($expression));
+ }
- $expressionLanguage = new ExpressionLanguage();
- $this->assertEquals('\constant("PHP_VERSION")', $expressionLanguage->compile('constant("PHP_VERSION")'));
+ public static function basicPhpFunctionProvider()
+ {
+ return [
+ ['constant("PHP_VERSION")', \PHP_VERSION, '\constant("PHP_VERSION")'],
+ ['min(1,2,3)', 1, '\min(1, 2, 3)'],
+ ['max(1,2,3)', 3, '\max(1, 2, 3)'],
+ ];
}
public function testEnumFunctionWithConstantThrows()
@@ -168,6 +178,14 @@ public function testParseThrowsInsteadOfNotice()
$expressionLanguage->parse('node.', ['node']);
}
+ public function testParseReturnsObjectOnAlreadyParsedExpression()
+ {
+ $expressionLanguage = new ExpressionLanguage();
+ $expression = $expressionLanguage->parse('1 + 1', []);
+
+ $this->assertSame($expression, $expressionLanguage->parse($expression, []));
+ }
+
public static function shortCircuitProviderEvaluate()
{
$object = new class(static::fail(...)) {
@@ -366,7 +384,7 @@ public function testNullSafeCompileFails($expression, $foo)
$this->expectException(\ErrorException::class);
- set_error_handler(static function (int $errno, string $errstr, string $errfile = null, int $errline = null): bool {
+ set_error_handler(static function (int $errno, string $errstr, ?string $errfile = null, ?int $errline = null): bool {
if ($errno & (\E_WARNING | \E_USER_WARNING) && (str_contains($errstr, 'Attempt to read property') || str_contains($errstr, 'Trying to access'))) {
throw new \ErrorException($errstr, 0, $errno, $errfile, $errline);
}
@@ -440,6 +458,24 @@ public function testRegisterAfterCompile($registerCallback)
$registerCallback($el);
}
+ public function testLintDoesntThrowOnValidExpression()
+ {
+ $el = new ExpressionLanguage();
+ $el->lint('1 + 1', null);
+
+ $this->expectNotToPerformAssertions();
+ }
+
+ public function testLintThrowsOnInvalidExpression()
+ {
+ $el = new ExpressionLanguage();
+
+ $this->expectException(SyntaxError::class);
+ $this->expectExceptionMessage('Unexpected end of expression around position 6 for expression `node.`.');
+
+ $el->lint('node.', ['node']);
+ }
+
public static function getRegisterCallbacks()
{
return [
diff --git a/src/Symfony/Component/ExpressionLanguage/Tests/ParserTest.php b/src/Symfony/Component/ExpressionLanguage/Tests/ParserTest.php
index 58a232eb8145a..e3170ba809fde 100644
--- a/src/Symfony/Component/ExpressionLanguage/Tests/ParserTest.php
+++ b/src/Symfony/Component/ExpressionLanguage/Tests/ParserTest.php
@@ -37,6 +37,17 @@ public function testParseWithZeroInNames()
$parser->parse($lexer->tokenize('foo'), [0]);
}
+ public function testParseUnknownFunction()
+ {
+ $parser = new Parser([]);
+ $tokenized = (new Lexer())->tokenize('foo()');
+
+ $this->expectException(SyntaxError::class);
+ $this->expectExceptionMessage('The function "foo" does not exist around position 1 for expression `foo()`.');
+
+ $parser->parse($tokenized);
+ }
+
/**
* @dataProvider getParseData
*/
@@ -284,7 +295,7 @@ public function testNameProposal()
/**
* @dataProvider getLintData
*/
- public function testLint($expression, $names, string $exception = null)
+ public function testLint($expression, $names, ?string $exception = null)
{
if ($exception) {
$this->expectException(SyntaxError::class);
@@ -314,6 +325,14 @@ public static function getLintData(): array
'expression' => 'foo.bar',
'names' => null,
],
+ 'array with trailing comma' => [
+ 'expression' => '[value1, value2, value3,]',
+ 'names' => ['value1', 'value2', 'value3'],
+ ],
+ 'hashmap with trailing comma' => [
+ 'expression' => '{val1: value1, val2: value2, val3: value3,}',
+ 'names' => ['value1', 'value2', 'value3'],
+ ],
'disallow expression without names' => [
'expression' => 'foo.bar',
'names' => [],
@@ -347,6 +366,11 @@ public static function getLintData(): array
'names' => ['foo'],
'exception' => 'Unclosed "[" around position 3 for expression `foo["some_key")`.',
],
+ 'incorrect hash key' => [
+ 'expression' => '{+: value1}',
+ 'names' => ['value1'],
+ 'exception' => 'A hash key must be a quoted string, a number, a name, or an expression enclosed in parentheses (unexpected token "operator" of value "+" around position 2 for expression `{+: value1}`.',
+ ],
'missed array key' => [
'expression' => 'foo[]',
'names' => ['foo'],
diff --git a/src/Symfony/Component/ExpressionLanguage/Token.php b/src/Symfony/Component/ExpressionLanguage/Token.php
index 14ed27704f16c..c1a7c107d1f87 100644
--- a/src/Symfony/Component/ExpressionLanguage/Token.php
+++ b/src/Symfony/Component/ExpressionLanguage/Token.php
@@ -47,7 +47,7 @@ public function __toString(): string
/**
* Tests the current token for a type and/or a value.
*/
- public function test(string $type, string $value = null): bool
+ public function test(string $type, ?string $value = null): bool
{
return $this->type === $type && (null === $value || $this->value == $value);
}
diff --git a/src/Symfony/Component/ExpressionLanguage/TokenStream.php b/src/Symfony/Component/ExpressionLanguage/TokenStream.php
index da9e3aceca9d9..a7f67351076bc 100644
--- a/src/Symfony/Component/ExpressionLanguage/TokenStream.php
+++ b/src/Symfony/Component/ExpressionLanguage/TokenStream.php
@@ -56,7 +56,7 @@ public function next(): void
/**
* @param string|null $message The syntax error message
*/
- public function expect(string $type, string $value = null, string $message = null): void
+ public function expect(string $type, ?string $value = null, ?string $message = null): void
{
$token = $this->current;
if (!$token->test($type, $value)) {
diff --git a/src/Symfony/Component/Filesystem/Exception/FileNotFoundException.php b/src/Symfony/Component/Filesystem/Exception/FileNotFoundException.php
index 48b6408095a13..06b732b1685c8 100644
--- a/src/Symfony/Component/Filesystem/Exception/FileNotFoundException.php
+++ b/src/Symfony/Component/Filesystem/Exception/FileNotFoundException.php
@@ -19,7 +19,7 @@
*/
class FileNotFoundException extends IOException
{
- public function __construct(string $message = null, int $code = 0, \Throwable $previous = null, string $path = null)
+ public function __construct(?string $message = null, int $code = 0, ?\Throwable $previous = null, ?string $path = null)
{
if (null === $message) {
if (null === $path) {
diff --git a/src/Symfony/Component/Filesystem/Exception/IOException.php b/src/Symfony/Component/Filesystem/Exception/IOException.php
index a3c5445534c72..46ab8b4a5a9d5 100644
--- a/src/Symfony/Component/Filesystem/Exception/IOException.php
+++ b/src/Symfony/Component/Filesystem/Exception/IOException.php
@@ -20,12 +20,12 @@
*/
class IOException extends \RuntimeException implements IOExceptionInterface
{
- private ?string $path;
-
- public function __construct(string $message, int $code = 0, \Throwable $previous = null, string $path = null)
- {
- $this->path = $path;
-
+ public function __construct(
+ string $message,
+ int $code = 0,
+ ?\Throwable $previous = null,
+ private ?string $path = null,
+ ) {
parent::__construct($message, $code, $previous);
}
diff --git a/src/Symfony/Component/Filesystem/Filesystem.php b/src/Symfony/Component/Filesystem/Filesystem.php
index e8ba4958df79d..b7fc701182a4b 100644
--- a/src/Symfony/Component/Filesystem/Filesystem.php
+++ b/src/Symfony/Component/Filesystem/Filesystem.php
@@ -125,7 +125,7 @@ public function exists(string|iterable $files): bool
*
* @throws IOException When touch fails
*/
- public function touch(string|iterable $files, int $time = null, int $atime = null): void
+ public function touch(string|iterable $files, ?int $time = null, ?int $atime = null): void
{
foreach ($this->toIterable($files) as $file) {
if (!($time ? self::box('touch', $file, $time, $atime) : self::box('touch', $file))) {
@@ -508,7 +508,7 @@ public function makePathRelative(string $endPath, string $startPath): string
*
* @throws IOException When file type is unknown
*/
- public function mirror(string $originDir, string $targetDir, \Traversable $iterator = null, array $options = []): void
+ public function mirror(string $originDir, string $targetDir, ?\Traversable $iterator = null, array $options = []): void
{
$targetDir = rtrim($targetDir, '/\\');
$originDir = rtrim($originDir, '/\\');
diff --git a/src/Symfony/Component/Filesystem/Path.php b/src/Symfony/Component/Filesystem/Path.php
index 0650c8e98cb50..80c616049b2d4 100644
--- a/src/Symfony/Component/Filesystem/Path.php
+++ b/src/Symfony/Component/Filesystem/Path.php
@@ -254,7 +254,7 @@ public static function getRoot(string $path): string
* @param string|null $extension if specified, only that extension is cut
* off (may contain leading dot)
*/
- public static function getFilenameWithoutExtension(string $path, string $extension = null): string
+ public static function getFilenameWithoutExtension(string $path, ?string $extension = null): string
{
if ('' === $path) {
return '';
diff --git a/src/Symfony/Component/Finder/Comparator/Comparator.php b/src/Symfony/Component/Finder/Comparator/Comparator.php
index bd685834739d2..c3d40e70e9946 100644
--- a/src/Symfony/Component/Finder/Comparator/Comparator.php
+++ b/src/Symfony/Component/Finder/Comparator/Comparator.php
@@ -16,16 +16,16 @@
*/
class Comparator
{
- private string $target;
private string $operator;
- public function __construct(string $target, string $operator = '==')
- {
+ public function __construct(
+ private string $target,
+ string $operator = '==',
+ ) {
if (!\in_array($operator, ['>', '<', '>=', '<=', '==', '!='])) {
throw new \InvalidArgumentException(sprintf('Invalid operator "%s".', $operator));
}
- $this->target = $target;
$this->operator = $operator;
}
diff --git a/src/Symfony/Component/Finder/SplFileInfo.php b/src/Symfony/Component/Finder/SplFileInfo.php
index 867e8e81a2084..2afc37826b8c8 100644
--- a/src/Symfony/Component/Finder/SplFileInfo.php
+++ b/src/Symfony/Component/Finder/SplFileInfo.php
@@ -18,19 +18,17 @@
*/
class SplFileInfo extends \SplFileInfo
{
- private string $relativePath;
- private string $relativePathname;
-
/**
* @param string $file The file name
* @param string $relativePath The relative path
* @param string $relativePathname The relative path name
*/
- public function __construct(string $file, string $relativePath, string $relativePathname)
- {
+ public function __construct(
+ string $file,
+ private string $relativePath,
+ private string $relativePathname,
+ ) {
parent::__construct($file);
- $this->relativePath = $relativePath;
- $this->relativePathname = $relativePathname;
}
/**
diff --git a/src/Symfony/Component/Form/AbstractRendererEngine.php b/src/Symfony/Component/Form/AbstractRendererEngine.php
index bccdf69cc5922..1968f5a3766c6 100644
--- a/src/Symfony/Component/Form/AbstractRendererEngine.php
+++ b/src/Symfony/Component/Form/AbstractRendererEngine.php
@@ -25,8 +25,6 @@ abstract class AbstractRendererEngine implements FormRendererEngineInterface, Re
*/
public const CACHE_KEY_VAR = 'cache_key';
- protected array $defaultThemes;
-
/**
* @var array[]
*/
@@ -53,9 +51,9 @@ abstract class AbstractRendererEngine implements FormRendererEngineInterface, Re
* @param array $defaultThemes The default themes. The type of these
* themes is open to the implementation.
*/
- public function __construct(array $defaultThemes = [])
- {
- $this->defaultThemes = $defaultThemes;
+ public function __construct(
+ protected array $defaultThemes = [],
+ ) {
}
public function setTheme(FormView $view, mixed $themes, bool $useDefaultThemes = true): void
diff --git a/src/Symfony/Component/Form/Button.php b/src/Symfony/Component/Form/Button.php
index 67772ccfe1c6b..f172a7ee31dec 100644
--- a/src/Symfony/Component/Form/Button.php
+++ b/src/Symfony/Component/Form/Button.php
@@ -26,15 +26,14 @@
class Button implements \IteratorAggregate, FormInterface
{
private ?FormInterface $parent = null;
- private FormConfigInterface $config;
private bool $submitted = false;
/**
* Creates a new button from a form configuration.
*/
- public function __construct(FormConfigInterface $config)
- {
- $this->config = $config;
+ public function __construct(
+ private FormConfigInterface $config,
+ ) {
}
/**
@@ -104,7 +103,7 @@ public function getParent(): ?FormInterface
*
* @throws BadMethodCallException
*/
- public function add(string|FormInterface $child, string $type = null, array $options = []): static
+ public function add(string|FormInterface $child, ?string $type = null, array $options = []): static
{
throw new BadMethodCallException('Buttons cannot have children.');
}
@@ -335,7 +334,7 @@ public function isRoot(): bool
return null === $this->parent;
}
- public function createView(FormView $parent = null): FormView
+ public function createView(?FormView $parent = null): FormView
{
if (null === $parent && $this->parent) {
$parent = $this->parent->createView();
diff --git a/src/Symfony/Component/Form/ButtonBuilder.php b/src/Symfony/Component/Form/ButtonBuilder.php
index e640149bb86e7..4f7079142ef1a 100644
--- a/src/Symfony/Component/Form/ButtonBuilder.php
+++ b/src/Symfony/Component/Form/ButtonBuilder.php
@@ -31,19 +31,19 @@ class ButtonBuilder implements \IteratorAggregate, FormBuilderInterface
private ResolvedFormTypeInterface $type;
private string $name;
private array $attributes = [];
- private array $options;
/**
* @throws InvalidArgumentException if the name is empty
*/
- public function __construct(?string $name, array $options = [])
- {
+ public function __construct(
+ ?string $name,
+ private array $options = [],
+ ) {
if ('' === $name || null === $name) {
throw new InvalidArgumentException('Buttons cannot have empty names.');
}
$this->name = $name;
- $this->options = $options;
FormConfigBuilder::validateName($name);
}
@@ -53,7 +53,7 @@ public function __construct(?string $name, array $options = [])
*
* @throws BadMethodCallException
*/
- public function add(string|FormBuilderInterface $child, string $type = null, array $options = []): never
+ public function add(string|FormBuilderInterface $child, ?string $type = null, array $options = []): never
{
throw new BadMethodCallException('Buttons cannot have children.');
}
@@ -63,7 +63,7 @@ public function add(string|FormBuilderInterface $child, string $type = null, arr
*
* @throws BadMethodCallException
*/
- public function create(string $name, string $type = null, array $options = []): never
+ public function create(string $name, ?string $type = null, array $options = []): never
{
throw new BadMethodCallException('Buttons cannot have children.');
}
diff --git a/src/Symfony/Component/Form/ChoiceList/ArrayChoiceList.php b/src/Symfony/Component/Form/ChoiceList/ArrayChoiceList.php
index 5f0d7dc36e2bc..9ac4fd6e5286f 100644
--- a/src/Symfony/Component/Form/ChoiceList/ArrayChoiceList.php
+++ b/src/Symfony/Component/Form/ChoiceList/ArrayChoiceList.php
@@ -48,7 +48,7 @@ class ArrayChoiceList implements ChoiceListInterface
* incrementing integers are used as
* values
*/
- public function __construct(iterable $choices, callable $value = null)
+ public function __construct(iterable $choices, ?callable $value = null)
{
if ($choices instanceof \Traversable) {
$choices = iterator_to_array($choices);
diff --git a/src/Symfony/Component/Form/ChoiceList/Factory/Cache/ChoiceLoader.php b/src/Symfony/Component/Form/ChoiceList/Factory/Cache/ChoiceLoader.php
index 70c3f77e869e7..1d64f101c0b2c 100644
--- a/src/Symfony/Component/Form/ChoiceList/Factory/Cache/ChoiceLoader.php
+++ b/src/Symfony/Component/Form/ChoiceList/Factory/Cache/ChoiceLoader.php
@@ -26,17 +26,17 @@
*/
final class ChoiceLoader extends AbstractStaticOption implements ChoiceLoaderInterface
{
- public function loadChoiceList(callable $value = null): ChoiceListInterface
+ public function loadChoiceList(?callable $value = null): ChoiceListInterface
{
return $this->getOption()->loadChoiceList($value);
}
- public function loadChoicesForValues(array $values, callable $value = null): array
+ public function loadChoicesForValues(array $values, ?callable $value = null): array
{
return $this->getOption()->loadChoicesForValues($values, $value);
}
- public function loadValuesForChoices(array $choices, callable $value = null): array
+ public function loadValuesForChoices(array $choices, ?callable $value = null): array
{
return $this->getOption()->loadValuesForChoices($choices, $value);
}
diff --git a/src/Symfony/Component/Form/ChoiceList/Factory/ChoiceListFactoryInterface.php b/src/Symfony/Component/Form/ChoiceList/Factory/ChoiceListFactoryInterface.php
index 7c94ad809ee2d..a9ca6db20e569 100644
--- a/src/Symfony/Component/Form/ChoiceList/Factory/ChoiceListFactoryInterface.php
+++ b/src/Symfony/Component/Form/ChoiceList/Factory/ChoiceListFactoryInterface.php
@@ -33,7 +33,7 @@ interface ChoiceListFactoryInterface
*
* @param callable|null $filter The callable filtering the choices
*/
- public function createListFromChoices(iterable $choices, callable $value = null, callable $filter = null): ChoiceListInterface;
+ public function createListFromChoices(iterable $choices, ?callable $value = null, ?callable $filter = null): ChoiceListInterface;
/**
* Creates a choice list that is loaded with the given loader.
@@ -44,7 +44,7 @@ public function createListFromChoices(iterable $choices, callable $value = null,
*
* @param callable|null $filter The callable filtering the choices
*/
- public function createListFromLoader(ChoiceLoaderInterface $loader, callable $value = null, callable $filter = null): ChoiceListInterface;
+ public function createListFromLoader(ChoiceLoaderInterface $loader, ?callable $value = null, ?callable $filter = null): ChoiceListInterface;
/**
* Creates a view for the given choice list.
@@ -81,5 +81,5 @@ public function createListFromLoader(ChoiceLoaderInterface $loader, callable $va
* on top of the list and in their original position
* or only in the top of the list
*/
- public function createView(ChoiceListInterface $list, array|callable $preferredChoices = null, callable|false $label = null, callable $index = null, callable $groupBy = null, array|callable $attr = null, array|callable $labelTranslationParameters = [], bool $duplicatePreferredChoices = true): ChoiceListView;
+ public function createView(ChoiceListInterface $list, array|callable|null $preferredChoices = null, callable|false|null $label = null, ?callable $index = null, ?callable $groupBy = null, array|callable|null $attr = null, array|callable $labelTranslationParameters = [], bool $duplicatePreferredChoices = true): ChoiceListView;
}
diff --git a/src/Symfony/Component/Form/ChoiceList/Factory/DefaultChoiceListFactory.php b/src/Symfony/Component/Form/ChoiceList/Factory/DefaultChoiceListFactory.php
index abac8eae311f1..586ac822a8005 100644
--- a/src/Symfony/Component/Form/ChoiceList/Factory/DefaultChoiceListFactory.php
+++ b/src/Symfony/Component/Form/ChoiceList/Factory/DefaultChoiceListFactory.php
@@ -30,7 +30,7 @@
*/
class DefaultChoiceListFactory implements ChoiceListFactoryInterface
{
- public function createListFromChoices(iterable $choices, callable $value = null, callable $filter = null): ChoiceListInterface
+ public function createListFromChoices(iterable $choices, ?callable $value = null, ?callable $filter = null): ChoiceListInterface
{
if ($filter) {
// filter the choice list lazily
@@ -43,7 +43,7 @@ public function createListFromChoices(iterable $choices, callable $value = null,
return new ArrayChoiceList($choices, $value);
}
- public function createListFromLoader(ChoiceLoaderInterface $loader, callable $value = null, callable $filter = null): ChoiceListInterface
+ public function createListFromLoader(ChoiceLoaderInterface $loader, ?callable $value = null, ?callable $filter = null): ChoiceListInterface
{
if ($filter) {
$loader = new FilterChoiceLoaderDecorator($loader, $filter);
@@ -52,7 +52,7 @@ public function createListFromLoader(ChoiceLoaderInterface $loader, callable $va
return new LazyChoiceList($loader, $value);
}
- public function createView(ChoiceListInterface $list, array|callable $preferredChoices = null, callable|false $label = null, callable $index = null, callable $groupBy = null, array|callable $attr = null, array|callable $labelTranslationParameters = [], bool $duplicatePreferredChoices = true): ChoiceListView
+ public function createView(ChoiceListInterface $list, array|callable|null $preferredChoices = null, callable|false|null $label = null, ?callable $index = null, ?callable $groupBy = null, array|callable|null $attr = null, array|callable $labelTranslationParameters = [], bool $duplicatePreferredChoices = true): ChoiceListView
{
$preferredViews = [];
$preferredViewsOrder = [];
diff --git a/src/Symfony/Component/Form/ChoiceList/Factory/PropertyAccessDecorator.php b/src/Symfony/Component/Form/ChoiceList/Factory/PropertyAccessDecorator.php
index 91460774f37b0..c83ef17e9f434 100644
--- a/src/Symfony/Component/Form/ChoiceList/Factory/PropertyAccessDecorator.php
+++ b/src/Symfony/Component/Form/ChoiceList/Factory/PropertyAccessDecorator.php
@@ -41,7 +41,7 @@ class PropertyAccessDecorator implements ChoiceListFactoryInterface
private ChoiceListFactoryInterface $decoratedFactory;
private PropertyAccessorInterface $propertyAccessor;
- public function __construct(ChoiceListFactoryInterface $decoratedFactory, PropertyAccessorInterface $propertyAccessor = null)
+ public function __construct(ChoiceListFactoryInterface $decoratedFactory, ?PropertyAccessorInterface $propertyAccessor = null)
{
$this->decoratedFactory = $decoratedFactory;
$this->propertyAccessor = $propertyAccessor ?: PropertyAccess::createPropertyAccessor();
diff --git a/src/Symfony/Component/Form/ChoiceList/LazyChoiceList.php b/src/Symfony/Component/Form/ChoiceList/LazyChoiceList.php
index b34d3708ab069..8e0eaaa8fc4ec 100644
--- a/src/Symfony/Component/Form/ChoiceList/LazyChoiceList.php
+++ b/src/Symfony/Component/Form/ChoiceList/LazyChoiceList.php
@@ -27,8 +27,6 @@
*/
class LazyChoiceList implements ChoiceListInterface
{
- private ChoiceLoaderInterface $loader;
-
/**
* The callable creating string values for each choice.
*
@@ -43,11 +41,13 @@ class LazyChoiceList implements ChoiceListInterface
* The callable receives the choice as first and the array key as the second
* argument.
*
- * @param callable|null $value The callable generating the choice values
+ * @param callable|null $value The callable creating string values for each choice.
+ * If null, choices are cast to strings.
*/
- public function __construct(ChoiceLoaderInterface $loader, callable $value = null)
- {
- $this->loader = $loader;
+ public function __construct(
+ private ChoiceLoaderInterface $loader,
+ ?callable $value = null,
+ ) {
$this->value = null === $value ? null : $value(...);
}
diff --git a/src/Symfony/Component/Form/ChoiceList/Loader/AbstractChoiceLoader.php b/src/Symfony/Component/Form/ChoiceList/Loader/AbstractChoiceLoader.php
index c585a08a9fb47..749e2fbcef161 100644
--- a/src/Symfony/Component/Form/ChoiceList/Loader/AbstractChoiceLoader.php
+++ b/src/Symfony/Component/Form/ChoiceList/Loader/AbstractChoiceLoader.php
@@ -24,12 +24,12 @@ abstract class AbstractChoiceLoader implements ChoiceLoaderInterface
/**
* @final
*/
- public function loadChoiceList(callable $value = null): ChoiceListInterface
+ public function loadChoiceList(?callable $value = null): ChoiceListInterface
{
return new ArrayChoiceList($this->choices ??= $this->loadChoices(), $value);
}
- public function loadChoicesForValues(array $values, callable $value = null): array
+ public function loadChoicesForValues(array $values, ?callable $value = null): array
{
if (!$values) {
return [];
@@ -38,7 +38,7 @@ public function loadChoicesForValues(array $values, callable $value = null): arr
return $this->doLoadChoicesForValues($values, $value);
}
- public function loadValuesForChoices(array $choices, callable $value = null): array
+ public function loadValuesForChoices(array $choices, ?callable $value = null): array
{
if (!$choices) {
return [];
diff --git a/src/Symfony/Component/Form/ChoiceList/Loader/ChoiceLoaderInterface.php b/src/Symfony/Component/Form/ChoiceList/Loader/ChoiceLoaderInterface.php
index 85cc4bddaac98..d5f803c778629 100644
--- a/src/Symfony/Component/Form/ChoiceList/Loader/ChoiceLoaderInterface.php
+++ b/src/Symfony/Component/Form/ChoiceList/Loader/ChoiceLoaderInterface.php
@@ -34,7 +34,7 @@ interface ChoiceLoaderInterface
* @param callable|null $value The callable which generates the values
* from choices
*/
- public function loadChoiceList(callable $value = null): ChoiceListInterface;
+ public function loadChoiceList(?callable $value = null): ChoiceListInterface;
/**
* Loads the choices corresponding to the given values.
@@ -50,7 +50,7 @@ public function loadChoiceList(callable $value = null): ChoiceListInterface;
* values in this array are ignored
* @param callable|null $value The callable generating the choice values
*/
- public function loadChoicesForValues(array $values, callable $value = null): array;
+ public function loadChoicesForValues(array $values, ?callable $value = null): array;
/**
* Loads the values corresponding to the given choices.
@@ -68,5 +68,5 @@ public function loadChoicesForValues(array $values, callable $value = null): arr
*
* @return string[]
*/
- public function loadValuesForChoices(array $choices, callable $value = null): array;
+ public function loadValuesForChoices(array $choices, ?callable $value = null): array;
}
diff --git a/src/Symfony/Component/Form/ChoiceList/Loader/FilterChoiceLoaderDecorator.php b/src/Symfony/Component/Form/ChoiceList/Loader/FilterChoiceLoaderDecorator.php
index 069941c1e2234..393c73eba8fc1 100644
--- a/src/Symfony/Component/Form/ChoiceList/Loader/FilterChoiceLoaderDecorator.php
+++ b/src/Symfony/Component/Form/ChoiceList/Loader/FilterChoiceLoaderDecorator.php
@@ -52,12 +52,12 @@ protected function loadChoices(): iterable
return $choices ?? [];
}
- public function loadChoicesForValues(array $values, callable $value = null): array
+ public function loadChoicesForValues(array $values, ?callable $value = null): array
{
return array_filter($this->decoratedLoader->loadChoicesForValues($values, $value), $this->filter);
}
- public function loadValuesForChoices(array $choices, callable $value = null): array
+ public function loadValuesForChoices(array $choices, ?callable $value = null): array
{
return $this->decoratedLoader->loadValuesForChoices(array_filter($choices, $this->filter), $value);
}
diff --git a/src/Symfony/Component/Form/ChoiceList/Loader/IntlCallbackChoiceLoader.php b/src/Symfony/Component/Form/ChoiceList/Loader/IntlCallbackChoiceLoader.php
index 448320f9d9fa4..0931d3ef56398 100644
--- a/src/Symfony/Component/Form/ChoiceList/Loader/IntlCallbackChoiceLoader.php
+++ b/src/Symfony/Component/Form/ChoiceList/Loader/IntlCallbackChoiceLoader.php
@@ -19,12 +19,12 @@
*/
class IntlCallbackChoiceLoader extends CallbackChoiceLoader
{
- public function loadChoicesForValues(array $values, callable $value = null): array
+ public function loadChoicesForValues(array $values, ?callable $value = null): array
{
return parent::loadChoicesForValues(array_filter($values), $value);
}
- public function loadValuesForChoices(array $choices, callable $value = null): array
+ public function loadValuesForChoices(array $choices, ?callable $value = null): array
{
$choices = array_filter($choices);
diff --git a/src/Symfony/Component/Form/ChoiceList/View/ChoiceGroupView.php b/src/Symfony/Component/Form/ChoiceList/View/ChoiceGroupView.php
index 562515012c423..923fab2241069 100644
--- a/src/Symfony/Component/Form/ChoiceList/View/ChoiceGroupView.php
+++ b/src/Symfony/Component/Form/ChoiceList/View/ChoiceGroupView.php
@@ -20,18 +20,15 @@
*/
class ChoiceGroupView implements \IteratorAggregate
{
- public string $label;
- public array $choices;
-
/**
* Creates a new choice group view.
*
* @param array $choices the choice views in the group
*/
- public function __construct(string $label, array $choices = [])
- {
- $this->label = $label;
- $this->choices = $choices;
+ public function __construct(
+ public string $label,
+ public array $choices = [],
+ ) {
}
/**
diff --git a/src/Symfony/Component/Form/ChoiceList/View/ChoiceListView.php b/src/Symfony/Component/Form/ChoiceList/View/ChoiceListView.php
index 15afc4a8a5f6d..f64d10e761a43 100644
--- a/src/Symfony/Component/Form/ChoiceList/View/ChoiceListView.php
+++ b/src/Symfony/Component/Form/ChoiceList/View/ChoiceListView.php
@@ -22,19 +22,16 @@
*/
class ChoiceListView
{
- public array $choices;
- public array $preferredChoices;
-
/**
* Creates a new choice list view.
*
* @param array $choices The choice views
* @param array $preferredChoices the preferred choice views
*/
- public function __construct(array $choices = [], array $preferredChoices = [])
- {
- $this->choices = $choices;
- $this->preferredChoices = $preferredChoices;
+ public function __construct(
+ public array $choices = [],
+ public array $preferredChoices = [],
+ ) {
}
/**
diff --git a/src/Symfony/Component/Form/ChoiceList/View/ChoiceView.php b/src/Symfony/Component/Form/ChoiceList/View/ChoiceView.php
index 52587fd363b2b..d59a7c947b465 100644
--- a/src/Symfony/Component/Form/ChoiceList/View/ChoiceView.php
+++ b/src/Symfony/Component/Form/ChoiceList/View/ChoiceView.php
@@ -20,20 +20,6 @@
*/
class ChoiceView
{
- public string|TranslatableInterface|false $label;
- public string $value;
- public mixed $data;
-
- /**
- * Additional attributes for the HTML tag.
- */
- public array $attr;
-
- /**
- * Additional parameters used to translate the label.
- */
- public array $labelTranslationParameters;
-
/**
* Creates a new choice view.
*
@@ -43,12 +29,12 @@ class ChoiceView
* @param array $attr Additional attributes for the HTML tag
* @param array $labelTranslationParameters Additional parameters used to translate the label
*/
- public function __construct(mixed $data, string $value, string|TranslatableInterface|false $label, array $attr = [], array $labelTranslationParameters = [])
- {
- $this->data = $data;
- $this->value = $value;
- $this->label = $label;
- $this->attr = $attr;
- $this->labelTranslationParameters = $labelTranslationParameters;
+ public function __construct(
+ public mixed $data,
+ public string $value,
+ public string|TranslatableInterface|false $label,
+ public array $attr = [],
+ public array $labelTranslationParameters = [],
+ ) {
}
}
diff --git a/src/Symfony/Component/Form/Command/DebugCommand.php b/src/Symfony/Component/Form/Command/DebugCommand.php
index a208be3e5bf54..4d990122981b0 100644
--- a/src/Symfony/Component/Form/Command/DebugCommand.php
+++ b/src/Symfony/Component/Form/Command/DebugCommand.php
@@ -35,23 +35,15 @@
#[AsCommand(name: 'debug:form', description: 'Display form type information')]
class DebugCommand extends Command
{
- private FormRegistryInterface $formRegistry;
- private array $namespaces;
- private array $types;
- private array $extensions;
- private array $guessers;
- private ?FileLinkFormatter $fileLinkFormatter;
-
- public function __construct(FormRegistryInterface $formRegistry, array $namespaces = ['Symfony\Component\Form\Extension\Core\Type'], array $types = [], array $extensions = [], array $guessers = [], FileLinkFormatter $fileLinkFormatter = null)
- {
+ public function __construct(
+ private FormRegistryInterface $formRegistry,
+ private array $namespaces = ['Symfony\Component\Form\Extension\Core\Type'],
+ private array $types = [],
+ private array $extensions = [],
+ private array $guessers = [],
+ private ?FileLinkFormatter $fileLinkFormatter = null,
+ ) {
parent::__construct();
-
- $this->formRegistry = $formRegistry;
- $this->namespaces = $namespaces;
- $this->types = $types;
- $this->extensions = $extensions;
- $this->guessers = $guessers;
- $this->fileLinkFormatter = $fileLinkFormatter;
}
protected function configure(): void
diff --git a/src/Symfony/Component/Form/Console/Descriptor/TextDescriptor.php b/src/Symfony/Component/Form/Console/Descriptor/TextDescriptor.php
index 14003ab2767f4..7b723a0af6ecd 100644
--- a/src/Symfony/Component/Form/Console/Descriptor/TextDescriptor.php
+++ b/src/Symfony/Component/Form/Console/Descriptor/TextDescriptor.php
@@ -188,7 +188,7 @@ private function normalizeAndSortOptionsColumns(array $options): array
return $options;
}
- private function formatClassLink(string $class, string $text = null): string
+ private function formatClassLink(string $class, ?string $text = null): string
{
$text ??= $class;
diff --git a/src/Symfony/Component/Form/Console/Helper/DescriptorHelper.php b/src/Symfony/Component/Form/Console/Helper/DescriptorHelper.php
index 2f4b271636053..776b9eaa1ceb3 100644
--- a/src/Symfony/Component/Form/Console/Helper/DescriptorHelper.php
+++ b/src/Symfony/Component/Form/Console/Helper/DescriptorHelper.php
@@ -23,7 +23,7 @@
*/
class DescriptorHelper extends BaseDescriptorHelper
{
- public function __construct(FileLinkFormatter $fileLinkFormatter = null)
+ public function __construct(?FileLinkFormatter $fileLinkFormatter = null)
{
$this
->register('txt', new TextDescriptor($fileLinkFormatter))
diff --git a/src/Symfony/Component/Form/Exception/TransformationFailedException.php b/src/Symfony/Component/Form/Exception/TransformationFailedException.php
index ceb01f1a9a1b1..3973d70b468ad 100644
--- a/src/Symfony/Component/Form/Exception/TransformationFailedException.php
+++ b/src/Symfony/Component/Form/Exception/TransformationFailedException.php
@@ -21,7 +21,7 @@ class TransformationFailedException extends RuntimeException
private ?string $invalidMessage;
private array $invalidMessageParameters;
- public function __construct(string $message = '', int $code = 0, \Throwable $previous = null, string $invalidMessage = null, array $invalidMessageParameters = [])
+ public function __construct(string $message = '', int $code = 0, ?\Throwable $previous = null, ?string $invalidMessage = null, array $invalidMessageParameters = [])
{
parent::__construct($message, $code, $previous);
diff --git a/src/Symfony/Component/Form/Extension/Core/CoreExtension.php b/src/Symfony/Component/Form/Extension/Core/CoreExtension.php
index 951bf345c0c42..1640ed05246ac 100644
--- a/src/Symfony/Component/Form/Extension/Core/CoreExtension.php
+++ b/src/Symfony/Component/Form/Extension/Core/CoreExtension.php
@@ -30,13 +30,14 @@ class CoreExtension extends AbstractExtension
{
private PropertyAccessorInterface $propertyAccessor;
private ChoiceListFactoryInterface $choiceListFactory;
- private ?TranslatorInterface $translator;
- public function __construct(PropertyAccessorInterface $propertyAccessor = null, ChoiceListFactoryInterface $choiceListFactory = null, TranslatorInterface $translator = null)
- {
+ public function __construct(
+ ?PropertyAccessorInterface $propertyAccessor = null,
+ ?ChoiceListFactoryInterface $choiceListFactory = null,
+ private ?TranslatorInterface $translator = null,
+ ) {
$this->propertyAccessor = $propertyAccessor ?: PropertyAccess::createPropertyAccessor();
$this->choiceListFactory = $choiceListFactory ?? new CachingFactoryDecorator(new PropertyAccessDecorator(new DefaultChoiceListFactory(), $this->propertyAccessor));
- $this->translator = $translator;
}
protected function loadTypes(): array
diff --git a/src/Symfony/Component/Form/Extension/Core/DataAccessor/ChainAccessor.php b/src/Symfony/Component/Form/Extension/Core/DataAccessor/ChainAccessor.php
index ac600f16f0d1c..e7b9da09ea5a8 100644
--- a/src/Symfony/Component/Form/Extension/Core/DataAccessor/ChainAccessor.php
+++ b/src/Symfony/Component/Form/Extension/Core/DataAccessor/ChainAccessor.php
@@ -20,14 +20,12 @@
*/
class ChainAccessor implements DataAccessorInterface
{
- private iterable $accessors;
-
/**
* @param DataAccessorInterface[]|iterable $accessors
*/
- public function __construct(iterable $accessors)
- {
- $this->accessors = $accessors;
+ public function __construct(
+ private iterable $accessors,
+ ) {
}
public function getValue(object|array $data, FormInterface $form): mixed
diff --git a/src/Symfony/Component/Form/Extension/Core/DataAccessor/PropertyPathAccessor.php b/src/Symfony/Component/Form/Extension/Core/DataAccessor/PropertyPathAccessor.php
index e06f583cbd5a3..c845c10f6d89a 100644
--- a/src/Symfony/Component/Form/Extension/Core/DataAccessor/PropertyPathAccessor.php
+++ b/src/Symfony/Component/Form/Extension/Core/DataAccessor/PropertyPathAccessor.php
@@ -31,7 +31,7 @@ class PropertyPathAccessor implements DataAccessorInterface
{
private PropertyAccessorInterface $propertyAccessor;
- public function __construct(PropertyAccessorInterface $propertyAccessor = null)
+ public function __construct(?PropertyAccessorInterface $propertyAccessor = null)
{
$this->propertyAccessor = $propertyAccessor ?? PropertyAccess::createPropertyAccessor();
}
diff --git a/src/Symfony/Component/Form/Extension/Core/DataMapper/DataMapper.php b/src/Symfony/Component/Form/Extension/Core/DataMapper/DataMapper.php
index 0404af0844661..f27f9d14bff98 100644
--- a/src/Symfony/Component/Form/Extension/Core/DataMapper/DataMapper.php
+++ b/src/Symfony/Component/Form/Extension/Core/DataMapper/DataMapper.php
@@ -27,7 +27,7 @@ class DataMapper implements DataMapperInterface
{
private DataAccessorInterface $dataAccessor;
- public function __construct(DataAccessorInterface $dataAccessor = null)
+ public function __construct(?DataAccessorInterface $dataAccessor = null)
{
$this->dataAccessor = $dataAccessor ?? new ChainAccessor([
new CallbackAccessor(),
diff --git a/src/Symfony/Component/Form/Extension/Core/DataTransformer/ArrayToPartsTransformer.php b/src/Symfony/Component/Form/Extension/Core/DataTransformer/ArrayToPartsTransformer.php
index 9256c0a0948a7..828bd811e5d64 100644
--- a/src/Symfony/Component/Form/Extension/Core/DataTransformer/ArrayToPartsTransformer.php
+++ b/src/Symfony/Component/Form/Extension/Core/DataTransformer/ArrayToPartsTransformer.php
@@ -21,11 +21,9 @@
*/
class ArrayToPartsTransformer implements DataTransformerInterface
{
- private array $partMapping;
-
- public function __construct(array $partMapping)
- {
- $this->partMapping = $partMapping;
+ public function __construct(
+ private array $partMapping,
+ ) {
}
public function transform(mixed $array): mixed
diff --git a/src/Symfony/Component/Form/Extension/Core/DataTransformer/BaseDateTimeTransformer.php b/src/Symfony/Component/Form/Extension/Core/DataTransformer/BaseDateTimeTransformer.php
index d2a897471495b..8d311b3f8fa10 100644
--- a/src/Symfony/Component/Form/Extension/Core/DataTransformer/BaseDateTimeTransformer.php
+++ b/src/Symfony/Component/Form/Extension/Core/DataTransformer/BaseDateTimeTransformer.php
@@ -38,7 +38,7 @@ abstract class BaseDateTimeTransformer implements DataTransformerInterface
*
* @throws InvalidArgumentException if a timezone is not valid
*/
- public function __construct(string $inputTimezone = null, string $outputTimezone = null)
+ public function __construct(?string $inputTimezone = null, ?string $outputTimezone = null)
{
$this->inputTimezone = $inputTimezone ?: date_default_timezone_get();
$this->outputTimezone = $outputTimezone ?: date_default_timezone_get();
diff --git a/src/Symfony/Component/Form/Extension/Core/DataTransformer/ChoiceToValueTransformer.php b/src/Symfony/Component/Form/Extension/Core/DataTransformer/ChoiceToValueTransformer.php
index daec9d71953a6..52ee25e93ebfd 100644
--- a/src/Symfony/Component/Form/Extension/Core/DataTransformer/ChoiceToValueTransformer.php
+++ b/src/Symfony/Component/Form/Extension/Core/DataTransformer/ChoiceToValueTransformer.php
@@ -22,11 +22,9 @@
*/
class ChoiceToValueTransformer implements DataTransformerInterface
{
- private ChoiceListInterface $choiceList;
-
- public function __construct(ChoiceListInterface $choiceList)
- {
- $this->choiceList = $choiceList;
+ public function __construct(
+ private ChoiceListInterface $choiceList,
+ ) {
}
public function transform(mixed $choice): mixed
diff --git a/src/Symfony/Component/Form/Extension/Core/DataTransformer/ChoicesToValuesTransformer.php b/src/Symfony/Component/Form/Extension/Core/DataTransformer/ChoicesToValuesTransformer.php
index f284ff34f9234..aa223385494ba 100644
--- a/src/Symfony/Component/Form/Extension/Core/DataTransformer/ChoicesToValuesTransformer.php
+++ b/src/Symfony/Component/Form/Extension/Core/DataTransformer/ChoicesToValuesTransformer.php
@@ -22,11 +22,9 @@
*/
class ChoicesToValuesTransformer implements DataTransformerInterface
{
- private ChoiceListInterface $choiceList;
-
- public function __construct(ChoiceListInterface $choiceList)
- {
- $this->choiceList = $choiceList;
+ public function __construct(
+ private ChoiceListInterface $choiceList,
+ ) {
}
/**
diff --git a/src/Symfony/Component/Form/Extension/Core/DataTransformer/DataTransformerChain.php b/src/Symfony/Component/Form/Extension/Core/DataTransformer/DataTransformerChain.php
index ec5def469520a..e34be745565cc 100644
--- a/src/Symfony/Component/Form/Extension/Core/DataTransformer/DataTransformerChain.php
+++ b/src/Symfony/Component/Form/Extension/Core/DataTransformer/DataTransformerChain.php
@@ -21,16 +21,14 @@
*/
class DataTransformerChain implements DataTransformerInterface
{
- protected array $transformers;
-
/**
* Uses the given value transformers to transform values.
*
* @param DataTransformerInterface[] $transformers
*/
- public function __construct(array $transformers)
- {
- $this->transformers = $transformers;
+ public function __construct(
+ protected array $transformers,
+ ) {
}
/**
diff --git a/src/Symfony/Component/Form/Extension/Core/DataTransformer/DateIntervalToArrayTransformer.php b/src/Symfony/Component/Form/Extension/Core/DataTransformer/DateIntervalToArrayTransformer.php
index 8638e4a84235e..08c05859798b2 100644
--- a/src/Symfony/Component/Form/Extension/Core/DataTransformer/DateIntervalToArrayTransformer.php
+++ b/src/Symfony/Component/Form/Extension/Core/DataTransformer/DateIntervalToArrayTransformer.php
@@ -42,16 +42,16 @@ class DateIntervalToArrayTransformer implements DataTransformerInterface
self::INVERT => 'r',
];
private array $fields;
- private bool $pad;
/**
* @param string[]|null $fields The date fields
* @param bool $pad Whether to use padding
*/
- public function __construct(array $fields = null, bool $pad = false)
- {
+ public function __construct(
+ ?array $fields = null,
+ private bool $pad = false,
+ ) {
$this->fields = $fields ?? ['years', 'months', 'days', 'hours', 'minutes', 'seconds', 'invert'];
- $this->pad = $pad;
}
/**
diff --git a/src/Symfony/Component/Form/Extension/Core/DataTransformer/DateIntervalToStringTransformer.php b/src/Symfony/Component/Form/Extension/Core/DataTransformer/DateIntervalToStringTransformer.php
index 4160f8f34c06e..e1a3d97246227 100644
--- a/src/Symfony/Component/Form/Extension/Core/DataTransformer/DateIntervalToStringTransformer.php
+++ b/src/Symfony/Component/Form/Extension/Core/DataTransformer/DateIntervalToStringTransformer.php
@@ -24,8 +24,6 @@
*/
class DateIntervalToStringTransformer implements DataTransformerInterface
{
- private string $format;
-
/**
* Transforms a \DateInterval instance to a string.
*
@@ -33,9 +31,9 @@ class DateIntervalToStringTransformer implements DataTransformerInterface
*
* @param string $format The date format
*/
- public function __construct(string $format = 'P%yY%mM%dDT%hH%iM%sS')
- {
- $this->format = $format;
+ public function __construct(
+ private string $format = 'P%yY%mM%dDT%hH%iM%sS',
+ ) {
}
/**
diff --git a/src/Symfony/Component/Form/Extension/Core/DataTransformer/DateTimeToArrayTransformer.php b/src/Symfony/Component/Form/Extension/Core/DataTransformer/DateTimeToArrayTransformer.php
index 6675d1c24a590..8c3d2d2266aa8 100644
--- a/src/Symfony/Component/Form/Extension/Core/DataTransformer/DateTimeToArrayTransformer.php
+++ b/src/Symfony/Component/Form/Extension/Core/DataTransformer/DateTimeToArrayTransformer.php
@@ -23,7 +23,6 @@
*/
class DateTimeToArrayTransformer extends BaseDateTimeTransformer
{
- private bool $pad;
private array $fields;
private \DateTimeInterface $referenceDate;
@@ -33,12 +32,16 @@ class DateTimeToArrayTransformer extends BaseDateTimeTransformer
* @param string[]|null $fields The date fields
* @param bool $pad Whether to use padding
*/
- public function __construct(string $inputTimezone = null, string $outputTimezone = null, array $fields = null, bool $pad = false, \DateTimeInterface $referenceDate = null)
- {
+ public function __construct(
+ ?string $inputTimezone = null,
+ ?string $outputTimezone = null,
+ ?array $fields = null,
+ private bool $pad = false,
+ ?\DateTimeInterface $referenceDate = null,
+ ) {
parent::__construct($inputTimezone, $outputTimezone);
$this->fields = $fields ?? ['year', 'month', 'day', 'hour', 'minute', 'second'];
- $this->pad = $pad;
$this->referenceDate = $referenceDate ?? new \DateTimeImmutable('1970-01-01 00:00:00');
}
diff --git a/src/Symfony/Component/Form/Extension/Core/DataTransformer/DateTimeToHtml5LocalDateTimeTransformer.php b/src/Symfony/Component/Form/Extension/Core/DataTransformer/DateTimeToHtml5LocalDateTimeTransformer.php
index 2dc157cd83e9e..855b22a499ce2 100644
--- a/src/Symfony/Component/Form/Extension/Core/DataTransformer/DateTimeToHtml5LocalDateTimeTransformer.php
+++ b/src/Symfony/Component/Form/Extension/Core/DataTransformer/DateTimeToHtml5LocalDateTimeTransformer.php
@@ -25,7 +25,7 @@ class DateTimeToHtml5LocalDateTimeTransformer extends BaseDateTimeTransformer
public const HTML5_FORMAT = 'Y-m-d\\TH:i:s';
public const HTML5_FORMAT_NO_SECONDS = 'Y-m-d\\TH:i';
- public function __construct(string $inputTimezone = null, string $outputTimezone = null, private bool $withSeconds = false)
+ public function __construct(?string $inputTimezone = null, ?string $outputTimezone = null, private bool $withSeconds = false)
{
parent::__construct($inputTimezone, $outputTimezone);
}
diff --git a/src/Symfony/Component/Form/Extension/Core/DataTransformer/DateTimeToLocalizedStringTransformer.php b/src/Symfony/Component/Form/Extension/Core/DataTransformer/DateTimeToLocalizedStringTransformer.php
index 22a5d41b5f88b..b7ea092591d51 100644
--- a/src/Symfony/Component/Form/Extension/Core/DataTransformer/DateTimeToLocalizedStringTransformer.php
+++ b/src/Symfony/Component/Form/Extension/Core/DataTransformer/DateTimeToLocalizedStringTransformer.php
@@ -26,8 +26,6 @@ class DateTimeToLocalizedStringTransformer extends BaseDateTimeTransformer
{
private int $dateFormat;
private int $timeFormat;
- private ?string $pattern;
- private int $calendar;
/**
* @see BaseDateTimeTransformer::formats for available format options
@@ -41,8 +39,14 @@ class DateTimeToLocalizedStringTransformer extends BaseDateTimeTransformer
*
* @throws UnexpectedTypeException If a format is not supported or if a timezone is not a string
*/
- public function __construct(string $inputTimezone = null, string $outputTimezone = null, int $dateFormat = null, int $timeFormat = null, int $calendar = \IntlDateFormatter::GREGORIAN, string $pattern = null)
- {
+ public function __construct(
+ ?string $inputTimezone = null,
+ ?string $outputTimezone = null,
+ ?int $dateFormat = null,
+ ?int $timeFormat = null,
+ private int $calendar = \IntlDateFormatter::GREGORIAN,
+ private ?string $pattern = null,
+ ) {
parent::__construct($inputTimezone, $outputTimezone);
$dateFormat ??= \IntlDateFormatter::MEDIUM;
@@ -58,8 +62,6 @@ public function __construct(string $inputTimezone = null, string $outputTimezone
$this->dateFormat = $dateFormat;
$this->timeFormat = $timeFormat;
- $this->calendar = $calendar;
- $this->pattern = $pattern;
}
/**
diff --git a/src/Symfony/Component/Form/Extension/Core/DataTransformer/DateTimeToStringTransformer.php b/src/Symfony/Component/Form/Extension/Core/DataTransformer/DateTimeToStringTransformer.php
index ca0d2e59db120..77b1e75bd49a5 100644
--- a/src/Symfony/Component/Form/Extension/Core/DataTransformer/DateTimeToStringTransformer.php
+++ b/src/Symfony/Component/Form/Extension/Core/DataTransformer/DateTimeToStringTransformer.php
@@ -47,7 +47,7 @@ class DateTimeToStringTransformer extends BaseDateTimeTransformer
* @param string $format The date format
* @param string|null $parseFormat The parse format when different from $format
*/
- public function __construct(string $inputTimezone = null, string $outputTimezone = null, string $format = 'Y-m-d H:i:s', string $parseFormat = null)
+ public function __construct(?string $inputTimezone = null, ?string $outputTimezone = null, string $format = 'Y-m-d H:i:s', ?string $parseFormat = null)
{
parent::__construct($inputTimezone, $outputTimezone);
diff --git a/src/Symfony/Component/Form/Extension/Core/DataTransformer/DateTimeZoneToStringTransformer.php b/src/Symfony/Component/Form/Extension/Core/DataTransformer/DateTimeZoneToStringTransformer.php
index f7bda175118ba..50767f7a01a5b 100644
--- a/src/Symfony/Component/Form/Extension/Core/DataTransformer/DateTimeZoneToStringTransformer.php
+++ b/src/Symfony/Component/Form/Extension/Core/DataTransformer/DateTimeZoneToStringTransformer.php
@@ -23,11 +23,9 @@
*/
class DateTimeZoneToStringTransformer implements DataTransformerInterface
{
- private bool $multiple;
-
- public function __construct(bool $multiple = false)
- {
- $this->multiple = $multiple;
+ public function __construct(
+ private bool $multiple = false,
+ ) {
}
public function transform(mixed $dateTimeZone): mixed
diff --git a/src/Symfony/Component/Form/Extension/Core/DataTransformer/IntegerToLocalizedStringTransformer.php b/src/Symfony/Component/Form/Extension/Core/DataTransformer/IntegerToLocalizedStringTransformer.php
index ee41efc47e596..eb5a2d6ff18e6 100644
--- a/src/Symfony/Component/Form/Extension/Core/DataTransformer/IntegerToLocalizedStringTransformer.php
+++ b/src/Symfony/Component/Form/Extension/Core/DataTransformer/IntegerToLocalizedStringTransformer.php
@@ -28,7 +28,7 @@ class IntegerToLocalizedStringTransformer extends NumberToLocalizedStringTransfo
* @param int|null $roundingMode One of the ROUND_ constants in this class
* @param string|null $locale locale used for transforming
*/
- public function __construct(?bool $grouping = false, ?int $roundingMode = \NumberFormatter::ROUND_DOWN, string $locale = null)
+ public function __construct(?bool $grouping = false, ?int $roundingMode = \NumberFormatter::ROUND_DOWN, ?string $locale = null)
{
parent::__construct(0, $grouping, $roundingMode, $locale);
}
diff --git a/src/Symfony/Component/Form/Extension/Core/DataTransformer/IntlTimeZoneToStringTransformer.php b/src/Symfony/Component/Form/Extension/Core/DataTransformer/IntlTimeZoneToStringTransformer.php
index d379164a7a9af..446a95f7082bb 100644
--- a/src/Symfony/Component/Form/Extension/Core/DataTransformer/IntlTimeZoneToStringTransformer.php
+++ b/src/Symfony/Component/Form/Extension/Core/DataTransformer/IntlTimeZoneToStringTransformer.php
@@ -23,11 +23,9 @@
*/
class IntlTimeZoneToStringTransformer implements DataTransformerInterface
{
- private bool $multiple;
-
- public function __construct(bool $multiple = false)
- {
- $this->multiple = $multiple;
+ public function __construct(
+ private bool $multiple = false,
+ ) {
}
public function transform(mixed $intlTimeZone): mixed
diff --git a/src/Symfony/Component/Form/Extension/Core/DataTransformer/MoneyToLocalizedStringTransformer.php b/src/Symfony/Component/Form/Extension/Core/DataTransformer/MoneyToLocalizedStringTransformer.php
index 9a768e8979149..d9a75a2604c16 100644
--- a/src/Symfony/Component/Form/Extension/Core/DataTransformer/MoneyToLocalizedStringTransformer.php
+++ b/src/Symfony/Component/Form/Extension/Core/DataTransformer/MoneyToLocalizedStringTransformer.php
@@ -22,14 +22,18 @@
class MoneyToLocalizedStringTransformer extends NumberToLocalizedStringTransformer
{
private int $divisor;
- private string $modelType;
- public function __construct(?int $scale = 2, ?bool $grouping = true, ?int $roundingMode = \NumberFormatter::ROUND_HALFUP, ?int $divisor = 1, string $locale = null, string $modelType = 'float')
- {
+ public function __construct(
+ ?int $scale = 2,
+ ?bool $grouping = true,
+ ?int $roundingMode = \NumberFormatter::ROUND_HALFUP,
+ ?int $divisor = 1,
+ ?string $locale = null,
+ private string $modelType = 'float',
+ ) {
parent::__construct($scale ?? 2, $grouping ?? true, $roundingMode, $locale);
$this->divisor = $divisor ?? 1;
- $this->modelType = $modelType;
}
/**
diff --git a/src/Symfony/Component/Form/Extension/Core/DataTransformer/NumberToLocalizedStringTransformer.php b/src/Symfony/Component/Form/Extension/Core/DataTransformer/NumberToLocalizedStringTransformer.php
index 0693e79797599..6e1c495aeeaef 100644
--- a/src/Symfony/Component/Form/Extension/Core/DataTransformer/NumberToLocalizedStringTransformer.php
+++ b/src/Symfony/Component/Form/Extension/Core/DataTransformer/NumberToLocalizedStringTransformer.php
@@ -28,15 +28,14 @@ class NumberToLocalizedStringTransformer implements DataTransformerInterface
protected bool $grouping;
protected int $roundingMode;
- private ?int $scale;
- private ?string $locale;
-
- public function __construct(int $scale = null, ?bool $grouping = false, ?int $roundingMode = \NumberFormatter::ROUND_HALFUP, string $locale = null)
- {
- $this->scale = $scale;
+ public function __construct(
+ private ?int $scale = null,
+ ?bool $grouping = false,
+ ?int $roundingMode = \NumberFormatter::ROUND_HALFUP,
+ private ?string $locale = null,
+ ) {
$this->grouping = $grouping ?? false;
$this->roundingMode = $roundingMode ?? \NumberFormatter::ROUND_HALFUP;
- $this->locale = $locale;
}
/**
diff --git a/src/Symfony/Component/Form/Extension/Core/DataTransformer/PercentToLocalizedStringTransformer.php b/src/Symfony/Component/Form/Extension/Core/DataTransformer/PercentToLocalizedStringTransformer.php
index 98d62783c1c00..d4d8aad9d44ba 100644
--- a/src/Symfony/Component/Form/Extension/Core/DataTransformer/PercentToLocalizedStringTransformer.php
+++ b/src/Symfony/Component/Form/Extension/Core/DataTransformer/PercentToLocalizedStringTransformer.php
@@ -33,10 +33,8 @@ class PercentToLocalizedStringTransformer implements DataTransformerInterface
self::INTEGER,
];
- private int $roundingMode;
private string $type;
private int $scale;
- private bool $html5Format;
/**
* @see self::$types for a list of supported types
@@ -46,8 +44,12 @@ class PercentToLocalizedStringTransformer implements DataTransformerInterface
*
* @throws UnexpectedTypeException if the given value of type is unknown
*/
- public function __construct(int $scale = null, string $type = null, int $roundingMode = \NumberFormatter::ROUND_HALFUP, bool $html5Format = false)
- {
+ public function __construct(
+ ?int $scale = null,
+ ?string $type = null,
+ private int $roundingMode = \NumberFormatter::ROUND_HALFUP,
+ private bool $html5Format = false,
+ ) {
$type ??= self::FRACTIONAL;
if (!\in_array($type, self::$types, true)) {
@@ -56,8 +58,6 @@ public function __construct(int $scale = null, string $type = null, int $roundin
$this->type = $type;
$this->scale = $scale ?? 0;
- $this->roundingMode = $roundingMode;
- $this->html5Format = $html5Format;
}
/**
diff --git a/src/Symfony/Component/Form/Extension/Core/DataTransformer/StringToFloatTransformer.php b/src/Symfony/Component/Form/Extension/Core/DataTransformer/StringToFloatTransformer.php
index 09b5e51faf786..f47fcb625487a 100644
--- a/src/Symfony/Component/Form/Extension/Core/DataTransformer/StringToFloatTransformer.php
+++ b/src/Symfony/Component/Form/Extension/Core/DataTransformer/StringToFloatTransformer.php
@@ -19,11 +19,9 @@
*/
class StringToFloatTransformer implements DataTransformerInterface
{
- private ?int $scale;
-
- public function __construct(int $scale = null)
- {
- $this->scale = $scale;
+ public function __construct(
+ private ?int $scale = null,
+ ) {
}
public function transform(mixed $value): ?float
diff --git a/src/Symfony/Component/Form/Extension/Core/DataTransformer/ValueToDuplicatesTransformer.php b/src/Symfony/Component/Form/Extension/Core/DataTransformer/ValueToDuplicatesTransformer.php
index 2399abf73c7a3..9700b0424e269 100644
--- a/src/Symfony/Component/Form/Extension/Core/DataTransformer/ValueToDuplicatesTransformer.php
+++ b/src/Symfony/Component/Form/Extension/Core/DataTransformer/ValueToDuplicatesTransformer.php
@@ -21,11 +21,9 @@
*/
class ValueToDuplicatesTransformer implements DataTransformerInterface
{
- private array $keys;
-
- public function __construct(array $keys)
- {
- $this->keys = $keys;
+ public function __construct(
+ private array $keys,
+ ) {
}
/**
diff --git a/src/Symfony/Component/Form/Extension/Core/EventListener/FixUrlProtocolListener.php b/src/Symfony/Component/Form/Extension/Core/EventListener/FixUrlProtocolListener.php
index d648d6f508d24..97cd3ad474669 100644
--- a/src/Symfony/Component/Form/Extension/Core/EventListener/FixUrlProtocolListener.php
+++ b/src/Symfony/Component/Form/Extension/Core/EventListener/FixUrlProtocolListener.php
@@ -22,14 +22,12 @@
*/
class FixUrlProtocolListener implements EventSubscriberInterface
{
- private ?string $defaultProtocol;
-
/**
* @param string|null $defaultProtocol The URL scheme to add when there is none or null to not modify the data
*/
- public function __construct(?string $defaultProtocol = 'http')
- {
- $this->defaultProtocol = $defaultProtocol;
+ public function __construct(
+ private ?string $defaultProtocol = 'http',
+ ) {
}
public function onSubmit(FormEvent $event): void
diff --git a/src/Symfony/Component/Form/Extension/Core/EventListener/MergeCollectionListener.php b/src/Symfony/Component/Form/Extension/Core/EventListener/MergeCollectionListener.php
index 23ee47bd2fadb..61428d5dfaa40 100644
--- a/src/Symfony/Component/Form/Extension/Core/EventListener/MergeCollectionListener.php
+++ b/src/Symfony/Component/Form/Extension/Core/EventListener/MergeCollectionListener.php
@@ -21,17 +21,14 @@
*/
class MergeCollectionListener implements EventSubscriberInterface
{
- private bool $allowAdd;
- private bool $allowDelete;
-
/**
* @param bool $allowAdd Whether values might be added to the collection
* @param bool $allowDelete Whether values might be removed from the collection
*/
- public function __construct(bool $allowAdd = false, bool $allowDelete = false)
- {
- $this->allowAdd = $allowAdd;
- $this->allowDelete = $allowDelete;
+ public function __construct(
+ private bool $allowAdd = false,
+ private bool $allowDelete = false,
+ ) {
}
public static function getSubscribedEvents(): array
diff --git a/src/Symfony/Component/Form/Extension/Core/EventListener/ResizeFormListener.php b/src/Symfony/Component/Form/Extension/Core/EventListener/ResizeFormListener.php
index 641f16525770e..d67efab31e636 100644
--- a/src/Symfony/Component/Form/Extension/Core/EventListener/ResizeFormListener.php
+++ b/src/Symfony/Component/Form/Extension/Core/EventListener/ResizeFormListener.php
@@ -24,24 +24,21 @@
*/
class ResizeFormListener implements EventSubscriberInterface
{
- protected string $type;
- protected array $options;
protected array $prototypeOptions;
- protected bool $allowAdd;
- protected bool $allowDelete;
private \Closure|bool $deleteEmpty;
- private bool $keepAsList;
- public function __construct(string $type, array $options = [], bool $allowAdd = false, bool $allowDelete = false, bool|callable $deleteEmpty = false, array $prototypeOptions = null, bool $keepAsList = false)
- {
- $this->type = $type;
- $this->allowAdd = $allowAdd;
- $this->allowDelete = $allowDelete;
- $this->options = $options;
+ public function __construct(
+ private string $type,
+ private array $options = [],
+ private bool $allowAdd = false,
+ private bool $allowDelete = false,
+ bool|callable $deleteEmpty = false,
+ ?array $prototypeOptions = null,
+ private bool $keepAsList = false,
+ ) {
$this->deleteEmpty = \is_bool($deleteEmpty) ? $deleteEmpty : $deleteEmpty(...);
$this->prototypeOptions = $prototypeOptions ?? $options;
- $this->keepAsList = $keepAsList;
}
public static function getSubscribedEvents(): array
diff --git a/src/Symfony/Component/Form/Extension/Core/EventListener/TransformationFailureListener.php b/src/Symfony/Component/Form/Extension/Core/EventListener/TransformationFailureListener.php
index 570a285aae988..48f0b9ac9feed 100644
--- a/src/Symfony/Component/Form/Extension/Core/EventListener/TransformationFailureListener.php
+++ b/src/Symfony/Component/Form/Extension/Core/EventListener/TransformationFailureListener.php
@@ -22,11 +22,9 @@
*/
class TransformationFailureListener implements EventSubscriberInterface
{
- private ?TranslatorInterface $translator;
-
- public function __construct(TranslatorInterface $translator = null)
- {
- $this->translator = $translator;
+ public function __construct(
+ private ?TranslatorInterface $translator = null,
+ ) {
}
public static function getSubscribedEvents(): array
diff --git a/src/Symfony/Component/Form/Extension/Core/Type/ChoiceType.php b/src/Symfony/Component/Form/Extension/Core/Type/ChoiceType.php
index 711dc5af4541a..2e9cb7087fb53 100644
--- a/src/Symfony/Component/Form/Extension/Core/Type/ChoiceType.php
+++ b/src/Symfony/Component/Form/Extension/Core/Type/ChoiceType.php
@@ -53,7 +53,7 @@ class ChoiceType extends AbstractType
private ChoiceListFactoryInterface $choiceListFactory;
private ?TranslatorInterface $translator;
- public function __construct(ChoiceListFactoryInterface $choiceListFactory = null, TranslatorInterface $translator = null)
+ public function __construct(?ChoiceListFactoryInterface $choiceListFactory = null, ?TranslatorInterface $translator = null)
{
$this->choiceListFactory = $choiceListFactory ?? new CachingFactoryDecorator(
new PropertyAccessDecorator(
diff --git a/src/Symfony/Component/Form/Extension/Core/Type/ColorType.php b/src/Symfony/Component/Form/Extension/Core/Type/ColorType.php
index 476050fbee987..d67d6dc73b914 100644
--- a/src/Symfony/Component/Form/Extension/Core/Type/ColorType.php
+++ b/src/Symfony/Component/Form/Extension/Core/Type/ColorType.php
@@ -26,11 +26,9 @@ class ColorType extends AbstractType
*/
private const HTML5_PATTERN = '/^#[0-9a-f]{6}$/i';
- private ?TranslatorInterface $translator;
-
- public function __construct(TranslatorInterface $translator = null)
- {
- $this->translator = $translator;
+ public function __construct(
+ private ?TranslatorInterface $translator = null,
+ ) {
}
public function buildForm(FormBuilderInterface $builder, array $options): void
diff --git a/src/Symfony/Component/Form/Extension/Core/Type/FileType.php b/src/Symfony/Component/Form/Extension/Core/Type/FileType.php
index 948f897f68aa6..b4b4d86d9515c 100644
--- a/src/Symfony/Component/Form/Extension/Core/Type/FileType.php
+++ b/src/Symfony/Component/Form/Extension/Core/Type/FileType.php
@@ -35,11 +35,9 @@ class FileType extends AbstractType
self::MIB_BYTES => 'MiB',
];
- private ?TranslatorInterface $translator;
-
- public function __construct(TranslatorInterface $translator = null)
- {
- $this->translator = $translator;
+ public function __construct(
+ private ?TranslatorInterface $translator = null,
+ ) {
}
public function buildForm(FormBuilderInterface $builder, array $options): void
diff --git a/src/Symfony/Component/Form/Extension/Core/Type/FormType.php b/src/Symfony/Component/Form/Extension/Core/Type/FormType.php
index 889d0578669b3..9497bad365823 100644
--- a/src/Symfony/Component/Form/Extension/Core/Type/FormType.php
+++ b/src/Symfony/Component/Form/Extension/Core/Type/FormType.php
@@ -30,7 +30,7 @@ class FormType extends BaseType
{
private DataMapper $dataMapper;
- public function __construct(PropertyAccessorInterface $propertyAccessor = null)
+ public function __construct(?PropertyAccessorInterface $propertyAccessor = null)
{
$this->dataMapper = new DataMapper(new ChainAccessor([
new CallbackAccessor(),
diff --git a/src/Symfony/Component/Form/Extension/Core/Type/TimezoneType.php b/src/Symfony/Component/Form/Extension/Core/Type/TimezoneType.php
index 4b64fd881c511..01ce68ce372f9 100644
--- a/src/Symfony/Component/Form/Extension/Core/Type/TimezoneType.php
+++ b/src/Symfony/Component/Form/Extension/Core/Type/TimezoneType.php
@@ -106,7 +106,7 @@ private static function getPhpTimezones(string $input): array
return $timezones;
}
- private static function getIntlTimezones(string $input, string $locale = null): array
+ private static function getIntlTimezones(string $input, ?string $locale = null): array
{
$timezones = array_flip(Timezones::getNames($locale));
diff --git a/src/Symfony/Component/Form/Extension/Core/Type/TransformationFailureExtension.php b/src/Symfony/Component/Form/Extension/Core/Type/TransformationFailureExtension.php
index 5539e57f9f65c..e90cd714e8665 100644
--- a/src/Symfony/Component/Form/Extension/Core/Type/TransformationFailureExtension.php
+++ b/src/Symfony/Component/Form/Extension/Core/Type/TransformationFailureExtension.php
@@ -21,11 +21,9 @@
*/
class TransformationFailureExtension extends AbstractTypeExtension
{
- private ?TranslatorInterface $translator;
-
- public function __construct(TranslatorInterface $translator = null)
- {
- $this->translator = $translator;
+ public function __construct(
+ private ?TranslatorInterface $translator = null,
+ ) {
}
public function buildForm(FormBuilderInterface $builder, array $options): void
diff --git a/src/Symfony/Component/Form/Extension/Csrf/CsrfExtension.php b/src/Symfony/Component/Form/Extension/Csrf/CsrfExtension.php
index 026bed3604464..33c4616b4cf62 100644
--- a/src/Symfony/Component/Form/Extension/Csrf/CsrfExtension.php
+++ b/src/Symfony/Component/Form/Extension/Csrf/CsrfExtension.php
@@ -22,15 +22,11 @@
*/
class CsrfExtension extends AbstractExtension
{
- private CsrfTokenManagerInterface $tokenManager;
- private ?TranslatorInterface $translator;
- private ?string $translationDomain;
-
- public function __construct(CsrfTokenManagerInterface $tokenManager, TranslatorInterface $translator = null, string $translationDomain = null)
- {
- $this->tokenManager = $tokenManager;
- $this->translator = $translator;
- $this->translationDomain = $translationDomain;
+ public function __construct(
+ private CsrfTokenManagerInterface $tokenManager,
+ private ?TranslatorInterface $translator = null,
+ private ?string $translationDomain = null,
+ ) {
}
protected function loadTypeExtensions(): array
diff --git a/src/Symfony/Component/Form/Extension/Csrf/EventListener/CsrfValidationListener.php b/src/Symfony/Component/Form/Extension/Csrf/EventListener/CsrfValidationListener.php
index dab31fb65f6b0..5aac521c84d40 100644
--- a/src/Symfony/Component/Form/Extension/Csrf/EventListener/CsrfValidationListener.php
+++ b/src/Symfony/Component/Form/Extension/Csrf/EventListener/CsrfValidationListener.php
@@ -25,12 +25,6 @@
*/
class CsrfValidationListener implements EventSubscriberInterface
{
- private string $fieldName;
- private CsrfTokenManagerInterface $tokenManager;
- private string $tokenId;
- private string $errorMessage;
- private ?TranslatorInterface $translator;
- private ?string $translationDomain;
private ServerParams $serverParams;
public static function getSubscribedEvents(): array
@@ -40,14 +34,16 @@ public static function getSubscribedEvents(): array
];
}
- public function __construct(string $fieldName, CsrfTokenManagerInterface $tokenManager, string $tokenId, string $errorMessage, TranslatorInterface $translator = null, string $translationDomain = null, ServerParams $serverParams = null)
+ public function __construct(
+ private string $fieldName,
+ private CsrfTokenManagerInterface $tokenManager,
+ private string $tokenId,
+ private string $errorMessage,
+ private ?TranslatorInterface $translator = null,
+ private ?string $translationDomain = null,
+ ?ServerParams $serverParams = null,
+ )
{
- $this->fieldName = $fieldName;
- $this->tokenManager = $tokenManager;
- $this->tokenId = $tokenId;
- $this->errorMessage = $errorMessage;
- $this->translator = $translator;
- $this->translationDomain = $translationDomain;
$this->serverParams = $serverParams ?? new ServerParams();
}
diff --git a/src/Symfony/Component/Form/Extension/Csrf/Type/FormTypeCsrfExtension.php b/src/Symfony/Component/Form/Extension/Csrf/Type/FormTypeCsrfExtension.php
index 7096b8957d84a..0ad4daeb3c108 100644
--- a/src/Symfony/Component/Form/Extension/Csrf/Type/FormTypeCsrfExtension.php
+++ b/src/Symfony/Component/Form/Extension/Csrf/Type/FormTypeCsrfExtension.php
@@ -28,21 +28,14 @@
*/
class FormTypeCsrfExtension extends AbstractTypeExtension
{
- private CsrfTokenManagerInterface $defaultTokenManager;
- private bool $defaultEnabled;
- private string $defaultFieldName;
- private ?TranslatorInterface $translator;
- private ?string $translationDomain;
- private ?ServerParams $serverParams;
-
- public function __construct(CsrfTokenManagerInterface $defaultTokenManager, bool $defaultEnabled = true, string $defaultFieldName = '_token', TranslatorInterface $translator = null, string $translationDomain = null, ServerParams $serverParams = null)
- {
- $this->defaultTokenManager = $defaultTokenManager;
- $this->defaultEnabled = $defaultEnabled;
- $this->defaultFieldName = $defaultFieldName;
- $this->translator = $translator;
- $this->translationDomain = $translationDomain;
- $this->serverParams = $serverParams;
+ public function __construct(
+ private CsrfTokenManagerInterface $defaultTokenManager,
+ private bool $defaultEnabled = true,
+ private string $defaultFieldName = '_token',
+ private ?TranslatorInterface $translator = null,
+ private ?string $translationDomain = null,
+ private ?ServerParams $serverParams = null,
+ ) {
}
/**
diff --git a/src/Symfony/Component/Form/Extension/DataCollector/DataCollectorExtension.php b/src/Symfony/Component/Form/Extension/DataCollector/DataCollectorExtension.php
index 50b36bd67f073..9fb84224473b9 100644
--- a/src/Symfony/Component/Form/Extension/DataCollector/DataCollectorExtension.php
+++ b/src/Symfony/Component/Form/Extension/DataCollector/DataCollectorExtension.php
@@ -21,11 +21,9 @@
*/
class DataCollectorExtension extends AbstractExtension
{
- private FormDataCollectorInterface $dataCollector;
-
- public function __construct(FormDataCollectorInterface $dataCollector)
- {
- $this->dataCollector = $dataCollector;
+ public function __construct(
+ private FormDataCollectorInterface $dataCollector,
+ ) {
}
protected function loadTypeExtensions(): array
diff --git a/src/Symfony/Component/Form/Extension/DataCollector/EventListener/DataCollectorListener.php b/src/Symfony/Component/Form/Extension/DataCollector/EventListener/DataCollectorListener.php
index f32dc9bc7d493..02cffbeffed7e 100644
--- a/src/Symfony/Component/Form/Extension/DataCollector/EventListener/DataCollectorListener.php
+++ b/src/Symfony/Component/Form/Extension/DataCollector/EventListener/DataCollectorListener.php
@@ -24,11 +24,9 @@
*/
class DataCollectorListener implements EventSubscriberInterface
{
- private FormDataCollectorInterface $dataCollector;
-
- public function __construct(FormDataCollectorInterface $dataCollector)
- {
- $this->dataCollector = $dataCollector;
+ public function __construct(
+ private FormDataCollectorInterface $dataCollector,
+ ) {
}
public static function getSubscribedEvents(): array
diff --git a/src/Symfony/Component/Form/Extension/DataCollector/FormDataCollector.php b/src/Symfony/Component/Form/Extension/DataCollector/FormDataCollector.php
index dab72bb309ff5..348be44aaa394 100644
--- a/src/Symfony/Component/Form/Extension/DataCollector/FormDataCollector.php
+++ b/src/Symfony/Component/Form/Extension/DataCollector/FormDataCollector.php
@@ -33,8 +33,6 @@
*/
class FormDataCollector extends DataCollector implements FormDataCollectorInterface
{
- private FormDataExtractorInterface $dataExtractor;
-
/**
* Stores the collected data per {@link FormInterface} instance.
*
@@ -62,21 +60,20 @@ class FormDataCollector extends DataCollector implements FormDataCollectorInterf
*/
private array $formsByView;
- public function __construct(FormDataExtractorInterface $dataExtractor)
- {
+ public function __construct(
+ private FormDataExtractorInterface $dataExtractor,
+ ) {
if (!class_exists(ClassStub::class)) {
throw new \LogicException(sprintf('The VarDumper component is needed for using the "%s" class. Install symfony/var-dumper version 3.4 or above.', __CLASS__));
}
- $this->dataExtractor = $dataExtractor;
-
$this->reset();
}
/**
* Does nothing. The data is collected during the form event listeners.
*/
- public function collect(Request $request, Response $response, \Throwable $exception = null): void
+ public function collect(Request $request, Response $response, ?\Throwable $exception = null): void
{
}
diff --git a/src/Symfony/Component/Form/Extension/DataCollector/Proxy/ResolvedTypeDataCollectorProxy.php b/src/Symfony/Component/Form/Extension/DataCollector/Proxy/ResolvedTypeDataCollectorProxy.php
index 1e922ff2ea398..90e28a61fb5f3 100644
--- a/src/Symfony/Component/Form/Extension/DataCollector/Proxy/ResolvedTypeDataCollectorProxy.php
+++ b/src/Symfony/Component/Form/Extension/DataCollector/Proxy/ResolvedTypeDataCollectorProxy.php
@@ -27,13 +27,10 @@
*/
class ResolvedTypeDataCollectorProxy implements ResolvedFormTypeInterface
{
- private ResolvedFormTypeInterface $proxiedType;
- private FormDataCollectorInterface $dataCollector;
-
- public function __construct(ResolvedFormTypeInterface $proxiedType, FormDataCollectorInterface $dataCollector)
- {
- $this->proxiedType = $proxiedType;
- $this->dataCollector = $dataCollector;
+ public function __construct(
+ private ResolvedFormTypeInterface $proxiedType,
+ private FormDataCollectorInterface $dataCollector,
+ ) {
}
public function getBlockPrefix(): string
@@ -66,7 +63,7 @@ public function createBuilder(FormFactoryInterface $factory, string $name, array
return $builder;
}
- public function createView(FormInterface $form, FormView $parent = null): FormView
+ public function createView(FormInterface $form, ?FormView $parent = null): FormView
{
return $this->proxiedType->createView($form, $parent);
}
diff --git a/src/Symfony/Component/Form/Extension/DataCollector/Proxy/ResolvedTypeFactoryDataCollectorProxy.php b/src/Symfony/Component/Form/Extension/DataCollector/Proxy/ResolvedTypeFactoryDataCollectorProxy.php
index eea5bfd4aec00..a052a178294cf 100644
--- a/src/Symfony/Component/Form/Extension/DataCollector/Proxy/ResolvedTypeFactoryDataCollectorProxy.php
+++ b/src/Symfony/Component/Form/Extension/DataCollector/Proxy/ResolvedTypeFactoryDataCollectorProxy.php
@@ -24,16 +24,13 @@
*/
class ResolvedTypeFactoryDataCollectorProxy implements ResolvedFormTypeFactoryInterface
{
- private ResolvedFormTypeFactoryInterface $proxiedFactory;
- private FormDataCollectorInterface $dataCollector;
-
- public function __construct(ResolvedFormTypeFactoryInterface $proxiedFactory, FormDataCollectorInterface $dataCollector)
- {
- $this->proxiedFactory = $proxiedFactory;
- $this->dataCollector = $dataCollector;
+ public function __construct(
+ private ResolvedFormTypeFactoryInterface $proxiedFactory,
+ private FormDataCollectorInterface $dataCollector,
+ ) {
}
- public function createResolvedType(FormTypeInterface $type, array $typeExtensions, ResolvedFormTypeInterface $parent = null): ResolvedFormTypeInterface
+ public function createResolvedType(FormTypeInterface $type, array $typeExtensions, ?ResolvedFormTypeInterface $parent = null): ResolvedFormTypeInterface
{
return new ResolvedTypeDataCollectorProxy(
$this->proxiedFactory->createResolvedType($type, $typeExtensions, $parent),
diff --git a/src/Symfony/Component/Form/Extension/DependencyInjection/DependencyInjectionExtension.php b/src/Symfony/Component/Form/Extension/DependencyInjection/DependencyInjectionExtension.php
index 6564bd56574a8..420f26b743f94 100644
--- a/src/Symfony/Component/Form/Extension/DependencyInjection/DependencyInjectionExtension.php
+++ b/src/Symfony/Component/Form/Extension/DependencyInjection/DependencyInjectionExtension.php
@@ -23,18 +23,15 @@ class DependencyInjectionExtension implements FormExtensionInterface
{
private ?FormTypeGuesserChain $guesser = null;
private bool $guesserLoaded = false;
- private ContainerInterface $typeContainer;
- private array $typeExtensionServices;
- private iterable $guesserServices;
/**
* @param array> $typeExtensionServices
*/
- public function __construct(ContainerInterface $typeContainer, array $typeExtensionServices, iterable $guesserServices)
- {
- $this->typeContainer = $typeContainer;
- $this->typeExtensionServices = $typeExtensionServices;
- $this->guesserServices = $guesserServices;
+ public function __construct(
+ private ContainerInterface $typeContainer,
+ private array $typeExtensionServices,
+ private iterable $guesserServices,
+ ) {
}
public function getType(string $name): FormTypeInterface
diff --git a/src/Symfony/Component/Form/Extension/HttpFoundation/HttpFoundationRequestHandler.php b/src/Symfony/Component/Form/Extension/HttpFoundation/HttpFoundationRequestHandler.php
index a627232c90210..d7875e7b0d9a0 100644
--- a/src/Symfony/Component/Form/Extension/HttpFoundation/HttpFoundationRequestHandler.php
+++ b/src/Symfony/Component/Form/Extension/HttpFoundation/HttpFoundationRequestHandler.php
@@ -31,7 +31,7 @@ class HttpFoundationRequestHandler implements RequestHandlerInterface
{
private ServerParams $serverParams;
- public function __construct(ServerParams $serverParams = null)
+ public function __construct(?ServerParams $serverParams = null)
{
$this->serverParams = $serverParams ?? new ServerParams();
}
diff --git a/src/Symfony/Component/Form/Extension/HttpFoundation/Type/FormTypeHttpFoundationExtension.php b/src/Symfony/Component/Form/Extension/HttpFoundation/Type/FormTypeHttpFoundationExtension.php
index ce90c30528357..5139308bd723f 100644
--- a/src/Symfony/Component/Form/Extension/HttpFoundation/Type/FormTypeHttpFoundationExtension.php
+++ b/src/Symfony/Component/Form/Extension/HttpFoundation/Type/FormTypeHttpFoundationExtension.php
@@ -24,7 +24,7 @@ class FormTypeHttpFoundationExtension extends AbstractTypeExtension
{
private RequestHandlerInterface $requestHandler;
- public function __construct(RequestHandlerInterface $requestHandler = null)
+ public function __construct(?RequestHandlerInterface $requestHandler = null)
{
$this->requestHandler = $requestHandler ?? new HttpFoundationRequestHandler();
}
diff --git a/src/Symfony/Component/Form/Extension/Validator/EventListener/ValidationListener.php b/src/Symfony/Component/Form/Extension/Validator/EventListener/ValidationListener.php
index d24264f24496b..b3c16dbad23d4 100644
--- a/src/Symfony/Component/Form/Extension/Validator/EventListener/ValidationListener.php
+++ b/src/Symfony/Component/Form/Extension/Validator/EventListener/ValidationListener.php
@@ -23,18 +23,15 @@
*/
class ValidationListener implements EventSubscriberInterface
{
- private ValidatorInterface $validator;
- private ViolationMapperInterface $violationMapper;
-
public static function getSubscribedEvents(): array
{
return [FormEvents::POST_SUBMIT => 'validateForm'];
}
- public function __construct(ValidatorInterface $validator, ViolationMapperInterface $violationMapper)
- {
- $this->validator = $validator;
- $this->violationMapper = $violationMapper;
+ public function __construct(
+ private ValidatorInterface $validator,
+ private ViolationMapperInterface $violationMapper,
+ ) {
}
public function validateForm(FormEvent $event): void
diff --git a/src/Symfony/Component/Form/Extension/Validator/Type/FormTypeValidatorExtension.php b/src/Symfony/Component/Form/Extension/Validator/Type/FormTypeValidatorExtension.php
index e904a4f16ebb7..14029e339dcc8 100644
--- a/src/Symfony/Component/Form/Extension/Validator/Type/FormTypeValidatorExtension.php
+++ b/src/Symfony/Component/Form/Extension/Validator/Type/FormTypeValidatorExtension.php
@@ -27,13 +27,14 @@
*/
class FormTypeValidatorExtension extends BaseValidatorExtension
{
- private ValidatorInterface $validator;
private ViolationMapper $violationMapper;
- private bool $legacyErrorMessages;
- public function __construct(ValidatorInterface $validator, bool $legacyErrorMessages = true, FormRendererInterface $formRenderer = null, TranslatorInterface $translator = null)
- {
- $this->validator = $validator;
+ public function __construct(
+ private ValidatorInterface $validator,
+ private bool $legacyErrorMessages = true,
+ ?FormRendererInterface $formRenderer = null,
+ ?TranslatorInterface $translator = null,
+ ) {
$this->violationMapper = new ViolationMapper($formRenderer, $translator);
}
diff --git a/src/Symfony/Component/Form/Extension/Validator/Type/UploadValidatorExtension.php b/src/Symfony/Component/Form/Extension/Validator/Type/UploadValidatorExtension.php
index 80e3315ae9acb..7c1e965aba834 100644
--- a/src/Symfony/Component/Form/Extension/Validator/Type/UploadValidatorExtension.php
+++ b/src/Symfony/Component/Form/Extension/Validator/Type/UploadValidatorExtension.php
@@ -23,13 +23,10 @@
*/
class UploadValidatorExtension extends AbstractTypeExtension
{
- private TranslatorInterface $translator;
- private ?string $translationDomain;
-
- public function __construct(TranslatorInterface $translator, string $translationDomain = null)
- {
- $this->translator = $translator;
- $this->translationDomain = $translationDomain;
+ public function __construct(
+ private TranslatorInterface $translator,
+ private ?string $translationDomain = null,
+ ) {
}
public function configureOptions(OptionsResolver $resolver): void
diff --git a/src/Symfony/Component/Form/Extension/Validator/ValidatorExtension.php b/src/Symfony/Component/Form/Extension/Validator/ValidatorExtension.php
index fe1bd33f5f8d5..522a7696293f6 100644
--- a/src/Symfony/Component/Form/Extension/Validator/ValidatorExtension.php
+++ b/src/Symfony/Component/Form/Extension/Validator/ValidatorExtension.php
@@ -27,15 +27,12 @@
*/
class ValidatorExtension extends AbstractExtension
{
- private ValidatorInterface $validator;
- private ?FormRendererInterface $formRenderer;
- private ?TranslatorInterface $translator;
- private bool $legacyErrorMessages;
-
- public function __construct(ValidatorInterface $validator, bool $legacyErrorMessages = true, FormRendererInterface $formRenderer = null, TranslatorInterface $translator = null)
- {
- $this->legacyErrorMessages = $legacyErrorMessages;
-
+ public function __construct(
+ private ValidatorInterface $validator,
+ private bool $legacyErrorMessages = true,
+ private ?FormRendererInterface $formRenderer = null,
+ private ?TranslatorInterface $translator = null,
+ ) {
$metadata = $validator->getMetadataFor(\Symfony\Component\Form\Form::class);
// Register the form constraints in the validator programmatically.
@@ -46,10 +43,6 @@ public function __construct(ValidatorInterface $validator, bool $legacyErrorMess
/* @var $metadata ClassMetadata */
$metadata->addConstraint(new Form());
$metadata->addConstraint(new Traverse(false));
-
- $this->validator = $validator;
- $this->formRenderer = $formRenderer;
- $this->translator = $translator;
}
public function loadTypeGuesser(): ?FormTypeGuesserInterface
diff --git a/src/Symfony/Component/Form/Extension/Validator/ValidatorTypeGuesser.php b/src/Symfony/Component/Form/Extension/Validator/ValidatorTypeGuesser.php
index 57bccaa39f4e8..72ae8ddd5783a 100644
--- a/src/Symfony/Component/Form/Extension/Validator/ValidatorTypeGuesser.php
+++ b/src/Symfony/Component/Form/Extension/Validator/ValidatorTypeGuesser.php
@@ -57,11 +57,9 @@
class ValidatorTypeGuesser implements FormTypeGuesserInterface
{
- private MetadataFactoryInterface $metadataFactory;
-
- public function __construct(MetadataFactoryInterface $metadataFactory)
- {
- $this->metadataFactory = $metadataFactory;
+ public function __construct(
+ private MetadataFactoryInterface $metadataFactory,
+ ) {
}
public function guessType(string $class, string $property): ?TypeGuess
diff --git a/src/Symfony/Component/Form/Extension/Validator/ViolationMapper/MappingRule.php b/src/Symfony/Component/Form/Extension/Validator/ViolationMapper/MappingRule.php
index 6e33f222979f6..f9a61cc817965 100644
--- a/src/Symfony/Component/Form/Extension/Validator/ViolationMapper/MappingRule.php
+++ b/src/Symfony/Component/Form/Extension/Validator/ViolationMapper/MappingRule.php
@@ -19,15 +19,11 @@
*/
class MappingRule
{
- private FormInterface $origin;
- private string $propertyPath;
- private string $targetPath;
-
- public function __construct(FormInterface $origin, string $propertyPath, string $targetPath)
- {
- $this->origin = $origin;
- $this->propertyPath = $propertyPath;
- $this->targetPath = $targetPath;
+ public function __construct(
+ private FormInterface $origin,
+ private string $propertyPath,
+ private string $targetPath,
+ ) {
}
public function getOrigin(): FormInterface
diff --git a/src/Symfony/Component/Form/Extension/Validator/ViolationMapper/RelativePath.php b/src/Symfony/Component/Form/Extension/Validator/ViolationMapper/RelativePath.php
index 0384edb4449d7..dbf0712e2fa6b 100644
--- a/src/Symfony/Component/Form/Extension/Validator/ViolationMapper/RelativePath.php
+++ b/src/Symfony/Component/Form/Extension/Validator/ViolationMapper/RelativePath.php
@@ -19,13 +19,12 @@
*/
class RelativePath extends PropertyPath
{
- private FormInterface $root;
-
- public function __construct(FormInterface $root, string $propertyPath)
+ public function __construct(
+ private FormInterface $root,
+ string $propertyPath,
+ )
{
parent::__construct($propertyPath);
-
- $this->root = $root;
}
public function getRoot(): FormInterface
diff --git a/src/Symfony/Component/Form/Extension/Validator/ViolationMapper/ViolationMapper.php b/src/Symfony/Component/Form/Extension/Validator/ViolationMapper/ViolationMapper.php
index fca010d70e4bf..faca255b5dcbb 100644
--- a/src/Symfony/Component/Form/Extension/Validator/ViolationMapper/ViolationMapper.php
+++ b/src/Symfony/Component/Form/Extension/Validator/ViolationMapper/ViolationMapper.php
@@ -28,14 +28,12 @@
*/
class ViolationMapper implements ViolationMapperInterface
{
- private ?FormRendererInterface $formRenderer;
- private ?TranslatorInterface $translator;
private bool $allowNonSynchronized = false;
- public function __construct(FormRendererInterface $formRenderer = null, TranslatorInterface $translator = null)
- {
- $this->formRenderer = $formRenderer;
- $this->translator = $translator;
+ public function __construct(
+ private ?FormRendererInterface $formRenderer = null,
+ private ?TranslatorInterface $translator = null,
+ ) {
}
public function mapViolation(ConstraintViolation $violation, FormInterface $form, bool $allowNonSynchronized = false): void
diff --git a/src/Symfony/Component/Form/Form.php b/src/Symfony/Component/Form/Form.php
index 88c43766190a9..ee75311a14a10 100644
--- a/src/Symfony/Component/Form/Form.php
+++ b/src/Symfony/Component/Form/Form.php
@@ -70,7 +70,6 @@
*/
class Form implements \IteratorAggregate, FormInterface, ClearableErrorsInterface
{
- private FormConfigInterface $config;
private ?FormInterface $parent = null;
/**
@@ -135,8 +134,9 @@ class Form implements \IteratorAggregate, FormInterface, ClearableErrorsInterfac
/**
* @throws LogicException if a data mapper is not provided for a compound form
*/
- public function __construct(FormConfigInterface $config)
- {
+ public function __construct(
+ private FormConfigInterface $config,
+ ) {
// Compound forms always need a data mapper, otherwise calls to
// `setData` and `add` will not lead to the correct population of
// the child forms.
@@ -150,7 +150,6 @@ public function __construct(FormConfigInterface $config)
$this->defaultDataSet = true;
}
- $this->config = $config;
$this->children = new OrderedHashMap();
$this->name = $config->getName();
}
@@ -715,7 +714,7 @@ public function all(): array
return iterator_to_array($this->children);
}
- public function add(FormInterface|string $child, string $type = null, array $options = []): static
+ public function add(FormInterface|string $child, ?string $type = null, array $options = []): static
{
if ($this->submitted) {
throw new AlreadySubmittedException('You cannot add children to a submitted form.');
@@ -872,7 +871,7 @@ public function count(): int
return \count($this->children);
}
- public function createView(FormView $parent = null): FormView
+ public function createView(?FormView $parent = null): FormView
{
if (null === $parent && $this->parent) {
$parent = $this->parent->createView();
diff --git a/src/Symfony/Component/Form/FormBuilder.php b/src/Symfony/Component/Form/FormBuilder.php
index 816c38810fc39..58bc9c86d9476 100644
--- a/src/Symfony/Component/Form/FormBuilder.php
+++ b/src/Symfony/Component/Form/FormBuilder.php
@@ -44,7 +44,7 @@ public function __construct(?string $name, ?string $dataClass, EventDispatcherIn
$this->setFormFactory($factory);
}
- public function add(FormBuilderInterface|string $child, string $type = null, array $options = []): static
+ public function add(FormBuilderInterface|string $child, ?string $type = null, array $options = []): static
{
if ($this->locked) {
throw new BadMethodCallException('FormBuilder methods cannot be accessed anymore once the builder is turned into a FormConfigInterface instance.');
@@ -66,7 +66,7 @@ public function add(FormBuilderInterface|string $child, string $type = null, arr
return $this;
}
- public function create(string $name, string $type = null, array $options = []): FormBuilderInterface
+ public function create(string $name, ?string $type = null, array $options = []): FormBuilderInterface
{
if ($this->locked) {
throw new BadMethodCallException('FormBuilder methods cannot be accessed anymore once the builder is turned into a FormConfigInterface instance.');
diff --git a/src/Symfony/Component/Form/FormBuilderInterface.php b/src/Symfony/Component/Form/FormBuilderInterface.php
index c00fae46a5b95..08d29303c9ab4 100644
--- a/src/Symfony/Component/Form/FormBuilderInterface.php
+++ b/src/Symfony/Component/Form/FormBuilderInterface.php
@@ -27,7 +27,7 @@ interface FormBuilderInterface extends \Traversable, \Countable, FormConfigBuild
*
* @param array $options
*/
- public function add(string|self $child, string $type = null, array $options = []): static;
+ public function add(string|self $child, ?string $type = null, array $options = []): static;
/**
* Creates a form builder.
@@ -36,7 +36,7 @@ public function add(string|self $child, string $type = null, array $options = []
* @param string|null $type The type of the form or null if name is a property
* @param array $options
*/
- public function create(string $name, string $type = null, array $options = []): self;
+ public function create(string $name, ?string $type = null, array $options = []): self;
/**
* Returns a child by name.
diff --git a/src/Symfony/Component/Form/FormConfigBuilder.php b/src/Symfony/Component/Form/FormConfigBuilder.php
index 49aa89ab048e1..e0fb01dad96a9 100644
--- a/src/Symfony/Component/Form/FormConfigBuilder.php
+++ b/src/Symfony/Component/Form/FormConfigBuilder.php
@@ -33,7 +33,6 @@ class FormConfigBuilder implements FormConfigBuilderInterface
*/
private static NativeRequestHandler $nativeRequestHandler;
- private EventDispatcherInterface $dispatcher;
private string $name;
private ?PropertyPathInterface $propertyPath = null;
private bool $mapped = true;
@@ -57,7 +56,6 @@ class FormConfigBuilder implements FormConfigBuilderInterface
private string $method = 'POST';
private RequestHandlerInterface $requestHandler;
private bool $autoInitialize = false;
- private array $options;
private ?\Closure $isEmptyCallback = null;
/**
@@ -69,8 +67,12 @@ class FormConfigBuilder implements FormConfigBuilderInterface
* @throws InvalidArgumentException if the data class is not a valid class or if
* the name contains invalid characters
*/
- public function __construct(?string $name, ?string $dataClass, EventDispatcherInterface $dispatcher, array $options = [])
- {
+ public function __construct(
+ ?string $name,
+ ?string $dataClass,
+ private EventDispatcherInterface $dispatcher,
+ private array $options = [],
+ ) {
self::validateName($name);
if (null !== $dataClass && !class_exists($dataClass) && !interface_exists($dataClass, false)) {
@@ -79,8 +81,6 @@ public function __construct(?string $name, ?string $dataClass, EventDispatcherIn
$this->name = (string) $name;
$this->dataClass = $dataClass;
- $this->dispatcher = $dispatcher;
- $this->options = $options;
}
public function addEventListener(string $eventName, callable $listener, int $priority = 0): static
diff --git a/src/Symfony/Component/Form/FormError.php b/src/Symfony/Component/Form/FormError.php
index face43bcef850..335d9e21d3eb7 100644
--- a/src/Symfony/Component/Form/FormError.php
+++ b/src/Symfony/Component/Form/FormError.php
@@ -21,11 +21,6 @@
class FormError
{
protected string $messageTemplate;
- protected array $messageParameters;
- protected ?int $messagePluralization;
-
- private string $message;
- private mixed $cause;
/**
* The form that spawned this error.
@@ -45,13 +40,14 @@ class FormError
*
* @see \Symfony\Component\Translation\Translator
*/
- public function __construct(string $message, string $messageTemplate = null, array $messageParameters = [], int $messagePluralization = null, mixed $cause = null)
- {
- $this->message = $message;
+ public function __construct(
+ private string $message,
+ ?string $messageTemplate = null,
+ protected array $messageParameters = [],
+ protected ?int $messagePluralization = null,
+ private mixed $cause = null,
+ ) {
$this->messageTemplate = $messageTemplate ?: $message;
- $this->messageParameters = $messageParameters;
- $this->messagePluralization = $messagePluralization;
- $this->cause = $cause;
}
/**
diff --git a/src/Symfony/Component/Form/FormErrorIterator.php b/src/Symfony/Component/Form/FormErrorIterator.php
index 42de0c8358ef5..a614e72c2ee8a 100644
--- a/src/Symfony/Component/Form/FormErrorIterator.php
+++ b/src/Symfony/Component/Form/FormErrorIterator.php
@@ -42,8 +42,6 @@ class FormErrorIterator implements \RecursiveIterator, \SeekableIterator, \Array
*/
public const INDENTATION = ' ';
- private FormInterface $form;
-
/**
* @var list
*/
@@ -54,15 +52,16 @@ class FormErrorIterator implements \RecursiveIterator, \SeekableIterator, \Array
*
* @throws InvalidArgumentException If the errors are invalid
*/
- public function __construct(FormInterface $form, array $errors)
- {
+ public function __construct(
+ private FormInterface $form,
+ array $errors,
+ ) {
foreach ($errors as $error) {
if (!($error instanceof FormError || $error instanceof self)) {
throw new InvalidArgumentException(sprintf('The errors must be instances of "Symfony\Component\Form\FormError" or "%s". Got: "%s".', __CLASS__, get_debug_type($error)));
}
}
- $this->form = $form;
$this->errors = $errors;
}
diff --git a/src/Symfony/Component/Form/FormEvent.php b/src/Symfony/Component/Form/FormEvent.php
index e46fbb6a6aca3..e6a3878f6dccf 100644
--- a/src/Symfony/Component/Form/FormEvent.php
+++ b/src/Symfony/Component/Form/FormEvent.php
@@ -18,14 +18,10 @@
*/
class FormEvent extends Event
{
- protected mixed $data;
-
- private FormInterface $form;
-
- public function __construct(FormInterface $form, mixed $data)
- {
- $this->form = $form;
- $this->data = $data;
+ public function __construct(
+ private FormInterface $form,
+ protected mixed $data,
+ ) {
}
/**
diff --git a/src/Symfony/Component/Form/FormFactory.php b/src/Symfony/Component/Form/FormFactory.php
index 9e1234f8317c9..dcf7b36f28d02 100644
--- a/src/Symfony/Component/Form/FormFactory.php
+++ b/src/Symfony/Component/Form/FormFactory.php
@@ -16,11 +16,9 @@
class FormFactory implements FormFactoryInterface
{
- private FormRegistryInterface $registry;
-
- public function __construct(FormRegistryInterface $registry)
- {
- $this->registry = $registry;
+ public function __construct(
+ private FormRegistryInterface $registry,
+ ) {
}
public function create(string $type = FormType::class, mixed $data = null, array $options = []): FormInterface
diff --git a/src/Symfony/Component/Form/FormFactoryBuilder.php b/src/Symfony/Component/Form/FormFactoryBuilder.php
index 42b8dec9f42ea..90e3bf20ca87b 100644
--- a/src/Symfony/Component/Form/FormFactoryBuilder.php
+++ b/src/Symfony/Component/Form/FormFactoryBuilder.php
@@ -20,8 +20,6 @@
*/
class FormFactoryBuilder implements FormFactoryBuilderInterface
{
- private bool $forceCoreExtension;
-
private ResolvedFormTypeFactoryInterface $resolvedTypeFactory;
/**
@@ -44,9 +42,9 @@ class FormFactoryBuilder implements FormFactoryBuilderInterface
*/
private array $typeGuessers = [];
- public function __construct(bool $forceCoreExtension = false)
- {
- $this->forceCoreExtension = $forceCoreExtension;
+ public function __construct(
+ private bool $forceCoreExtension = false,
+ ) {
}
public function setResolvedTypeFactory(ResolvedFormTypeFactoryInterface $resolvedTypeFactory): static
diff --git a/src/Symfony/Component/Form/FormInterface.php b/src/Symfony/Component/Form/FormInterface.php
index a66cf420c95e9..23392c4931237 100644
--- a/src/Symfony/Component/Form/FormInterface.php
+++ b/src/Symfony/Component/Form/FormInterface.php
@@ -54,7 +54,7 @@ public function getParent(): ?self;
* @throws Exception\LogicException when trying to add a child to a non-compound form
* @throws Exception\UnexpectedTypeException if $child or $type has an unexpected type
*/
- public function add(self|string $child, string $type = null, array $options = []): static;
+ public function add(self|string $child, ?string $type = null, array $options = []): static;
/**
* Returns the child with the given name.
@@ -285,5 +285,5 @@ public function getRoot(): self;
*/
public function isRoot(): bool;
- public function createView(FormView $parent = null): FormView;
+ public function createView(?FormView $parent = null): FormView;
}
diff --git a/src/Symfony/Component/Form/FormRegistry.php b/src/Symfony/Component/Form/FormRegistry.php
index ab3f55f9fb908..95a0077378568 100644
--- a/src/Symfony/Component/Form/FormRegistry.php
+++ b/src/Symfony/Component/Form/FormRegistry.php
@@ -33,8 +33,7 @@ class FormRegistry implements FormRegistryInterface
*/
private array $types = [];
- private FormTypeGuesserInterface|null|false $guesser = false;
- private ResolvedFormTypeFactoryInterface $resolvedTypeFactory;
+ private FormTypeGuesserInterface|false|null $guesser = false;
private array $checkedTypes = [];
/**
@@ -42,8 +41,10 @@ class FormRegistry implements FormRegistryInterface
*
* @throws UnexpectedTypeException if any extension does not implement FormExtensionInterface
*/
- public function __construct(array $extensions, ResolvedFormTypeFactoryInterface $resolvedTypeFactory)
- {
+ public function __construct(
+ array $extensions,
+ private ResolvedFormTypeFactoryInterface $resolvedTypeFactory,
+ ) {
foreach ($extensions as $extension) {
if (!$extension instanceof FormExtensionInterface) {
throw new UnexpectedTypeException($extension, FormExtensionInterface::class);
@@ -51,7 +52,6 @@ public function __construct(array $extensions, ResolvedFormTypeFactoryInterface
}
$this->extensions = $extensions;
- $this->resolvedTypeFactory = $resolvedTypeFactory;
}
public function getType(string $name): ResolvedFormTypeInterface
diff --git a/src/Symfony/Component/Form/FormRenderer.php b/src/Symfony/Component/Form/FormRenderer.php
index c2771d28c9433..a9ffd4f41ed73 100644
--- a/src/Symfony/Component/Form/FormRenderer.php
+++ b/src/Symfony/Component/Form/FormRenderer.php
@@ -25,16 +25,14 @@ class FormRenderer implements FormRendererInterface
{
public const CACHE_KEY_VAR = 'unique_block_prefix';
- private FormRendererEngineInterface $engine;
- private ?CsrfTokenManagerInterface $csrfTokenManager;
private array $blockNameHierarchyMap = [];
private array $hierarchyLevelMap = [];
private array $variableStack = [];
- public function __construct(FormRendererEngineInterface $engine, CsrfTokenManagerInterface $csrfTokenManager = null)
- {
- $this->engine = $engine;
- $this->csrfTokenManager = $csrfTokenManager;
+ public function __construct(
+ private FormRendererEngineInterface $engine,
+ private ?CsrfTokenManagerInterface $csrfTokenManager = null,
+ ) {
}
public function getEngine(): FormRendererEngineInterface
diff --git a/src/Symfony/Component/Form/FormView.php b/src/Symfony/Component/Form/FormView.php
index e9e9e9957b3e4..93804bb8798e8 100644
--- a/src/Symfony/Component/Form/FormView.php
+++ b/src/Symfony/Component/Form/FormView.php
@@ -29,11 +29,6 @@ class FormView implements \ArrayAccess, \IteratorAggregate, \Countable
'attr' => [],
];
- /**
- * The parent view.
- */
- public ?self $parent = null;
-
/**
* The child views.
*
@@ -52,9 +47,12 @@ class FormView implements \ArrayAccess, \IteratorAggregate, \Countable
private bool $methodRendered = false;
- public function __construct(self $parent = null)
- {
- $this->parent = $parent;
+ /**
+ * @param FormView|null $parent The parent view
+ */
+ public function __construct(
+ public ?self $parent = null,
+ ) {
}
/**
diff --git a/src/Symfony/Component/Form/Guess/TypeGuess.php b/src/Symfony/Component/Form/Guess/TypeGuess.php
index 8ede78eb8cec6..b62873daa4f8d 100644
--- a/src/Symfony/Component/Form/Guess/TypeGuess.php
+++ b/src/Symfony/Component/Form/Guess/TypeGuess.php
@@ -19,9 +19,6 @@
*/
class TypeGuess extends Guess
{
- private string $type;
- private array $options;
-
/**
* @param string $type The guessed field type
* @param array $options The options for creating instances of the
@@ -29,12 +26,12 @@ class TypeGuess extends Guess
* @param int $confidence The confidence that the guessed class name
* is correct
*/
- public function __construct(string $type, array $options, int $confidence)
- {
+ public function __construct(
+ private string $type,
+ private array $options,
+ int $confidence,
+ ) {
parent::__construct($confidence);
-
- $this->type = $type;
- $this->options = $options;
}
/**
diff --git a/src/Symfony/Component/Form/Guess/ValueGuess.php b/src/Symfony/Component/Form/Guess/ValueGuess.php
index 36abe6602d723..2283287472ade 100644
--- a/src/Symfony/Component/Form/Guess/ValueGuess.php
+++ b/src/Symfony/Component/Form/Guess/ValueGuess.php
@@ -18,16 +18,14 @@
*/
class ValueGuess extends Guess
{
- private string|int|bool|null $value;
-
/**
* @param int $confidence The confidence that the guessed class name is correct
*/
- public function __construct(string|int|bool|null $value, int $confidence)
- {
+ public function __construct(
+ private string|int|bool|null $value,
+ int $confidence,
+ ) {
parent::__construct($confidence);
-
- $this->value = $value;
}
/**
diff --git a/src/Symfony/Component/Form/NativeRequestHandler.php b/src/Symfony/Component/Form/NativeRequestHandler.php
index 8c74bd1ded8ae..4c03df13d5865 100644
--- a/src/Symfony/Component/Form/NativeRequestHandler.php
+++ b/src/Symfony/Component/Form/NativeRequestHandler.php
@@ -36,7 +36,7 @@ class NativeRequestHandler implements RequestHandlerInterface
'type',
];
- public function __construct(ServerParams $params = null)
+ public function __construct(?ServerParams $params = null)
{
$this->serverParams = $params ?? new ServerParams();
}
diff --git a/src/Symfony/Component/Form/PreloadedExtension.php b/src/Symfony/Component/Form/PreloadedExtension.php
index c8e628d2d20e9..58d8f13b1b93c 100644
--- a/src/Symfony/Component/Form/PreloadedExtension.php
+++ b/src/Symfony/Component/Form/PreloadedExtension.php
@@ -21,8 +21,6 @@
class PreloadedExtension implements FormExtensionInterface
{
private array $types = [];
- private array $typeExtensions = [];
- private ?FormTypeGuesserInterface $typeGuesser;
/**
* Creates a new preloaded extension.
@@ -30,11 +28,11 @@ class PreloadedExtension implements FormExtensionInterface
* @param FormTypeInterface[] $types The types that the extension should support
* @param FormTypeExtensionInterface[][] $typeExtensions The type extensions that the extension should support
*/
- public function __construct(array $types, array $typeExtensions, FormTypeGuesserInterface $typeGuesser = null)
- {
- $this->typeExtensions = $typeExtensions;
- $this->typeGuesser = $typeGuesser;
-
+ public function __construct(
+ array $types,
+ private array $typeExtensions,
+ private ?FormTypeGuesserInterface $typeGuesser = null,
+ ) {
foreach ($types as $type) {
$this->types[$type::class] = $type;
}
diff --git a/src/Symfony/Component/Form/ResolvedFormType.php b/src/Symfony/Component/Form/ResolvedFormType.php
index 1acdce837567a..964619c396b38 100644
--- a/src/Symfony/Component/Form/ResolvedFormType.php
+++ b/src/Symfony/Component/Form/ResolvedFormType.php
@@ -23,31 +23,28 @@
*/
class ResolvedFormType implements ResolvedFormTypeInterface
{
- private FormTypeInterface $innerType;
-
/**
* @var FormTypeExtensionInterface[]
*/
private array $typeExtensions;
- private ?ResolvedFormTypeInterface $parent;
-
private OptionsResolver $optionsResolver;
/**
* @param FormTypeExtensionInterface[] $typeExtensions
*/
- public function __construct(FormTypeInterface $innerType, array $typeExtensions = [], ResolvedFormTypeInterface $parent = null)
- {
+ public function __construct(
+ private FormTypeInterface $innerType,
+ array $typeExtensions = [],
+ private ?ResolvedFormTypeInterface $parent = null,
+ ) {
foreach ($typeExtensions as $extension) {
if (!$extension instanceof FormTypeExtensionInterface) {
throw new UnexpectedTypeException($extension, FormTypeExtensionInterface::class);
}
}
- $this->innerType = $innerType;
$this->typeExtensions = $typeExtensions;
- $this->parent = $parent;
}
public function getBlockPrefix(): string
@@ -87,7 +84,7 @@ public function createBuilder(FormFactoryInterface $factory, string $name, array
return $builder;
}
- public function createView(FormInterface $form, FormView $parent = null): FormView
+ public function createView(FormInterface $form, ?FormView $parent = null): FormView
{
return $this->newView($parent);
}
@@ -168,7 +165,7 @@ protected function newBuilder(string $name, ?string $dataClass, FormFactoryInter
*
* Override this method if you want to customize the view class.
*/
- protected function newView(FormView $parent = null): FormView
+ protected function newView(?FormView $parent = null): FormView
{
return new FormView($parent);
}
diff --git a/src/Symfony/Component/Form/ResolvedFormTypeFactory.php b/src/Symfony/Component/Form/ResolvedFormTypeFactory.php
index fd7c4521b28a0..437f9c553ca62 100644
--- a/src/Symfony/Component/Form/ResolvedFormTypeFactory.php
+++ b/src/Symfony/Component/Form/ResolvedFormTypeFactory.php
@@ -16,7 +16,7 @@
*/
class ResolvedFormTypeFactory implements ResolvedFormTypeFactoryInterface
{
- public function createResolvedType(FormTypeInterface $type, array $typeExtensions, ResolvedFormTypeInterface $parent = null): ResolvedFormTypeInterface
+ public function createResolvedType(FormTypeInterface $type, array $typeExtensions, ?ResolvedFormTypeInterface $parent = null): ResolvedFormTypeInterface
{
return new ResolvedFormType($type, $typeExtensions, $parent);
}
diff --git a/src/Symfony/Component/Form/ResolvedFormTypeFactoryInterface.php b/src/Symfony/Component/Form/ResolvedFormTypeFactoryInterface.php
index 8d44f0d24c655..9fd39e7fe24f7 100644
--- a/src/Symfony/Component/Form/ResolvedFormTypeFactoryInterface.php
+++ b/src/Symfony/Component/Form/ResolvedFormTypeFactoryInterface.php
@@ -30,5 +30,5 @@ interface ResolvedFormTypeFactoryInterface
* @throws Exception\UnexpectedTypeException if the types parent {@link FormTypeInterface::getParent()} is not a string
* @throws Exception\InvalidArgumentException if the types parent cannot be retrieved from any extension
*/
- public function createResolvedType(FormTypeInterface $type, array $typeExtensions, ResolvedFormTypeInterface $parent = null): ResolvedFormTypeInterface;
+ public function createResolvedType(FormTypeInterface $type, array $typeExtensions, ?ResolvedFormTypeInterface $parent = null): ResolvedFormTypeInterface;
}
diff --git a/src/Symfony/Component/Form/ResolvedFormTypeInterface.php b/src/Symfony/Component/Form/ResolvedFormTypeInterface.php
index 821d4d4b4e7b8..690e0d7834684 100644
--- a/src/Symfony/Component/Form/ResolvedFormTypeInterface.php
+++ b/src/Symfony/Component/Form/ResolvedFormTypeInterface.php
@@ -52,7 +52,7 @@ public function createBuilder(FormFactoryInterface $factory, string $name, array
/**
* Creates a new form view for a form of this type.
*/
- public function createView(FormInterface $form, FormView $parent = null): FormView;
+ public function createView(FormInterface $form, ?FormView $parent = null): FormView;
/**
* Configures a form builder for the type hierarchy.
diff --git a/src/Symfony/Component/Form/ReversedTransformer.php b/src/Symfony/Component/Form/ReversedTransformer.php
index b68387908081c..4aa92450a24e2 100644
--- a/src/Symfony/Component/Form/ReversedTransformer.php
+++ b/src/Symfony/Component/Form/ReversedTransformer.php
@@ -21,11 +21,9 @@
*/
class ReversedTransformer implements DataTransformerInterface
{
- protected DataTransformerInterface $reversedTransformer;
-
- public function __construct(DataTransformerInterface $reversedTransformer)
- {
- $this->reversedTransformer = $reversedTransformer;
+ public function __construct(
+ protected DataTransformerInterface $reversedTransformer,
+ ) {
}
public function transform(mixed $value): mixed
diff --git a/src/Symfony/Component/Form/Tests/ChoiceList/Factory/DefaultChoiceListFactoryTest.php b/src/Symfony/Component/Form/Tests/ChoiceList/Factory/DefaultChoiceListFactoryTest.php
index 9973c62ae9a3c..e7bf26d1780d3 100644
--- a/src/Symfony/Component/Form/Tests/ChoiceList/Factory/DefaultChoiceListFactoryTest.php
+++ b/src/Symfony/Component/Form/Tests/ChoiceList/Factory/DefaultChoiceListFactoryTest.php
@@ -729,7 +729,7 @@ public function testPassTranslatableMessageAsLabelDoesntCastItToString()
public function testPassTranslatableInterfaceAsLabelDoesntCastItToString()
{
$message = new class() implements TranslatableInterface {
- public function trans(TranslatorInterface $translator, string $locale = null): string
+ public function trans(TranslatorInterface $translator, ?string $locale = null): string
{
return 'my_message';
}
diff --git a/src/Symfony/Component/Form/Tests/CompoundFormTest.php b/src/Symfony/Component/Form/Tests/CompoundFormTest.php
index 8cb4d53d944e9..882e73034c86b 100644
--- a/src/Symfony/Component/Form/Tests/CompoundFormTest.php
+++ b/src/Symfony/Component/Form/Tests/CompoundFormTest.php
@@ -1117,7 +1117,7 @@ private function createForm(string $name = 'name', bool $compound = true): FormI
return $builder->getForm();
}
- private function getBuilder(string $name = 'name', string $dataClass = null, array $options = []): FormBuilder
+ private function getBuilder(string $name = 'name', ?string $dataClass = null, array $options = []): FormBuilder
{
return new FormBuilder($name, $dataClass, new EventDispatcher(), $this->factory, $options);
}
diff --git a/src/Symfony/Component/Form/Tests/Extension/Core/DataTransformer/BaseDateTimeTransformerTestCase.php b/src/Symfony/Component/Form/Tests/Extension/Core/DataTransformer/BaseDateTimeTransformerTestCase.php
index 7e86f2c069118..8210b22930e50 100644
--- a/src/Symfony/Component/Form/Tests/Extension/Core/DataTransformer/BaseDateTimeTransformerTestCase.php
+++ b/src/Symfony/Component/Form/Tests/Extension/Core/DataTransformer/BaseDateTimeTransformerTestCase.php
@@ -31,5 +31,5 @@ public function testConstructFailsIfOutputTimezoneIsInvalid()
$this->createDateTimeTransformer(null, 'that_timezone_does_not_exist');
}
- abstract protected function createDateTimeTransformer(string $inputTimezone = null, string $outputTimezone = null): BaseDateTimeTransformer;
+ abstract protected function createDateTimeTransformer(?string $inputTimezone = null, ?string $outputTimezone = null): BaseDateTimeTransformer;
}
diff --git a/src/Symfony/Component/Form/Tests/Extension/Core/DataTransformer/DateTimeToArrayTransformerTest.php b/src/Symfony/Component/Form/Tests/Extension/Core/DataTransformer/DateTimeToArrayTransformerTest.php
index 08e05c58405f2..8ed6114f04cfc 100644
--- a/src/Symfony/Component/Form/Tests/Extension/Core/DataTransformer/DateTimeToArrayTransformerTest.php
+++ b/src/Symfony/Component/Form/Tests/Extension/Core/DataTransformer/DateTimeToArrayTransformerTest.php
@@ -536,7 +536,7 @@ public function testReverseTransformWithEmptyStringSecond()
]);
}
- protected function createDateTimeTransformer(string $inputTimezone = null, string $outputTimezone = null): BaseDateTimeTransformer
+ protected function createDateTimeTransformer(?string $inputTimezone = null, ?string $outputTimezone = null): BaseDateTimeTransformer
{
return new DateTimeToArrayTransformer($inputTimezone, $outputTimezone);
}
diff --git a/src/Symfony/Component/Form/Tests/Extension/Core/DataTransformer/DateTimeToHtml5LocalDateTimeTransformerTest.php b/src/Symfony/Component/Form/Tests/Extension/Core/DataTransformer/DateTimeToHtml5LocalDateTimeTransformerTest.php
index 0b33f1584b59e..f2fb15cf0b410 100644
--- a/src/Symfony/Component/Form/Tests/Extension/Core/DataTransformer/DateTimeToHtml5LocalDateTimeTransformerTest.php
+++ b/src/Symfony/Component/Form/Tests/Extension/Core/DataTransformer/DateTimeToHtml5LocalDateTimeTransformerTest.php
@@ -120,7 +120,7 @@ public function testReverseTransformExpectsValidDateString()
$transformer->reverseTransform('2010-2010-2010');
}
- protected function createDateTimeTransformer(string $inputTimezone = null, string $outputTimezone = null): BaseDateTimeTransformer
+ protected function createDateTimeTransformer(?string $inputTimezone = null, ?string $outputTimezone = null): BaseDateTimeTransformer
{
return new DateTimeToHtml5LocalDateTimeTransformer($inputTimezone, $outputTimezone);
}
diff --git a/src/Symfony/Component/Form/Tests/Extension/Core/DataTransformer/DateTimeToLocalizedStringTransformerTest.php b/src/Symfony/Component/Form/Tests/Extension/Core/DataTransformer/DateTimeToLocalizedStringTransformerTest.php
index 107d5513d6c03..47f21203251d6 100644
--- a/src/Symfony/Component/Form/Tests/Extension/Core/DataTransformer/DateTimeToLocalizedStringTransformerTest.php
+++ b/src/Symfony/Component/Form/Tests/Extension/Core/DataTransformer/DateTimeToLocalizedStringTransformerTest.php
@@ -371,7 +371,7 @@ public function testReverseTransformWrapsIntlErrorsWithExceptionsAndErrorLevel()
$transformer->reverseTransform('12345');
}
- protected function createDateTimeTransformer(string $inputTimezone = null, string $outputTimezone = null): BaseDateTimeTransformer
+ protected function createDateTimeTransformer(?string $inputTimezone = null, ?string $outputTimezone = null): BaseDateTimeTransformer
{
return new DateTimeToLocalizedStringTransformer($inputTimezone, $outputTimezone);
}
diff --git a/src/Symfony/Component/Form/Tests/Extension/Core/DataTransformer/DateTimeToRfc3339TransformerTest.php b/src/Symfony/Component/Form/Tests/Extension/Core/DataTransformer/DateTimeToRfc3339TransformerTest.php
index eec23c5d36cf4..6a4d77039f150 100644
--- a/src/Symfony/Component/Form/Tests/Extension/Core/DataTransformer/DateTimeToRfc3339TransformerTest.php
+++ b/src/Symfony/Component/Form/Tests/Extension/Core/DataTransformer/DateTimeToRfc3339TransformerTest.php
@@ -138,7 +138,7 @@ public static function invalidDateStringProvider(): array
];
}
- protected function createDateTimeTransformer(string $inputTimezone = null, string $outputTimezone = null): BaseDateTimeTransformer
+ protected function createDateTimeTransformer(?string $inputTimezone = null, ?string $outputTimezone = null): BaseDateTimeTransformer
{
return new DateTimeToRfc3339Transformer($inputTimezone, $outputTimezone);
}
diff --git a/src/Symfony/Component/Form/Tests/Extension/Core/DataTransformer/DateTimeToStringTransformerTest.php b/src/Symfony/Component/Form/Tests/Extension/Core/DataTransformer/DateTimeToStringTransformerTest.php
index 56ff98117aee9..66ad9ff416e26 100644
--- a/src/Symfony/Component/Form/Tests/Extension/Core/DataTransformer/DateTimeToStringTransformerTest.php
+++ b/src/Symfony/Component/Form/Tests/Extension/Core/DataTransformer/DateTimeToStringTransformerTest.php
@@ -171,7 +171,7 @@ public function testReverseTransformWithNonExistingDate()
$reverseTransformer->reverseTransform('2010-04-31');
}
- protected function createDateTimeTransformer(string $inputTimezone = null, string $outputTimezone = null): BaseDateTimeTransformer
+ protected function createDateTimeTransformer(?string $inputTimezone = null, ?string $outputTimezone = null): BaseDateTimeTransformer
{
return new DateTimeToStringTransformer($inputTimezone, $outputTimezone);
}
diff --git a/src/Symfony/Component/Form/Tests/Extension/Core/DataTransformer/DateTimeToTimestampTransformerTest.php b/src/Symfony/Component/Form/Tests/Extension/Core/DataTransformer/DateTimeToTimestampTransformerTest.php
index bf662d6464bef..183a7f9bd47d7 100644
--- a/src/Symfony/Component/Form/Tests/Extension/Core/DataTransformer/DateTimeToTimestampTransformerTest.php
+++ b/src/Symfony/Component/Form/Tests/Extension/Core/DataTransformer/DateTimeToTimestampTransformerTest.php
@@ -115,7 +115,7 @@ public function testReverseTransformExpectsValidTimestamp()
$reverseTransformer->reverseTransform('2010-2010-2010');
}
- protected function createDateTimeTransformer(string $inputTimezone = null, string $outputTimezone = null): BaseDateTimeTransformer
+ protected function createDateTimeTransformer(?string $inputTimezone = null, ?string $outputTimezone = null): BaseDateTimeTransformer
{
return new DateTimeToTimestampTransformer($inputTimezone, $outputTimezone);
}
diff --git a/src/Symfony/Component/Form/Tests/Extension/Core/DataTransformer/StringToFloatTransformerTest.php b/src/Symfony/Component/Form/Tests/Extension/Core/DataTransformer/StringToFloatTransformerTest.php
index 0ffb0b0ea8941..aaea8b2984d3e 100644
--- a/src/Symfony/Component/Form/Tests/Extension/Core/DataTransformer/StringToFloatTransformerTest.php
+++ b/src/Symfony/Component/Form/Tests/Extension/Core/DataTransformer/StringToFloatTransformerTest.php
@@ -71,7 +71,7 @@ public static function provideReverseTransformations(): array
/**
* @dataProvider provideReverseTransformations
*/
- public function testReverseTransform($from, $to, int $scale = null)
+ public function testReverseTransform($from, $to, ?int $scale = null)
{
$transformer = new StringToFloatTransformer($scale);
diff --git a/src/Symfony/Component/Form/Tests/Extension/Core/Type/CollectionTypeTest.php b/src/Symfony/Component/Form/Tests/Extension/Core/Type/CollectionTypeTest.php
index dd92b7c89e11d..08d512caf17ad 100644
--- a/src/Symfony/Component/Form/Tests/Extension/Core/Type/CollectionTypeTest.php
+++ b/src/Symfony/Component/Form/Tests/Extension/Core/Type/CollectionTypeTest.php
@@ -120,7 +120,7 @@ public function testResizedDownWithDeleteEmptyCallable()
$form = $this->factory->create(static::TESTED_TYPE, null, [
'entry_type' => AuthorType::class,
'allow_delete' => true,
- 'delete_empty' => fn (Author $obj = null) => null === $obj || empty($obj->firstName),
+ 'delete_empty' => fn (?Author $obj = null) => null === $obj || empty($obj->firstName),
]);
$form->setData([new Author('Bob'), new Author('Alice')]);
diff --git a/src/Symfony/Component/Form/Tests/Extension/Validator/Constraints/FormValidatorTest.php b/src/Symfony/Component/Form/Tests/Extension/Validator/Constraints/FormValidatorTest.php
index e26d31299c389..4e1588a9c7f74 100644
--- a/src/Symfony/Component/Form/Tests/Extension/Validator/Constraints/FormValidatorTest.php
+++ b/src/Symfony/Component/Form/Tests/Extension/Validator/Constraints/FormValidatorTest.php
@@ -707,7 +707,7 @@ protected function createValidator(): FormValidator
return new FormValidator();
}
- private function getBuilder(string $name = 'name', string $dataClass = null, array $options = []): FormBuilder
+ private function getBuilder(string $name = 'name', ?string $dataClass = null, array $options = []): FormBuilder
{
$options = array_replace([
'constraints' => [],
diff --git a/src/Symfony/Component/Form/Tests/SimpleFormTest.php b/src/Symfony/Component/Form/Tests/SimpleFormTest.php
index 83880600f81c8..7ded9b8535a0b 100644
--- a/src/Symfony/Component/Form/Tests/SimpleFormTest.php
+++ b/src/Symfony/Component/Form/Tests/SimpleFormTest.php
@@ -1128,7 +1128,7 @@ private function createForm(): FormInterface
return $this->getBuilder()->getForm();
}
- private function getBuilder(?string $name = 'name', string $dataClass = null, array $options = []): FormBuilder
+ private function getBuilder(?string $name = 'name', ?string $dataClass = null, array $options = []): FormBuilder
{
return new FormBuilder($name, $dataClass, new EventDispatcher(), new FormFactory(new FormRegistry([], new ResolvedFormTypeFactory())), $options);
}
diff --git a/src/Symfony/Component/Form/Util/OrderedHashMap.php b/src/Symfony/Component/Form/Util/OrderedHashMap.php
index 32d08caa8fb6e..c0cab7aac6049 100644
--- a/src/Symfony/Component/Form/Util/OrderedHashMap.php
+++ b/src/Symfony/Component/Form/Util/OrderedHashMap.php
@@ -71,13 +71,6 @@
*/
class OrderedHashMap implements \ArrayAccess, \IteratorAggregate, \Countable
{
- /**
- * The elements of the map, indexed by their keys.
- *
- * @var TValue[]
- */
- private array $elements = [];
-
/**
* The keys of the map in the order in which they were inserted or changed.
*
@@ -95,11 +88,11 @@ class OrderedHashMap implements \ArrayAccess, \IteratorAggregate, \Countable
/**
* Creates a new map.
*
- * @param TValue[] $elements The elements to insert initially
+ * @param TValue[] $elements The initial elements of the map, indexed by their keys.
*/
- public function __construct(array $elements = [])
- {
- $this->elements = $elements;
+ public function __construct(
+ private array $elements = [],
+ ) {
// the explicit string type-cast is necessary as digit-only keys would be returned as integers otherwise
$this->orderedKeys = array_map(strval(...), array_keys($elements));
}
diff --git a/src/Symfony/Component/Form/Util/OrderedHashMapIterator.php b/src/Symfony/Component/Form/Util/OrderedHashMapIterator.php
index 4a8eebe61d921..927a28c04a3a4 100644
--- a/src/Symfony/Component/Form/Util/OrderedHashMapIterator.php
+++ b/src/Symfony/Component/Form/Util/OrderedHashMapIterator.php
@@ -24,14 +24,8 @@
*/
class OrderedHashMapIterator implements \Iterator
{
- /** @var TValue[] */
- private array $elements;
- /** @var list */
- private array $orderedKeys;
private int $cursor = 0;
private int $cursorId;
- /** @var array */
- private array $managedCursors;
private ?string $key = null;
/** @var TValue|null */
private mixed $current = null;
@@ -47,11 +41,11 @@ class OrderedHashMapIterator implements \Iterator
* {@link OrderedHashMap} instance to support
* recognizing the deletion of elements.
*/
- public function __construct(array &$elements, array &$orderedKeys, array &$managedCursors)
- {
- $this->elements = &$elements;
- $this->orderedKeys = &$orderedKeys;
- $this->managedCursors = &$managedCursors;
+ public function __construct(
+ private array &$elements,
+ private array &$orderedKeys,
+ private array &$managedCursors,
+ ) {
$this->cursorId = \count($managedCursors);
$this->managedCursors[$this->cursorId] = &$this->cursor;
diff --git a/src/Symfony/Component/Form/Util/ServerParams.php b/src/Symfony/Component/Form/Util/ServerParams.php
index eb317ff36a439..2c23efcc88482 100644
--- a/src/Symfony/Component/Form/Util/ServerParams.php
+++ b/src/Symfony/Component/Form/Util/ServerParams.php
@@ -18,11 +18,9 @@
*/
class ServerParams
{
- private ?RequestStack $requestStack;
-
- public function __construct(RequestStack $requestStack = null)
- {
- $this->requestStack = $requestStack;
+ public function __construct(
+ private ?RequestStack $requestStack = null,
+ ) {
}
/**
diff --git a/src/Symfony/Component/HtmlSanitizer/HtmlSanitizer.php b/src/Symfony/Component/HtmlSanitizer/HtmlSanitizer.php
index ccc6f69379c3f..1147435a0409c 100644
--- a/src/Symfony/Component/HtmlSanitizer/HtmlSanitizer.php
+++ b/src/Symfony/Component/HtmlSanitizer/HtmlSanitizer.php
@@ -30,7 +30,7 @@ final class HtmlSanitizer implements HtmlSanitizerInterface
*/
private array $domVisitors = [];
- public function __construct(HtmlSanitizerConfig $config, ParserInterface $parser = null)
+ public function __construct(HtmlSanitizerConfig $config, ?ParserInterface $parser = null)
{
$this->config = $config;
$this->parser = $parser ?? new MastermindsParser();
diff --git a/src/Symfony/Component/HtmlSanitizer/TextSanitizer/UrlSanitizer.php b/src/Symfony/Component/HtmlSanitizer/TextSanitizer/UrlSanitizer.php
index c4643f7b24635..a806981de770f 100644
--- a/src/Symfony/Component/HtmlSanitizer/TextSanitizer/UrlSanitizer.php
+++ b/src/Symfony/Component/HtmlSanitizer/TextSanitizer/UrlSanitizer.php
@@ -29,7 +29,7 @@ final class UrlSanitizer
*
* It also transforms the URL to HTTPS if requested.
*/
- public static function sanitize(?string $input, array $allowedSchemes = null, bool $forceHttps = false, array $allowedHosts = null, bool $allowRelative = false): ?string
+ public static function sanitize(?string $input, ?array $allowedSchemes = null, bool $forceHttps = false, ?array $allowedHosts = null, bool $allowRelative = false): ?string
{
if (!$input) {
return null;
diff --git a/src/Symfony/Component/HttpClient/AmpHttpClient.php b/src/Symfony/Component/HttpClient/AmpHttpClient.php
index 341961ee7fa9e..f93aaa81eb065 100644
--- a/src/Symfony/Component/HttpClient/AmpHttpClient.php
+++ b/src/Symfony/Component/HttpClient/AmpHttpClient.php
@@ -64,7 +64,7 @@ final class AmpHttpClient implements HttpClientInterface, LoggerAwareInterface,
*
* @see HttpClientInterface::OPTIONS_DEFAULTS for available options
*/
- public function __construct(array $defaultOptions = [], callable $clientConfigurator = null, int $maxHostConnections = 6, int $maxPendingPushes = 50)
+ public function __construct(array $defaultOptions = [], ?callable $clientConfigurator = null, int $maxHostConnections = 6, int $maxPendingPushes = 50)
{
$this->defaultOptions['buffer'] ??= self::shouldBuffer(...);
@@ -148,7 +148,7 @@ public function request(string $method, string $url, array $options = []): Respo
return new AmpResponse($this->multi, $request, $options, $this->logger);
}
- public function stream(ResponseInterface|iterable $responses, float $timeout = null): ResponseStreamInterface
+ public function stream(ResponseInterface|iterable $responses, ?float $timeout = null): ResponseStreamInterface
{
if ($responses instanceof AmpResponse) {
$responses = [$responses];
diff --git a/src/Symfony/Component/HttpClient/AsyncDecoratorTrait.php b/src/Symfony/Component/HttpClient/AsyncDecoratorTrait.php
index 912b8250eacee..785c34a37d19c 100644
--- a/src/Symfony/Component/HttpClient/AsyncDecoratorTrait.php
+++ b/src/Symfony/Component/HttpClient/AsyncDecoratorTrait.php
@@ -30,7 +30,7 @@ trait AsyncDecoratorTrait
*/
abstract public function request(string $method, string $url, array $options = []): ResponseInterface;
- public function stream(ResponseInterface|iterable $responses, float $timeout = null): ResponseStreamInterface
+ public function stream(ResponseInterface|iterable $responses, ?float $timeout = null): ResponseStreamInterface
{
if ($responses instanceof AsyncResponse) {
$responses = [$responses];
diff --git a/src/Symfony/Component/HttpClient/CHANGELOG.md b/src/Symfony/Component/HttpClient/CHANGELOG.md
index 581247bbab847..0b6ceba0851c5 100644
--- a/src/Symfony/Component/HttpClient/CHANGELOG.md
+++ b/src/Symfony/Component/HttpClient/CHANGELOG.md
@@ -7,6 +7,7 @@ CHANGELOG
* Add `HttpOptions::setHeader()` to add or replace a single header
* Allow mocking `start_time` info in `MockResponse`
* Add `MockResponse::fromFile()` and `JsonMockResponse::fromFile()` methods to help using fixtures files
+ * Add `ThrottlingHttpClient` to enable limiting the number of requests within a certain period
7.0
---
diff --git a/src/Symfony/Component/HttpClient/CachingHttpClient.php b/src/Symfony/Component/HttpClient/CachingHttpClient.php
index 8940c6d3f47e5..fd6a18c3cc1b1 100644
--- a/src/Symfony/Component/HttpClient/CachingHttpClient.php
+++ b/src/Symfony/Component/HttpClient/CachingHttpClient.php
@@ -105,7 +105,7 @@ public function request(string $method, string $url, array $options = []): Respo
return MockResponse::fromRequest($method, $url, $options, $response);
}
- public function stream(ResponseInterface|iterable $responses, float $timeout = null): ResponseStreamInterface
+ public function stream(ResponseInterface|iterable $responses, ?float $timeout = null): ResponseStreamInterface
{
if ($responses instanceof ResponseInterface) {
$responses = [$responses];
diff --git a/src/Symfony/Component/HttpClient/Chunk/DataChunk.php b/src/Symfony/Component/HttpClient/Chunk/DataChunk.php
index 3507a0cd021d0..70f1b13bc59df 100644
--- a/src/Symfony/Component/HttpClient/Chunk/DataChunk.php
+++ b/src/Symfony/Component/HttpClient/Chunk/DataChunk.php
@@ -20,13 +20,10 @@
*/
class DataChunk implements ChunkInterface
{
- private int $offset = 0;
- private string $content = '';
-
- public function __construct(int $offset = 0, string $content = '')
- {
- $this->offset = $offset;
- $this->content = $content;
+ public function __construct(
+ private int $offset = 0,
+ private string $content = '',
+ ) {
}
public function isTimeout(): bool
diff --git a/src/Symfony/Component/HttpClient/Chunk/ErrorChunk.php b/src/Symfony/Component/HttpClient/Chunk/ErrorChunk.php
index 5584438595915..819056a9d83f3 100644
--- a/src/Symfony/Component/HttpClient/Chunk/ErrorChunk.php
+++ b/src/Symfony/Component/HttpClient/Chunk/ErrorChunk.php
@@ -23,14 +23,13 @@
class ErrorChunk implements ChunkInterface
{
private bool $didThrow = false;
- private int $offset;
private string $errorMessage;
private ?\Throwable $error = null;
- public function __construct(int $offset, \Throwable|string $error)
- {
- $this->offset = $offset;
-
+ public function __construct(
+ private int $offset,
+ \Throwable|string $error,
+ ) {
if (\is_string($error)) {
$this->errorMessage = $error;
} else {
@@ -84,7 +83,7 @@ public function getError(): ?string
return $this->errorMessage;
}
- public function didThrow(bool $didThrow = null): bool
+ public function didThrow(?bool $didThrow = null): bool
{
if (null !== $didThrow && $this->didThrow !== $didThrow) {
return !$this->didThrow = $didThrow;
diff --git a/src/Symfony/Component/HttpClient/CurlHttpClient.php b/src/Symfony/Component/HttpClient/CurlHttpClient.php
index 4817ffc794afa..f3bd513b1dbfe 100644
--- a/src/Symfony/Component/HttpClient/CurlHttpClient.php
+++ b/src/Symfony/Component/HttpClient/CurlHttpClient.php
@@ -317,7 +317,7 @@ public function request(string $method, string $url, array $options = []): Respo
return $pushedResponse ?? new CurlResponse($this->multi, $ch, $options, $this->logger, $method, self::createRedirectResolver($options, $host, $port), CurlClientState::$curlVersion['version_number'], $url);
}
- public function stream(ResponseInterface|iterable $responses, float $timeout = null): ResponseStreamInterface
+ public function stream(ResponseInterface|iterable $responses, ?float $timeout = null): ResponseStreamInterface
{
if ($responses instanceof CurlResponse) {
$responses = [$responses];
diff --git a/src/Symfony/Component/HttpClient/DataCollector/HttpClientDataCollector.php b/src/Symfony/Component/HttpClient/DataCollector/HttpClientDataCollector.php
index 58399890c2654..8e85462737e99 100644
--- a/src/Symfony/Component/HttpClient/DataCollector/HttpClientDataCollector.php
+++ b/src/Symfony/Component/HttpClient/DataCollector/HttpClientDataCollector.php
@@ -38,7 +38,7 @@ public function registerClient(string $name, TraceableHttpClient $client): void
$this->clients[$name] = $client;
}
- public function collect(Request $request, Response $response, \Throwable $exception = null): void
+ public function collect(Request $request, Response $response, ?\Throwable $exception = null): void
{
$this->lateCollect();
}
diff --git a/src/Symfony/Component/HttpClient/DecoratorTrait.php b/src/Symfony/Component/HttpClient/DecoratorTrait.php
index c100a733e8327..6fcb349243450 100644
--- a/src/Symfony/Component/HttpClient/DecoratorTrait.php
+++ b/src/Symfony/Component/HttpClient/DecoratorTrait.php
@@ -25,7 +25,7 @@ trait DecoratorTrait
{
private HttpClientInterface $client;
- public function __construct(HttpClientInterface $client = null)
+ public function __construct(?HttpClientInterface $client = null)
{
$this->client = $client ?? HttpClient::create();
}
@@ -35,7 +35,7 @@ public function request(string $method, string $url, array $options = []): Respo
return $this->client->request($method, $url, $options);
}
- public function stream(ResponseInterface|iterable $responses, float $timeout = null): ResponseStreamInterface
+ public function stream(ResponseInterface|iterable $responses, ?float $timeout = null): ResponseStreamInterface
{
return $this->client->stream($responses, $timeout);
}
diff --git a/src/Symfony/Component/HttpClient/EventSourceHttpClient.php b/src/Symfony/Component/HttpClient/EventSourceHttpClient.php
index 853657c770eff..80022eaf26653 100644
--- a/src/Symfony/Component/HttpClient/EventSourceHttpClient.php
+++ b/src/Symfony/Component/HttpClient/EventSourceHttpClient.php
@@ -33,7 +33,7 @@ final class EventSourceHttpClient implements HttpClientInterface, ResetInterface
private float $reconnectionTime;
- public function __construct(HttpClientInterface $client = null, float $reconnectionTime = 10.0)
+ public function __construct(?HttpClientInterface $client = null, float $reconnectionTime = 10.0)
{
$this->client = $client ?? HttpClient::create();
$this->reconnectionTime = $reconnectionTime;
diff --git a/src/Symfony/Component/HttpClient/HttpClientTrait.php b/src/Symfony/Component/HttpClient/HttpClientTrait.php
index 193efbff25567..85a1814032468 100644
--- a/src/Symfony/Component/HttpClient/HttpClientTrait.php
+++ b/src/Symfony/Component/HttpClient/HttpClientTrait.php
@@ -535,7 +535,7 @@ private static function normalizePeerFingerprint(mixed $fingerprint): array
/**
* @throws InvalidArgumentException When the value cannot be json-encoded
*/
- private static function jsonEncode(mixed $value, int $flags = null, int $maxDepth = 512): string
+ private static function jsonEncode(mixed $value, ?int $flags = null, int $maxDepth = 512): string
{
$flags ??= \JSON_HEX_TAG | \JSON_HEX_APOS | \JSON_HEX_AMP | \JSON_HEX_QUOT | \JSON_PRESERVE_ZERO_FRACTION;
diff --git a/src/Symfony/Component/HttpClient/HttplugClient.php b/src/Symfony/Component/HttpClient/HttplugClient.php
index 2652f15c7309c..67cf8273d9634 100644
--- a/src/Symfony/Component/HttpClient/HttplugClient.php
+++ b/src/Symfony/Component/HttpClient/HttplugClient.php
@@ -69,7 +69,7 @@ final class HttplugClient implements ClientInterface, HttpAsyncClient, RequestFa
private HttplugWaitLoop $waitLoop;
- public function __construct(HttpClientInterface $client = null, ResponseFactoryInterface $responseFactory = null, StreamFactoryInterface $streamFactory = null)
+ public function __construct(?HttpClientInterface $client = null, ?ResponseFactoryInterface $responseFactory = null, ?StreamFactoryInterface $streamFactory = null)
{
$this->client = $client ?? HttpClient::create();
$streamFactory ??= $responseFactory instanceof StreamFactoryInterface ? $responseFactory : null;
@@ -143,7 +143,7 @@ public function sendAsyncRequest(RequestInterface $request): HttplugPromise
*
* @return int The number of remaining pending promises
*/
- public function wait(float $maxDuration = null, float $idleTimeout = null): int
+ public function wait(?float $maxDuration = null, ?float $idleTimeout = null): int
{
return $this->waitLoop->wait(null, $maxDuration, $idleTimeout);
}
@@ -220,7 +220,7 @@ public function reset(): void
}
}
- private function sendPsr7Request(RequestInterface $request, bool $buffer = null): ResponseInterface
+ private function sendPsr7Request(RequestInterface $request, ?bool $buffer = null): ResponseInterface
{
try {
$body = $request->getBody();
diff --git a/src/Symfony/Component/HttpClient/Internal/AmpBody.php b/src/Symfony/Component/HttpClient/Internal/AmpBody.php
index bd995e17d8b81..abf8fbd177afb 100644
--- a/src/Symfony/Component/HttpClient/Internal/AmpBody.php
+++ b/src/Symfony/Component/HttpClient/Internal/AmpBody.php
@@ -27,7 +27,6 @@ class AmpBody implements RequestBody, InputStream
{
private ResourceInputStream|\Closure|string $body;
private array $info;
- private \Closure $onProgress;
private ?int $offset = 0;
private int $length = -1;
private ?int $uploaded = null;
@@ -35,10 +34,12 @@ class AmpBody implements RequestBody, InputStream
/**
* @param \Closure|resource|string $body
*/
- public function __construct($body, &$info, \Closure $onProgress)
- {
+ public function __construct(
+ $body,
+ &$info,
+ private \Closure $onProgress,
+ ) {
$this->info = &$info;
- $this->onProgress = $onProgress;
if (\is_resource($body)) {
$this->offset = ftell($body);
diff --git a/src/Symfony/Component/HttpClient/Internal/AmpClientState.php b/src/Symfony/Component/HttpClient/Internal/AmpClientState.php
index 90a002fe1a654..6c47854c05650 100644
--- a/src/Symfony/Component/HttpClient/Internal/AmpClientState.php
+++ b/src/Symfony/Component/HttpClient/Internal/AmpClientState.php
@@ -47,18 +47,15 @@ final class AmpClientState extends ClientState
private array $clients = [];
private \Closure $clientConfigurator;
- private int $maxHostConnections;
- private int $maxPendingPushes;
- private ?LoggerInterface $logger;
- public function __construct(?callable $clientConfigurator, int $maxHostConnections, int $maxPendingPushes, ?LoggerInterface &$logger)
- {
+ public function __construct(
+ ?callable $clientConfigurator,
+ private int $maxHostConnections,
+ private int $maxPendingPushes,
+ private ?LoggerInterface &$logger,
+ ) {
$clientConfigurator ??= static fn (PooledHttpClient $client) => new InterceptedHttpClient($client, new RetryRequests(2));
$this->clientConfigurator = $clientConfigurator(...);
-
- $this->maxHostConnections = $maxHostConnections;
- $this->maxPendingPushes = $maxPendingPushes;
- $this->logger = &$logger;
}
/**
@@ -150,7 +147,7 @@ private function getClient(array $options): array
/** @var resource|null */
public $handle;
- public function connect(string $uri, ConnectContext $context = null, CancellationToken $token = null): Promise
+ public function connect(string $uri, ?ConnectContext $context = null, ?CancellationToken $token = null): Promise
{
$result = $this->connector->connect($this->uri ?? $uri, $context, $token);
$result->onResolve(function ($e, $socket) {
diff --git a/src/Symfony/Component/HttpClient/Internal/AmpListener.php b/src/Symfony/Component/HttpClient/Internal/AmpListener.php
index 95c3bb0ed68f9..999742511beda 100644
--- a/src/Symfony/Component/HttpClient/Internal/AmpListener.php
+++ b/src/Symfony/Component/HttpClient/Internal/AmpListener.php
@@ -26,13 +26,16 @@
class AmpListener implements EventListener
{
private array $info;
- private array $pinSha256;
- private \Closure $onProgress;
- /** @var resource|null */
- private $handle;
- public function __construct(array &$info, array $pinSha256, \Closure $onProgress, &$handle)
- {
+ /**
+ * @param resource|null $handle
+ */
+ public function __construct(
+ array &$info,
+ private array $pinSha256,
+ private \Closure $onProgress,
+ private &$handle,
+ ) {
$info += [
'connect_time' => 0.0,
'pretransfer_time' => 0.0,
@@ -44,9 +47,6 @@ public function __construct(array &$info, array $pinSha256, \Closure $onProgress
];
$this->info = &$info;
- $this->pinSha256 = $pinSha256;
- $this->onProgress = $onProgress;
- $this->handle = &$handle;
}
public function startRequest(Request $request): Promise
diff --git a/src/Symfony/Component/HttpClient/Internal/AmpResolver.php b/src/Symfony/Component/HttpClient/Internal/AmpResolver.php
index 12880236fe56b..aff847524ecf2 100644
--- a/src/Symfony/Component/HttpClient/Internal/AmpResolver.php
+++ b/src/Symfony/Component/HttpClient/Internal/AmpResolver.php
@@ -25,14 +25,12 @@
*/
class AmpResolver implements Dns\Resolver
{
- private array $dnsMap;
-
- public function __construct(array &$dnsMap)
- {
- $this->dnsMap = &$dnsMap;
+ public function __construct(
+ private array &$dnsMap,
+ ) {
}
- public function resolve(string $name, int $typeRestriction = null): Promise
+ public function resolve(string $name, ?int $typeRestriction = null): Promise
{
if (!isset($this->dnsMap[$name]) || !\in_array($typeRestriction, [Record::A, null], true)) {
return Dns\resolver()->resolve($name, $typeRestriction);
diff --git a/src/Symfony/Component/HttpClient/Internal/Canary.php b/src/Symfony/Component/HttpClient/Internal/Canary.php
index b4438d94d0e37..69da0fc004bd7 100644
--- a/src/Symfony/Component/HttpClient/Internal/Canary.php
+++ b/src/Symfony/Component/HttpClient/Internal/Canary.php
@@ -18,11 +18,9 @@
*/
final class Canary
{
- private \Closure $canceller;
-
- public function __construct(\Closure $canceller)
- {
- $this->canceller = $canceller;
+ public function __construct(
+ private \Closure $canceller,
+ ) {
}
public function cancel(): void
diff --git a/src/Symfony/Component/HttpClient/Internal/HttplugWaitLoop.php b/src/Symfony/Component/HttpClient/Internal/HttplugWaitLoop.php
index eaccdb8c7cc65..aa172b89b160d 100644
--- a/src/Symfony/Component/HttpClient/Internal/HttplugWaitLoop.php
+++ b/src/Symfony/Component/HttpClient/Internal/HttplugWaitLoop.php
@@ -30,23 +30,18 @@
*/
final class HttplugWaitLoop
{
- private HttpClientInterface $client;
- private ?\SplObjectStorage $promisePool;
- private ResponseFactoryInterface $responseFactory;
- private StreamFactoryInterface $streamFactory;
-
/**
* @param \SplObjectStorage|null $promisePool
*/
- public function __construct(HttpClientInterface $client, ?\SplObjectStorage $promisePool, ResponseFactoryInterface $responseFactory, StreamFactoryInterface $streamFactory)
- {
- $this->client = $client;
- $this->promisePool = $promisePool;
- $this->responseFactory = $responseFactory;
- $this->streamFactory = $streamFactory;
+ public function __construct(
+ private HttpClientInterface $client,
+ private ?\SplObjectStorage $promisePool,
+ private ResponseFactoryInterface $responseFactory,
+ private StreamFactoryInterface $streamFactory,
+ ) {
}
- public function wait(?ResponseInterface $pendingResponse, float $maxDuration = null, float $idleTimeout = null): int
+ public function wait(?ResponseInterface $pendingResponse, ?float $maxDuration = null, ?float $idleTimeout = null): int
{
if (!$this->promisePool) {
return 0;
diff --git a/src/Symfony/Component/HttpClient/MockHttpClient.php b/src/Symfony/Component/HttpClient/MockHttpClient.php
index e4b6c96af918d..a0e08f940cdac 100644
--- a/src/Symfony/Component/HttpClient/MockHttpClient.php
+++ b/src/Symfony/Component/HttpClient/MockHttpClient.php
@@ -35,7 +35,7 @@ class MockHttpClient implements HttpClientInterface, ResetInterface
/**
* @param callable|callable[]|ResponseInterface|ResponseInterface[]|iterable|null $responseFactory
*/
- public function __construct(callable|iterable|ResponseInterface $responseFactory = null, ?string $baseUri = 'https://example.com')
+ public function __construct(callable|iterable|ResponseInterface|null $responseFactory = null, ?string $baseUri = 'https://example.com')
{
$this->setResponseFactory($responseFactory);
$this->defaultOptions['base_uri'] = $baseUri;
@@ -84,7 +84,7 @@ public function request(string $method, string $url, array $options = []): Respo
return MockResponse::fromRequest($method, $url, $options, $response);
}
- public function stream(ResponseInterface|iterable $responses, float $timeout = null): ResponseStreamInterface
+ public function stream(ResponseInterface|iterable $responses, ?float $timeout = null): ResponseStreamInterface
{
if ($responses instanceof ResponseInterface) {
$responses = [$responses];
diff --git a/src/Symfony/Component/HttpClient/NativeHttpClient.php b/src/Symfony/Component/HttpClient/NativeHttpClient.php
index ad6bfde5f4b58..68f1fc247763e 100644
--- a/src/Symfony/Component/HttpClient/NativeHttpClient.php
+++ b/src/Symfony/Component/HttpClient/NativeHttpClient.php
@@ -269,7 +269,7 @@ public function request(string $method, string $url, array $options = []): Respo
return new NativeResponse($this->multi, $context, implode('', $url), $options, $info, $resolver, $onProgress, $this->logger);
}
- public function stream(ResponseInterface|iterable $responses, float $timeout = null): ResponseStreamInterface
+ public function stream(ResponseInterface|iterable $responses, ?float $timeout = null): ResponseStreamInterface
{
if ($responses instanceof NativeResponse) {
$responses = [$responses];
diff --git a/src/Symfony/Component/HttpClient/NoPrivateNetworkHttpClient.php b/src/Symfony/Component/HttpClient/NoPrivateNetworkHttpClient.php
index 70c172f68678e..7bfe24db20330 100644
--- a/src/Symfony/Component/HttpClient/NoPrivateNetworkHttpClient.php
+++ b/src/Symfony/Component/HttpClient/NoPrivateNetworkHttpClient.php
@@ -37,7 +37,7 @@ final class NoPrivateNetworkHttpClient implements HttpClientInterface, LoggerAwa
* @param string|array|null $subnets String or array of subnets using CIDR notation that will be used by IpUtils.
* If null is passed, the standard private subnets will be used.
*/
- public function __construct(HttpClientInterface $client, string|array $subnets = null)
+ public function __construct(HttpClientInterface $client, string|array|null $subnets = null)
{
if (!class_exists(IpUtils::class)) {
throw new \LogicException(sprintf('You cannot use "%s" if the HttpFoundation component is not installed. Try running "composer require symfony/http-foundation".', __CLASS__));
@@ -72,7 +72,7 @@ public function request(string $method, string $url, array $options = []): Respo
return $this->client->request($method, $url, $options);
}
- public function stream(ResponseInterface|iterable $responses, float $timeout = null): ResponseStreamInterface
+ public function stream(ResponseInterface|iterable $responses, ?float $timeout = null): ResponseStreamInterface
{
return $this->client->stream($responses, $timeout);
}
diff --git a/src/Symfony/Component/HttpClient/Psr18Client.php b/src/Symfony/Component/HttpClient/Psr18Client.php
index 61201465db86c..d46a7b14d19a7 100644
--- a/src/Symfony/Component/HttpClient/Psr18Client.php
+++ b/src/Symfony/Component/HttpClient/Psr18Client.php
@@ -54,7 +54,7 @@ final class Psr18Client implements ClientInterface, RequestFactoryInterface, Str
private ResponseFactoryInterface $responseFactory;
private StreamFactoryInterface $streamFactory;
- public function __construct(HttpClientInterface $client = null, ResponseFactoryInterface $responseFactory = null, StreamFactoryInterface $streamFactory = null)
+ public function __construct(?HttpClientInterface $client = null, ?ResponseFactoryInterface $responseFactory = null, ?StreamFactoryInterface $streamFactory = null)
{
$this->client = $client ?? HttpClient::create();
$streamFactory ??= $responseFactory instanceof StreamFactoryInterface ? $responseFactory : null;
diff --git a/src/Symfony/Component/HttpClient/Response/AmpResponse.php b/src/Symfony/Component/HttpClient/Response/AmpResponse.php
index 6dfb9a01ece15..6f73c91b46af5 100644
--- a/src/Symfony/Component/HttpClient/Response/AmpResponse.php
+++ b/src/Symfony/Component/HttpClient/Response/AmpResponse.php
@@ -45,7 +45,6 @@ final class AmpResponse implements ResponseInterface, StreamableInterface
private static string $nextId = 'a';
- private AmpClientState $multi;
private ?array $options;
private \Closure $onProgress;
@@ -54,9 +53,12 @@ final class AmpResponse implements ResponseInterface, StreamableInterface
/**
* @internal
*/
- public function __construct(AmpClientState $multi, Request $request, array $options, ?LoggerInterface $logger)
- {
- $this->multi = $multi;
+ public function __construct(
+ private AmpClientState $multi,
+ Request $request,
+ array $options,
+ ?LoggerInterface $logger,
+ ) {
$this->options = &$options;
$this->logger = $logger;
$this->timeout = $options['timeout'];
@@ -134,7 +136,7 @@ public function __construct(AmpClientState $multi, Request $request, array $opti
});
}
- public function getInfo(string $type = null): mixed
+ public function getInfo(?string $type = null): mixed
{
return null !== $type ? $this->info[$type] ?? null : $this->info;
}
@@ -179,7 +181,7 @@ private static function schedule(self $response, array &$runningResponses): void
/**
* @param AmpClientState $multi
*/
- private static function perform(ClientState $multi, array &$responses = null): void
+ private static function perform(ClientState $multi, ?array &$responses = null): void
{
if ($responses) {
foreach ($responses as $response) {
diff --git a/src/Symfony/Component/HttpClient/Response/AsyncContext.php b/src/Symfony/Component/HttpClient/Response/AsyncContext.php
index eeb7a11ba0c45..4f4d10616c608 100644
--- a/src/Symfony/Component/HttpClient/Response/AsyncContext.php
+++ b/src/Symfony/Component/HttpClient/Response/AsyncContext.php
@@ -116,7 +116,7 @@ public function cancel(): ChunkInterface
/**
* Returns the current info of the response.
*/
- public function getInfo(string $type = null): mixed
+ public function getInfo(?string $type = null): mixed
{
if (null !== $type) {
return $this->info[$type] ?? $this->response->getInfo($type);
@@ -189,7 +189,7 @@ public function replaceResponse(ResponseInterface $response): ResponseInterface
*
* @param ?callable(ChunkInterface, self): ?\Iterator $passthru
*/
- public function passthru(callable $passthru = null): void
+ public function passthru(?callable $passthru = null): void
{
$this->passthru = $passthru ?? static function ($chunk, $context) {
$context->passthru = null;
diff --git a/src/Symfony/Component/HttpClient/Response/AsyncResponse.php b/src/Symfony/Component/HttpClient/Response/AsyncResponse.php
index 6f9791546d30b..ea27b1c4a120b 100644
--- a/src/Symfony/Component/HttpClient/Response/AsyncResponse.php
+++ b/src/Symfony/Component/HttpClient/Response/AsyncResponse.php
@@ -45,7 +45,7 @@ class AsyncResponse implements ResponseInterface, StreamableInterface
/**
* @param ?callable(ChunkInterface, AsyncContext): ?\Iterator $passthru
*/
- public function __construct(HttpClientInterface $client, string $method, string $url, array $options, callable $passthru = null)
+ public function __construct(HttpClientInterface $client, string $method, string $url, array $options, ?callable $passthru = null)
{
$this->client = $client;
$this->shouldBuffer = $options['buffer'] ?? true;
@@ -58,7 +58,7 @@ public function __construct(HttpClientInterface $client, string $method, string
}
$this->response = $client->request($method, $url, ['buffer' => false] + $options);
$this->passthru = $passthru;
- $this->initializer = static function (self $response, float $timeout = null) {
+ $this->initializer = static function (self $response, ?float $timeout = null) {
if (null === $response->shouldBuffer) {
return false;
}
@@ -66,7 +66,7 @@ public function __construct(HttpClientInterface $client, string $method, string
while (true) {
foreach (self::stream([$response], $timeout) as $chunk) {
if ($chunk->isTimeout() && $response->passthru) {
- foreach (self::passthru($response->client, $response, new ErrorChunk($response->offset, new TransportException($chunk->getError()))) as $chunk) {
+ foreach (self::passthru($response->client, $response, new ErrorChunk($response->offset, $chunk->getError())) as $chunk) {
if ($chunk->isFirst()) {
return false;
}
@@ -115,7 +115,7 @@ public function getHeaders(bool $throw = true): array
return $headers;
}
- public function getInfo(string $type = null): mixed
+ public function getInfo(?string $type = null): mixed
{
if (null !== $type) {
return $this->info[$type] ?? $this->response->getInfo($type);
@@ -207,7 +207,7 @@ public function __destruct()
/**
* @internal
*/
- public static function stream(iterable $responses, float $timeout = null, string $class = null): \Generator
+ public static function stream(iterable $responses, ?float $timeout = null, ?string $class = null): \Generator
{
while ($responses) {
$wrappedResponses = [];
@@ -315,7 +315,7 @@ public static function stream(iterable $responses, float $timeout = null, string
/**
* @param \SplObjectStorage|null $asyncMap
*/
- private static function passthru(HttpClientInterface $client, self $r, ChunkInterface $chunk, \SplObjectStorage $asyncMap = null): \Generator
+ private static function passthru(HttpClientInterface $client, self $r, ChunkInterface $chunk, ?\SplObjectStorage $asyncMap = null): \Generator
{
$r->stream = null;
$response = $r->response;
diff --git a/src/Symfony/Component/HttpClient/Response/CurlResponse.php b/src/Symfony/Component/HttpClient/Response/CurlResponse.php
index d472aca543554..8858342b7545a 100644
--- a/src/Symfony/Component/HttpClient/Response/CurlResponse.php
+++ b/src/Symfony/Component/HttpClient/Response/CurlResponse.php
@@ -32,8 +32,6 @@ final class CurlResponse implements ResponseInterface, StreamableInterface
}
use TransportResponseTrait;
- private CurlClientState $multi;
-
/**
* @var resource
*/
@@ -42,10 +40,16 @@ final class CurlResponse implements ResponseInterface, StreamableInterface
/**
* @internal
*/
- public function __construct(CurlClientState $multi, \CurlHandle|string $ch, array $options = null, LoggerInterface $logger = null, string $method = 'GET', callable $resolveRedirect = null, int $curlVersion = null, string $originalUrl = null)
- {
- $this->multi = $multi;
-
+ public function __construct(
+ private CurlClientState $multi,
+ \CurlHandle|string $ch,
+ ?array $options = null,
+ ?LoggerInterface $logger = null,
+ string $method = 'GET',
+ ?callable $resolveRedirect = null,
+ ?int $curlVersion = null,
+ ?string $originalUrl = null,
+ ) {
if ($ch instanceof \CurlHandle) {
$this->handle = $ch;
$this->debugBuffer = fopen('php://temp', 'w+');
@@ -98,7 +102,6 @@ public function __construct(CurlClientState $multi, \CurlHandle|string $ch, arra
$this->info['pause_handler'] = static function (float $duration) use ($ch, $multi, $execCounter) {
if (0 < $duration) {
if ($execCounter === $multi->execCounter) {
- $multi->execCounter = !\is_float($execCounter) ? 1 + $execCounter : \PHP_INT_MIN;
curl_multi_remove_handle($multi->handle, $ch);
}
@@ -193,7 +196,7 @@ public function __construct(CurlClientState $multi, \CurlHandle|string $ch, arra
});
}
- public function getInfo(string $type = null): mixed
+ public function getInfo(?string $type = null): mixed
{
if (!$info = $this->finalInfo) {
$info = array_merge($this->info, curl_getinfo($this->handle));
@@ -266,7 +269,7 @@ private static function schedule(self $response, array &$runningResponses): void
/**
* @param CurlClientState $multi
*/
- private static function perform(ClientState $multi, array &$responses = null): void
+ private static function perform(ClientState $multi, ?array &$responses = null): void
{
if ($multi->performing) {
if ($responses) {
diff --git a/src/Symfony/Component/HttpClient/Response/HttplugPromise.php b/src/Symfony/Component/HttpClient/Response/HttplugPromise.php
index e9dc24041e5fa..2ec04a18e7703 100644
--- a/src/Symfony/Component/HttpClient/Response/HttplugPromise.php
+++ b/src/Symfony/Component/HttpClient/Response/HttplugPromise.php
@@ -23,14 +23,12 @@
*/
final class HttplugPromise implements HttplugPromiseInterface
{
- private GuzzlePromiseInterface $promise;
-
- public function __construct(GuzzlePromiseInterface $promise)
- {
- $this->promise = $promise;
+ public function __construct(
+ private GuzzlePromiseInterface $promise,
+ ) {
}
- public function then(callable $onFulfilled = null, callable $onRejected = null): self
+ public function then(?callable $onFulfilled = null, ?callable $onRejected = null): self
{
return new self($this->promise->then(
$this->wrapThenCallback($onFulfilled),
diff --git a/src/Symfony/Component/HttpClient/Response/MockResponse.php b/src/Symfony/Component/HttpClient/Response/MockResponse.php
index 19041e3070ccd..f57311e385501 100644
--- a/src/Symfony/Component/HttpClient/Response/MockResponse.php
+++ b/src/Symfony/Component/HttpClient/Response/MockResponse.php
@@ -97,7 +97,7 @@ public function getRequestMethod(): string
return $this->requestMethod;
}
- public function getInfo(string $type = null): mixed
+ public function getInfo(?string $type = null): mixed
{
return null !== $type ? $this->info[$type] ?? null : $this->info;
}
diff --git a/src/Symfony/Component/HttpClient/Response/NativeResponse.php b/src/Symfony/Component/HttpClient/Response/NativeResponse.php
index 4d9e3e2176d82..af7b25f296769 100644
--- a/src/Symfony/Component/HttpClient/Response/NativeResponse.php
+++ b/src/Symfony/Component/HttpClient/Response/NativeResponse.php
@@ -29,11 +29,6 @@ final class NativeResponse implements ResponseInterface, StreamableInterface
use CommonResponseTrait;
use TransportResponseTrait;
- /**
- * @var resource
- */
- private $context;
- private string $url;
private \Closure $resolver;
private ?\Closure $onProgress;
private ?int $remaining = null;
@@ -43,18 +38,23 @@ final class NativeResponse implements ResponseInterface, StreamableInterface
*/
private $buffer;
- private NativeClientState $multi;
private float $pauseExpiry = 0.0;
/**
* @internal
+ * @param $context resource
*/
- public function __construct(NativeClientState $multi, $context, string $url, array $options, array &$info, callable $resolver, ?callable $onProgress, ?LoggerInterface $logger)
- {
- $this->multi = $multi;
+ public function __construct(
+ private NativeClientState $multi,
+ private $context,
+ private string $url,
+ array $options,
+ array &$info,
+ callable $resolver,
+ ?callable $onProgress,
+ ?LoggerInterface $logger,
+ ) {
$this->id = $id = (int) $context;
- $this->context = $context;
- $this->url = $url;
$this->logger = $logger;
$this->timeout = $options['timeout'];
$this->info = &$info;
@@ -86,7 +86,7 @@ public function __construct(NativeClientState $multi, $context, string $url, arr
});
}
- public function getInfo(string $type = null): mixed
+ public function getInfo(?string $type = null): mixed
{
if (!$info = $this->finalInfo) {
$info = $this->info;
@@ -228,7 +228,7 @@ private static function schedule(self $response, array &$runningResponses): void
/**
* @param NativeClientState $multi
*/
- private static function perform(ClientState $multi, array &$responses = null): void
+ private static function perform(ClientState $multi, ?array &$responses = null): void
{
foreach ($multi->openHandles as $i => [$pauseExpiry, $h, $buffer, $onProgress]) {
if ($pauseExpiry) {
diff --git a/src/Symfony/Component/HttpClient/Response/ResponseStream.php b/src/Symfony/Component/HttpClient/Response/ResponseStream.php
index 3fea27a77d02d..624b2f1e88e84 100644
--- a/src/Symfony/Component/HttpClient/Response/ResponseStream.php
+++ b/src/Symfony/Component/HttpClient/Response/ResponseStream.php
@@ -20,11 +20,9 @@
*/
final class ResponseStream implements ResponseStreamInterface
{
- private \Generator $generator;
-
- public function __construct(\Generator $generator)
- {
- $this->generator = $generator;
+ public function __construct(
+ private \Generator $generator,
+ ) {
}
public function key(): ResponseInterface
diff --git a/src/Symfony/Component/HttpClient/Response/StreamWrapper.php b/src/Symfony/Component/HttpClient/Response/StreamWrapper.php
index b5554a8ad2ced..50b99378494ab 100644
--- a/src/Symfony/Component/HttpClient/Response/StreamWrapper.php
+++ b/src/Symfony/Component/HttpClient/Response/StreamWrapper.php
@@ -45,7 +45,7 @@ class StreamWrapper
*
* @return resource
*/
- public static function createResource(ResponseInterface $response, HttpClientInterface $client = null)
+ public static function createResource(ResponseInterface $response, ?HttpClientInterface $client = null)
{
if ($response instanceof StreamableInterface) {
$stack = debug_backtrace(\DEBUG_BACKTRACE_PROVIDE_OBJECT | \DEBUG_BACKTRACE_IGNORE_ARGS, 2);
diff --git a/src/Symfony/Component/HttpClient/Response/TraceableResponse.php b/src/Symfony/Component/HttpClient/Response/TraceableResponse.php
index 4944e2525c11d..e382f2393cfdd 100644
--- a/src/Symfony/Component/HttpClient/Response/TraceableResponse.php
+++ b/src/Symfony/Component/HttpClient/Response/TraceableResponse.php
@@ -31,17 +31,12 @@
*/
class TraceableResponse implements ResponseInterface, StreamableInterface
{
- private HttpClientInterface $client;
- private ResponseInterface $response;
- private mixed $content;
- private ?StopwatchEvent $event;
-
- public function __construct(HttpClientInterface $client, ResponseInterface $response, &$content, StopwatchEvent $event = null)
- {
- $this->client = $client;
- $this->response = $response;
- $this->content = &$content;
- $this->event = $event;
+ public function __construct(
+ private HttpClientInterface $client,
+ private ResponseInterface $response,
+ private mixed &$content,
+ private ?StopwatchEvent $event = null,
+ ) {
}
public function __sleep(): array
@@ -134,7 +129,7 @@ public function cancel(): void
}
}
- public function getInfo(string $type = null): mixed
+ public function getInfo(?string $type = null): mixed
{
return $this->response->getInfo($type);
}
diff --git a/src/Symfony/Component/HttpClient/Response/TransportResponseTrait.php b/src/Symfony/Component/HttpClient/Response/TransportResponseTrait.php
index ca27178f96205..7b65fd7990464 100644
--- a/src/Symfony/Component/HttpClient/Response/TransportResponseTrait.php
+++ b/src/Symfony/Component/HttpClient/Response/TransportResponseTrait.php
@@ -139,7 +139,7 @@ private function doDestruct(): void
*
* @internal
*/
- public static function stream(iterable $responses, float $timeout = null): \Generator
+ public static function stream(iterable $responses, ?float $timeout = null): \Generator
{
$runningResponses = [];
diff --git a/src/Symfony/Component/HttpClient/Retry/GenericRetryStrategy.php b/src/Symfony/Component/HttpClient/Retry/GenericRetryStrategy.php
index ecfa5cd3c2748..95daf3b6c82b6 100644
--- a/src/Symfony/Component/HttpClient/Retry/GenericRetryStrategy.php
+++ b/src/Symfony/Component/HttpClient/Retry/GenericRetryStrategy.php
@@ -36,7 +36,6 @@ class GenericRetryStrategy implements RetryStrategyInterface
510 => self::IDEMPOTENT_METHODS,
];
- private array $statusCodes;
private int $delayMs;
private float $multiplier;
private int $maxDelayMs;
@@ -49,10 +48,13 @@ class GenericRetryStrategy implements RetryStrategyInterface
* @param int $maxDelayMs Maximum delay to allow (0 means no maximum)
* @param float $jitter Probability of randomness int delay (0 = none, 1 = 100% random)
*/
- public function __construct(array $statusCodes = self::DEFAULT_RETRY_STATUS_CODES, int $delayMs = 1000, float $multiplier = 2.0, int $maxDelayMs = 0, float $jitter = 0.1)
- {
- $this->statusCodes = $statusCodes;
-
+ public function __construct(
+ private array $statusCodes = self::DEFAULT_RETRY_STATUS_CODES,
+ int $delayMs = 1000,
+ float $multiplier = 2.0,
+ int $maxDelayMs = 0,
+ float $jitter = 0.1,
+ ) {
if ($delayMs < 0) {
throw new InvalidArgumentException(sprintf('Delay must be greater than or equal to zero: "%s" given.', $delayMs));
}
diff --git a/src/Symfony/Component/HttpClient/RetryableHttpClient.php b/src/Symfony/Component/HttpClient/RetryableHttpClient.php
index b506c9bccfa95..d3b779420ffa9 100644
--- a/src/Symfony/Component/HttpClient/RetryableHttpClient.php
+++ b/src/Symfony/Component/HttpClient/RetryableHttpClient.php
@@ -39,7 +39,7 @@ class RetryableHttpClient implements HttpClientInterface, ResetInterface
/**
* @param int $maxRetries The maximum number of times to retry
*/
- public function __construct(HttpClientInterface $client, RetryStrategyInterface $strategy = null, int $maxRetries = 3, LoggerInterface $logger = null)
+ public function __construct(HttpClientInterface $client, ?RetryStrategyInterface $strategy = null, int $maxRetries = 3, ?LoggerInterface $logger = null)
{
$this->client = $client;
$this->strategy = $strategy ?? new GenericRetryStrategy();
diff --git a/src/Symfony/Component/HttpClient/ScopingHttpClient.php b/src/Symfony/Component/HttpClient/ScopingHttpClient.php
index fd92a8520d48b..5734d3e4e7c5a 100644
--- a/src/Symfony/Component/HttpClient/ScopingHttpClient.php
+++ b/src/Symfony/Component/HttpClient/ScopingHttpClient.php
@@ -32,7 +32,7 @@ class ScopingHttpClient implements HttpClientInterface, ResetInterface, LoggerAw
private array $defaultOptionsByRegexp;
private ?string $defaultRegexp;
- public function __construct(HttpClientInterface $client, array $defaultOptionsByRegexp, string $defaultRegexp = null)
+ public function __construct(HttpClientInterface $client, array $defaultOptionsByRegexp, ?string $defaultRegexp = null)
{
$this->client = $client;
$this->defaultOptionsByRegexp = $defaultOptionsByRegexp;
@@ -43,7 +43,7 @@ public function __construct(HttpClientInterface $client, array $defaultOptionsBy
}
}
- public static function forBaseUri(HttpClientInterface $client, string $baseUri, array $defaultOptions = [], string $regexp = null): self
+ public static function forBaseUri(HttpClientInterface $client, string $baseUri, array $defaultOptions = [], ?string $regexp = null): self
{
$regexp ??= preg_quote(implode('', self::resolveUrl(self::parseUrl('.'), self::parseUrl($baseUri))));
@@ -88,7 +88,7 @@ public function request(string $method, string $url, array $options = []): Respo
return $this->client->request($method, $url, $options);
}
- public function stream(ResponseInterface|iterable $responses, float $timeout = null): ResponseStreamInterface
+ public function stream(ResponseInterface|iterable $responses, ?float $timeout = null): ResponseStreamInterface
{
return $this->client->stream($responses, $timeout);
}
diff --git a/src/Symfony/Component/HttpClient/Tests/AsyncDecoratorTraitTest.php b/src/Symfony/Component/HttpClient/Tests/AsyncDecoratorTraitTest.php
index e1c4b7ee34bff..97e4c42a0c79a 100644
--- a/src/Symfony/Component/HttpClient/Tests/AsyncDecoratorTraitTest.php
+++ b/src/Symfony/Component/HttpClient/Tests/AsyncDecoratorTraitTest.php
@@ -26,7 +26,7 @@
class AsyncDecoratorTraitTest extends NativeHttpClientTest
{
- protected function getHttpClient(string $testCase, \Closure $chunkFilter = null, HttpClientInterface $decoratedClient = null): HttpClientInterface
+ protected function getHttpClient(string $testCase, ?\Closure $chunkFilter = null, ?HttpClientInterface $decoratedClient = null): HttpClientInterface
{
if ('testHandleIsRemovedOnException' === $testCase) {
$this->markTestSkipped("AsyncDecoratorTrait doesn't cache handles");
@@ -43,7 +43,7 @@ protected function getHttpClient(string $testCase, \Closure $chunkFilter = null,
private ?\Closure $chunkFilter;
- public function __construct(HttpClientInterface $client, \Closure $chunkFilter = null)
+ public function __construct(HttpClientInterface $client, ?\Closure $chunkFilter = null)
{
$this->chunkFilter = $chunkFilter;
$this->client = $client;
diff --git a/src/Symfony/Component/HttpClient/Tests/RetryableHttpClientTest.php b/src/Symfony/Component/HttpClient/Tests/RetryableHttpClientTest.php
index fcd839da18c67..849d4119f4ae8 100644
--- a/src/Symfony/Component/HttpClient/Tests/RetryableHttpClientTest.php
+++ b/src/Symfony/Component/HttpClient/Tests/RetryableHttpClientTest.php
@@ -13,6 +13,7 @@
use PHPUnit\Framework\TestCase;
use Symfony\Component\HttpClient\Exception\ServerException;
+use Symfony\Component\HttpClient\Exception\TimeoutException;
use Symfony\Component\HttpClient\HttpClient;
use Symfony\Component\HttpClient\MockHttpClient;
use Symfony\Component\HttpClient\NativeHttpClient;
@@ -21,6 +22,7 @@
use Symfony\Component\HttpClient\Retry\GenericRetryStrategy;
use Symfony\Component\HttpClient\RetryableHttpClient;
use Symfony\Contracts\HttpClient\Exception\TransportExceptionInterface;
+use Symfony\Contracts\HttpClient\Test\TestHttpServer;
class RetryableHttpClientTest extends TestCase
{
@@ -245,6 +247,35 @@ public function testRetryOnErrorAssertContent()
self::assertSame('Test out content', $response->getContent(), 'Content should be buffered');
}
+ /**
+ * @testWith ["GET"]
+ * ["POST"]
+ * ["PUT"]
+ * ["PATCH"]
+ * ["DELETE"]
+ */
+ public function testRetryOnHeaderTimeout(string $method)
+ {
+ $client = HttpClient::create();
+
+ if ($client instanceof NativeHttpClient) {
+ $this->markTestSkipped('NativeHttpClient cannot timeout before receiving headers');
+ }
+
+ TestHttpServer::start();
+
+ $client = new RetryableHttpClient($client);
+ $response = $client->request($method, 'http://localhost:8057/timeout-header', ['timeout' => 0.1]);
+
+ try {
+ $response->getStatusCode();
+ $this->fail(TimeoutException::class.' expected');
+ } catch (TimeoutException $e) {
+ }
+
+ $this->assertSame('Idle timeout reached for "http://localhost:8057/timeout-header".', $response->getInfo('error'));
+ }
+
public function testRetryWithMultipleBaseUris()
{
$client = new RetryableHttpClient(
diff --git a/src/Symfony/Component/HttpClient/Tests/ThrottlingHttpClientTest.php b/src/Symfony/Component/HttpClient/Tests/ThrottlingHttpClientTest.php
new file mode 100644
index 0000000000000..b63c5bab63a3e
--- /dev/null
+++ b/src/Symfony/Component/HttpClient/Tests/ThrottlingHttpClientTest.php
@@ -0,0 +1,57 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\HttpClient\Tests;
+
+use PHPUnit\Framework\TestCase;
+use Symfony\Component\HttpClient\MockHttpClient;
+use Symfony\Component\HttpClient\Response\MockResponse;
+use Symfony\Component\HttpClient\ThrottlingHttpClient;
+use Symfony\Component\RateLimiter\RateLimiterFactory;
+use Symfony\Component\RateLimiter\Storage\InMemoryStorage;
+
+class ThrottlingHttpClientTest extends TestCase
+{
+ public function testThrottling()
+ {
+ $failPauseHandler = static function (float $duration) {
+ self::fail(sprintf('The pause handler should\'t have been called, but it was called with %f.', $duration));
+ };
+
+ $pauseHandler = static fn (float $expectedDuration) => function (float $duration) use ($expectedDuration) {
+ self::assertEqualsWithDelta($expectedDuration, $duration, 1);
+ };
+
+ $rateLimiterFactory = new RateLimiterFactory([
+ 'id' => 'token_bucket',
+ 'policy' => 'token_bucket',
+ 'limit' => 2,
+ 'rate' => ['interval' => '5 seconds', 'amount' => 2],
+ ], new InMemoryStorage());
+
+ $client = new ThrottlingHttpClient(
+ new MockHttpClient([
+ new MockResponse('', ['http_code' => 200, 'pause_handler' => $failPauseHandler]),
+ new MockResponse('', ['http_code' => 200, 'pause_handler' => $failPauseHandler]),
+ new MockResponse('', ['http_code' => 200, 'pause_handler' => $pauseHandler(5)]),
+ new MockResponse('', ['http_code' => 200, 'pause_handler' => $pauseHandler(5)]),
+ new MockResponse('', ['http_code' => 200, 'pause_handler' => $pauseHandler(10)]),
+ ]),
+ $rateLimiterFactory->create(),
+ );
+
+ $client->request('GET', 'http://example.com/foo');
+ $client->request('GET', 'http://example.com/bar');
+ $client->request('GET', 'http://example.com/baz');
+ $client->request('GET', 'http://example.com/qux');
+ $client->request('GET', 'http://example.com/corge');
+ }
+}
diff --git a/src/Symfony/Component/HttpClient/ThrottlingHttpClient.php b/src/Symfony/Component/HttpClient/ThrottlingHttpClient.php
new file mode 100644
index 0000000000000..66fc173053771
--- /dev/null
+++ b/src/Symfony/Component/HttpClient/ThrottlingHttpClient.php
@@ -0,0 +1,51 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\HttpClient;
+
+use Symfony\Component\RateLimiter\LimiterInterface;
+use Symfony\Contracts\HttpClient\HttpClientInterface;
+use Symfony\Contracts\HttpClient\ResponseInterface;
+use Symfony\Contracts\Service\ResetInterface;
+
+/**
+ * Limits the number of requests within a certain period.
+ */
+class ThrottlingHttpClient implements HttpClientInterface, ResetInterface
+{
+ use DecoratorTrait {
+ reset as private traitReset;
+ }
+
+ public function __construct(
+ HttpClientInterface $client,
+ private readonly LimiterInterface $rateLimiter,
+ ) {
+ $this->client = $client;
+ }
+
+ public function request(string $method, string $url, array $options = []): ResponseInterface
+ {
+ $response = $this->client->request($method, $url, $options);
+
+ if (0 < $waitDuration = $this->rateLimiter->reserve()->getWaitDuration()) {
+ $response->getInfo('pause_handler')($waitDuration);
+ }
+
+ return $response;
+ }
+
+ public function reset(): void
+ {
+ $this->traitReset();
+ $this->rateLimiter->reset();
+ }
+}
diff --git a/src/Symfony/Component/HttpClient/TraceableHttpClient.php b/src/Symfony/Component/HttpClient/TraceableHttpClient.php
index 974e9f6f00646..9f1bd515e0914 100644
--- a/src/Symfony/Component/HttpClient/TraceableHttpClient.php
+++ b/src/Symfony/Component/HttpClient/TraceableHttpClient.php
@@ -30,7 +30,7 @@ final class TraceableHttpClient implements HttpClientInterface, ResetInterface,
private ?Stopwatch $stopwatch;
private \ArrayObject $tracedRequests;
- public function __construct(HttpClientInterface $client, Stopwatch $stopwatch = null)
+ public function __construct(HttpClientInterface $client, ?Stopwatch $stopwatch = null)
{
$this->client = $client;
$this->stopwatch = $stopwatch;
@@ -66,7 +66,7 @@ public function request(string $method, string $url, array $options = []): Respo
return new TraceableResponse($this->client, $this->client->request($method, $url, $options), $content, $this->stopwatch?->start("$method $url", 'http_client'));
}
- public function stream(ResponseInterface|iterable $responses, float $timeout = null): ResponseStreamInterface
+ public function stream(ResponseInterface|iterable $responses, ?float $timeout = null): ResponseStreamInterface
{
if ($responses instanceof TraceableResponse) {
$responses = [$responses];
diff --git a/src/Symfony/Component/HttpClient/UriTemplateHttpClient.php b/src/Symfony/Component/HttpClient/UriTemplateHttpClient.php
index 55ae724f12207..2767ed3687eaf 100644
--- a/src/Symfony/Component/HttpClient/UriTemplateHttpClient.php
+++ b/src/Symfony/Component/HttpClient/UriTemplateHttpClient.php
@@ -22,7 +22,7 @@ class UriTemplateHttpClient implements HttpClientInterface, ResetInterface
/**
* @param (\Closure(string $url, array $vars): string)|null $expander
*/
- public function __construct(HttpClientInterface $client = null, private ?\Closure $expander = null, private array $defaultVars = [])
+ public function __construct(?HttpClientInterface $client = null, private ?\Closure $expander = null, private array $defaultVars = [])
{
$this->client = $client ?? HttpClient::create();
}
diff --git a/src/Symfony/Component/HttpClient/composer.json b/src/Symfony/Component/HttpClient/composer.json
index 278a9b23601f9..5f56f21db99ba 100644
--- a/src/Symfony/Component/HttpClient/composer.json
+++ b/src/Symfony/Component/HttpClient/composer.json
@@ -40,6 +40,7 @@
"symfony/http-kernel": "^6.4|^7.0",
"symfony/messenger": "^6.4|^7.0",
"symfony/process": "^6.4|^7.0",
+ "symfony/rate-limiter": "^6.4|^7.0",
"symfony/stopwatch": "^6.4|^7.0"
},
"conflict": {
diff --git a/src/Symfony/Component/HttpFoundation/BinaryFileResponse.php b/src/Symfony/Component/HttpFoundation/BinaryFileResponse.php
index 844153745b2cb..6a466f5711d7c 100644
--- a/src/Symfony/Component/HttpFoundation/BinaryFileResponse.php
+++ b/src/Symfony/Component/HttpFoundation/BinaryFileResponse.php
@@ -42,7 +42,7 @@ class BinaryFileResponse extends Response
* @param bool $autoEtag Whether the ETag header should be automatically set
* @param bool $autoLastModified Whether the Last-Modified header should be automatically set
*/
- public function __construct(\SplFileInfo|string $file, int $status = 200, array $headers = [], bool $public = true, string $contentDisposition = null, bool $autoEtag = false, bool $autoLastModified = true)
+ public function __construct(\SplFileInfo|string $file, int $status = 200, array $headers = [], bool $public = true, ?string $contentDisposition = null, bool $autoEtag = false, bool $autoLastModified = true)
{
parent::__construct(null, $status, $headers);
@@ -60,7 +60,7 @@ public function __construct(\SplFileInfo|string $file, int $status = 200, array
*
* @throws FileException
*/
- public function setFile(\SplFileInfo|string $file, string $contentDisposition = null, bool $autoEtag = false, bool $autoLastModified = true): static
+ public function setFile(\SplFileInfo|string $file, ?string $contentDisposition = null, bool $autoEtag = false, bool $autoLastModified = true): static
{
if (!$file instanceof File) {
if ($file instanceof \SplFileInfo) {
diff --git a/src/Symfony/Component/HttpFoundation/CHANGELOG.md b/src/Symfony/Component/HttpFoundation/CHANGELOG.md
index d4d07411f70e7..a26edc4626a77 100644
--- a/src/Symfony/Component/HttpFoundation/CHANGELOG.md
+++ b/src/Symfony/Component/HttpFoundation/CHANGELOG.md
@@ -5,6 +5,8 @@ CHANGELOG
---
* Add `UploadedFile::getClientOriginalPath()`
+ * Add `QueryParameterRequestMatcher`
+ * Add `HeaderRequestMatcher`
7.0
---
diff --git a/src/Symfony/Component/HttpFoundation/Cookie.php b/src/Symfony/Component/HttpFoundation/Cookie.php
index b8982f75fc8d2..402ae41797630 100644
--- a/src/Symfony/Component/HttpFoundation/Cookie.php
+++ b/src/Symfony/Component/HttpFoundation/Cookie.php
@@ -76,7 +76,7 @@ public static function fromString(string $cookie, bool $decode = false): static
*
* @param self::SAMESITE_*|''|null $sameSite
*/
- public static function create(string $name, string $value = null, int|string|\DateTimeInterface $expire = 0, ?string $path = '/', string $domain = null, bool $secure = null, bool $httpOnly = true, bool $raw = false, ?string $sameSite = self::SAMESITE_LAX, bool $partitioned = false): self
+ public static function create(string $name, ?string $value = null, int|string|\DateTimeInterface $expire = 0, ?string $path = '/', ?string $domain = null, ?bool $secure = null, bool $httpOnly = true, bool $raw = false, ?string $sameSite = self::SAMESITE_LAX, bool $partitioned = false): self
{
return new self($name, $value, $expire, $path, $domain, $secure, $httpOnly, $raw, $sameSite, $partitioned);
}
@@ -94,7 +94,7 @@ public static function create(string $name, string $value = null, int|string|\Da
*
* @throws \InvalidArgumentException
*/
- public function __construct(string $name, string $value = null, int|string|\DateTimeInterface $expire = 0, ?string $path = '/', string $domain = null, bool $secure = null, bool $httpOnly = true, bool $raw = false, ?string $sameSite = self::SAMESITE_LAX, bool $partitioned = false)
+ public function __construct(string $name, ?string $value = null, int|string|\DateTimeInterface $expire = 0, ?string $path = '/', ?string $domain = null, ?bool $secure = null, bool $httpOnly = true, bool $raw = false, ?string $sameSite = self::SAMESITE_LAX, bool $partitioned = false)
{
// from PHP source code
if ($raw && false !== strpbrk($name, self::RESERVED_CHARS_LIST)) {
diff --git a/src/Symfony/Component/HttpFoundation/Exception/SessionNotFoundException.php b/src/Symfony/Component/HttpFoundation/Exception/SessionNotFoundException.php
index 94b0cb69aae1f..80a21bf151c8e 100644
--- a/src/Symfony/Component/HttpFoundation/Exception/SessionNotFoundException.php
+++ b/src/Symfony/Component/HttpFoundation/Exception/SessionNotFoundException.php
@@ -20,7 +20,7 @@
*/
class SessionNotFoundException extends \LogicException implements RequestExceptionInterface
{
- public function __construct(string $message = 'There is currently no session available.', int $code = 0, \Throwable $previous = null)
+ public function __construct(string $message = 'There is currently no session available.', int $code = 0, ?\Throwable $previous = null)
{
parent::__construct($message, $code, $previous);
}
diff --git a/src/Symfony/Component/HttpFoundation/File/File.php b/src/Symfony/Component/HttpFoundation/File/File.php
index e8ce4bcf8075b..34ca5a53774ae 100644
--- a/src/Symfony/Component/HttpFoundation/File/File.php
+++ b/src/Symfony/Component/HttpFoundation/File/File.php
@@ -82,7 +82,7 @@ public function getMimeType(): ?string
*
* @throws FileException if the target file could not be created
*/
- public function move(string $directory, string $name = null): self
+ public function move(string $directory, ?string $name = null): self
{
$target = $this->getTargetFile($directory, $name);
@@ -112,7 +112,7 @@ public function getContent(): string
return $content;
}
- protected function getTargetFile(string $directory, string $name = null): self
+ protected function getTargetFile(string $directory, ?string $name = null): self
{
if (!is_dir($directory)) {
if (false === @mkdir($directory, 0777, true) && !is_dir($directory)) {
diff --git a/src/Symfony/Component/HttpFoundation/File/UploadedFile.php b/src/Symfony/Component/HttpFoundation/File/UploadedFile.php
index b0a01f30f68b6..74e929f9b89e5 100644
--- a/src/Symfony/Component/HttpFoundation/File/UploadedFile.php
+++ b/src/Symfony/Component/HttpFoundation/File/UploadedFile.php
@@ -61,7 +61,7 @@ class UploadedFile extends File
* @throws FileException If file_uploads is disabled
* @throws FileNotFoundException If the file does not exist
*/
- public function __construct(string $path, string $originalName, string $mimeType = null, int $error = null, bool $test = false)
+ public function __construct(string $path, string $originalName, ?string $mimeType = null, ?int $error = null, bool $test = false)
{
$this->originalName = $this->getName($originalName);
$this->originalPath = strtr($originalName, '\\', '/');
@@ -175,7 +175,7 @@ public function isValid(): bool
*
* @throws FileException if, for any reason, the file could not have been moved
*/
- public function move(string $directory, string $name = null): File
+ public function move(string $directory, ?string $name = null): File
{
if ($this->isValid()) {
if ($this->test) {
diff --git a/src/Symfony/Component/HttpFoundation/HeaderBag.php b/src/Symfony/Component/HttpFoundation/HeaderBag.php
index 40750d1c0910b..4bab3764b1f51 100644
--- a/src/Symfony/Component/HttpFoundation/HeaderBag.php
+++ b/src/Symfony/Component/HttpFoundation/HeaderBag.php
@@ -65,7 +65,7 @@ public function __toString(): string
*
* @return ($key is null ? array> : list)
*/
- public function all(string $key = null): array
+ public function all(?string $key = null): array
{
if (null !== $key) {
return $this->headers[strtr($key, self::UPPER, self::LOWER)] ?? [];
@@ -106,7 +106,7 @@ public function add(array $headers): void
/**
* Returns the first header by name or the default one.
*/
- public function get(string $key, string $default = null): ?string
+ public function get(string $key, ?string $default = null): ?string
{
$headers = $this->all($key);
@@ -187,7 +187,7 @@ public function remove(string $key): void
*
* @throws \RuntimeException When the HTTP header is not parseable
*/
- public function getDate(string $key, \DateTimeInterface $default = null): ?\DateTimeImmutable
+ public function getDate(string $key, ?\DateTimeInterface $default = null): ?\DateTimeImmutable
{
if (null === $value = $this->get($key)) {
return null !== $default ? \DateTimeImmutable::createFromInterface($default) : null;
diff --git a/src/Symfony/Component/HttpFoundation/InputBag.php b/src/Symfony/Component/HttpFoundation/InputBag.php
index 343adbcce6273..78903f2101eeb 100644
--- a/src/Symfony/Component/HttpFoundation/InputBag.php
+++ b/src/Symfony/Component/HttpFoundation/InputBag.php
@@ -84,7 +84,7 @@ public function set(string $key, mixed $value): void
*
* @return ?T
*/
- public function getEnum(string $key, string $class, \BackedEnum $default = null): ?\BackedEnum
+ public function getEnum(string $key, string $class, ?\BackedEnum $default = null): ?\BackedEnum
{
try {
return parent::getEnum($key, $class, $default);
diff --git a/src/Symfony/Component/HttpFoundation/ParameterBag.php b/src/Symfony/Component/HttpFoundation/ParameterBag.php
index 004b59a919213..4cfc5b3a8fc6b 100644
--- a/src/Symfony/Component/HttpFoundation/ParameterBag.php
+++ b/src/Symfony/Component/HttpFoundation/ParameterBag.php
@@ -35,7 +35,7 @@ public function __construct(array $parameters = [])
*
* @param string|null $key The name of the parameter to return or null to get them all
*/
- public function all(string $key = null): array
+ public function all(?string $key = null): array
{
if (null === $key) {
return $this->parameters;
@@ -161,7 +161,7 @@ public function getBoolean(string $key, bool $default = false): bool
*
* @return ?T
*/
- public function getEnum(string $key, string $class, \BackedEnum $default = null): ?\BackedEnum
+ public function getEnum(string $key, string $class, ?\BackedEnum $default = null): ?\BackedEnum
{
$value = $this->get($key);
diff --git a/src/Symfony/Component/HttpFoundation/Request.php b/src/Symfony/Component/HttpFoundation/Request.php
index a31f1aace29d5..919e9e01ff9cd 100644
--- a/src/Symfony/Component/HttpFoundation/Request.php
+++ b/src/Symfony/Component/HttpFoundation/Request.php
@@ -395,7 +395,7 @@ public static function setFactory(?callable $callable): void
* @param array|null $files The FILES parameters
* @param array|null $server The SERVER parameters
*/
- public function duplicate(array $query = null, array $request = null, array $attributes = null, array $cookies = null, array $files = null, array $server = null): static
+ public function duplicate(?array $query = null, ?array $request = null, ?array $attributes = null, ?array $cookies = null, ?array $files = null, ?array $server = null): static
{
$dup = clone $this;
if (null !== $query) {
@@ -1524,7 +1524,7 @@ public function getPreferredFormat(?string $default = 'html'): ?string
*
* @param string[] $locales An array of ordered available locales
*/
- public function getPreferredLanguage(array $locales = null): ?string
+ public function getPreferredLanguage(?array $locales = null): ?string
{
$preferredLanguages = $this->getLanguages();
@@ -1917,7 +1917,7 @@ public function isFromTrustedProxy(): bool
* getPort(), isSecure(), getHost(), getClientIps(), getBaseUrl() etc. Thus, we try to cache the results for
* best performance.
*/
- private function getTrustedValues(int $type, string $ip = null): array
+ private function getTrustedValues(int $type, ?string $ip = null): array
{
$cacheKey = $type."\0".((self::$trustedHeaderSet & $type) ? $this->headers->get(self::TRUSTED_HEADERS[$type]) : '');
$cacheKey .= "\0".$ip."\0".$this->headers->get(self::TRUSTED_HEADERS[self::HEADER_FORWARDED]);
diff --git a/src/Symfony/Component/HttpFoundation/RequestMatcher/HeaderRequestMatcher.php b/src/Symfony/Component/HttpFoundation/RequestMatcher/HeaderRequestMatcher.php
new file mode 100644
index 0000000000000..8617a8aca40b9
--- /dev/null
+++ b/src/Symfony/Component/HttpFoundation/RequestMatcher/HeaderRequestMatcher.php
@@ -0,0 +1,52 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\HttpFoundation\RequestMatcher;
+
+use Symfony\Component\HttpFoundation\Request;
+use Symfony\Component\HttpFoundation\RequestMatcherInterface;
+
+/**
+ * Checks the presence of HTTP headers in a Request.
+ *
+ * @author Alexandre Daubois
+ */
+class HeaderRequestMatcher implements RequestMatcherInterface
+{
+ /**
+ * @var string[]
+ */
+ private array $headers;
+
+ /**
+ * @param string[]|string $headers A header or a list of headers
+ * Strings can contain a comma-delimited list of headers
+ */
+ public function __construct(array|string $headers)
+ {
+ $this->headers = array_reduce((array) $headers, static fn (array $headers, string $header) => array_merge($headers, preg_split('/\s*,\s*/', $header)), []);
+ }
+
+ public function matches(Request $request): bool
+ {
+ if (!$this->headers) {
+ return true;
+ }
+
+ foreach ($this->headers as $header) {
+ if (!$request->headers->has($header)) {
+ return false;
+ }
+ }
+
+ return true;
+ }
+}
diff --git a/src/Symfony/Component/HttpFoundation/RequestMatcher/QueryParameterRequestMatcher.php b/src/Symfony/Component/HttpFoundation/RequestMatcher/QueryParameterRequestMatcher.php
new file mode 100644
index 0000000000000..86161e7c031dc
--- /dev/null
+++ b/src/Symfony/Component/HttpFoundation/RequestMatcher/QueryParameterRequestMatcher.php
@@ -0,0 +1,46 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\HttpFoundation\RequestMatcher;
+
+use Symfony\Component\HttpFoundation\Request;
+use Symfony\Component\HttpFoundation\RequestMatcherInterface;
+
+/**
+ * Checks the presence of HTTP query parameters of a Request.
+ *
+ * @author Alexandre Daubois
+ */
+class QueryParameterRequestMatcher implements RequestMatcherInterface
+{
+ /**
+ * @var string[]
+ */
+ private array $parameters;
+
+ /**
+ * @param string[]|string $parameters A parameter or a list of parameters
+ * Strings can contain a comma-delimited list of query parameters
+ */
+ public function __construct(array|string $parameters)
+ {
+ $this->parameters = array_reduce(array_map(strtolower(...), (array) $parameters), static fn (array $parameters, string $parameter) => array_merge($parameters, preg_split('/\s*,\s*/', $parameter)), []);
+ }
+
+ public function matches(Request $request): bool
+ {
+ if (!$this->parameters) {
+ return true;
+ }
+
+ return 0 === \count(array_diff_assoc($this->parameters, $request->query->keys()));
+ }
+}
diff --git a/src/Symfony/Component/HttpFoundation/Response.php b/src/Symfony/Component/HttpFoundation/Response.php
index efe61358f1478..19f8f5e1e84f5 100644
--- a/src/Symfony/Component/HttpFoundation/Response.php
+++ b/src/Symfony/Component/HttpFoundation/Response.php
@@ -311,7 +311,7 @@ public function prepare(Request $request): static
*
* @return $this
*/
- public function sendHeaders(int $statusCode = null): static
+ public function sendHeaders(?int $statusCode = null): static
{
// headers have already been sent by the developer
if (headers_sent()) {
@@ -471,7 +471,7 @@ public function getProtocolVersion(): string
*
* @final
*/
- public function setStatusCode(int $code, string $text = null): static
+ public function setStatusCode(int $code, ?string $text = null): static
{
$this->statusCode = $code;
if ($this->isInvalid()) {
@@ -1249,7 +1249,7 @@ public function isNotFound(): bool
*
* @final
*/
- public function isRedirect(string $location = null): bool
+ public function isRedirect(?string $location = null): bool
{
return \in_array($this->statusCode, [201, 301, 302, 303, 307, 308]) && (null === $location ?: $location == $this->headers->get('Location'));
}
diff --git a/src/Symfony/Component/HttpFoundation/ResponseHeaderBag.php b/src/Symfony/Component/HttpFoundation/ResponseHeaderBag.php
index 2b5f6712837cf..c5a28f579519a 100644
--- a/src/Symfony/Component/HttpFoundation/ResponseHeaderBag.php
+++ b/src/Symfony/Component/HttpFoundation/ResponseHeaderBag.php
@@ -80,7 +80,7 @@ public function replace(array $headers = []): void
}
}
- public function all(string $key = null): array
+ public function all(?string $key = null): array
{
$headers = parent::all();
@@ -166,7 +166,7 @@ public function setCookie(Cookie $cookie): void
/**
* Removes a cookie from the array, but does not unset it in the browser.
*/
- public function removeCookie(string $name, ?string $path = '/', string $domain = null): void
+ public function removeCookie(string $name, ?string $path = '/', ?string $domain = null): void
{
$path ??= '/';
@@ -216,10 +216,14 @@ public function getCookies(string $format = self::COOKIES_FLAT): array
/**
* Clears a cookie in the browser.
+ *
+ * @param bool $partitioned
*/
- public function clearCookie(string $name, ?string $path = '/', string $domain = null, bool $secure = false, bool $httpOnly = true, string $sameSite = null): void
+ public function clearCookie(string $name, ?string $path = '/', ?string $domain = null, bool $secure = false, bool $httpOnly = true, ?string $sameSite = null /* , bool $partitioned = false */): void
{
- $this->setCookie(new Cookie($name, null, 1, $path, $domain, $secure, $httpOnly, false, $sameSite));
+ $partitioned = 6 < \func_num_args() ? \func_get_arg(6) : false;
+
+ $this->setCookie(new Cookie($name, null, 1, $path, $domain, $secure, $httpOnly, false, $sameSite, $partitioned));
}
/**
diff --git a/src/Symfony/Component/HttpFoundation/ServerBag.php b/src/Symfony/Component/HttpFoundation/ServerBag.php
index 3e912cb8004eb..09fc386643bbb 100644
--- a/src/Symfony/Component/HttpFoundation/ServerBag.php
+++ b/src/Symfony/Component/HttpFoundation/ServerBag.php
@@ -29,7 +29,7 @@ public function getHeaders(): array
foreach ($this->parameters as $key => $value) {
if (str_starts_with($key, 'HTTP_')) {
$headers[substr($key, 5)] = $value;
- } elseif (\in_array($key, ['CONTENT_TYPE', 'CONTENT_LENGTH', 'CONTENT_MD5'], true)) {
+ } elseif (\in_array($key, ['CONTENT_TYPE', 'CONTENT_LENGTH', 'CONTENT_MD5'], true) && '' !== $value) {
$headers[$key] = $value;
}
}
diff --git a/src/Symfony/Component/HttpFoundation/Session/Session.php b/src/Symfony/Component/HttpFoundation/Session/Session.php
index f212b52e49662..f25e81052e1cd 100644
--- a/src/Symfony/Component/HttpFoundation/Session/Session.php
+++ b/src/Symfony/Component/HttpFoundation/Session/Session.php
@@ -40,7 +40,7 @@ class Session implements FlashBagAwareSessionInterface, \IteratorAggregate, \Cou
private int $usageIndex = 0;
private ?\Closure $usageReporter;
- public function __construct(SessionStorageInterface $storage = null, AttributeBagInterface $attributes = null, FlashBagInterface $flashes = null, callable $usageReporter = null)
+ public function __construct(?SessionStorageInterface $storage = null, ?AttributeBagInterface $attributes = null, ?FlashBagInterface $flashes = null, ?callable $usageReporter = null)
{
$this->storage = $storage ?? new NativeSessionStorage();
$this->usageReporter = null === $usageReporter ? null : $usageReporter(...);
@@ -142,14 +142,14 @@ public function isEmpty(): bool
return true;
}
- public function invalidate(int $lifetime = null): bool
+ public function invalidate(?int $lifetime = null): bool
{
$this->storage->clear();
return $this->migrate(true, $lifetime);
}
- public function migrate(bool $destroy = false, int $lifetime = null): bool
+ public function migrate(bool $destroy = false, ?int $lifetime = null): bool
{
return $this->storage->regenerate($destroy, $lifetime);
}
diff --git a/src/Symfony/Component/HttpFoundation/Session/SessionFactory.php b/src/Symfony/Component/HttpFoundation/Session/SessionFactory.php
index cdb6af51e7e16..c06ed4b7d84f4 100644
--- a/src/Symfony/Component/HttpFoundation/Session/SessionFactory.php
+++ b/src/Symfony/Component/HttpFoundation/Session/SessionFactory.php
@@ -26,7 +26,7 @@ class SessionFactory implements SessionFactoryInterface
private SessionStorageFactoryInterface $storageFactory;
private ?\Closure $usageReporter;
- public function __construct(RequestStack $requestStack, SessionStorageFactoryInterface $storageFactory, callable $usageReporter = null)
+ public function __construct(RequestStack $requestStack, SessionStorageFactoryInterface $storageFactory, ?callable $usageReporter = null)
{
$this->requestStack = $requestStack;
$this->storageFactory = $storageFactory;
diff --git a/src/Symfony/Component/HttpFoundation/Session/SessionInterface.php b/src/Symfony/Component/HttpFoundation/Session/SessionInterface.php
index f8ce12e228f85..3e29ba42c9724 100644
--- a/src/Symfony/Component/HttpFoundation/Session/SessionInterface.php
+++ b/src/Symfony/Component/HttpFoundation/Session/SessionInterface.php
@@ -58,7 +58,7 @@ public function setName(string $name): void;
* to expire with browser session. Time is in seconds, and is
* not a Unix timestamp.
*/
- public function invalidate(int $lifetime = null): bool;
+ public function invalidate(?int $lifetime = null): bool;
/**
* Migrates the current session to a new session id while maintaining all
@@ -70,7 +70,7 @@ public function invalidate(int $lifetime = null): bool;
* to expire with browser session. Time is in seconds, and is
* not a Unix timestamp.
*/
- public function migrate(bool $destroy = false, int $lifetime = null): bool;
+ public function migrate(bool $destroy = false, ?int $lifetime = null): bool;
/**
* Force the session to be saved and closed.
diff --git a/src/Symfony/Component/HttpFoundation/Session/Storage/Handler/NativeFileSessionHandler.php b/src/Symfony/Component/HttpFoundation/Session/Storage/Handler/NativeFileSessionHandler.php
index f6e73f9e6ce62..f8c6151a4f436 100644
--- a/src/Symfony/Component/HttpFoundation/Session/Storage/Handler/NativeFileSessionHandler.php
+++ b/src/Symfony/Component/HttpFoundation/Session/Storage/Handler/NativeFileSessionHandler.php
@@ -28,7 +28,7 @@ class NativeFileSessionHandler extends \SessionHandler
* @throws \InvalidArgumentException On invalid $savePath
* @throws \RuntimeException When failing to create the save directory
*/
- public function __construct(string $savePath = null)
+ public function __construct(?string $savePath = null)
{
$baseDir = $savePath ??= \ini_get('session.save_path');
diff --git a/src/Symfony/Component/HttpFoundation/Session/Storage/Handler/PdoSessionHandler.php b/src/Symfony/Component/HttpFoundation/Session/Storage/Handler/PdoSessionHandler.php
index c09c9cb0c12fc..aa8ab5690ae62 100644
--- a/src/Symfony/Component/HttpFoundation/Session/Storage/Handler/PdoSessionHandler.php
+++ b/src/Symfony/Component/HttpFoundation/Session/Storage/Handler/PdoSessionHandler.php
@@ -151,7 +151,7 @@ class PdoSessionHandler extends AbstractSessionHandler
*
* @throws \InvalidArgumentException When PDO error mode is not PDO::ERRMODE_EXCEPTION
*/
- public function __construct(#[\SensitiveParameter] \PDO|string $pdoOrDsn = null, #[\SensitiveParameter] array $options = [])
+ public function __construct(#[\SensitiveParameter] \PDO|string|null $pdoOrDsn = null, #[\SensitiveParameter] array $options = [])
{
if ($pdoOrDsn instanceof \PDO) {
if (\PDO::ERRMODE_EXCEPTION !== $pdoOrDsn->getAttribute(\PDO::ATTR_ERRMODE)) {
@@ -181,7 +181,7 @@ public function __construct(#[\SensitiveParameter] \PDO|string $pdoOrDsn = null,
/**
* Adds the Table to the Schema if it doesn't exist.
*/
- public function configureSchema(Schema $schema, \Closure $isSameDatabase = null): void
+ public function configureSchema(Schema $schema, ?\Closure $isSameDatabase = null): void
{
if ($schema->hasTable($this->table) || ($isSameDatabase && !$isSameDatabase($this->getConnection()->exec(...)))) {
return;
diff --git a/src/Symfony/Component/HttpFoundation/Session/Storage/MetadataBag.php b/src/Symfony/Component/HttpFoundation/Session/Storage/MetadataBag.php
index 9bcaafc4e7def..3e80f7dd80b6a 100644
--- a/src/Symfony/Component/HttpFoundation/Session/Storage/MetadataBag.php
+++ b/src/Symfony/Component/HttpFoundation/Session/Storage/MetadataBag.php
@@ -75,7 +75,7 @@ public function getLifetime(): int
* to expire with browser session. Time is in seconds, and is
* not a Unix timestamp.
*/
- public function stampNew(int $lifetime = null): void
+ public function stampNew(?int $lifetime = null): void
{
$this->stampCreated($lifetime);
}
@@ -124,7 +124,7 @@ public function setName(string $name): void
$this->name = $name;
}
- private function stampCreated(int $lifetime = null): void
+ private function stampCreated(?int $lifetime = null): void
{
$timeStamp = time();
$this->meta[self::CREATED] = $this->meta[self::UPDATED] = $this->lastUsed = $timeStamp;
diff --git a/src/Symfony/Component/HttpFoundation/Session/Storage/MockArraySessionStorage.php b/src/Symfony/Component/HttpFoundation/Session/Storage/MockArraySessionStorage.php
index 8ba28835d77ca..f4f5132a1407e 100644
--- a/src/Symfony/Component/HttpFoundation/Session/Storage/MockArraySessionStorage.php
+++ b/src/Symfony/Component/HttpFoundation/Session/Storage/MockArraySessionStorage.php
@@ -39,7 +39,7 @@ class MockArraySessionStorage implements SessionStorageInterface
*/
protected array $bags = [];
- public function __construct(string $name = 'MOCKSESSID', MetadataBag $metaBag = null)
+ public function __construct(string $name = 'MOCKSESSID', ?MetadataBag $metaBag = null)
{
$this->name = $name;
$this->setMetadataBag($metaBag);
@@ -65,7 +65,7 @@ public function start(): bool
return true;
}
- public function regenerate(bool $destroy = false, int $lifetime = null): bool
+ public function regenerate(bool $destroy = false, ?int $lifetime = null): bool
{
if (!$this->started) {
$this->start();
diff --git a/src/Symfony/Component/HttpFoundation/Session/Storage/MockFileSessionStorage.php b/src/Symfony/Component/HttpFoundation/Session/Storage/MockFileSessionStorage.php
index d5ca171066632..48dd74dfbb255 100644
--- a/src/Symfony/Component/HttpFoundation/Session/Storage/MockFileSessionStorage.php
+++ b/src/Symfony/Component/HttpFoundation/Session/Storage/MockFileSessionStorage.php
@@ -30,7 +30,7 @@ class MockFileSessionStorage extends MockArraySessionStorage
/**
* @param string|null $savePath Path of directory to save session files
*/
- public function __construct(string $savePath = null, string $name = 'MOCKSESSID', MetadataBag $metaBag = null)
+ public function __construct(?string $savePath = null, string $name = 'MOCKSESSID', ?MetadataBag $metaBag = null)
{
$savePath ??= sys_get_temp_dir();
@@ -60,7 +60,7 @@ public function start(): bool
return true;
}
- public function regenerate(bool $destroy = false, int $lifetime = null): bool
+ public function regenerate(bool $destroy = false, ?int $lifetime = null): bool
{
if (!$this->started) {
$this->start();
diff --git a/src/Symfony/Component/HttpFoundation/Session/Storage/MockFileSessionStorageFactory.php b/src/Symfony/Component/HttpFoundation/Session/Storage/MockFileSessionStorageFactory.php
index 8ecf943dcb39b..6727cf14fc52b 100644
--- a/src/Symfony/Component/HttpFoundation/Session/Storage/MockFileSessionStorageFactory.php
+++ b/src/Symfony/Component/HttpFoundation/Session/Storage/MockFileSessionStorageFactory.php
@@ -28,7 +28,7 @@ class MockFileSessionStorageFactory implements SessionStorageFactoryInterface
/**
* @see MockFileSessionStorage constructor.
*/
- public function __construct(string $savePath = null, string $name = 'MOCKSESSID', MetadataBag $metaBag = null)
+ public function __construct(?string $savePath = null, string $name = 'MOCKSESSID', ?MetadataBag $metaBag = null)
{
$this->savePath = $savePath;
$this->name = $name;
diff --git a/src/Symfony/Component/HttpFoundation/Session/Storage/NativeSessionStorage.php b/src/Symfony/Component/HttpFoundation/Session/Storage/NativeSessionStorage.php
index 4f6a9ba0d0482..d32292ae02c59 100644
--- a/src/Symfony/Component/HttpFoundation/Session/Storage/NativeSessionStorage.php
+++ b/src/Symfony/Component/HttpFoundation/Session/Storage/NativeSessionStorage.php
@@ -73,7 +73,7 @@ class NativeSessionStorage implements SessionStorageInterface
* trans_sid_hosts, $_SERVER['HTTP_HOST']
* trans_sid_tags, "a=href,area=href,frame=src,form="
*/
- public function __construct(array $options = [], AbstractProxy|\SessionHandlerInterface $handler = null, MetadataBag $metaBag = null)
+ public function __construct(array $options = [], AbstractProxy|\SessionHandlerInterface|null $handler = null, ?MetadataBag $metaBag = null)
{
if (!\extension_loaded('session')) {
throw new \LogicException('PHP extension "session" is required.');
@@ -182,7 +182,7 @@ public function setName(string $name): void
$this->saveHandler->setName($name);
}
- public function regenerate(bool $destroy = false, int $lifetime = null): bool
+ public function regenerate(bool $destroy = false, ?int $lifetime = null): bool
{
// Cannot regenerate the session ID for non-active sessions.
if (\PHP_SESSION_ACTIVE !== session_status()) {
@@ -382,7 +382,7 @@ public function setSaveHandler(AbstractProxy|\SessionHandlerInterface|null $save
* PHP takes the return value from the read() handler, unserializes it
* and populates $_SESSION with the result automatically.
*/
- protected function loadSession(array &$session = null): void
+ protected function loadSession(?array &$session = null): void
{
if (null === $session) {
$session = &$_SESSION;
diff --git a/src/Symfony/Component/HttpFoundation/Session/Storage/NativeSessionStorageFactory.php b/src/Symfony/Component/HttpFoundation/Session/Storage/NativeSessionStorageFactory.php
index 08901284c33a2..6463a4c1b19db 100644
--- a/src/Symfony/Component/HttpFoundation/Session/Storage/NativeSessionStorageFactory.php
+++ b/src/Symfony/Component/HttpFoundation/Session/Storage/NativeSessionStorageFactory.php
@@ -30,7 +30,7 @@ class NativeSessionStorageFactory implements SessionStorageFactoryInterface
/**
* @see NativeSessionStorage constructor.
*/
- public function __construct(array $options = [], AbstractProxy|\SessionHandlerInterface $handler = null, MetadataBag $metaBag = null, bool $secure = false)
+ public function __construct(array $options = [], AbstractProxy|\SessionHandlerInterface|null $handler = null, ?MetadataBag $metaBag = null, bool $secure = false)
{
$this->options = $options;
$this->handler = $handler;
diff --git a/src/Symfony/Component/HttpFoundation/Session/Storage/PhpBridgeSessionStorage.php b/src/Symfony/Component/HttpFoundation/Session/Storage/PhpBridgeSessionStorage.php
index 2583aeb0bc682..8a8c50c933438 100644
--- a/src/Symfony/Component/HttpFoundation/Session/Storage/PhpBridgeSessionStorage.php
+++ b/src/Symfony/Component/HttpFoundation/Session/Storage/PhpBridgeSessionStorage.php
@@ -20,7 +20,7 @@
*/
class PhpBridgeSessionStorage extends NativeSessionStorage
{
- public function __construct(AbstractProxy|\SessionHandlerInterface $handler = null, MetadataBag $metaBag = null)
+ public function __construct(AbstractProxy|\SessionHandlerInterface|null $handler = null, ?MetadataBag $metaBag = null)
{
if (!\extension_loaded('session')) {
throw new \LogicException('PHP extension "session" is required.');
diff --git a/src/Symfony/Component/HttpFoundation/Session/Storage/PhpBridgeSessionStorageFactory.php b/src/Symfony/Component/HttpFoundation/Session/Storage/PhpBridgeSessionStorageFactory.php
index 5cc73802422f3..aa4f800d3af1c 100644
--- a/src/Symfony/Component/HttpFoundation/Session/Storage/PhpBridgeSessionStorageFactory.php
+++ b/src/Symfony/Component/HttpFoundation/Session/Storage/PhpBridgeSessionStorageFactory.php
@@ -26,7 +26,7 @@ class PhpBridgeSessionStorageFactory implements SessionStorageFactoryInterface
private ?MetadataBag $metaBag;
private bool $secure;
- public function __construct(AbstractProxy|\SessionHandlerInterface $handler = null, MetadataBag $metaBag = null, bool $secure = false)
+ public function __construct(AbstractProxy|\SessionHandlerInterface|null $handler = null, ?MetadataBag $metaBag = null, bool $secure = false)
{
$this->handler = $handler;
$this->metaBag = $metaBag;
diff --git a/src/Symfony/Component/HttpFoundation/Session/Storage/SessionStorageInterface.php b/src/Symfony/Component/HttpFoundation/Session/Storage/SessionStorageInterface.php
index 18cfec1b66ad1..c51850de73085 100644
--- a/src/Symfony/Component/HttpFoundation/Session/Storage/SessionStorageInterface.php
+++ b/src/Symfony/Component/HttpFoundation/Session/Storage/SessionStorageInterface.php
@@ -80,7 +80,7 @@ public function setName(string $name): void;
*
* @throws \RuntimeException If an error occurs while regenerating this storage
*/
- public function regenerate(bool $destroy = false, int $lifetime = null): bool;
+ public function regenerate(bool $destroy = false, ?int $lifetime = null): bool;
/**
* Force the session to be saved and closed.
diff --git a/src/Symfony/Component/HttpFoundation/StreamedResponse.php b/src/Symfony/Component/HttpFoundation/StreamedResponse.php
index e6a0c0fef50dd..3acaade17d645 100644
--- a/src/Symfony/Component/HttpFoundation/StreamedResponse.php
+++ b/src/Symfony/Component/HttpFoundation/StreamedResponse.php
@@ -34,7 +34,7 @@ class StreamedResponse extends Response
/**
* @param int $status The HTTP status code (200 "OK" by default)
*/
- public function __construct(callable $callback = null, int $status = 200, array $headers = [])
+ public function __construct(?callable $callback = null, int $status = 200, array $headers = [])
{
parent::__construct(null, $status, $headers);
@@ -73,7 +73,7 @@ public function getCallback(): ?\Closure
*
* @return $this
*/
- public function sendHeaders(int $statusCode = null): static
+ public function sendHeaders(?int $statusCode = null): static
{
if ($this->headersSent) {
return $this;
diff --git a/src/Symfony/Component/HttpFoundation/Test/Constraint/ResponseCookieValueSame.php b/src/Symfony/Component/HttpFoundation/Test/Constraint/ResponseCookieValueSame.php
index 417efc77a6688..768007b9593d5 100644
--- a/src/Symfony/Component/HttpFoundation/Test/Constraint/ResponseCookieValueSame.php
+++ b/src/Symfony/Component/HttpFoundation/Test/Constraint/ResponseCookieValueSame.php
@@ -22,7 +22,7 @@ final class ResponseCookieValueSame extends Constraint
private string $path;
private ?string $domain;
- public function __construct(string $name, string $value, string $path = '/', string $domain = null)
+ public function __construct(string $name, string $value, string $path = '/', ?string $domain = null)
{
$this->name = $name;
$this->value = $value;
diff --git a/src/Symfony/Component/HttpFoundation/Test/Constraint/ResponseHasCookie.php b/src/Symfony/Component/HttpFoundation/Test/Constraint/ResponseHasCookie.php
index 73393d386fbce..8eccea9d147d5 100644
--- a/src/Symfony/Component/HttpFoundation/Test/Constraint/ResponseHasCookie.php
+++ b/src/Symfony/Component/HttpFoundation/Test/Constraint/ResponseHasCookie.php
@@ -21,7 +21,7 @@ final class ResponseHasCookie extends Constraint
private string $path;
private ?string $domain;
- public function __construct(string $name, string $path = '/', string $domain = null)
+ public function __construct(string $name, string $path = '/', ?string $domain = null)
{
$this->name = $name;
$this->path = $path;
diff --git a/src/Symfony/Component/HttpFoundation/Tests/HeaderUtilsTest.php b/src/Symfony/Component/HttpFoundation/Tests/HeaderUtilsTest.php
index befa4aea035a5..3279b9a53b47d 100644
--- a/src/Symfony/Component/HttpFoundation/Tests/HeaderUtilsTest.php
+++ b/src/Symfony/Component/HttpFoundation/Tests/HeaderUtilsTest.php
@@ -149,7 +149,7 @@ public static function provideMakeDispositionFail()
/**
* @dataProvider provideParseQuery
*/
- public function testParseQuery(string $query, string $expected = null)
+ public function testParseQuery(string $query, ?string $expected = null)
{
$this->assertSame($expected ?? $query, http_build_query(HeaderUtils::parseQuery($query), '', '&'));
}
diff --git a/src/Symfony/Component/HttpFoundation/Tests/RequestMatcher/HeaderRequestMatcherTest.php b/src/Symfony/Component/HttpFoundation/Tests/RequestMatcher/HeaderRequestMatcherTest.php
new file mode 100644
index 0000000000000..47a5c7ee83ae4
--- /dev/null
+++ b/src/Symfony/Component/HttpFoundation/Tests/RequestMatcher/HeaderRequestMatcherTest.php
@@ -0,0 +1,84 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\HttpFoundation\Tests\RequestMatcher;
+
+use PHPUnit\Framework\TestCase;
+use Symfony\Component\HttpFoundation\Request;
+use Symfony\Component\HttpFoundation\RequestMatcher\HeaderRequestMatcher;
+
+class HeaderRequestMatcherTest extends TestCase
+{
+ /**
+ * @dataProvider getDataForArray
+ */
+ public function testArray(array $headers, bool $matches)
+ {
+ $matcher = new HeaderRequestMatcher(['x-foo', 'bar']);
+
+ $request = Request::create('https://example.com');
+ foreach ($headers as $k => $v) {
+ $request->headers->set($k, $v);
+ }
+
+ $this->assertSame($matches, $matcher->matches($request));
+ }
+
+ /**
+ * @dataProvider getDataForArray
+ */
+ public function testCommaSeparatedString(array $headers, bool $matches)
+ {
+ $matcher = new HeaderRequestMatcher('x-foo, bar');
+
+ $request = Request::create('https://example.com');
+ foreach ($headers as $k => $v) {
+ $request->headers->set($k, $v);
+ }
+
+ $this->assertSame($matches, $matcher->matches($request));
+ }
+
+ /**
+ * @dataProvider getDataForSingleString
+ */
+ public function testSingleString(array $headers, bool $matches)
+ {
+ $matcher = new HeaderRequestMatcher('x-foo');
+
+ $request = Request::create('https://example.com');
+ foreach ($headers as $k => $v) {
+ $request->headers->set($k, $v);
+ }
+
+ $this->assertSame($matches, $matcher->matches($request));
+ }
+
+ public static function getDataForArray(): \Generator
+ {
+ yield 'Superfluous header' => [['X-Foo' => 'foo', 'bar' => 'bar', 'baz' => 'baz'], true];
+ yield 'Exact match' => [['X-Foo' => 'foo', 'bar' => 'bar'], true];
+ yield 'Case insensitivity' => [['x-foo' => 'foo', 'BAR' => 'bar'], true];
+ yield 'Only one header matching' => [['bar' => 'bar', 'baz' => 'baz'], false];
+ yield 'Only one header' => [['X-foo' => 'foo'], false];
+ yield 'Header name as a value' => [['X-foo'], false];
+ yield 'Empty headers' => [[], false];
+ }
+
+ public static function getDataForSingleString(): \Generator
+ {
+ yield 'Superfluous header' => [['X-Foo' => 'foo', 'bar' => 'bar'], true];
+ yield 'Exact match' => [['X-foo' => 'foo'], true];
+ yield 'Case insensitivity' => [['x-foo' => 'foo'], true];
+ yield 'Header name as a value' => [['X-foo'], false];
+ yield 'Empty headers' => [[], false];
+ }
+}
diff --git a/src/Symfony/Component/HttpFoundation/Tests/RequestMatcher/QueryParameterRequestMatcherTest.php b/src/Symfony/Component/HttpFoundation/Tests/RequestMatcher/QueryParameterRequestMatcherTest.php
new file mode 100644
index 0000000000000..202ca649ab05f
--- /dev/null
+++ b/src/Symfony/Component/HttpFoundation/Tests/RequestMatcher/QueryParameterRequestMatcherTest.php
@@ -0,0 +1,67 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\HttpFoundation\Tests\RequestMatcher;
+
+use PHPUnit\Framework\TestCase;
+use Symfony\Component\HttpFoundation\Request;
+use Symfony\Component\HttpFoundation\RequestMatcher\QueryParameterRequestMatcher;
+
+class QueryParameterRequestMatcherTest extends TestCase
+{
+ /**
+ * @dataProvider getDataForArray
+ */
+ public function testArray(string $uri, bool $matches)
+ {
+ $matcher = new QueryParameterRequestMatcher(['foo', 'bar']);
+ $request = Request::create($uri);
+ $this->assertSame($matches, $matcher->matches($request));
+ }
+
+ /**
+ * @dataProvider getDataForArray
+ */
+ public function testCommaSeparatedString(string $uri, bool $matches)
+ {
+ $matcher = new QueryParameterRequestMatcher('foo, bar');
+ $request = Request::create($uri);
+ $this->assertSame($matches, $matcher->matches($request));
+ }
+
+ /**
+ * @dataProvider getDataForSingleString
+ */
+ public function testSingleString(string $uri, bool $matches)
+ {
+ $matcher = new QueryParameterRequestMatcher('foo');
+ $request = Request::create($uri);
+ $this->assertSame($matches, $matcher->matches($request));
+ }
+
+ public static function getDataForArray(): \Generator
+ {
+ yield ['https://example.com?foo=&bar=', true];
+ yield ['https://example.com?foo=foo1&bar=bar1', true];
+ yield ['https://example.com?foo=foo1&bar=bar1&baz=baz1', true];
+ yield ['https://example.com?foo=', false];
+ yield ['https://example.com', false];
+ }
+
+ public static function getDataForSingleString(): \Generator
+ {
+ yield ['https://example.com?foo=&bar=', true];
+ yield ['https://example.com?foo=foo1', true];
+ yield ['https://example.com?foo=', true];
+ yield ['https://example.com?bar=bar1&baz=baz1', false];
+ yield ['https://example.com', false];
+ }
+}
diff --git a/src/Symfony/Component/HttpFoundation/Tests/ResponseHeaderBagTest.php b/src/Symfony/Component/HttpFoundation/Tests/ResponseHeaderBagTest.php
index 8165e43740a66..9e61dd684e60f 100644
--- a/src/Symfony/Component/HttpFoundation/Tests/ResponseHeaderBagTest.php
+++ b/src/Symfony/Component/HttpFoundation/Tests/ResponseHeaderBagTest.php
@@ -136,6 +136,14 @@ public function testClearCookieSamesite()
$this->assertSetCookieHeader('foo=deleted; expires='.gmdate('D, d M Y H:i:s T', time() - 31536001).'; Max-Age=0; path=/; secure; samesite=none', $bag);
}
+ public function testClearCookiePartitioned()
+ {
+ $bag = new ResponseHeaderBag([]);
+
+ $bag->clearCookie('foo', '/', null, true, false, 'none', true);
+ $this->assertSetCookieHeader('foo=deleted; expires='.gmdate('D, d M Y H:i:s T', time() - 31536001).'; Max-Age=0; path=/; secure; samesite=none; partitioned', $bag);
+ }
+
public function testReplace()
{
$bag = new ResponseHeaderBag([]);
diff --git a/src/Symfony/Component/HttpFoundation/Tests/ServerBagTest.php b/src/Symfony/Component/HttpFoundation/Tests/ServerBagTest.php
index e26714bc4640a..3d675c5127868 100644
--- a/src/Symfony/Component/HttpFoundation/Tests/ServerBagTest.php
+++ b/src/Symfony/Component/HttpFoundation/Tests/ServerBagTest.php
@@ -177,4 +177,20 @@ public function testItDoesNotOverwriteTheAuthorizationHeaderIfItIsAlreadySet()
'PHP_AUTH_PW' => '',
], $bag->getHeaders());
}
+
+ /**
+ * An HTTP request without content-type and content-length will result in
+ * the variables $_SERVER['CONTENT_TYPE'] and $_SERVER['CONTENT_LENGTH']
+ * containing an empty string in PHP.
+ */
+ public function testRequestWithoutContentTypeAndContentLength()
+ {
+ $bag = new ServerBag([
+ 'CONTENT_TYPE' => '',
+ 'CONTENT_LENGTH' => '',
+ 'HTTP_USER_AGENT' => 'foo',
+ ]);
+
+ $this->assertSame(['USER_AGENT' => 'foo'], $bag->getHeaders());
+ }
}
diff --git a/src/Symfony/Component/HttpFoundation/Tests/Session/Storage/Handler/PdoSessionHandlerTest.php b/src/Symfony/Component/HttpFoundation/Tests/Session/Storage/Handler/PdoSessionHandlerTest.php
index cd34c72e34342..ede4703aa04f7 100644
--- a/src/Symfony/Component/HttpFoundation/Tests/Session/Storage/Handler/PdoSessionHandlerTest.php
+++ b/src/Symfony/Component/HttpFoundation/Tests/Session/Storage/Handler/PdoSessionHandlerTest.php
@@ -408,7 +408,7 @@ class MockPdo extends \PDO
private ?string $driverName;
private bool|int $errorMode;
- public function __construct(string $driverName = null, int $errorMode = null)
+ public function __construct(?string $driverName = null, ?int $errorMode = null)
{
$this->driverName = $driverName;
$this->errorMode = null !== $errorMode ?: \PDO::ERRMODE_EXCEPTION;
diff --git a/src/Symfony/Component/HttpKernel/CacheWarmer/CacheWarmerAggregate.php b/src/Symfony/Component/HttpKernel/CacheWarmer/CacheWarmerAggregate.php
index beb98133862c1..b96d7c3d7617f 100644
--- a/src/Symfony/Component/HttpKernel/CacheWarmer/CacheWarmerAggregate.php
+++ b/src/Symfony/Component/HttpKernel/CacheWarmer/CacheWarmerAggregate.php
@@ -31,7 +31,7 @@ class CacheWarmerAggregate implements CacheWarmerInterface
/**
* @param iterable $warmers
*/
- public function __construct(iterable $warmers = [], bool $debug = false, string $deprecationLogsFilepath = null)
+ public function __construct(iterable $warmers = [], bool $debug = false, ?string $deprecationLogsFilepath = null)
{
$this->warmers = $warmers;
$this->debug = $debug;
@@ -48,7 +48,7 @@ public function enableOnlyOptionalWarmers(): void
$this->onlyOptionalsEnabled = $this->optionalsEnabled = true;
}
- public function warmUp(string $cacheDir, string $buildDir = null, SymfonyStyle $io = null): array
+ public function warmUp(string $cacheDir, ?string $buildDir = null, ?SymfonyStyle $io = null): array
{
if ($collectDeprecations = $this->debug && !\defined('PHPUNIT_COMPOSER_INSTALL')) {
$collectedLogs = [];
diff --git a/src/Symfony/Component/HttpKernel/CacheWarmer/WarmableInterface.php b/src/Symfony/Component/HttpKernel/CacheWarmer/WarmableInterface.php
index abef0f0134cdd..7ffe3c0dfde4d 100644
--- a/src/Symfony/Component/HttpKernel/CacheWarmer/WarmableInterface.php
+++ b/src/Symfony/Component/HttpKernel/CacheWarmer/WarmableInterface.php
@@ -26,5 +26,5 @@ interface WarmableInterface
*
* @return string[] A list of classes or files to preload
*/
- public function warmUp(string $cacheDir, string $buildDir = null): array;
+ public function warmUp(string $cacheDir, ?string $buildDir = null): array;
}
diff --git a/src/Symfony/Component/HttpKernel/Config/FileLocator.php b/src/Symfony/Component/HttpKernel/Config/FileLocator.php
index f81f91925bbe5..fb6bb10f1f1b7 100644
--- a/src/Symfony/Component/HttpKernel/Config/FileLocator.php
+++ b/src/Symfony/Component/HttpKernel/Config/FileLocator.php
@@ -30,7 +30,7 @@ public function __construct(KernelInterface $kernel)
parent::__construct();
}
- public function locate(string $file, string $currentPath = null, bool $first = true): string|array
+ public function locate(string $file, ?string $currentPath = null, bool $first = true): string|array
{
if (isset($file[0]) && '@' === $file[0]) {
$resource = $this->kernel->locateResource($file);
diff --git a/src/Symfony/Component/HttpKernel/Controller/ArgumentResolver.php b/src/Symfony/Component/HttpKernel/Controller/ArgumentResolver.php
index d4c790e8eab9d..dbd47b73db36f 100644
--- a/src/Symfony/Component/HttpKernel/Controller/ArgumentResolver.php
+++ b/src/Symfony/Component/HttpKernel/Controller/ArgumentResolver.php
@@ -38,14 +38,14 @@ final class ArgumentResolver implements ArgumentResolverInterface
/**
* @param iterable $argumentValueResolvers
*/
- public function __construct(ArgumentMetadataFactoryInterface $argumentMetadataFactory = null, iterable $argumentValueResolvers = [], ContainerInterface $namedResolvers = null)
+ public function __construct(?ArgumentMetadataFactoryInterface $argumentMetadataFactory = null, iterable $argumentValueResolvers = [], ?ContainerInterface $namedResolvers = null)
{
$this->argumentMetadataFactory = $argumentMetadataFactory ?? new ArgumentMetadataFactory();
$this->argumentValueResolvers = $argumentValueResolvers ?: self::getDefaultArgumentValueResolvers();
$this->namedResolvers = $namedResolvers;
}
- public function getArguments(Request $request, callable $controller, \ReflectionFunctionAbstract $reflector = null): array
+ public function getArguments(Request $request, callable $controller, ?\ReflectionFunctionAbstract $reflector = null): array
{
$arguments = [];
diff --git a/src/Symfony/Component/HttpKernel/Controller/ArgumentResolver/RequestPayloadValueResolver.php b/src/Symfony/Component/HttpKernel/Controller/ArgumentResolver/RequestPayloadValueResolver.php
index d48c01649fa1d..efa78dfb05878 100644
--- a/src/Symfony/Component/HttpKernel/Controller/ArgumentResolver/RequestPayloadValueResolver.php
+++ b/src/Symfony/Component/HttpKernel/Controller/ArgumentResolver/RequestPayloadValueResolver.php
@@ -109,11 +109,15 @@ public function onKernelControllerArguments(ControllerArgumentsEvent $event): vo
} catch (PartialDenormalizationException $e) {
$trans = $this->translator ? $this->translator->trans(...) : fn ($m, $p) => strtr($m, $p);
foreach ($e->getErrors() as $error) {
- $parameters = ['{{ type }}' => implode('|', $error->getExpectedTypes())];
+ $parameters = [];
+ $template = 'This value was of an unexpected type.';
+ if ($expectedTypes = $error->getExpectedTypes()) {
+ $template = 'This value should be of type {{ type }}.';
+ $parameters['{{ type }}'] = implode('|', $expectedTypes);
+ }
if ($error->canUseMessageForUser()) {
$parameters['hint'] = $error->getMessage();
}
- $template = 'This value should be of type {{ type }}.';
$message = $trans($template, $parameters, 'validators');
$violations->add(new ConstraintViolation($message, $template, $parameters, null, $error->getPath(), null));
}
diff --git a/src/Symfony/Component/HttpKernel/Controller/ArgumentResolverInterface.php b/src/Symfony/Component/HttpKernel/Controller/ArgumentResolverInterface.php
index a1f999fd49ee1..2090a599288df 100644
--- a/src/Symfony/Component/HttpKernel/Controller/ArgumentResolverInterface.php
+++ b/src/Symfony/Component/HttpKernel/Controller/ArgumentResolverInterface.php
@@ -26,5 +26,5 @@ interface ArgumentResolverInterface
*
* @throws \RuntimeException When no value could be provided for a required argument
*/
- public function getArguments(Request $request, callable $controller, \ReflectionFunctionAbstract $reflector = null): array;
+ public function getArguments(Request $request, callable $controller, ?\ReflectionFunctionAbstract $reflector = null): array;
}
diff --git a/src/Symfony/Component/HttpKernel/Controller/ContainerControllerResolver.php b/src/Symfony/Component/HttpKernel/Controller/ContainerControllerResolver.php
index 5e1531de525ee..44b75860d4a4b 100644
--- a/src/Symfony/Component/HttpKernel/Controller/ContainerControllerResolver.php
+++ b/src/Symfony/Component/HttpKernel/Controller/ContainerControllerResolver.php
@@ -25,7 +25,7 @@ class ContainerControllerResolver extends ControllerResolver
{
protected ContainerInterface $container;
- public function __construct(ContainerInterface $container, LoggerInterface $logger = null)
+ public function __construct(ContainerInterface $container, ?LoggerInterface $logger = null)
{
$this->container = $container;
diff --git a/src/Symfony/Component/HttpKernel/Controller/ControllerResolver.php b/src/Symfony/Component/HttpKernel/Controller/ControllerResolver.php
index 6c78668be81f6..c1622b96e2cfe 100644
--- a/src/Symfony/Component/HttpKernel/Controller/ControllerResolver.php
+++ b/src/Symfony/Component/HttpKernel/Controller/ControllerResolver.php
@@ -29,7 +29,7 @@ class ControllerResolver implements ControllerResolverInterface
private array $allowedControllerTypes = [];
private array $allowedControllerAttributes = [AsController::class => AsController::class];
- public function __construct(LoggerInterface $logger = null)
+ public function __construct(?LoggerInterface $logger = null)
{
$this->logger = $logger;
}
diff --git a/src/Symfony/Component/HttpKernel/Controller/TraceableArgumentResolver.php b/src/Symfony/Component/HttpKernel/Controller/TraceableArgumentResolver.php
index a71d8db5c9bee..8d182fa4199db 100644
--- a/src/Symfony/Component/HttpKernel/Controller/TraceableArgumentResolver.php
+++ b/src/Symfony/Component/HttpKernel/Controller/TraceableArgumentResolver.php
@@ -28,7 +28,7 @@ public function __construct(ArgumentResolverInterface $resolver, Stopwatch $stop
$this->stopwatch = $stopwatch;
}
- public function getArguments(Request $request, callable $controller, \ReflectionFunctionAbstract $reflector = null): array
+ public function getArguments(Request $request, callable $controller, ?\ReflectionFunctionAbstract $reflector = null): array
{
$e = $this->stopwatch->start('controller.get_arguments');
diff --git a/src/Symfony/Component/HttpKernel/ControllerMetadata/ArgumentMetadata.php b/src/Symfony/Component/HttpKernel/ControllerMetadata/ArgumentMetadata.php
index a352090eac842..dd6c8be86fec6 100644
--- a/src/Symfony/Component/HttpKernel/ControllerMetadata/ArgumentMetadata.php
+++ b/src/Symfony/Component/HttpKernel/ControllerMetadata/ArgumentMetadata.php
@@ -106,7 +106,7 @@ public function getDefaultValue(): mixed
*
* @return array