8000 diff --git a/.appveyor.yml b/.appveyor.yml deleted file mode 100644 index 17723f34aa873..0000000000000 --- a/.appveyor.yml +++ /dev/null @@ -1,71 +0,0 @@ -build: false -clone_depth: 2 -clone_folder: c:\projects\symfony -image: Visual Studio 2019 - -init: - - SET PATH=c:\php;%PATH% - - SET COMPOSER_NO_INTERACTION=1 - - SET SYMFONY_DEPRECATIONS_HELPER=strict - - SET ANSICON=121x90 (121x90) - - SET SYMFONY_PHPUNIT_DISABLE_RESULT_CACHE=1 - - REG ADD "HKEY_CURRENT_USER\Software\Microsoft\Command Processor" /v DelayedExpansion /t REG_DWORD /d 1 /f - -install: - - mkdir c:\php && cd c:\php - - appveyor DownloadFile https://github.com/symfony/binary-utils/releases/download/v0.1/php-8.2.0-Win32-vs16-x86.zip - - 7z x php-8.2.0-Win32-vs16-x86.zip -y >nul - - cd ext - - appveyor DownloadFile https://github.com/symfony/binary-utils/releases/download/v0.1/php_apcu-5.1.22-8.2-ts-vs16-x86.zip - - 7z x php_apcu-5.1.22-8.2-ts-vs16-x86.zip -y >nul - - appveyor DownloadFile https://github.com/symfony/binary-utils/releases/download/v0.1/php_redis-6.0.0-dev-8.2-ts-vs16-x86.zip - - 7z x php_redis-6.0.0-dev-8.2-ts-vs16-x86.zip -y >nul - - cd .. - - copy /Y php.ini-development php.ini-min - - echo memory_limit=-1 >> php.ini-min - - echo serialize_precision=-1 >> php.ini-min - - echo max_execution_time=1200 >> php.ini-min - - echo post_max_size=2047M >> php.ini-min - - echo upload_max_filesize=2047M >> php.ini-min - - echo date.timezone="America/Los_Angeles" >> php.ini-min - - echo extension_dir=ext >> php.ini-min - - echo extension=php_xsl.dll >> php.ini-min - - copy /Y php.ini-min php.ini-max - - echo zend_extension=php_opcache.dll >> php.ini-max - - echo opcache.enable_cli=1 >> php.ini-max - - echo extension=php_openssl.dll >> php.ini-max - - echo extension=php_apcu.dll >> php.ini-max - - echo extension=php_igbinary.dll >> php.ini-max - - echo extension=php_redis.dll >> php.ini-max - - echo apc.enable_cli=1 >> php.ini-max - - echo extension=php_intl.dll >> php.ini-max - - echo extension=php_mbstring.dll >> php.ini-max - - echo extension=php_fileinfo.dll >> php.ini-max - - echo extension=php_pdo_sqlite.dll >> php.ini-max - - echo extension=php_curl.dll >> php.ini-max - - echo extension=php_sodium.dll >> php.ini-max - - copy /Y php.ini-max php.ini - - cd c:\projects\symfony - - appveyor DownloadFile https://getcomposer.org/download/latest-stable/composer.phar - - mkdir %APPDATA%\Composer && copy /Y .github\composer-config.json %APPDATA%\Composer\config.json - - git config --global user.email "" - - git config --global user.name "Symfony" - - FOR /F "tokens=* USEBACKQ" %%F IN (`bash -c "grep ' VERSION = ' src/Symfony/Component/HttpKernel/Kernel.php | grep -o '[0-9][0-9]*\.[0-9]'"`) DO (SET SYMFONY_VERSION=%%F) - - php .github/build-packages.php HEAD^ %SYMFONY_VERSION% src\Symfony\Bridge\PhpUnit - - SET COMPOSER_ROOT_VERSION=%SYMFONY_VERSION%.x-dev - - php composer.phar update --no-progress --ansi - - php phpunit install - - choco install memurai-developer - -test_script: - - SET X=0 - - SET SYMFONY_PHPUNIT_SKIPPED_TESTS=phpunit.skipped - - copy /Y c:\php\php.ini-min c:\php\php.ini - - IF %APPVEYOR_REPO_BRANCH:~-2% neq .x (rm -Rf src\Symfony\Bridge\PhpUnit) - - mv src\Symfony\Component\HttpClient\phpunit.xml.dist src\Symfony\Component\HttpClient\phpunit.xml - - php phpunit src\Symfony --exclude-group tty,benchmark,intl-data,network,transient-on-windows || SET X=!errorlevel! - - php phpunit src\Symfony\Component\HttpClient || SET X=!errorlevel! - - copy /Y c:\php\php.ini-max c:\php\php.ini - - php phpunit src\Symfony --exclude-group tty,benchmark,intl-data,network,transient-on-windows || SET X=!errorlevel! - - php phpunit src\Symfony\Component\HttpClient || SET X=!errorlevel! - - exit %X% diff --git a/.git-blame-ignore-revs b/.git-blame-ignore-revs new file mode 100644 index 0000000000000..84a03c743b95a --- /dev/null +++ b/.git-blame-ignore-revs @@ -0,0 +1,8 @@ +# Apply php-cs-fixer fix --rules nullable_type_declaration_for_default_null_value +f4118e110a46de3ffb799e7d79bf15128d1646ea +9519b54417c09c49496a4a6be238e63be9a73465 +ae0a783425b80b78376488619bf9106e69193fa4 +9c1e36257c4df0929179462d6b2bdd00453ac8aa +6ae74d38e3d20d0ffcc66c7c3d28767fab76bdfb +# Prefix all sprintf() calls +6ce530c5e90397d88e3a76a56db266c74d651584 diff --git a/.gitattributes b/.gitattributes index d1570aff1cd79..c7aefa05ef8be 100644 --- a/.gitattributes +++ b/.gitattributes @@ -5,4 +5,9 @@ /src/Symfony/Component/Notifier/Bridge export-ignore /src/Symfony/Component/Runtime export-ignore /src/Symfony/Component/Translation/Bridge export-ignore +/src/Symfony/Component/Emoji/Resources/data/* linguist-generated=true /src/Symfony/Component/Intl/Resources/data/*/* linguist-generated=true +/src/Symfony/Component/JsonEncoder/Tests/Fixtures/encoder/* linguist-generated=true +/src/Symfony/Component/JsonEncoder/Tests/Fixtures/decoder/* linguist-generated=true +/src/Symfony/**/.github/workflows/close-pull-request.yml linguist-generated=true +/src/Symfony/**/.github/PULL_REQUEST_TEMPLATE.md linguist-generated=true diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index be833bfec1a14..d4dafb2aa0029 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.4 for features / 6.4, 7.2, or 7.3 for bug fixes | Bug fix? | yes/no | New feature? | yes/no | Deprecations? | yes/no diff --git a/.github/build-packages.php b/.github/build-packages.php index d69a3c8198ec0..4793b8483d7ed 100644 --- a/.github/build-packages.php +++ b/.github/build-packages.php @@ -1,5 +1,15 @@ '__unset' !== $v); + }, []); + + return $expandedVersions ?? []; +} + if (3 > $_SERVER['argc']) { echo "Usage: branch version dir1 dir2 ... dirN\n"; exit(1); @@ -52,11 +62,13 @@ $packages[$package->name][$package->version] = $package; - $versions = @file_get_contents('https://repo.packagist.org/p/'.$package->name.'.json') ?: sprintf('{"packages":{"%s":{"%s":%s}}}', $package->name, $package->version, file_get_contents($dir.'/composer.json')); - $versions = json_decode($versions)->packages->{$package->name}; + foreach (['.json', '~dev.json'] as $ext) { + $versions = @file_get_contents('https://repo.packagist.org/p2/'.$package->name.$ext) ?: '[]'; + $versions = json_decode($versions, true)['packages'][$package->name] ?? []; - foreach ($versions as $v => $package) { - $packages[$package->name] += [$v => $package]; + foreach (expandComposerMetadata($versions) as $p) { + $packages[$package->name] += [$p['version'] => $p]; + } } } diff --git a/.github/expected-missing-return-types.diff b/.github/expected-missing-return-types.diff index e477abe0fa71b..1979bba26f58c 100644 --- a/.github/expected-missing-return-types.diff +++ b/.github/expected-missing-return-types.diff @@ -1,5 +1,5 @@ # Run these steps to update this file: -sed -i 's/ *"\*\*\/Tests\/"//' composer.json +sed -i 's/ *"\*\*\/Tests\/",//' composer.json composer u -o SYMFONY_PATCH_TYPE_DECLARATIONS='force=2&php=8.1' php .github/patch-types.php head=$(sed '/^diff /Q' .github/expected-missing-return-types.diff) @@ -7,38 +7,48 @@ git checkout src/Symfony/Contracts/Service/ResetInterface.php (echo "$head" && echo && git diff -U2 src/ | grep '^index ' -v) > .github/expected-missing-return-types.diff git checkout composer.json src/ +diff --git a/src/Symfony/Bridge/Twig/Test/Traits/RuntimeLoaderProvider.php b/src/Symfony/Bridge/Twig/Test/Traits/RuntimeLoaderProvider.php +--- a/src/Symfony/Bridge/Twig/Test/Traits/RuntimeLoaderProvider.php ++++ b/src/Symfony/Bridge/Twig/Test/Traits/RuntimeLoaderProvider.php +@@ -21,5 +21,5 @@ trait RuntimeLoaderProvider + * @return void + */ +- protected function registerTwigRuntimeLoader(Environment $environment, FormRenderer $renderer) ++ protected function registerTwigRuntimeLoader(Environment $environment, FormRenderer $renderer): void + { + $loader = $this->createMock(RuntimeLoaderInterface::class); diff --git a/src/Symfony/Component/BrowserKit/AbstractBrowser.php b/src/Symfony/Component/BrowserKit/AbstractBrowser.php --- a/src/Symfony/Component/BrowserKit/AbstractBrowser.php +++ b/src/Symfony/Component/BrowserKit/AbstractBrowser.php -@@ -407,5 +407,5 @@ abstract class AbstractBrowser +@@ -420,5 +420,5 @@ abstract class AbstractBrowser * @throws \RuntimeException When processing returns exit code */ - protected function doRequestInProcess(object $request) + protected function doRequestInProcess(object $request): object { $deprecationsFile = tempnam(sys_get_temp_dir(), 'deprec'); -@@ -440,5 +440,5 @@ abstract class AbstractBrowser - * @return object +@@ -457,5 +457,5 @@ abstract class AbstractBrowser + * @psalm-return TResponse */ - abstract protected function doRequest(object $request); + abstract protected function doRequest(object $request): object; /** -@@ -451,5 +451,5 @@ abstract class AbstractBrowser +@@ -470,5 +470,5 @@ abstract class AbstractBrowser * @throws LogicException When this abstract class is not implemented */ - protected function getScript(object $request) + protected function getScript(object $request): string { throw new LogicException('To insulate requests, you need to override the getScript() method.'); -@@ -461,5 +461,5 @@ abstract class AbstractBrowser - * @return object +@@ -482,5 +482,5 @@ abstract class AbstractBrowser + * @psalm-return TRequest */ - protected function filterRequest(Request $request) + protected function filterRequest(Request $request): object { return $request; -@@ -471,5 +471,5 @@ abstract class AbstractBrowser +@@ -494,5 +494,5 @@ abstract class AbstractBrowser * @return Response */ - protected function filterResponse(object $response) @@ -48,7 +58,7 @@ diff --git a/src/Symfony/Component/BrowserKit/AbstractBrowser.php b/src/Symfony/ diff --git a/src/Symfony/Component/Config/Definition/Builder/NodeDefinition.php b/src/Symfony/Component/Config/Definition/Builder/NodeDefinition.php --- a/src/Symfony/Component/Config/Definition/Builder/NodeDefinition.php +++ b/src/Symfony/Component/Config/Definition/Builder/NodeDefinition.php -@@ -94,5 +94,5 @@ abstract class NodeDefinition implements NodeParentInterface +@@ -115,5 +115,5 @@ abstract class NodeDefinition implements NodeParentInterface * @return NodeParentInterface|NodeBuilder|self|ArrayNodeDefinition|VariableNodeDefinition */ - public function end(): NodeParentInterface @@ -58,21 +68,21 @@ diff --git a/src/Symfony/Component/Config/Definition/Builder/NodeDefinition.php diff --git a/src/Symfony/Component/Console/Command/Command.php b/src/Symfony/Component/Console/Command/Command.php --- a/src/Symfony/Component/Console/Command/Command.php +++ b/src/Symfony/Component/Console/Command/Command.php -@@ -163,5 +163,5 @@ class Command +@@ -201,5 +201,5 @@ class Command implements SignalableCommandInterface * @return void */ - protected function configure() + protected function configure(): void { } -@@ -195,5 +195,5 @@ class Command +@@ -233,5 +233,5 @@ class Command implements SignalableCommandInterface * @return void */ - protected function interact(InputInterface $input, OutputInterface $output) + protected function interact(InputInterface $input, OutputInterface $output): void { } -@@ -211,5 +211,5 @@ class Command +@@ -249,5 +249,5 @@ class Command implements SignalableCommandInterface * @return void */ - protected function initialize(InputInterface $input, OutputInterface $output) @@ -177,6 +187,23 @@ diff --git a/src/Symfony/Component/DependencyInjection/Extension/PrependExtensio - public function prepend(ContainerBuilder $container); + public function prepend(ContainerBuilder $container): void; } +diff --git a/src/Symfony/Component/Emoji/EmojiTransliterator.php b/src/Symfony/Component/Emoji/EmojiTransliterator.php +--- a/src/Symfony/Component/Emoji/EmojiTransliterator.php ++++ b/src/Symfony/Component/Emoji/EmojiTransliterator.php +@@ -88,5 +88,5 @@ final class EmojiTransliterator extends \Transliterator + */ + #[\ReturnTypeWillChange] +- public function getErrorCode(): int|false ++ public function getErrorCode(): int + { + return isset($this->transliterator) ? $this->transliterator->getErrorCode() : 0; +@@ -97,5 +97,5 @@ final class EmojiTransliterator extends \Transliterator + */ + #[\ReturnTypeWillChange] +- public function getErrorMessage(): string|false ++ public function getErrorMessage(): string + { + return isset($this->transliterator) ? $this->transliterator->getErrorMessage() : ''; diff --git a/src/Symfony/Component/EventDispatcher/EventSubscriberInterface.php b/src/Symfony/Component/EventDispatcher/EventSubscriberInterface.php --- a/src/Symfony/Component/EventDispatcher/EventSubscriberInterface.php +++ b/src/Symfony/Component/EventDispatcher/EventSubscriberInterface.php @@ -189,13 +216,13 @@ diff --git a/src/Symfony/Component/EventDispatcher/EventSubscriberInterface.php diff --git a/src/Symfony/Component/ExpressionLanguage/ExpressionLanguage.php b/src/Symfony/Component/ExpressionLanguage/ExpressionLanguage.php --- a/src/Symfony/Component/ExpressionLanguage/ExpressionLanguage.php +++ b/src/Symfony/Component/ExpressionLanguage/ExpressionLanguage.php -@@ -139,5 +139,5 @@ class ExpressionLanguage +@@ -149,5 +149,5 @@ class ExpressionLanguage * @return void */ - protected function registerFunctions() + protected function registerFunctions(): void { - $this->addFunction(ExpressionFunction::fromPhp('constant')); + $basicPhpFunctions = ['constant', 'min', 'max']; diff --git a/src/Symfony/Component/Form/AbstractType.php b/src/Symfony/Component/Form/AbstractType.php --- a/src/Symfony/Component/Form/AbstractType.php +++ b/src/Symfony/Component/Form/AbstractType.php @@ -285,6 +312,61 @@ diff --git a/src/Symfony/Component/Form/FormTypeInterface.php b/src/Symfony/Comp - public function getBlockPrefix(); + public function getBlockPrefix(): string; } +diff --git a/src/Symfony/Component/Form/Test/FormIntegrationTestCase.php b/src/Symfony/Component/Form/Test/FormIntegrationTestCase.php +--- a/src/Symfony/Component/Form/Test/FormIntegrationTestCase.php ++++ b/src/Symfony/Component/Form/Test/FormIntegrationTestCase.php +@@ -40,5 +40,5 @@ abstract class FormIntegrationTestCase extends TestCase + * @return FormExtensionInterface[] + */ +- protected function getExtensions() ++ protected function getExtensions(): array + { + return []; +@@ -48,5 +48,5 @@ abstract class FormIntegrationTestCase extends TestCase + * @return FormTypeExtensionInterface[] + */ +- protected function getTypeExtensions() ++ protected function getTypeExtensions(): array + { + return []; +@@ -56,5 +56,5 @@ abstract class FormIntegrationTestCase extends TestCase + * @return FormTypeInterface[] + */ +- protected function getTypes() ++ protected function getTypes(): array + { + return []; +@@ -64,5 +64,5 @@ abstract class FormIntegrationTestCase extends TestCase + * @return FormTypeGuesserInterface[] + */ +- protected function getTypeGuessers() ++ protected function getTypeGuessers(): array + { + return []; +diff --git a/src/Symfony/Component/Form/Test/TypeTestCase.php b/src/Symfony/Component/Form/Test/TypeTestCase.php +--- a/src/Symfony/Component/Form/Test/TypeTestCase.php ++++ b/src/Symfony/Component/Form/Test/TypeTestCase.php +@@ -33,5 +33,5 @@ abstract class TypeTestCase extends FormIntegrationTestCase + * @return FormExtensionInterface[] + */ +- protected function getExtensions() ++ protected function getExtensions(): array + { + $extensions = []; +@@ -47,5 +47,5 @@ abstract class TypeTestCase extends FormIntegrationTestCase + * @return void + */ +- public static function assertDateTimeEquals(\DateTime $expected, \DateTime $actual) ++ public static function assertDateTimeEquals(\DateTime $expected, \DateTime $actual): void + { + self::assertEquals($expected->format('c'), $actual->format('c')); +@@ -55,5 +55,5 @@ abstract class TypeTestCase extends FormIntegrationTestCase + * @return void + */ +- public static function assertDateIntervalEquals(\DateInterval $expected, \DateInterval $actual) ++ public static function assertDateIntervalEquals(\DateInterval $expected, \DateInterval $actual): void + { + self::assertEquals($expected->format('%RP%yY%mM%dDT%hH%iM%sS'), $actual->format('%RP%yY%mM%dDT%hH%iM%sS')); diff --git a/src/Symfony/Component/HttpKernel/Bundle/Bundle.php b/src/Symfony/Component/HttpKernel/Bundle/Bundle.php --- a/src/Symfony/Component/HttpKernel/Bundle/Bundle.php +++ b/src/Symfony/Component/HttpKernel/Bundle/Bundle.php @@ -343,7 +425,7 @@ diff --git a/src/Symfony/Component/HttpKernel/Bundle/BundleInterface.php b/src/S 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 +++ b/src/Symfony/Component/HttpKernel/DataCollector/DataCollector.php -@@ -101,5 +101,5 @@ abstract class DataCollector implements DataCollectorInterface +@@ -111,5 +111,5 @@ abstract class DataCollector implements DataCollectorInterface * @return void */ - public function reset() @@ -356,8 +438,8 @@ 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 @@ -402,18 +484,18 @@ diff --git a/src/Symfony/Component/HttpKernel/KernelInterface.php b/src/Symfony/ 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 +++ b/src/Symfony/Component/Routing/Loader/AttributeClassLoader.php -@@ -234,5 +234,5 @@ abstract class AttributeClassLoader implements LoaderInterface +@@ -277,5 +277,5 @@ abstract class AttributeClassLoader implements LoaderInterface * @return string */ - protected function getDefaultRouteName(\ReflectionClass $class, \ReflectionMethod $method) + protected function getDefaultRouteName(\ReflectionClass $class, \ReflectionMethod $method): string { $name = str_replace('\\', '_', $class->name).'_'.$method->name; -@@ -333,5 +333,5 @@ abstract class AttributeClassLoader implements LoaderInterface +@@ -379,5 +379,5 @@ abstract class AttributeClassLoader implements LoaderInterface * @return void */ -- 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; +- abstract protected function configureRoute(Route $route, \ReflectionClass $class, \ReflectionMethod $method, object $attr); ++ abstract protected function configureRoute(Route $route, \ReflectionClass $class, \ReflectionMethod $method, object $attr): void; /** diff --git a/src/Symfony/Component/Security/Core/Authentication/RememberMe/TokenProviderInterface.php b/src/Symfony/Component/Security/Core/Authentication/RememberMe/TokenProviderInterface.php @@ -449,34 +531,44 @@ diff --git a/src/Symfony/Component/Security/Core/Authentication/RememberMe/Token diff --git a/src/Symfony/Component/Security/Http/Firewall.php b/src/Symfony/Component/Security/Http/Firewall.php --- a/src/Symfony/Component/Security/Http/Firewall.php +++ b/src/Symfony/Component/Security/Http/Firewall.php -@@ -51,5 +51,5 @@ class Firewall implements EventSubscriberInterface +@@ -48,5 +48,5 @@ class Firewall implements EventSubscriberInterface * @return void */ - public function onKernelRequest(RequestEvent $event) + public function onKernelRequest(RequestEvent $event): void { if (!$event->isMainRequest()) { -@@ -99,5 +99,5 @@ class Firewall implements EventSubscriberInterface +@@ -96,5 +96,5 @@ class Firewall implements EventSubscriberInterface * @return void */ - public function onKernelFinishRequest(FinishRequestEvent $event) + public function onKernelFinishRequest(FinishRequestEvent $event): void { $request = $event->getRequest(); -@@ -112,5 +112,5 @@ class Firewall implements EventSubscriberInterface +@@ -109,5 +109,5 @@ class Firewall implements EventSubscriberInterface * @return array */ - public static function getSubscribedEvents() + public static function getSubscribedEvents(): array { return [ -@@ -123,5 +123,5 @@ class Firewall implements EventSubscriberInterface +@@ -120,5 +120,5 @@ class Firewall implements EventSubscriberInterface * @return void */ - protected function callListeners(RequestEvent $event, iterable $listeners) + protected function callListeners(RequestEvent $event, iterable $listeners): void { foreach ($listeners as $listener) { +diff --git a/src/Symfony/Component/Serializer/Tests/Encoder/XmlEncoderTest.php b/src/Symfony/Component/Serializer/Tests/Encoder/XmlEncoderTest.php +--- a/src/Symfony/Component/Serializer/Tests/Encoder/XmlEncoderTest.php ++++ b/src/Symfony/Component/Serializer/Tests/Encoder/XmlEncoderTest.php +@@ -820,5 +820,5 @@ XML; + * @return Dummy + */ +- protected static function getObject(): object ++ protected static function getObject(): Dummy + { + $obj = new Dummy(); diff --git a/src/Symfony/Component/Translation/Extractor/ExtractorInterface.php b/src/Symfony/Component/Translation/Extractor/ExtractorInterface.php --- a/src/Symfony/Component/Translation/Extractor/ExtractorInterface.php +++ b/src/Symfony/Component/Translation/Extractor/ExtractorInterface.php @@ -493,6 +585,16 @@ diff --git a/src/Symfony/Component/Translation/Extractor/ExtractorInterface.php - public function setPrefix(string $prefix); + public function setPrefix(string $prefix): void; } +diff --git a/src/Symfony/Component/TypeInfo/Tests/Fixtures/DummyWithPhpDoc.php b/src/Symfony/Component/TypeInfo/Tests/Fixtures/DummyWithPhpDoc.php +--- a/src/Symfony/Component/TypeInfo/Tests/Fixtures/DummyWithPhpDoc.php ++++ b/src/Symfony/Component/TypeInfo/Tests/Fixtures/DummyWithPhpDoc.php +@@ -50,5 +50,5 @@ final class DummyWithPhpDoc + * @return Dummy + */ +- public function getNextDummy(mixed $dummy): mixed ++ public function getNextDummy(mixed $dummy): Dummy + { + throw new \BadMethodCallException(sprintf('"%s" is not implemented.', __METHOD__)); diff --git a/src/Symfony/Component/Validator/ConstraintValidatorInterface.php b/src/Symfony/Component/Validator/ConstraintValidatorInterface.php --- a/src/Symfony/Component/Validator/ConstraintValidatorInterface.php +++ b/src/Symfony/Component/Validator/ConstraintValidatorInterface.php @@ -518,6 +620,23 @@ diff --git a/src/Symfony/Component/VarDumper/Dumper/DataDumperInterface.php b/sr - public function dump(Data $data); + public function dump(Data $data): ?string; } +diff --git a/src/Symfony/Component/VarDumper/Test/VarDumperTestTrait.php b/src/Symfony/Component/VarDumper/Test/VarDumperTestTrait.php +--- a/src/Symfony/Component/VarDumper/Test/VarDumperTestTrait.php ++++ b/src/Symfony/Component/VarDumper/Test/VarDumperTestTrait.php +@@ -49,5 +49,5 @@ trait VarDumperTestTrait + * @return void + */ +- public function assertDumpEquals(mixed $expected, mixed $data, int $filter = 0, string $message = '') ++ public function assertDumpEquals(mixed $expected, mixed $data, int $filter = 0, string $message = ''): void + { + $this->assertSame($this->prepareExpectation($expected, $filter), $this->getDump($data, null, $filter), $message); +@@ -57,5 +57,5 @@ trait VarDumperTestTrait + * @return void + */ +- public function assertDumpMatchesFormat(mixed $expected, mixed $data, int $filter = 0, string $message = '') ++ public function assertDumpMatchesFormat(mixed $expected, mixed $data, int $filter = 0, string $message = ''): void + { + $this->assertStringMatchesFormat($this->prepareExpectation($expected, $filter), $this->getDump($data, null, $filter), $message); diff --git a/src/Symfony/Contracts/Translation/LocaleAwareInterface.php b/src/Symfony/Contracts/Translation/LocaleAwareInterface.php --- a/src/Symfony/Contracts/Translation/LocaleAwareInterface.php +++ b/src/Symfony/Contracts/Translation/LocaleAwareInterface.php diff --git a/.github/get-modified-packages.php b/.github/get-modified-packages.php index 11478cbe935c0..24de414fdd266 100644 --- a/.github/get-modified-packages.php +++ b/.github/get-modified-packages.php @@ -22,7 +22,7 @@ function getPackageType(string $packageDir): string return match (true) { str_contains($packageDir, 'Symfony/Bridge/') => 'bridge', str_contains($packageDir, 'Symfony/Bundle/') => 'bundle', - preg_match('@Symfony/Component/[^/]+/Bridge/@', $packageDir) => 'component_bridge', + 1 === preg_match('@Symfony/Component/[^/]+/Bridge/@', $packageDir) => 'component_bridge', str_contains($packageDir, 'Symfony/Component/') => 'component', str_contains($packageDir, 'Symfony/Contracts/') => 'contract', str_ends_with($packageDir, 'Symfony/Contracts') => 'contracts', diff --git a/.github/patch-types.php b/.github/patch-types.php index 08c1e1dedbee5..0a25ef95af146 100644 --- a/.github/patch-types.php +++ b/.github/patch-types.php @@ -1,5 +1,7 @@ getMethods() as $method) { if ( $method->getReturnType() - || str_contains($method->getDocComment(), '@return') + || (str_contains($method->getDocComment(), '@return') && str_contains($method->getDocComment(), 'resource')) || '__construct' === $method->getName() || '__destruct' === $method->getName() || '__clone' === $method->getName() || $method->getDeclaringClass()->getName() !== $class - || str_contains($method->getDeclaringClass()->getName(), '\\Test\\') + || str_contains($method->getDeclaringClass()->getName(), '\\Tests\\') + || str_contains($method->getDeclaringClass()->getName(), '\\Test\\') && str_starts_with($method->getName(), 'test') ) { continue; } @@ -93,6 +90,7 @@ class_exists($class); if ($missingReturnTypes) { echo \count($missingReturnTypes)." missing return types on interfaces\n\n"; echo implode("\n", $missingReturnTypes); + echo "\n"; exit(1); } diff --git a/.github/sync-packages.php b/.github/sync-packages.php new file mode 100644 index 0000000000000..8eb8db47c85e4 --- /dev/null +++ b/.github/sync-packages.php @@ -0,0 +1,57 @@ +formatOutput = true; @@ -27,12 +27,19 @@ function dumpXliff1(string $defaultLocale, MessageCatalogue $messages, string $d $xliffFile->setAttribute('datatype', 'plaintext'); $xliffFile->setAttribute('original', 'file.ext'); + if (null !== $header) { + mergeDom($dom, $xliffFile, $header); + } + $xliffBody = $xliffFile->appendChild($dom->createElement('body')); foreach ($messages->all($domain) as $source => $target) { $translation = $dom->createElement('trans-unit'); $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)); @@ -59,30 +66,66 @@ function dumpXliff1(string $defaultLocale, MessageCatalogue $messages, string $d return preg_replace('/^ +/m', '$0$0', $dom->saveXML()); } +function mergeDom(\DOMDocument $dom, \DOMNode $tree, \DOMNode $input) +{ + $new = $dom->createElement($input->tagName); + foreach ($input->attributes as $key => $value) { + $new->setAttribute($key, $value); + } + $tree->appendChild($new); + foreach ($input->childNodes as $child) { + if ($child instanceof \DOMText) { + $new->appendChild($dom->createTextNode(str_replace(' ', ' ', $child->textContent))); + } elseif ($child instanceof \DOMNode) { + mergeDom($dom, $new, $child); + } else { + // We just need to update our script to handle this node types + throw new \LogicException('Unsupported node type: '.get_class($child)); + } + } +} foreach (['Security/Core' => 'security', 'Form' => 'validators', 'Validator' => 'validators'] as $component => $domain) { $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); + } else { + $translation = $source; } - $metadata['id'] = $enCatalogue->getMetadata($id, $domain)['id']; - $localeCatalogue->set($id, $translation, $domain); - $localeCatalogue->setMetadata($id, $metadata, $domain); + $metadata['id'] = $enCatalogue->getMetadata($resname, $domain)['id']; + if ($resname !== $source) { + $metadata['resname'] = $resname; + } + $localeCatalogue->set($source, $translation, $domain); + $localeCatalogue->setMetadata($source, $metadata, $domain); + } + + $inputDom = new \DOMDocument(); + $inputDom->loadXML(file_get_contents($file->getRealPath())); + $header = null; + if (1 === $inputDom->getElementsByTagName('header')->count()) { + $header = $inputDom->getElementsByTagName('header')->item(0); } - file_put_contents($file, dumpXliff1('en', $localeCatalogue, $domain)); + file_put_contents($file, dumpXliff1('en', $localeCatalogue, $domain, $header)); } } diff --git a/.github/workflows/integration-tests.yml b/.github/workflows/integration-tests.yml index 71182fcbaaa32..a2a3f8853882a 100644 --- a/.github/workflows/integration-tests.yml +++ b/.github/workflows/integration-tests.yml @@ -19,7 +19,7 @@ jobs: tests: name: Integration - runs-on: Ubuntu-20.04 + runs-on: ubuntu-24.04 strategy: matrix: @@ -28,7 +28,7 @@ jobs: services: postgres: - image: postgres:10.6-alpine + image: postgres:16-alpine ports: - 5432:5432 env: @@ -44,6 +44,13 @@ jobs: LDAP_PORT_NUMBER: 3389 LDAP_USERS: a LDAP_PASSWORDS: a + ftp: + image: onekilo79/ftpd_test + ports: + - 21:21 + - 30000-30009:30000-30009 + volumes: + - ./:/hostmount redis: image: redis:6.2.8 ports: @@ -74,6 +81,26 @@ jobs: REDIS_MASTER_HOST: redis REDIS_MASTER_SET: redis_sentinel REDIS_SENTINEL_QUORUM: 1 + redis-primary: + image: bitnami/redis:latest + ports: + - 16381:6379 + env: + ALLOW_EMPTY_PASSWORD: "yes" + REDIS_REPLICATION_MODE: "master" + options: >- + --name=redis-primary + redis-replica: + image: bitnami/redis:latest + ports: + - 16382:6379 + env: + ALLOW_EMPTY_PASSWORD: "yes" + REDIS_REPLICATION_MODE: "slave" + REDIS_MASTER_HOST: redis-primary + REDIS_MASTER_PORT_NUMBER: "6379" + options: >- + --name=redis-replica memcached: image: memcached:1.6.5 ports: @@ -95,31 +122,57 @@ 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 + image: zookeeper kafka: - image: wurstmeister/kafka:2.12-2.0.1 + image: bitnami/kafka:3.7 ports: - 9092:9092 env: - KAFKA_AUTO_CREATE_TOPICS_ENABLE: false - KAFKA_CREATE_TOPICS: 'test-topic:1:1:compact' - KAFKA_ADVERTISED_HOST_NAME: 127.0.0.1 - KAFKA_ZOOKEEPER_CONNECT: 'zookeeper:2181' - KAFKA_ADVERTISED_PORT: 9092 + KAFKA_CFG_AUTO_CREATE_TOPICS_ENABLE: false + ALLOW_PLAINTEXT_LISTENER: 'yes' + KAFKA_CFG_ADVERTISED_LISTENERS: 'PLAINTEXT://127.0.0.1:9092' + KAFKA_CFG_LISTENERS: 'PLAINTEXT://:9092' + KAFKA_CFG_ZOOKEEPER_CONNECT: 'zookeeper:2181' + options: --name=kafka + frankenphp: + image: dunglas/frankenphp:1.1.0 + ports: + - 80:80 + - 8681:81 + - 8682:82 + - 8683:83 + - 8684:84 + volumes: + - ${{ github.workspace }}:/symfony + env: + SERVER_NAME: 'http://localhost http://localhost:81 http://localhost:82 http://localhost:83 http://localhost:84' + CADDY_SERVER_EXTRA_DIRECTIVES: | + route /http-client* { + root * /symfony/src/Symfony/Component/HttpClient/Tests/Fixtures/response-functional/ + php_server + } + + root * /symfony/src/Symfony/Component/HttpFoundation/Tests/Fixtures/response-functional/ steps: - name: Checkout uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - name: Init Kafka topics + run: | + docker exec kafka /opt/bitnami/kafka/bin/kafka-topics.sh --create --topic test-topic --bootstrap-server kafka:9092 - name: Install system dependencies run: | echo "::group::apt-get update" sudo wget -O - https://packages.couchbase.com/clients/c/repos/deb/couchbase.key | sudo apt-key add - - echo "deb https://packages.couchbase.com/clients/c/repos/deb/ubuntu2004 focal focal/main" | sudo tee /etc/apt/sources.list.d/couchbase.list + echo "deb https://packages.couchbase.com/clients/c/repos/deb/ubuntu2404 noble noble/main" | sudo tee /etc/apt/sources.list.d/couchbase.list sudo apt-get update echo "::endgroup::" @@ -130,6 +183,14 @@ jobs: sudo service redis-server restart echo "::endgroup::" + - name: Install pgbouncer + run: | + sudo apt-get install -y pgbouncer + sudo cp src/Symfony/Component/Messenger/Bridge/Doctrine/Tests/Fixtures/pgbouncer/pgbouncer.ini /etc/pgbouncer/pgbouncer.ini + sudo cp src/Symfony/Component/Messenger/Bridge/Doctrine/Tests/Fixtures/pgbouncer/userlist.txt /etc/pgbouncer/userlist.txt + sudo service pgbouncer restart + sudo su - postgres -c "PGPASSWORD=password psql -Atq -h localhost -p 5432 -U postgres -d postgres -c \"SELECT usename, passwd FROM pg_shadow\"" + - name: Configure Couchbase run: | curl -s -u 'username=Administrator&password=111111@' -X POST http://localhost:8091/node/controller/setupServices -d 'services=kv%2Cn1ql%2Cindex%2Cfts' @@ -137,6 +198,11 @@ jobs: curl -s -u Administrator:111111@ -X POST http://localhost:8091/pools/default/buckets -d 'ramQuotaMB=100&bucketType=ephemeral&name=cache' curl -s -u Administrator:111111@ -X POST http://localhost:8091/pools/default -d 'memoryQuota=256' + - name: Create FTP fixtures + run: | + mkdir -p ./ftpusers/test/pub + touch ./ftpusers/test/pub/example ./ftpusers/test/readme.txt + - name: Setup PHP uses: shivammathur/setup-php@v2 with: @@ -172,20 +238,35 @@ jobs: ./phpunit install echo "::endgroup::" + - name: Check for changes in translation files + id: changed-translation-files + run: | + echo 'changed='$((git diff --quiet HEAD~1 HEAD -- 'src/**/Resources/translations/*.xlf' || (echo 'true' && exit 1)) && echo 'false') >> $GITHUB_OUTPUT + + - name: Check Translation Status + if: steps.changed-translation-files.outputs.changed == 'true' + run: | + php src/Symfony/Component/Translation/Resources/bin/translation-status.php -v + php .github/sync-translations.php + git diff --exit-code src/ || (echo '::error::Run "php .github/sync-translations.php" to fix XLIFF files.' && exit 1) + - name: Run tests run: ./phpunit --group integration -v env: + INTEGRATION_FTP_URL: 'ftp://test:test@localhost' REDIS_HOST: 'localhost:16379' REDIS_AUTHENTICATED_HOST: 'localhost:16380' REDIS_CLUSTER_HOSTS: 'localhost:7000 localhost:7001 localhost:7002 localhost:7003 localhost:7004 localhost:7005' REDIS_SENTINEL_HOSTS: 'unreachable-host:26379 localhost:26379 localhost:26379' REDIS_SENTINEL_SERVICE: redis_sentinel + REDIS_REPLICATION_HOSTS: 'localhost:16382 localhost:16381' 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 + PGBOUNCER_HOST: localhost:6432 #- name: Run HTTP push tests # if: matrix.php == '8.2' @@ -195,13 +276,3 @@ jobs: # docker run --rm -e COMPOSER_ROOT_VERSION -v $(pwd):/app -v $(which composer):/usr/local/bin/composer -v $(which vulcain):/usr/local/bin/vulcain -w /app php:8.1-alpine ./phpunit src/Symfony/Component/HttpClient/Tests/CurlHttpClientTest.php --filter testHttp2Push # sudo rm -rf .phpunit # [ -d .phpunit.bak ] && mv .phpunit.bak .phpunit - - - uses: marceloprado/has-changed-path@v1.0.1 - id: changed-translation-files - with: - paths: src/**/Resources/translations/*.xlf - - - name: Check Translation Status - if: steps.changed-translation-files.outputs.changed == 'true' - run: | - php src/Symfony/Component/Translation/Resources/bin/translation-status.php -v diff --git a/.github/workflows/intl-data-tests.yml b/.github/workflows/intl-data-tests.yml index 01401fedc232f..193b3dd1df14d 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,8 +35,8 @@ permissions: jobs: tests: - name: Intl data - runs-on: Ubuntu-20.04 + name: Intl/Emoji data + runs-on: ubuntu-24.04 steps: - name: Checkout @@ -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..55d1c82e3661a 100644 --- a/.github/workflows/package-tests.yml +++ b/.github/workflows/package-tests.yml @@ -11,7 +11,7 @@ permissions: jobs: verify: name: Verify Packages - runs-on: Ubuntu-20.04 + runs-on: ubuntu-24.04 steps: - name: Checkout code uses: actions/checkout@v4 @@ -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/phpunit-bridge.yml b/.github/workflows/phpunit-bridge.yml index fd169dfae782d..5de320ee91c0e 100644 --- a/.github/workflows/phpunit-bridge.yml +++ b/.github/workflows/phpunit-bridge.yml @@ -22,7 +22,7 @@ permissions: jobs: lint: name: Lint PhpUnitBridge - runs-on: Ubuntu-20.04 + runs-on: ubuntu-24.04 steps: - name: Checkout @@ -35,4 +35,4 @@ jobs: php-version: "7.2" - name: Lint - run: find ./src/Symfony/Bridge/PhpUnit -name '*.php' | grep -v -e /Tests/ -e ForV7 -e ForV8 -e ForV9 -e ConstraintLogicTrait | parallel -j 4 php -l {} + run: find ./src/Symfony/Bridge/PhpUnit -name '*.php' | grep -v -e /Tests/ -e /Attribute/ -e /Extension/ -e /Metadata/ -e ForV7 -e ForV8 -e ForV9 -e ConstraintLogicTrait -e SymfonyExtension | parallel -j 4 php -l {} diff --git a/.github/workflows/psalm.yml b/.github/workflows/psalm.yml index a165d0c7dc126..33a5f58b44c6a 100644 --- a/.github/workflows/psalm.yml +++ b/.github/workflows/psalm.yml @@ -17,7 +17,7 @@ permissions: jobs: psalm: name: Psalm - runs-on: Ubuntu-20.04 + runs-on: ubuntu-24.04 env: php-version: '8.2' diff --git a/.github/workflows/scorecards.yml b/.github/workflows/scorecards.yml index 0753dc03e2789..1033e761a2d0b 100644 --- a/.github/workflows/scorecards.yml +++ b/.github/workflows/scorecards.yml @@ -6,7 +6,7 @@ on: schedule: - cron: '34 4 * * 6' push: - branches: [ "7.1" ] + branches: [ "7.4" ] # Declare default permissions as read only. permissions: read-all @@ -14,7 +14,7 @@ permissions: read-all jobs: analysis: name: Scorecards analysis - runs-on: ubuntu-latest + runs-on: ubuntu-24.04 permissions: # Needed to upload the results to code-scanning dashboard. security-events: write @@ -26,38 +26,45 @@ jobs: steps: - name: "Checkout code" - uses: actions/checkout@a12a3943b4bdde767164f792f33f40b04645d846 # v3.0.0 + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 with: persist-credentials: false - name: "Run analysis" - uses: ossf/scorecard-action@3e15ea8318eee9b333819ec77a36aca8d39df13e # v1.1.1 + uses: ossf/scorecard-action@f49aabe0b5af0936a0987cfb85d86b75731b0186 # v2.4.1 with: results_file: results.sarif results_format: sarif - # (Optional) Read-only PAT token. Uncomment the `repo_token` line below if: + # (Optional) "write" PAT token. Uncomment the `repo_token` line below if: # - you want to enable the Branch-Protection check on a *public* repository, or - # - you are installing Scorecards on a *private* repository - # To create the PAT, follow the steps in https://github.com/ossf/scorecard-action#authentication-with-pat. - # repo_token: ${{ secrets.SCORECARD_READ_TOKEN }} - - # Publish the results for public repositories to enable scorecard badges. For more details, see - # https://github.com/ossf/scorecard-action#publishing-results. - # For private repositories, `publish_results` will automatically be set to `false`, regardless - # of the value entered here. + # - you are installing Scorecard on a *private* repository + # To create the PAT, follow the steps in https://github.com/ossf/scorecard-action?tab=readme-ov-file#authentication-with-fine-grained-pat-optional. + # repo_token: ${{ secrets.SCORECARD_TOKEN }} + + # Public repositories: + # - Publish results to OpenSSF REST API for easy access by consumers + # - Allows the repository to include the Scorecard badge. + # - See https://github.com/ossf/scorecard-action#publishing-results. + # For private repositories: + # - `publish_results` will always be set to `false`, regardless + # of the value entered here. publish_results: true + # (Optional) Uncomment file_mode if you have a .gitattributes with files marked export-ignore + # file_mode: git + # Upload the results as artifacts (optional). Commenting out will disable uploads of run results in SARIF # format to the repository Actions tab. - name: "Upload artifact" - uses: actions/upload-artifact@6673cd052c4cd6fcf4b4e6e60ea986c889389535 # v3.0.0 + uses: actions/upload-artifact@4cec3d8aa04e39d1a68397de0c4cd6fb9dce8ec1 # v4.6.1 with: name: SARIF file path: results.sarif retention-days: 5 - # Upload the results to GitHub's code scanning dashboard. + # Upload the results to GitHub's code scanning dashboard (optional). + # Commenting out will disable upload of results to your repo's Code Scanning dashboard - name: "Upload to code-scanning" - uses: github/codeql-action/upload-sarif@5f532563584d71fdef14ee64d17bafb34f751ce5 # v1.0.26 + uses: github/codeql-action/upload-sarif@v3 with: sarif_file: results.sarif diff --git a/.github/workflows/unit-tests.yml b/.github/workflows/unit-tests.yml index 414408098f091..a378511725a96 100644 --- a/.github/workflows/unit-tests.yml +++ b/.github/workflows/unit-tests.yml @@ -21,7 +21,7 @@ jobs: name: Unit Tests env: - extensions: amqp,apcu,igbinary,intl,mbstring,memcached,redis,relay + extensions: amqp,apcu,brotli,igbinary,intl,mbstring,memcached,redis,relay,zstd strategy: matrix: @@ -32,10 +32,12 @@ jobs: - php: '8.2' mode: low-deps - php: '8.3' + - php: '8.4' + - php: '8.5' #mode: experimental fail-fast: false - runs-on: ubuntu-20.04 + runs-on: ubuntu-24.04 steps: - name: Checkout @@ -49,9 +51,15 @@ jobs: coverage: "none" ini-values: date.timezone=UTC,memory_limit=-1,default_socket_timeout=10,session.gc_probability=0,apc.enable_cli=1,zend.assertions=1 php-version: "${{ matrix.php }}" - extensions: "${{ env.extensions }}" + extensions: "${{ matrix.extensions || env.extensions }}" tools: flex + - name: Install optional commands + if: matrix.php == '8.4' + run: | + sudo apt-get update + sudo apt-get install zopfli + - name: Configure environment run: | git config --global user.email "" @@ -59,7 +67,7 @@ jobs: git config --global init.defaultBranch main git config --global advice.detachedHead false - (php --ri relay 2>&1 > /dev/null) || sudo rm /etc/php/*/cli/conf.d/20-relay.ini + (php --ri relay 2>&1 > /dev/null) || sudo rm -f /etc/php/*/cli/conf.d/20-relay.ini COMPOSER_HOME="$(composer config home)" ([ -d "$COMPOSER_HOME" ] || mkdir "$COMPOSER_HOME") && cp .github/composer-config.json "$COMPOSER_HOME/config.json" @@ -90,12 +98,12 @@ jobs: # Create local composer packages for each patched components and reference them in composer.json files when cross-testing components if [[ ! "${{ matrix.mode }}" = *-deps ]]; then - php .github/build-packages.php HEAD^ $SYMFONY_VERSION src/Symfony/Bridge/PhpUnit + php .github/build-packages.php HEAD^ $SYMFONY_VERSION src/Symfony/Bridge/PhpUnit else 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 @@ -125,13 +133,9 @@ jobs: echo SYMFONY_VERSION=$SYMFONY_VERSION >> $GITHUB_ENV echo COMPOSER_ROOT_VERSION=$SYMFONY_VERSION.x-dev >> $GITHUB_ENV - echo SYMFONY_REQUIRE=">=$([ '${{ matrix.mode }}' = low-deps ] && echo 5.4 || echo $SYMFONY_VERSION)" >> $GITHUB_ENV + echo SYMFONY_REQUIRE=">=$([ '${{ matrix.mode }}' = low-deps ] && echo 6.4 || echo $SYMFONY_VERSION)" >> $GITHUB_ENV [[ "${{ 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 - fi - - name: Install dependencies run: | echo "::group::composer update" @@ -147,9 +151,10 @@ jobs: run: | patch -sp1 < .github/expected-missing-return-types.diff git add . + sed -i 's/ *"\*\*\/Tests\/",//' composer.json composer install -q --optimize-autoloader || composer install --optimize-autoloader SYMFONY_PATCH_TYPE_DECLARATIONS='force=2&php=8.2' php .github/patch-types.php - git checkout src/Symfony/Contracts/Service/ResetInterface.php + git checkout composer.json src/Symfony/Contracts/Service/ResetInterface.php SYMFONY_PATCH_TYPE_DECLARATIONS='force=2&php=8.2' php .github/patch-types.php # ensure the script is idempotent git checkout src/Symfony/Contracts/Service/ResetInterface.php git diff --exit-code @@ -201,8 +206,8 @@ jobs: # get a list of the patched components (relies on .github/build-packages.php being called in the previous step) PATCHED_COMPONENTS=$(git diff --name-only src/ | grep composer.json || true) - # for 6.4 LTS, checkout and test previous major with the patched components (only for patched components) - if [[ $PATCHED_COMPONENTS && $SYMFONY_VERSION = 6.4 ]]; then + # for 7.4 LTS, checkout and test previous major with the patched components (only for patched components) + if [[ $PATCHED_COMPONENTS && $SYMFONY_VERSION = 7.4 ]]; then export FLIP='^' SYMFONY_VERSION=$(echo $SYMFONY_VERSION | awk '{print $1 - 1}') echo -e "\\n\\e[33;1mChecking out Symfony $SYMFONY_VERSION and running tests with patched components as deps\\e[0m" @@ -226,6 +231,12 @@ jobs: run: | script -e -c './phpunit --group tty' /dev/null + - name: Run AssetMapper without ext-brotli nor ext-zstd + if: "! matrix.mode" + run: | + sudo rm /etc/php/*/cli/conf.d/*-{brotli,zstd}.ini + ./phpunit src/Symfony/Component/AssetMapper + - name: Run tests with SIGCHLD enabled PHP if: "matrix.php == '8.2' && ! matrix.mode" run: | @@ -238,3 +249,11 @@ jobs: mkdir -p /opt/php/lib echo memory_limit=-1 > /opt/php/lib/php.ini ./build/php/bin/php ./phpunit --colors=always src/Symfony/Component/Process + + - name: Run PhpUnitBridge tests with PHPUnit 11 + if: '! matrix.mode' + run: | + ./phpunit src/Symfony/Bridge/PhpUnit + env: + SYMFONY_PHPUNIT_VERSION: '11.3' + SYMFONY_DEPRECATIONS_HELPER: 'disabled' diff --git a/.github/workflows/windows.yml b/.github/workflows/windows.yml new file mode 100644 index 0000000000000..62ab3e5e6a3aa --- /dev/null +++ b/.github/workflows/windows.yml @@ -0,0 +1,131 @@ +name: Windows + +on: + push: + pull_request: + +concurrency: + group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }} + cancel-in-progress: true + +permissions: + contents: read + +jobs: + windows: + name: x86 / minimal-exts / lowest-php + + defaults: + run: + shell: p 8000 wsh + + runs-on: windows-2022 + + env: + COMPOSER_NO_INTERACTION: '1' + SYMFONY_DEPRECATIONS_HELPER: 'strict' + ANSICON: '121x90 (121x90)' + SYMFONY_PHPUNIT_DISABLE_RESULT_CACHE: '1' + + steps: + - name: Setup Git + run: | + git config --global core.autocrlf false + git config --global user.email "" + git config --global user.name "Symfony" + + - name: Checkout + uses: actions/checkout@v4 + with: + fetch-depth: 2 + + - name: Setup PHP + run: | + $env:Path = 'c:\php;' + $env:Path + mkdir c:\php && cd c:\php + iwr -outf php-8.2.0-Win32-vs16-x86.zip https://github.com/symfony/binary-utils/releases/download/v0.1/php-8.2.0-Win32-vs16-x86.zip + 7z x php-8.2.0-Win32-vs16-x86.zip -y >nul + cd ext + iwr -outf php_apcu-5.1.22-8.2-ts-vs16-x86.zip https://github.com/symfony/binary-utils/releases/download/v0.1/php_apcu-5.1.22-8.2-ts-vs16-x86.zip + 7z x php_apcu-5.1.22-8.2-ts-vs16-x86.zip -y >nul + iwr -outf php_redis-6.0.0-dev-8.2-ts-vs16-x86.zip https://github.com/symfony/binary-utils/releases/download/v0.1/php_redis-6.0.0-dev-8.2-ts-vs16-x86.zip + 7z x php_redis-6.0.0-dev-8.2-ts-vs16-x86.zip -y >nul + cd .. + Copy php.ini-development php.ini-min + "memory_limit=-1" >> php.ini-min + "serialize_precision=-1" >> php.ini-min + "max_execution_time=1200" >> php.ini-min + "post_max_size=2047M" >> php.ini-min + "upload_max_filesize=2047M" >> php.ini-min + "date.timezone=`"America/Los_Angeles`"" >> php.ini-min + "extension_dir=ext" >> php.ini-min + "extension=php_xsl.dll" >> php.ini-min + "extension=php_mbstring.dll" >> php.ini-min + Copy php.ini-min php.ini-max + "zend_extension=php_opcache.dll" >> php.ini-max + "opcache.enable_cli=1" >> php.ini-max + "extension=php_openssl.dll" >> php.ini-max + "extension=php_apcu.dll" >> php.ini-max + "extension=php_igbinary.dll" >> php.ini-max + "extension=php_redis.dll" >> php.ini-max + "apc.enable_cli=1" >> php.ini-max + "extension=php_intl.dll" >> php.ini-max + "extension=php_fileinfo.dll" >> php.ini-max + "extension=php_pdo_sqlite.dll" >> php.ini-max + "extension=php_curl.dll" >> php.ini-max + "extension=php_sodium.dll" >> php.ini-max + Copy php.ini-max php.ini + cd ${{ github.workspace }} + iwr -outf composer.phar https://getcomposer.org/download/latest-stable/composer.phar + + - name: Install dependencies + id: setup + run: | + $env:Path = 'c:\php;' + $env:Path + mkdir $env:APPDATA\Composer && Copy .github\composer-config.json $env:APPDATA\Composer\config.json + + $env:SYMFONY_VERSION=(Select-String -CaseSensitive -Pattern " VERSION =" -SimpleMatch -Path src/Symfony/Component/HttpKernel/Kernel.php | Select Line | Select-String -Pattern "([0-9][0-9]*\.[0-9])").Matches.Value + $env:COMPOSER_ROOT_VERSION=$env:SYMFONY_VERSION + ".x-dev" + + php .github/build-packages.php HEAD^ $env:SYMFONY_VERSION src\Symfony\Bridge\PhpUnit + php composer.phar update --no-progress --ansi + + - name: Install PHPUnit + run: | + $env:Path = 'c:\php;' + $env:Path + + php phpunit install + + - name: Install memurai-developer + run: | + choco install --no-progress memurai-developer + + - name: Run tests (minimal extensions) + if: always() && steps.setup.outcome == 'success' + run: | + $env:Path = 'c:\php;' + $env:Path + $env:SYMFONY_PHPUNIT_SKIPPED_TESTS = 'phpunit.skipped' + $x = 0 + + Copy c:\php\php.ini-min c:\php\php.ini + Remove-Item -Path src\Symfony\Bridge\PhpUnit -Recurse + mv src\Symfony\Component\HttpClient\phpunit.xml.dist src\Symfony\Component\HttpClient\phpunit.xml + php phpunit src\Symfony --exclude-group tty,benchmark,intl-data,network,transient-on-windows || ($x = 1) + # HttpClient tests need to run separately, they block when run with other components' tests concurrently + php phpunit src\Symfony\Component\HttpClient || ($x = 1) + + exit $x + + - name: Run tests + if: always() && steps.setup.outcome == 'success' + run: | + $env:Path = 'c:\php;' + $env:Path + $env:SYMFONY_PHPUNIT_SKIPPED_TESTS = 'phpunit.skipped' + $x = 0 + + Copy c:\php\php.ini-max c:\php\php.ini + php phpunit src\Symfony --exclude-group tty,benchmark,intl-data,network,transient-on-windows || ($x = 1) + # HttpClient tests need to run separately, they block when run with other components' tests concurrently + php phpunit src\Symfony\Component\HttpClient || ($x = 1) + + exit $x diff --git a/.php-cs-fixer.dist.php b/.php-cs-fixer.dist.php index 86c5b0f1b7371..f3e25eaa66a0d 100644 --- a/.php-cs-fixer.dist.php +++ b/.php-cs-fixer.dist.php @@ -13,32 +13,39 @@ exit(0); } -$fileHeaderComment = <<<'EOF' -This file is part of the Symfony package. +$fileHeaderParts = [ + <<<'EOF' + This file is part of the Symfony package. -(c) Fabien Potencier + (c) Fabien Potencier -For the full copyright and license information, please view the LICENSE -file that was distributed with this source code. -EOF; + EOF, + <<<'EOF' + + For the full copyright and license information, please view the LICENSE + file that was distributed with this source code. + EOF, +]; return (new PhpCsFixer\Config()) + // @see https://github.com/PHP-CS-Fixer/PHP-CS-Fixer/pull/7777 + ->setParallelConfig(PhpCsFixer\Runner\Parallel\ParallelConfigFactory::detect()) ->setRules([ '@PHP71Migration' => true, '@PHPUnit75Migration:risky' => true, '@Symfony' => true, '@Symfony:risky' => true, 'protected_to_private' => false, - 'native_constant_invocation' => ['strict' => false], - 'no_superfluous_phpdoc_tags' => [ - '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 + 'header_comment' => [ + 'header' => implode('', $fileHeaderParts), + 'validator' => implode('', [ + '/', + preg_quote($fileHeaderParts[0], '/'), + '(?P.*)??', + preg_quote($fileHeaderParts[1], '/'), + '/s', + ]) ], - 'header_comment' => ['header' => $fileHeaderComment], - 'modernize_strpos' => true, - 'get_class_to_class_keyword' => true, - 'nullable_type_declaration' => true, - 'trailing_comma_in_multiline' => ['elements' => ['arrays', 'match', 'parameters']], ]) ->setRiskyAllowed(true) ->setFinder( @@ -47,13 +54,9 @@ ->append([__FILE__]) ->notPath('#/Fixtures/#') ->exclude([ - // directories containing files with content that is autogenerated by `var_export`, which breaks CS in output code - // fixture templates - 'Symfony/Bundle/FrameworkBundle/Tests/Templating/Helper/Resources/Custom', - // resource templates - '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` @@ -63,22 +66,22 @@ ->notPath('Symfony/Bridge/PhpUnit/SymfonyTestsListener.php') ->notPath('#Symfony/Bridge/PhpUnit/.*Mock\.php#') ->notPath('#Symfony/Bridge/PhpUnit/.*Legacy#') - // file content autogenerated by `var_export` - ->notPath('Symfony/Component/Translation/Tests/Fixtures/resources.php') - // file content autogenerated by `VarExporter::export` - ->notPath('Symfony/Component/Serializer/Tests/Fixtures/serializer.class.metadata.php') - // test template - ->notPath('Symfony/Bundle/FrameworkBundle/Tests/Templating/Helper/Resources/Custom/_name_entry_label.html.php') // explicit trigger_error tests ->notPath('Symfony/Component/ErrorHandler/Tests/DebugClassLoaderTest.php') // stop removing spaces on the end of the line in strings ->notPath('Symfony/Component/Messenger/Tests/Command/FailedMessagesShowCommandTest.php') + // disable to not apply `native_function_invocation` rule, as we explicitly break it for testability reason, ref https://github.com/symfony/symfony/pull/59195 + ->notPath('Symfony/Component/Mailer/Transport/NativeTransportFactory.php') // auto-generated proxies ->notPath('Symfony/Component/Cache/Traits/RelayProxy.php') ->notPath('Symfony/Component/Cache/Traits/Redis5Proxy.php') ->notPath('Symfony/Component/Cache/Traits/Redis6Proxy.php') ->notPath('Symfony/Component/Cache/Traits/RedisCluster5Proxy.php') ->notPath('Symfony/Component/Cache/Traits/RedisCluster6Proxy.php') + // svg + ->notPath('Symfony/Component/ErrorHandler/Resources/assets/images/symfony-ghost.svg.php') + // HTML templates + ->notPath('#Symfony/.*\.html\.php#') ) ->setCacheFile('.php-cs-fixer.cache') ; diff --git a/CHANGELOG-7.0.md b/CHANGELOG-7.0.md index 17289415f1144..5dbc2a701c8cd 100644 --- a/CHANGELOG-7.0.md +++ b/CHANGELOG-7.0.md @@ -7,6 +7,323 @@ 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.10 (2024-07-26) + + * bug #57803 [FrameworkBundle] move adding detailed JSON error messages to the validate phase (xabbuh) + * bug #57815 [Console][PhpUnitBridge][VarDumper] Fix `NO_COLOR` empty value handling (alexandre-daubois) + * bug #57828 [Translation] Fix CSV escape char in `CsvFileLoader` on PHP >= 7.4 (alexandre-daubois) + * bug #57812 [Validator] treat uninitialized properties referenced by property paths as null (xabbuh) + * bug #57816 [DoctrineBridge] fix messenger bus dispatch inside an active transaction (IndraGunawan) + * bug #57799 [ErrorHandler][VarDumper] Remove PHP 8.4 deprecations (alexandre-daubois) + * bug #57772 [WebProfilerBundle] Add word wrap in tables in dialog to see all the text in workflow listeners dialog (SpartakusMd) + * bug #57802 [PropertyInfo] Fix nullable value returned from extractFromMutator on CollectionType (benjilebon) + * bug #57832 [DependencyInjection] Do not try to load default method name on interface (lyrixx) + * bug #57748 [SecurityBundle] use firewall-specific user checkers when manually logging in users (xabbuh) + * bug #57753 [ErrorHandler] restrict the maximum length of the X-Debug-Exception header (xabbuh) + * bug #57646 [Serializer] Raise correct exception in `ArrayDenormalizer` when called without a nested denormalizer (derrabus) + * bug #57674 [Cache] Improve `dbindex` DSN parameter parsing (constantable) + * bug #57678 [Validator] Add `setGroupProvider` to `AttributeLoader` (Maximilian Zumbansen) + * bug #57679 [WebProfilerBundle] Change incorrect check for the `stateless` request attribute (themasch) + * bug #57663 [Cache] use copy() instead of rename() on Windows (xabbuh) + * bug #57617 [PropertyInfo] Handle collection in PhpStan same as PhpDoc (mtarld) + * bug #54057 [Messenger] Passing actual `Envelope` to `WorkerMessageRetriedEvent` (daffoxdev) + * bug #57645 [Routing] Discard in-memory cache of routes when writing the file-based cache (mpdude) + * bug #57621 [Mailer]  force HTTP 1.1 for Mailgun API requests (xabbuh) + * bug #57616 [String] Revert "Fixed u()->snake(), b()->snake() and s()->snake() methods" (nicolas-grekas) + * bug #57593 [SecurityBundle] Compare paths after realpath() has been applied to both (xabbuh) + * bug #57594 [String] Normalize underscores in snake() (xabbuh) + * bug #57585 [HttpFoundation] Fix MockArraySessionStorage to generate more conform ids (Seldaek) + * bug #57589 [FrameworkBundle] fix AssetMapper usage without assets enabled (xabbuh) + +* 7.0.9 (2024-06-28) + + * bug #57345 [DependencyInjection] Fix regression in ordering service locators by priority (longwave) + * bug #57553 [HttpKernel] Enable optional cache-warmers when cache-dir != build-dir (nicolas-grekas) + * bug #57497 [String] Fixed u()->snake(), b()->snake() and s()->snake() methods (arczinosek) + * bug #57574 [Filesystem] Fix Filesystem::remove() on Windows (nicolas-grekas) + * bug #57572 [DoctrineBridge] Fix compat with DI >= 6.4 (nicolas-grekas) + * bug #57538 [String] Add `alias` case to `EnglishInflector` (alexandre-daubois) + * bug #57533 [FrameworkBundle] Throw runtime exception when trying to use asset-mapper while http-client is disabled (nicolas-grekas) + * bug #57520 [SecurityBundle] Remove unused memory users’ `name` attribute from the XSD (MatTheCat) + * feature #57557 Ibexa is sponsoring Symfony 5.4, thanks to them! \o/ (nicolas-grekas) + * bug #57569 [HttpClient][Mailer] Revert "Let curl handle transfer encoding", use HTTP/1.1 for Mailgun (nicolas-grekas) + * bug #57499 [Mailer] Add additional headers in Scaleway bridge (MrMicky-FR) + * bug #57460 [VarExporter] fix contravariance problem with __unserialize() in lazy proxy (nikophil) + * bug #57397 [VarDumper] Fix FFI caster test (alexandre-daubois) + * bug #57453 [HttpClient] Fix parsing SSE (fancyweb) + * bug #57467 [SecurityBundle] Add `provider` XML attribute to the authenticators it’s missing from (MatTheCat) + * bug #57384 [Notifier] Fix thread key in GoogleChat bridge (romain-jacquart) + * bug #57372 [HttpKernel][Security] Fix accessing session for stateless request (VincentLanglet) + * bug #57112 [Messenger] Handle `AMQPConnectionException` when publishing a message (jwage) + * bug #57341 [Serializer] properly handle invalid data for false/true types (xabbuh) + * bug #57187 [Serializer] Fix `ObjectNormalizer` with property path (HypeMC) + * bug #57355 [ErrorHandler] Fix rendered exception code highlighting on PHP 8.3 (tscni) + * bug #57310 [DependencyInjection] Fix ternary in `AutowireCallable` attribute (alamirault) + * bug #57273 [FrameworkBundle] Fix setting default context for certain normalizers (HypeMC) + * bug #57395 [Notifier]  send the recipient phone number as an array (xabbuh) + * bug #52699 [Serializer] [PropertyAccessor] Ignore non-collection interface generics (mtarld) + * bug #54634 [String] Fix #54611 pluralization of -on ending words + singularization of -a ending foreign words (Geordie, DesLynx) + * bug #57213 [Validator] [UniqueValidator] Use correct variable as parameter in (custom) error message (seho-nl, Sebastien Hoek) + * bug #54920 [Messenger] Comply with Amazon SQS requirements for message body (VincentLanglet) + * bug #57321 [AssetMapper] fix npm version constraint conversion (Jean-Beru) + * bug #57110 [PhpUnitBridge] Fix error handler triggered outside of tests (HypeMC) + * bug #57297 [FrameworkBundle] not registered definitions must not be modified (xabbuh) + * bug #57234 [String] Fix Inflector for 'hardware' (podhy) + * bug #57224 [Mime] Use streams instead of loading raw message generator into memory (bytestream) + +* 7.0.8 (2024-06-02) + + * bug #57284 [Mime] Fix TextPart using an unknown File (fabpot) + * bug #57282 [Scheduler] Throw an exception when no dispatcher has been passed to a Schedule (fabpot) + * bug #57275 Fix autoload configs to avoid warnings when building optimized autoloaders (Seldaek) + * bug #54572 [Mailer] Fix sendmail transport failure handling and interactive mode (bobvandevijver) + * bug #57228 [Mime] fix PHP 7 compatibility (xabbuh) + * bug #57065 [Mime] Fixed `Mime\Message::ensureValidity()` when a required header is set, but has an empty body (rhertogh) + * bug #57069 [Config] gracefully handle cases when no resolver is set (xabbuh) + * bug #57109 [Notifier] keep boolean options when their value is false (xabbuh) + * bug #54971 [Serializer] Cache readability/writability computation (mtarld) + * bug #56488 [VarExporter] Fix exporting default values involving global constants (kylekatarnls) + * bug #49186 [Serializer] Improve exception message in UnwrappingDenormalizer (andersonamuller) + * bug #54694 [PropertyInfo] Update DoctrineExtractor for new DBAL 4 BIGINT type (llupa) + * bug #54913 [Serializer] Fix CurrentType for missing property (ElisDN) + * bug #54797 [PhpUnitBridge] Fix `DeprecationErrorHandler` with PhpUnit 10 (HypeMC) + * bug #54878 [Filesystem] Fix dumpFile `stat failed` error hitting custom handler (acoulton) + * bug #54924 [Validator] IBAN Check digits should always between 2 and 98 (karstennilsen) + * bug #54919 [ErrorHandler] Do not call xdebug_get_function_stack() with xdebug >= 3.0 when not in develop mode (fmata) + * bug #54910 [HttpFoundation]  filter out empty HTTP header parts (xabbuh) + * bug #54888 [String] Fix folded in compat mode (smnandre) + * bug #54863 [Process] Return `false` when `open_basedir` prevents access to `/dev/tty` (mjauvin) + * bug #54860 [HttpClient] Revert fixing curl default options (alexandre-daubois) + * bug #54850 [VarExporter] fix `ProxyHelper::generateLazyProxy()` when a method returns null (nikophil) + * bug #54842 [Messenger] Don't drop stamps when message validation fails (valtzu) + * bug #54838 [WebProfilerBundle] Fix assignment to constant variable (HypeMC) + * bug #54837 [Mailer] [Sendgrid] Use `DataPart::getContentId()` when `DataPart::setContentId()` is used (SherinBloemendaal) + * bug #54839 Fix exception thrown during `LDAP_MODIFY_BATCH_REMOVE_ALL` batch operations (phasdev) + * bug #54834 [Validator] Check `Locale` class existence before using it (alexandre-daubois) + * bug #54830 [HttpClient] Fix cURL default options for PHP 8.4 (alexandre-daubois) + * bug #54828 [Serializer] Fix `GetSetMethodNormalizer` not working with setters with optional args (HypeMC) + * bug #54816 [Cache] Fix support for predis/predis:^2.0 (mfettig) + * bug #54804 [Serializer] separate the property info and write info extractors (xabbuh) + * bug #54800 [WebProfilerBundle] fix compatibility with Twig 3.10 (xabbuh) + * bug #54794 [Strings][EnglishInflector] Fix incorrect pluralisation of 'Album' (timporter) + * bug #54714 [Serializer] convert empty CSV header names into numeric keys (xabbuh) + * bug #54775 [Messenger] accept AbstractAsset instances when filtering schemas (xabbuh) + * bug #54758 [Validator] handle edge cases when constructing constraints with named arguments (xabbuh) + * bug #54759 [Filesystem] better distinguish URL schemes and Windows drive letters (xabbuh) + * bug #54791 [FrameworkBundle] move wiring of the property info extractor to the ObjectNormalizer (xabbuh) + * bug #54760 [Validator] handle union and intersection types for cascaded validations (xabbuh) + * bug #54776 [Cache] fix: remove unwanted cast to int (Arend Hummeling) + * bug #54700 [Dotenv] show overridden vars too when running debug:dotenv (HMRDevil) + +* 7.0.7 (2024-04-29) + + * bug #54699 [DoctrineBridge] Update AbstractSchemaListener to adjust more database params (ywisax) + * bug #54691 [Finder] Also consider .git inside the basedir of in() directory (nickvergessen) + * bug #54724 [AssetMapper] Check asset/vendor directory is writable (smnandre) + * bug #54750 [Validator] detect wrong usages of minMessage/maxMessage in options (xabbuh) + * bug #54751 [Validator]  detect wrong e-mail validation modes (xabbuh) + * bug #54723 [Form] read form values using the chain data accessor (xabbuh) + * bug #54706 [Yaml] call substr() with integer offsets (xabbuh) + * bug #54675 [PropertyInfo] Fix PHPStan properties type in trait (mtarld) + * bug #54673 [Messenger] explicitly cast boolean SSL stream options (xabbuh) + * bug #54665 Add test for AccessTokenHeaderRegex and adjust regex (Spomky) + * bug #54635 [Serializer] Revert "Fix object normalizer when properties has the same name as their accessor" - it was a BC Break (NeilPeyssard) + * bug #54625 [Intl] Remove resources data from classmap generation (shyim) + * bug #54598 [TwigBridge]  implement NodeVisitorInterface instead of extending AbstractNodeVisitor (xabbuh) + * bug #54072 [HttpKernel] Fix datacollector caster for reference object property (ebuildy) + * bug #54395 [Serializer] Fixing PHP warning in the ObjectNormalizer with MaxDepth enabled (jaydiablo) + * bug #54564 [Translation] Skip state=needs-translation entries only when source == target (nicolas-grekas) + * bug #54579 [Cache] Always select database for persistent redis connections (uncaught) + * bug #54059 [Security] Validate that CSRF token in form login is string similar to username/password (glaubinix) + * bug #54530 [Clock] initialize the current time with midnight before modifying the date (xabbuh) + * bug #54547 [HttpKernel] Force non lazy controller services (smnandre) + * bug #54517 [HttpClient] Let curl handle transfer encoding (michaelhue) + * bug #52917 [Serializer] Fix unexpected allowed attributes (mtarld) + * bug #54063 [FrameworkBundle] Fix registration of the bundle path to translation (FlyingDR) + * bug #54392 [Messenger] Make Doctrine connection ignore unrelated tables on setup (MatTheCat) + * bug #54513 [HtmlSanitizer] Ignore Processing Instructions (smnandre) + * bug #54506 [HttpFoundation] Set content-type header in RedirectResponse (smnandre) + * bug #54505 [Serializer]  initialize serializer in trait with null (xabbuh) + * bug #52698 [Serializer] Fix XML scalar to object denormalization (mtarld) + * bug #54485 [Serializer] Ignore when using #[Ignore] on a non-accessor (nicolas-grekas) + * bug #54105 [Messenger] Improve deadlock handling on `ack()` and `reject()` (jwage) + * bug #54242 [HttpClient] [EventSourceHttpClient] Fix consuming SSEs with \r\n separator (fancyweb) + * bug #54487 [Validator] Accept `Stringable` in `ExecutionContext::build/addViolation()` (alexandre-daubois) + * bug #54456 [DomCrawler] Encode html entities only if nessecary (ausi) + * bug #54484 [Serializer] reset backed_enum priority, and re-prioritise translatable (GwendolenLynch) + * bug #54471 [Filesystem] Strengthen the check of file permissions in `dumpFile` (alexandre-daubois) + * bug #54403 [FrameworkBundle] [Command] Fix #54402: Suppress PHP warning when is_readable() tries to access dirs outside of open_basedir restrictions (Jeldrik Geraedts) + * bug #54440 [Console] return null when message with name is not set (xabbuh) + * bug #54468 [Translation] Fix LocaleSwitcher throws when intl not loaded (smnandre) + +* 7.0.6 (2024-04-03) + + * bug #54400 [HttpClient] stop all server processes after tests have run (xabbuh) + * bug #54435 [Console] respect multi-byte characters when rendering vertical-style tables (xabbuh) + * bug #54419 Fix TypeError on ProgressBar (Fan2Shrek) + * bug #54425 [TwigBridge] Remove whitespaces from block form_help output (rosier) + * bug #53969 [Mailer] include message id provided by the MTA when dispatching the `SentMessageEvent` (xabbuh) + * bug #54315 [Serializer] Fixed BackedEnumNormalizer priority for translatable enum (IndraGunawan) + * bug #54372 [Config] Fix `YamlReferenceDumper` handling of array examples (MatTheCat) + * bug #54362 [Filesystem] preserve the file modification time when mirroring directories (xabbuh) + * bug #54333 [HttpFoundation] Allow array style callable setting for Request setFactory method (simbera) + * bug #54121 [Messenger] Catch TableNotFoundException in MySQL delete (acbramley) + * bug #54271 [DoctrineBridge] Fix deprecation warning with ORM 3 when guessing field lengths (eltharin) + * bug #54306 Throw TransformationFailedException when there is a null bytes injection (sormes) + * bug #54148 [Serializer] Fix object normalizer when properties has the same name as their accessor (NeilPeyssard) + * bug #54305 [Cache][Lock] Identify missing table in pgsql correctly and address failing integration tests (arifszn) + * bug #54199 [Mailer] [Brevo] Check that tags is present in payload before calling setTags (palgalik) + * bug #54292 [FrameworkBundle] Fix mailer config with XML (lyrixx) + * bug #54298 [Filesystem] Fix str_contains deprecation (NeilPeyssard) + * bug #54248 [Security] Correctly initialize the voter property (aschempp) + * bug #54273 [DependencyInjection] fix XmlDumper when a tag contains also a 'name' property (lyrixx) + * bug #54191 [Validator] add missing invalid extension error entry (xabbuh) + * bug #54194 [PropertyAccess] Fix checking for missing properties (nicolas-grekas) + * bug #54201 [Lock] Check the correct SQLSTATE error code for MySQL (edomato) + * bug #54252 [Lock] compatiblity with redis cluster 7 (bastnic) + * bug #54265 [VarDumper] prevent error in value to Typed property must not be accessed before initialization (shakaran) + * bug #54124 [Messenger] trigger retry logic when message is a redelivery (nikophil) + * bug #54254 [HttpKernel] Fix creating `ReflectionMethod` with only one argument (alexandre-daubois) + * bug #54219 [Validator] Allow BICs’ first four characters to be digits (MatTheCat) + * bug #54239 [Mailer] Fix sendmail transport not handling failure (aboks) + * bug #54207 [HttpClient] Lazily initialize CurlClientState (arjenm) + * bug #53865 [Workflow]Fix Marking when it must contains more than one tokens (lyrixx) + * bug #54137 [Validator] UniqueValidator - normalize before reducing keys (Brajk19) + * bug #54187 [FrameworkBundle] Fix PHP 8.4 deprecation on `ReflectionMethod` (alexandre-daubois) + * bug #54167 [Messenger] [Amqp] Handle AMQPConnectionException when publishing a message. (jwage) + * bug #54146 [HttpClient] Preserve float in JsonMockResponse (Jibbarth) + +* 7.0.5 (2024-03-04) + + * bug #54113 [AssetMapper] Throw exception in Javascript compiler when PCRE error (smnandre) + * bug #54129 [Clock] Add attributes to support PHPUnit 10 + 11 (ruudk) + * bug #54079 [AssetMapper] Fix `JavaScriptImportPathCompiler` regression in regex (PhilETaylor) + * bug #54102 [HttpClient] Fix deprecation on PHP 8.3 (nicolas-grekas) + * bug #54089 [Mailer] [Brevo] Remove tags from mandatory event arguments (palgalik) + * bug #54081 [DoctrineBridge] Safeguard dynamic access to Doctrine metadata properties (derrabus) + * bug #54080 [Routing] Enhance error handling in StaticPrefixCollection for compatibility with libpcre2-10.43 (Lustmored) + +* 7.0.4 (2024-02-27) + + * bug #53985 [HttpKernel] Allow tagged controllers in ControllerResolver (marein) + * bug #54054 [VarExporter] Bugfix/workaround jit issue (verfriemelt-dot-org) + * bug #54050 [Messenger] Revert "Resend failed retries back to failure transport " (ro0NL) + * bug #54045 [Config][Messenger][Security] Don't turn deprecations into exceptions when unserializing (nicolas-grekas) + * bug #54035 [DependencyInjection] Fix computing error messages involving service locators (nicolas-grekas) + * bug #53959 [Serializer] Fix unknown types normalization type when know type (Myks92) + * bug #53960 [Messenger] the 'use_notify' option is on the factory, not on the postgres connection (dbu) + * bug #54031 [ErrorHandler] Fix parsing messages that contain anonymous classes on PHP >= 8.3.3 (nicolas-grekas) + * bug #54014 [AssetMapper] Fix enquoted string pattern (smnandre) + * bug #54010 [Translation] Fix extracting qualified `t()` function calls (rvanvelzen) + * bug #53967 [ErrorHandler] return the unchanged text if preg_replace_callback() fails (xabbuh) + * bug #54009 [Console] Fix display of vertical Table on Windows OS (VincentLanglet) + * bug #54001 [Console] Fix display of Table on Windows OS (VincentLanglet) + * bug #53989 [FrameworkBundle] Fix config builder with extensions extended in `build()` (HypeMC) + * bug #54005 Fix a minor design issue in the Welcome Page (javiereguiluz) + * bug #54004 [WebProfilerBundle] disable turbo in web profiler toolbar to avoid link prefetching (davidgorges) + * bug #54006 [Process] Fix the `command -v` exception (kayw-geek) + * bug #53975 [Cache] explicitly cast boolean SSL stream options (xabbuh) + * bug #53926 [TwigBridge] foundation 5 layout: use form_label_content block for checkbox and radio labels (wetternest) + * bug #53913 [TwigBridge] Fix compat with Twig v3.9 (nicolas-grekas) + * bug #53819 [Doctrine Messenger] Fix support for pgsql + pgbouncer. (jwage) + * bug #53944 [Messenger] Gracefully fallback to empty queue config (Wirone) + * bug #53935 [Mailer] [Mailgun] Fix expecting payload without tags or user variables (norkunas) + * bug #53934 [Mailer] Fix signed emails breaking the profiler (HypeMC) + * bug #53924 [FrameworkBundle] Check if the _route attribute exists on the request (xvilo) + * bug #53910 [Messenger] Fix SQS visibility_timeout type (valtzu) + * bug #53891 [PropertyAccess] Fixes getValue() on an unitialized object property on a lazy ghost (priyadi) + * bug #53889 [HttpClient] Make retry strategy work again (Nyholm) + * bug #53906 [VarDumper] Fix serialization of stubs with null or uninitialized values (derrabus) + * bug #53890 [VarExporter] Uniform unitialized property error message under ghost and non-ghost objects (priyadi) + * bug #53893 [AssetMapper] Ignore comment lines in JavaScriptImportPathCompiler (smnandre) + * bug #53826 [DomCrawler][Form] Fix the exclusion of