From 21532cb6bcbd67dcc497dacc6a4135d9f8d51268 Mon Sep 17 00:00:00 2001 From: Guillaume Smolders Date: Wed, 26 Jul 2023 22:51:25 +0200 Subject: [PATCH 01/67] Fix breaking change in AccessTokenAuthenticator fixes #50511 --- .../Tests/Functional/AccessTokenTest.php | 12 ++ .../AccessToken/config_custom_user_loader.yml | 32 ++++ .../AccessToken/Oidc/OidcTokenHandler.php | 3 +- .../Oidc/OidcUserInfoTokenHandler.php | 3 +- .../AccessTokenAuthenticator.php | 2 +- .../Http/Authenticator/FallbackUserLoader.php | 32 ++++ .../AccessToken/Oidc/OidcTokenHandlerTest.php | 3 +- .../Oidc/OidcUserInfoTokenHandlerTest.php | 3 +- .../AccessTokenAuthenticatorTest.php | 162 ++++++++++++++++++ 9 files changed, 247 insertions(+), 5 deletions(-) create mode 100644 src/Symfony/Bundle/SecurityBundle/Tests/Functional/app/AccessToken/config_custom_user_loader.yml create mode 100644 src/Symfony/Component/Security/Http/Authenticator/FallbackUserLoader.php create mode 100644 src/Symfony/Component/Security/Http/Tests/Authenticator/AccessTokenAuthenticatorTest.php diff --git a/src/Symfony/Bundle/SecurityBundle/Tests/Functional/AccessTokenTest.php b/src/Symfony/Bundle/SecurityBundle/Tests/Functional/AccessTokenTest.php index 3deb91402165e..6cc2b1f0fb150 100644 --- a/src/Symfony/Bundle/SecurityBundle/Tests/Functional/AccessTokenTest.php +++ b/src/Symfony/Bundle/SecurityBundle/Tests/Functional/AccessTokenTest.php @@ -333,6 +333,18 @@ public function testSelfContainedTokens() $this->assertSame(['message' => 'Welcome @dunglas!'], json_decode($response->getContent(), true)); } + public function testCustomUserLoader() + { + $client = $this->createClient(['test_case' => 'AccessToken', 'root_config' => 'config_custom_user_loader.yml']); + $client->catchExceptions(false); + $client->request('GET', '/foo', [], [], ['HTTP_AUTHORIZATION' => 'Bearer SELF_CONTAINED_ACCESS_TOKEN']); + $response = $client->getResponse(); + + $this->assertInstanceOf(Response::class, $response); + $this->assertSame(200, $response->getStatusCode()); + $this->assertSame(['message' => 'Welcome @dunglas!'], json_decode($response->getContent(), true)); + } + /** * @requires extension openssl */ diff --git a/src/Symfony/Bundle/SecurityBundle/Tests/Functional/app/AccessToken/config_custom_user_loader.yml b/src/Symfony/Bundle/SecurityBundle/Tests/Functional/app/AccessToken/config_custom_user_loader.yml new file mode 100644 index 0000000000000..2027656b4d83c --- /dev/null +++ b/src/Symfony/Bundle/SecurityBundle/Tests/Functional/app/AccessToken/config_custom_user_loader.yml @@ -0,0 +1,32 @@ +imports: + - { resource: ./../config/framework.yml } + +framework: + http_method_override: false + serializer: ~ + +security: + password_hashers: + Symfony\Component\Security\Core\User\InMemoryUser: plaintext + + providers: + in_memory: + memory: + users: + dunglas: { password: foo, roles: [ROLE_MISSING] } + + firewalls: + main: + pattern: ^/ + stateless: true + access_token: + token_handler: access_token.access_token_handler + token_extractors: 'header' + realm: 'My API' + + access_control: + - { path: ^/foo, roles: ROLE_USER } + +services: + access_token.access_token_handler: + class: Symfony\Bundle\SecurityBundle\Tests\Functional\Bundle\AccessTokenBundle\Security\Handler\AccessTokenHandler diff --git a/src/Symfony/Component/Security/Http/AccessToken/Oidc/OidcTokenHandler.php b/src/Symfony/Component/Security/Http/AccessToken/Oidc/OidcTokenHandler.php index d595bfa88d4c9..94184e3f84ed0 100644 --- a/src/Symfony/Component/Security/Http/AccessToken/Oidc/OidcTokenHandler.php +++ b/src/Symfony/Component/Security/Http/AccessToken/Oidc/OidcTokenHandler.php @@ -27,6 +27,7 @@ use Symfony\Component\Security\Http\AccessToken\AccessTokenHandlerInterface; use Symfony\Component\Security\Http\AccessToken\Oidc\Exception\InvalidSignatureException; use Symfony\Component\Security\Http\AccessToken\Oidc\Exception\MissingClaimException; +use Symfony\Component\Security\Http\Authenticator\FallbackUserLoader; use Symfony\Component\Security\Http\Authenticator\Passport\Badge\UserBadge; /** @@ -93,7 +94,7 @@ public function getUserBadgeFrom(string $accessToken): UserBadge } // UserLoader argument can be overridden by a UserProvider on AccessTokenAuthenticator::authenticate - return new UserBadge($claims[$this->claim], fn () => $this->createUser($claims), $claims); + return new UserBadge($claims[$this->claim], new FallbackUserLoader(fn () => $this->createUser($claims)), $claims); } catch (\Exception $e) { $this->logger?->error('An error occurred while decoding and validating the token.', [ 'error' => $e->getMessage(), diff --git a/src/Symfony/Component/Security/Http/AccessToken/Oidc/OidcUserInfoTokenHandler.php b/src/Symfony/Component/Security/Http/AccessToken/Oidc/OidcUserInfoTokenHandler.php index 26279ebf19e68..191e460b55216 100644 --- a/src/Symfony/Component/Security/Http/AccessToken/Oidc/OidcUserInfoTokenHandler.php +++ b/src/Symfony/Component/Security/Http/AccessToken/Oidc/OidcUserInfoTokenHandler.php @@ -15,6 +15,7 @@ use Symfony\Component\Security\Core\Exception\BadCredentialsException; use Symfony\Component\Security\Http\AccessToken\AccessTokenHandlerInterface; use Symfony\Component\Security\Http\AccessToken\Oidc\Exception\MissingClaimException; +use Symfony\Component\Security\Http\Authenticator\FallbackUserLoader; use Symfony\Component\Security\Http\Authenticator\Passport\Badge\UserBadge; use Symfony\Contracts\HttpClient\HttpClientInterface; @@ -48,7 +49,7 @@ public function getUserBadgeFrom(string $accessToken): UserBadge } // UserLoader argument can be overridden by a UserProvider on AccessTokenAuthenticator::authenticate - return new UserBadge($claims[$this->claim], fn () => $this->createUser($claims), $claims); + return new UserBadge($claims[$this->claim], new FallbackUserLoader(fn () => $this->createUser($claims)), $claims); } catch (\Exception $e) { $this->logger?->error('An error occurred on OIDC server.', [ 'error' => $e->getMessage(), diff --git a/src/Symfony/Component/Security/Http/Authenticator/AccessTokenAuthenticator.php b/src/Symfony/Component/Security/Http/Authenticator/AccessTokenAuthenticator.php index c925e00050bed..7b769870749e5 100644 --- a/src/Symfony/Component/Security/Http/Authenticator/AccessTokenAuthenticator.php +++ b/src/Symfony/Component/Security/Http/Authenticator/AccessTokenAuthenticator.php @@ -59,7 +59,7 @@ public function authenticate(Request $request): Passport } $userBadge = $this->accessTokenHandler->getUserBadgeFrom($accessToken); - if ($this->userProvider) { + if ($this->userProvider && (null === $userBadge->getUserLoader() || $userBadge->getUserLoader() instanceof FallbackUserLoader)) { $userBadge->setUserLoader($this->userProvider->loadUserByIdentifier(...)); } diff --git a/src/Symfony/Component/Security/Http/Authenticator/FallbackUserLoader.php b/src/Symfony/Component/Security/Http/Authenticator/FallbackUserLoader.php new file mode 100644 index 0000000000000..65392781518ce --- /dev/null +++ b/src/Symfony/Component/Security/Http/Authenticator/FallbackUserLoader.php @@ -0,0 +1,32 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Security\Http\Authenticator; + +use Symfony\Component\Security\Core\User\UserInterface; + +/** + * This wrapper serves as a marker interface to indicate badge user loaders that should not be overridden by the + * default user provider. + * + * @internal + */ +final class FallbackUserLoader +{ + public function __construct(private $inner) + { + } + + public function __invoke(mixed ...$args): ?UserInterface + { + return ($this->inner)(...$args); + } +} diff --git a/src/Symfony/Component/Security/Http/Tests/AccessToken/Oidc/OidcTokenHandlerTest.php b/src/Symfony/Component/Security/Http/Tests/AccessToken/Oidc/OidcTokenHandlerTest.php index 8c8d86284b59a..ccf11e49862b6 100644 --- a/src/Symfony/Component/Security/Http/Tests/AccessToken/Oidc/OidcTokenHandlerTest.php +++ b/src/Symfony/Component/Security/Http/Tests/AccessToken/Oidc/OidcTokenHandlerTest.php @@ -21,6 +21,7 @@ use Symfony\Component\Security\Core\Exception\BadCredentialsException; use Symfony\Component\Security\Core\User\OidcUser; use Symfony\Component\Security\Http\AccessToken\Oidc\OidcTokenHandler; +use Symfony\Component\Security\Http\Authenticator\FallbackUserLoader; use Symfony\Component\Security\Http\Authenticator\Passport\Badge\UserBadge; /** @@ -61,7 +62,7 @@ public function testGetsUserIdentifierFromSignedToken(string $claim, string $exp ))->getUserBadgeFrom($token); $actualUser = $userBadge->getUserLoader()(); - $this->assertEquals(new UserBadge($expected, fn () => $expectedUser, $claims), $userBadge); + $this->assertEquals(new UserBadge($expected, new FallbackUserLoader(fn () => $expectedUser), $claims), $userBadge); $this->assertInstanceOf(OidcUser::class, $actualUser); $this->assertEquals($expectedUser, $actualUser); $this->assertEquals($claims, $userBadge->getAttributes()); diff --git a/src/Symfony/Component/Security/Http/Tests/AccessToken/Oidc/OidcUserInfoTokenHandlerTest.php b/src/Symfony/Component/Security/Http/Tests/AccessToken/Oidc/OidcUserInfoTokenHandlerTest.php index 3b96174a0d63e..2c8d9ae803f9d 100644 --- a/src/Symfony/Component/Security/Http/Tests/AccessToken/Oidc/OidcUserInfoTokenHandlerTest.php +++ b/src/Symfony/Component/Security/Http/Tests/AccessToken/Oidc/OidcUserInfoTokenHandlerTest.php @@ -16,6 +16,7 @@ use Symfony\Component\Security\Core\Exception\BadCredentialsException; use Symfony\Component\Security\Core\User\OidcUser; use Symfony\Component\Security\Http\AccessToken\Oidc\OidcUserInfoTokenHandler; +use Symfony\Component\Security\Http\Authenticator\FallbackUserLoader; use Symfony\Component\Security\Http\Authenticator\Passport\Badge\UserBadge; use Symfony\Contracts\HttpClient\HttpClientInterface; use Symfony\Contracts\HttpClient\ResponseInterface; @@ -47,7 +48,7 @@ public function testGetsUserIdentifierFromOidcServerResponse(string $claim, stri $userBadge = (new OidcUserInfoTokenHandler($clientMock, null, $claim))->getUserBadgeFrom($accessToken); $actualUser = $userBadge->getUserLoader()(); - $this->assertEquals(new UserBadge($expected, fn () => $expectedUser, $claims), $userBadge); + $this->assertEquals(new UserBadge($expected, new FallbackUserLoader(fn () => $expectedUser), $claims), $userBadge); $this->assertInstanceOf(OidcUser::class, $actualUser); $this->assertEquals($expectedUser, $actualUser); $this->assertEquals($claims, $userBadge->getAttributes()); diff --git a/src/Symfony/Component/Security/Http/Tests/Authenticator/AccessTokenAuthenticatorTest.php b/src/Symfony/Component/Security/Http/Tests/Authenticator/AccessTokenAuthenticatorTest.php new file mode 100644 index 0000000000000..4f010000429dd --- /dev/null +++ b/src/Symfony/Component/Security/Http/Tests/Authenticator/AccessTokenAuthenticatorTest.php @@ -0,0 +1,162 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Authenticator; + +use PHPUnit\Framework\TestCase; +use Symfony\Component\HttpFoundation\Request; +use Symfony\Component\Security\Core\Exception\BadCredentialsException; +use Symfony\Component\Security\Core\User\InMemoryUser; +use Symfony\Component\Security\Core\User\InMemoryUserProvider; +use Symfony\Component\Security\Http\AccessToken\AccessTokenExtractorInterface; +use Symfony\Component\Security\Http\AccessToken\AccessTokenHandlerInterface; +use Symfony\Component\Security\Http\Authenticator\AccessTokenAuthenticator; +use Symfony\Component\Security\Http\Authenticator\FallbackUserLoader; +use Symfony\Component\Security\Http\Authenticator\Passport\Badge\UserBadge; + +class AccessTokenAuthenticatorTest extends TestCase +{ + private AccessTokenHandlerInterface $accessTokenHandler; + private AccessTokenExtractorInterface $accessTokenExtractor; + private InMemoryUserProvider $userProvider; + + protected function setUp(): void + { + $this->accessTokenHandler = $this->createMock(AccessTokenHandlerInterface::class); + $this->accessTokenExtractor = $this->createMock(AccessTokenExtractorInterface::class); + $this->userProvider = new InMemoryUserProvider(['test' => ['password' => 's$cr$t']]); + } + + public function testAuthenticateWithoutAccessToken() + { + $this->expectException(BadCredentialsException::class); + $this->expectExceptionMessage('Invalid credentials.'); + + $request = Request::create('/test'); + + $this->accessTokenExtractor + ->expects($this->once()) + ->method('extractAccessToken') + ->with($request) + ->willReturn(null); + + $authenticator = new AccessTokenAuthenticator( + $this->accessTokenHandler, + $this->accessTokenExtractor, + ); + + $authenticator->authenticate($request); + } + + public function testAuthenticateWithoutProvider() + { + $request = Request::create('/test'); + + $this->accessTokenExtractor + ->expects($this->once()) + ->method('extractAccessToken') + ->with($request) + ->willReturn('test'); + $this->accessTokenHandler + ->expects($this->once()) + ->method('getUserBadgeFrom') + ->with('test') + ->willReturn(new UserBadge('john', fn () => new InMemoryUser('john', null))); + + $authenticator = new AccessTokenAuthenticator( + $this->accessTokenHandler, + $this->accessTokenExtractor, + $this->userProvider, + ); + + $passport = $authenticator->authenticate($request); + + $this->assertEquals('john', $passport->getUser()->getUserIdentifier()); + } + + public function testAuthenticateWithoutUserLoader() + { + $request = Request::create('/test'); + + $this->accessTokenExtractor + ->expects($this->once()) + ->method('extractAccessToken') + ->with($request) + ->willReturn('test'); + $this->accessTokenHandler + ->expects($this->once()) + ->method('getUserBadgeFrom') + ->with('test') + ->willReturn(new UserBadge('test')); + + $authenticator = new AccessTokenAuthenticator( + $this->accessTokenHandler, + $this->accessTokenExtractor, + $this->userProvider, + ); + + $passport = $authenticator->authenticate($request); + + $this->assertEquals('test', $passport->getUser()->getUserIdentifier()); + } + + public function testAuthenticateWithUserLoader() + { + $request = Request::create('/test'); + + $this->accessTokenExtractor + ->expects($this->once()) + ->method('extractAccessToken') + ->with($request) + ->willReturn('test'); + $this->accessTokenHandler + ->expects($this->once()) + ->method('getUserBadgeFrom') + ->with('test') + ->willReturn(new UserBadge('john', fn () => new InMemoryUser('john', null))); + + $authenticator = new AccessTokenAuthenticator( + $this->accessTokenHandler, + $this->accessTokenExtractor, + $this->userProvider, + ); + + $passport = $authenticator->authenticate($request); + + $this->assertEquals('john', $passport->getUser()->getUserIdentifier()); + } + + public function testAuthenticateWithFallbackUserLoader() + { + $request = Request::create('/test'); + + $this->accessTokenExtractor + ->expects($this->once()) + ->method('extractAccessToken') + ->with($request) + ->willReturn('test'); + $this->accessTokenHandler + ->expects($this->once()) + ->method('getUserBadgeFrom') + ->with('test') + ->willReturn(new UserBadge('test', new FallbackUserLoader(fn () => new InMemoryUser('john', null)))); + + $authenticator = new AccessTokenAuthenticator( + $this->accessTokenHandler, + $this->accessTokenExtractor, + $this->userProvider, + ); + + $passport = $authenticator->authenticate($request); + + $this->assertEquals('test', $passport->getUser()->getUserIdentifier()); + } +} From 95939101e1d7304df03a9566d452c0169fa6c14f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gr=C3=A9goire=20Pineau?= Date: Sun, 30 Jul 2023 12:43:06 +0200 Subject: [PATCH 02/67] [Messenger] Add forward compatibily with php-amqp v2 see https://github.com/php-amqp/php-amqp/issues/424#issuecomment-1656692661 --- .../Component/Messenger/Bridge/Amqp/Transport/Connection.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Symfony/Component/Messenger/Bridge/Amqp/Transport/Connection.php b/src/Symfony/Component/Messenger/Bridge/Amqp/Transport/Connection.php index ab8d6f980d519..ece0c1716b69b 100644 --- a/src/Symfony/Component/Messenger/Bridge/Amqp/Transport/Connection.php +++ b/src/Symfony/Component/Messenger/Bridge/Amqp/Transport/Connection.php @@ -456,7 +456,7 @@ public function get(string $queueName): ?\AMQPEnvelope public function ack(\AMQPEnvelope $message, string $queueName): bool { - return $this->queue($queueName)->ack($message->getDeliveryTag()); + return $this->queue($queueName)->ack($message->getDeliveryTag()) ?? true; } public function nack(\AMQPEnvelope $message, string $queueName, int $flags = \AMQP_NOPARAM): bool From 2290340a3a061e96aac9713352972573fcbb206b Mon Sep 17 00:00:00 2001 From: Fabien Potencier Date: Mon, 31 Jul 2023 12:26:11 +0200 Subject: [PATCH 03/67] Bump Symfony version to 5.4.28 --- src/Symfony/Component/HttpKernel/Kernel.php | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Symfony/Component/HttpKernel/Kernel.php b/src/Symfony/Component/HttpKernel/Kernel.php index 5decdd57ada05..1d92ef4639f5d 100644 --- a/src/Symfony/Component/HttpKernel/Kernel.php +++ b/src/Symfony/Component/HttpKernel/Kernel.php @@ -78,12 +78,12 @@ abstract class Kernel implements KernelInterface, RebootableInterface, Terminabl */ private static $freshCache = []; - public const VERSION = '5.4.27'; - public const VERSION_ID = 50427; + public const VERSION = '5.4.28-DEV'; + public const VERSION_ID = 50428; public const MAJOR_VERSION = 5; public const MINOR_VERSION = 4; - public const RELEASE_VERSION = 27; - public const EXTRA_VERSION = ''; + public const RELEASE_VERSION = 28; + public const EXTRA_VERSION = 'DEV'; public const END_OF_MAINTENANCE = '11/2024'; public const END_OF_LIFE = '11/2025'; From e804806c8a6bd081439f8484e12a318b4d02aa9c Mon Sep 17 00:00:00 2001 From: Fabien Potencier Date: Mon, 31 Jul 2023 12:37:01 +0200 Subject: [PATCH 04/67] Bump Symfony version to 6.3.4 --- src/Symfony/Component/HttpKernel/Kernel.php | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Symfony/Component/HttpKernel/Kernel.php b/src/Symfony/Component/HttpKernel/Kernel.php index 904ee141073ec..df3e33444db21 100644 --- a/src/Symfony/Component/HttpKernel/Kernel.php +++ b/src/Symfony/Component/HttpKernel/Kernel.php @@ -76,12 +76,12 @@ abstract class Kernel implements KernelInterface, RebootableInterface, Terminabl */ private static array $freshCache = []; - public const VERSION = '6.3.3'; - public const VERSION_ID = 60303; + public const VERSION = '6.3.4-DEV'; + public const VERSION_ID = 60304; public const MAJOR_VERSION = 6; public const MINOR_VERSION = 3; - public const RELEASE_VERSION = 3; - public const EXTRA_VERSION = ''; + public const RELEASE_VERSION = 4; + public const EXTRA_VERSION = 'DEV'; public const END_OF_MAINTENANCE = '01/2024'; public const END_OF_LIFE = '01/2024'; From 0358d76c9ee0d56f711a771f845723002231840c Mon Sep 17 00:00:00 2001 From: Fabien Potencier Date: Mon, 31 Jul 2023 12:40:30 +0200 Subject: [PATCH 05/67] Update CHANGELOG for 6.2.14 --- CHANGELOG-6.2.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGELOG-6.2.md b/CHANGELOG-6.2.md index e3d55ce447a2b..1e66ed8becaa8 100644 --- a/CHANGELOG-6.2.md +++ b/CHANGELOG-6.2.md @@ -7,6 +7,10 @@ in 6.2 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/v6.2.0...v6.2.1 +* 6.2.14 (2023-07-31) + + * bug #51178 [Finder] Revert "Fix children condition in ExcludeDirectoryFilterIterator" (derrabus) + * 6.2.13 (2023-07-30) * bug #50933 [Serializer] Fix deserializing nested arrays of objects with mixed keys (HypeMC) From 4e91836541e67f2e9fe4cbe7bcd1eac19e2414f5 Mon Sep 17 00:00:00 2001 From: Fabien Potencier Date: Mon, 31 Jul 2023 12:40:35 +0200 Subject: [PATCH 06/67] Update VERSION for 6.2.14 --- src/Symfony/Component/HttpKernel/Kernel.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Symfony/Component/HttpKernel/Kernel.php b/src/Symfony/Component/HttpKernel/Kernel.php index e13fe4c6d7ee2..64dc43aa9ce62 100644 --- a/src/Symfony/Component/HttpKernel/Kernel.php +++ b/src/Symfony/Component/HttpKernel/Kernel.php @@ -75,11 +75,11 @@ abstract class Kernel implements KernelInterface, RebootableInterface, Terminabl */ private static array $freshCache = []; - public const VERSION = '6.2.13'; - public const VERSION_ID = 60213; + public const VERSION = '6.2.14'; + public const VERSION_ID = 60214; public const MAJOR_VERSION = 6; public const MINOR_VERSION = 2; - public const RELEASE_VERSION = 13; + public const RELEASE_VERSION = 14; public const EXTRA_VERSION = ''; public const END_OF_MAINTENANCE = '07/2023'; From 6a9f47c6940e86f9cbb5d67867335cde3b1ce5f8 Mon Sep 17 00:00:00 2001 From: Fabien Potencier Date: Mon, 31 Jul 2023 12:54:03 +0200 Subject: [PATCH 07/67] Bump Symfony version to 6.2.15 --- src/Symfony/Component/HttpKernel/Kernel.php | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Symfony/Component/HttpKernel/Kernel.php b/src/Symfony/Component/HttpKernel/Kernel.php index 64dc43aa9ce62..e1dbb417e4141 100644 --- a/src/Symfony/Component/HttpKernel/Kernel.php +++ b/src/Symfony/Component/HttpKernel/Kernel.php @@ -75,12 +75,12 @@ abstract class Kernel implements KernelInterface, RebootableInterface, Terminabl */ private static array $freshCache = []; - public const VERSION = '6.2.14'; - public const VERSION_ID = 60214; + public const VERSION = '6.2.15-DEV'; + public const VERSION_ID = 60215; public const MAJOR_VERSION = 6; public const MINOR_VERSION = 2; - public const RELEASE_VERSION = 14; - public const EXTRA_VERSION = ''; + public const RELEASE_VERSION = 15; + public const EXTRA_VERSION = 'DEV'; public const END_OF_MAINTENANCE = '07/2023'; public const END_OF_LIFE = '07/2023'; From 6b88ea7e13215b949fdc91f94b2f6b0d2e04df3c Mon Sep 17 00:00:00 2001 From: Christian Flothmann Date: Mon, 31 Jul 2023 13:35:03 +0200 Subject: [PATCH 08/67] load function only if not loaded before --- src/Symfony/Component/Clock/Resources/now.php | 20 ++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/src/Symfony/Component/Clock/Resources/now.php b/src/Symfony/Component/Clock/Resources/now.php index 7da0142b1c8bc..9a88efbe4d43d 100644 --- a/src/Symfony/Component/Clock/Resources/now.php +++ b/src/Symfony/Component/Clock/Resources/now.php @@ -11,13 +11,15 @@ namespace Symfony\Component\Clock; -/** - * Returns the current time as a DateTimeImmutable. - * - * Note that you should prefer injecting a ClockInterface or using - * ClockAwareTrait when possible instead of using this function. - */ -function now(): \DateTimeImmutable -{ - return Clock::get()->now(); +if (!\function_exists(now::class)) { + /** + * Returns the current time as a DateTimeImmutable. + * + * Note that you should prefer injecting a ClockInterface or using + * ClockAwareTrait when possible instead of using this function. + */ + function now(): \DateTimeImmutable + { + return Clock::get()->now(); + } } From 8965c0c7f3a4ef1c111e109b9afcfa5a3c73a064 Mon Sep 17 00:00:00 2001 From: Vincent Langlet Date: Fri, 21 Jul 2023 13:15:16 +0200 Subject: [PATCH 09/67] [DoctrineBridge] Bugfix - Allow to remove LazyLoaded listeners by object --- .../Doctrine/ContainerAwareEventManager.php | 23 +++++++++++++++++-- .../Tests/ContainerAwareEventManagerTest.php | 15 ++++++++++++ 2 files changed, 36 insertions(+), 2 deletions(-) diff --git a/src/Symfony/Bridge/Doctrine/ContainerAwareEventManager.php b/src/Symfony/Bridge/Doctrine/ContainerAwareEventManager.php index db5cc920f361f..be31c7218af5b 100644 --- a/src/Symfony/Bridge/Doctrine/ContainerAwareEventManager.php +++ b/src/Symfony/Bridge/Doctrine/ContainerAwareEventManager.php @@ -32,6 +32,7 @@ class ContainerAwareEventManager extends EventManager private $subscribers; private $initialized = []; private $initializedSubscribers = false; + private $initializedHashMapping = []; private $methods = []; private $container; @@ -138,6 +139,7 @@ public function addEventListener($events, $listener) if (\is_string($listener)) { unset($this->initialized[$event]); + unset($this->initializedHashMapping[$event][$hash]); } else { $this->methods[$event][$hash] = $this->getMethod($listener, $event); } @@ -158,6 +160,11 @@ public function removeEventListener($events, $listener) $hash = $this->getHash($listener); foreach ((array) $events as $event) { + if (isset($this->initializedHashMapping[$event][$hash])) { + $hash = $this->initializedHashMapping[$event][$hash]; + unset($this->initializedHashMapping[$event][$hash]); + } + // Check if we actually have this listener associated if (isset($this->listeners[$event][$hash])) { unset($this->listeners[$event][$hash]); @@ -190,13 +197,25 @@ public function removeEventSubscriber(EventSubscriber $subscriber): void private function initializeListeners(string $eventName) { $this->initialized[$eventName] = true; + + // We'll refill the whole array in order to keep the same order + $listeners = []; foreach ($this->listeners[$eventName] as $hash => $listener) { if (\is_string($listener)) { - $this->listeners[$eventName][$hash] = $listener = $this->container->get($listener); + $listener = $this->container->get($listener); + $newHash = $this->getHash($listener); + + $this->initializedHashMapping[$eventName][$hash] = $newHash; - $this->methods[$eventName][$hash] = $this->getMethod($listener, $eventName); + $listeners[$newHash] = $listener; + + $this->methods[$eventName][$newHash] = $this->getMethod($listener, $eventName); + } else { + $listeners[$hash] = $listener; } } + + $this->listeners[$eventName] = $listeners; } private function initializeSubscribers() diff --git a/src/Symfony/Bridge/Doctrine/Tests/ContainerAwareEventManagerTest.php b/src/Symfony/Bridge/Doctrine/Tests/ContainerAwareEventManagerTest.php index 9d86eeed54ef1..80d6e30a22453 100644 --- a/src/Symfony/Bridge/Doctrine/Tests/ContainerAwareEventManagerTest.php +++ b/src/Symfony/Bridge/Doctrine/Tests/ContainerAwareEventManagerTest.php @@ -202,6 +202,21 @@ public function testRemoveEventListener() $this->assertSame([], $this->evm->getListeners('foo')); } + public function testRemoveAllEventListener() + { + $this->container->set('lazy', new MyListener()); + $this->evm->addEventListener('foo', 'lazy'); + $this->evm->addEventListener('foo', new MyListener()); + + foreach ($this->evm->getAllListeners() as $event => $listeners) { + foreach ($listeners as $listener) { + $this->evm->removeEventListener($event, $listener); + } + } + + $this->assertSame([], $this->evm->getListeners('foo')); + } + public function testRemoveEventListenerAfterDispatchEvent() { $this->container->set('lazy', $listener1 = new MyListener()); From 23c1dda1b687bfc8383a808bb6ded6bf2e26b1bc Mon Sep 17 00:00:00 2001 From: NanoSector Date: Thu, 2 Feb 2023 11:10:14 +0100 Subject: [PATCH 10/67] [Crawler] Fix regression where cdata nodes will return empty string --- src/Symfony/Component/DomCrawler/Crawler.php | 2 +- .../Component/DomCrawler/Tests/AbstractCrawlerTestCase.php | 7 +++++++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/src/Symfony/Component/DomCrawler/Crawler.php b/src/Symfony/Component/DomCrawler/Crawler.php index 274aeee5fc803..8274ee3ee5bf3 100644 --- a/src/Symfony/Component/DomCrawler/Crawler.php +++ b/src/Symfony/Component/DomCrawler/Crawler.php @@ -588,7 +588,7 @@ public function innerText(/* bool $normalizeWhitespace = true */): string $normalizeWhitespace = 1 <= \func_num_args() ? func_get_arg(0) : true; foreach ($this->getNode(0)->childNodes as $childNode) { - if (\XML_TEXT_NODE !== $childNode->nodeType) { + if (\XML_TEXT_NODE !== $childNode->nodeType && \XML_CDATA_SECTION_NODE !== $childNode->nodeType) { continue; } if (!$normalizeWhitespace) { diff --git a/src/Symfony/Component/DomCrawler/Tests/AbstractCrawlerTestCase.php b/src/Symfony/Component/DomCrawler/Tests/AbstractCrawlerTestCase.php index e682ff405a349..2a227b10574f9 100644 --- a/src/Symfony/Component/DomCrawler/Tests/AbstractCrawlerTestCase.php +++ b/src/Symfony/Component/DomCrawler/Tests/AbstractCrawlerTestCase.php @@ -377,6 +377,12 @@ public static function provideInnerTextExamples() '', ' ', ], + [ + '//*[@id="complex-elements"]/*[@class="six"]', + 'console.log("Test JavaScript content");', + 'console.log("Test JavaScript content");', + ' console.log("Test JavaScript content"); ', + ], ]; } @@ -1311,6 +1317,7 @@ public function createTestCrawler($uri = null)
Parent text Child text Parent text
Child text
Child text Another child
+ From 375dd08af5bd446ac77c081723b461556ea26393 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gr=C3=A9goire=20Pineau?= Date: Tue, 1 Aug 2023 10:27:53 +0200 Subject: [PATCH 11/67] [Workflow] fix MermaidDumper when place contains special char --- .../Workflow/Dumper/MermaidDumper.php | 8 +- .../Tests/Dumper/MermaidDumperTest.php | 247 +++++++++--------- 2 files changed, 126 insertions(+), 129 deletions(-) diff --git a/src/Symfony/Component/Workflow/Dumper/MermaidDumper.php b/src/Symfony/Component/Workflow/Dumper/MermaidDumper.php index b7f5eae1421fc..9f6a5b5f95a9c 100644 --- a/src/Symfony/Component/Workflow/Dumper/MermaidDumper.php +++ b/src/Symfony/Component/Workflow/Dumper/MermaidDumper.php @@ -77,7 +77,7 @@ public function dump(Definition $definition, Marking $marking = null, array $opt $meta = $definition->getMetadataStore(); foreach ($definition->getPlaces() as $place) { - [$placeNode, $placeStyle] = $this->preparePlace( + [$placeNodeName, $placeNode, $placeStyle] = $this->preparePlace( $placeId, $place, $meta->getPlaceMetadata($place), @@ -91,7 +91,7 @@ public function dump(Definition $definition, Marking $marking = null, array $opt $output[] = $placeStyle; } - $placeNameMap[$place] = $place.$placeId; + $placeNameMap[$place] = $placeNodeName; ++$placeId; } @@ -161,13 +161,13 @@ private function preparePlace(int $placeId, string $placeName, array $meta, bool $labelShape = '([%s])'; } - $placeNodeName = $placeName.$placeId; + $placeNodeName = 'place'.$placeId; $placeNodeFormat = '%s'.$labelShape; $placeNode = sprintf($placeNodeFormat, $placeNodeName, $placeLabel); $placeStyle = $this->styleNode($meta, $placeNodeName, $hasMarking); - return [$placeNode, $placeStyle]; + return [$placeNodeName, $placeNode, $placeStyle]; } private function styleNode(array $meta, string $nodeName, bool $hasMarking = false): string diff --git a/src/Symfony/Component/Workflow/Tests/Dumper/MermaidDumperTest.php b/src/Symfony/Component/Workflow/Tests/Dumper/MermaidDumperTest.php index 93c1e339486ee..5a657ed9c212a 100644 --- a/src/Symfony/Component/Workflow/Tests/Dumper/MermaidDumperTest.php +++ b/src/Symfony/Component/Workflow/Tests/Dumper/MermaidDumperTest.php @@ -48,9 +48,9 @@ public function testDumpWithReservedWordsAsPlacenames(Definition $definition, st } /** - * @dataProvider provideStatemachine + * @dataProvider provideStateMachine */ - public function testDumpAsStatemachine(Definition $definition, string $expected) + public function testDumpAsStateMachine(Definition $definition, string $expected) { $dumper = new MermaidDumper(MermaidDumper::TRANSITION_TYPE_STATEMACHINE); @@ -71,82 +71,82 @@ public function testDumpWorkflowWithMarking(Definition $definition, Marking $mar $this->assertEquals($expected, $dump); } - public static function provideWorkflowDefinitionWithoutMarking(): array + public static function provideWorkflowDefinitionWithoutMarking(): iterable { - return [ - [ - self::createComplexWorkflowDefinition(), - "graph LR\n" - ."a0([\"a\"])\n" - ."b1((\"b\"))\n" - ."c2((\"c\"))\n" - ."d3((\"d\"))\n" - ."e4((\"e\"))\n" - ."f5((\"f\"))\n" - ."g6((\"g\"))\n" - ."transition0[\"t1\"]\n" - ."a0-->transition0\n" - ."transition0-->b1\n" - ."transition0-->c2\n" - ."transition1[\"t2\"]\n" - ."b1-->transition1\n" - ."transition1-->d3\n" - ."c2-->transition1\n" - ."transition2[\"My custom transition label 1\"]\n" - ."d3-->transition2\n" - ."linkStyle 6 stroke:Red\n" - ."transition2-->e4\n" - ."linkStyle 7 stroke:Red\n" - ."transition3[\"t4\"]\n" - ."d3-->transition3\n" - ."transition3-->f5\n" - ."transition4[\"t5\"]\n" - ."e4-->transition4\n" - ."transition4-->g6\n" - ."transition5[\"t6\"]\n" - ."f5-->transition5\n" - .'transition5-->g6', - ], - [ - self::createWorkflowWithSameNameTransition(), - "graph LR\n" - ."a0([\"a\"])\n" - ."b1((\"b\"))\n" - ."c2((\"c\"))\n" - ."transition0[\"a_to_bc\"]\n" - ."a0-->transition0\n" - ."transition0-->b1\n" - ."transition0-->c2\n" - ."transition1[\"b_to_c\"]\n" - ."b1-->transition1\n" - ."transition1-->c2\n" - ."transition2[\"to_a\"]\n" - ."b1-->transition2\n" - ."transition2-->a0\n" - ."transition3[\"to_a\"]\n" - ."c2-->transition3\n" - .'transition3-->a0', - ], - [ - self::createSimpleWorkflowDefinition(), - "graph LR\n" - ."a0([\"a\"])\n" - ."b1((\"b\"))\n" - ."c2((\"c\"))\n" - ."style c2 fill:DeepSkyBlue\n" - ."transition0[\"My custom transition label 2\"]\n" - ."a0-->transition0\n" - ."linkStyle 0 stroke:Grey\n" - ."transition0-->b1\n" - ."linkStyle 1 stroke:Grey\n" - ."transition1[\"t2\"]\n" - ."b1-->transition1\n" - .'transition1-->c2', - ], + yield [ + self::createComplexWorkflowDefinition(), + "graph LR\n" + ."place0([\"a\"])\n" + ."place1((\"b\"))\n" + ."place2((\"c\"))\n" + ."place3((\"d\"))\n" + ."place4((\"e\"))\n" + ."place5((\"f\"))\n" + ."place6((\"g\"))\n" + ."transition0[\"t1\"]\n" + ."place0-->transition0\n" + ."transition0-->place1\n" + ."transition0-->place2\n" + ."transition1[\"t2\"]\n" + ."place1-->transition1\n" + ."transition1-->place3\n" + ."place2-->transition1\n" + ."transition2[\"My custom transition label 1\"]\n" + ."place3-->transition2\n" + ."linkStyle 6 stroke:Red\n" + ."transition2-->place4\n" + ."linkStyle 7 stroke:Red\n" + ."transition3[\"t4\"]\n" + ."place3-->transition3\n" + ."transition3-->place5\n" + ."transition4[\"t5\"]\n" + ."place4-->transition4\n" + ."transition4-->place6\n" + ."transition5[\"t6\"]\n" + ."place5-->transition5\n" + ."transition5-->place6" + + ]; + yield [ + self::createWorkflowWithSameNameTransition(), + "graph LR\n" + ."place0([\"a\"])\n" + ."place1((\"b\"))\n" + ."place2((\"c\"))\n" + ."transition0[\"a_to_bc\"]\n" + ."place0-->transition0\n" + ."transition0-->place1\n" + ."transition0-->place2\n" + ."transition1[\"b_to_c\"]\n" + ."place1-->transition1\n" + ."transition1-->place2\n" + ."transition2[\"to_a\"]\n" + ."place1-->transition2\n" + ."transition2-->place0\n" + ."transition3[\"to_a\"]\n" + ."place2-->transition3\n" + ."transition3-->place0" + + ]; + yield [ + self::createSimpleWorkflowDefinition(), + "graph LR\n" + ."place0([\"a\"])\n" + ."place1((\"b\"))\n" + ."place2((\"c\"))\n" + ."style place2 fill:DeepSkyBlue\n" + ."transition0[\"My custom transition label 2\"]\n" + ."place0-->transition0\n" + ."linkStyle 0 stroke:Grey\n" + ."transition0-->place1\n" + ."linkStyle 1 stroke:Grey\n" + ."transition1[\"t2\"]\n" + ."place1-->transition1\n" + ."transition1-->place2" ]; } - public static function provideWorkflowWithReservedWords() + public static function provideWorkflowWithReservedWords(): iterable { $builder = new DefinitionBuilder(); @@ -158,69 +158,66 @@ public static function provideWorkflowWithReservedWords() $definition = $builder->build(); - return [ - [ - $definition, - "graph LR\n" - ."start0([\"start\"])\n" - ."subgraph1((\"subgraph\"))\n" - ."end2((\"end\"))\n" - ."finis3((\"finis\"))\n" - ."transition0[\"t0\"]\n" - ."start0-->transition0\n" - ."transition0-->end2\n" - ."subgraph1-->transition0\n" - ."transition1[\"t1\"]\n" - ."end2-->transition1\n" - .'transition1-->finis3', - ], + yield [ + $definition, + "graph LR\n" + ."place0([\"start\"])\n" + ."place1((\"subgraph\"))\n" + ."place2((\"end\"))\n" + ."place3((\"finis\"))\n" + ."transition0[\"t0\"]\n" + ."place0-->transition0\n" + ."transition0-->place2\n" + ."place1-->transition0\n" + ."transition1[\"t1\"]\n" + ."place2-->transition1\n" + ."transition1-->place3" + ]; } - public static function provideStatemachine(): array + public static function provideStateMachine(): iterable { - return [ - [ - self::createComplexStateMachineDefinition(), - "graph LR\n" - ."a0([\"a\"])\n" - ."b1((\"b\"))\n" - ."c2((\"c\"))\n" - ."d3((\"d\"))\n" - ."a0-->|\"t1\"|b1\n" - ."d3-->|\"My custom transition label 3\"|b1\n" - ."linkStyle 1 stroke:Grey\n" - ."b1-->|\"t2\"|c2\n" - .'b1-->|"t3"|d3', - ], + yield [ + self::createComplexStateMachineDefinition(), + "graph LR\n" + ."place0([\"a\"])\n" + ."place1((\"b\"))\n" + ."place2((\"c\"))\n" + ."place3((\"d\"))\n" + ."place0-->|\"t1\"|place1\n" + ."place3-->|\"My custom transition label 3\"|place1\n" + ."linkStyle 1 stroke:Grey\n" + ."place1-->|\"t2\"|place2\n" + ."place1-->|\"t3\"|place3" + ]; } - public static function provideWorkflowWithMarking(): array + public static function provideWorkflowWithMarking(): iterable { $marking = new Marking(); $marking->mark('b'); $marking->mark('c'); - return [ - [ - self::createSimpleWorkflowDefinition(), - $marking, - "graph LR\n" - ."a0([\"a\"])\n" - ."b1((\"b\"))\n" - ."style b1 stroke-width:4px\n" - ."c2((\"c\"))\n" - ."style c2 fill:DeepSkyBlue,stroke-width:4px\n" - ."transition0[\"My custom transition label 2\"]\n" - ."a0-->transition0\n" - ."linkStyle 0 stroke:Grey\n" - ."transition0-->b1\n" - ."linkStyle 1 stroke:Grey\n" - ."transition1[\"t2\"]\n" - ."b1-->transition1\n" - .'transition1-->c2', - ], + yield [ + self::createSimpleWorkflowDefinition(), + $marking, + "graph LR\n" + ."place0([\"a\"])\n" + ."place1((\"b\"))\n" + ."style place1 stroke-width:4px\n" + ."place2((\"c\"))\n" + ."style place2 fill:DeepSkyBlue,stroke-width:4px\n" + ."transition0[\"My custom transition label 2\"]\n" + ."place0-->transition0\n" + ."linkStyle 0 stroke:Grey\n" + ."transition0-->place1\n" + ."linkStyle 1 stroke:Grey\n" + ."transition1[\"t2\"]\n" + ."place1-->transition1\n" + ."transition1-->place2" + ]; } } From 05b5648cdfcdbebd9930b4104cfd90da8f1ecc9e Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Tue, 1 Aug 2023 15:39:00 +0200 Subject: [PATCH 12/67] [Process] Fix test case --- src/Symfony/Component/Process/Tests/ErrorProcessInitiator.php | 4 ++-- src/Symfony/Component/Process/Tests/ProcessTest.php | 4 ++++ 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/src/Symfony/Component/Process/Tests/ErrorProcessInitiator.php b/src/Symfony/Component/Process/Tests/ErrorProcessInitiator.php index 4c8556acf51c2..541680224d740 100644 --- a/src/Symfony/Component/Process/Tests/ErrorProcessInitiator.php +++ b/src/Symfony/Component/Process/Tests/ErrorProcessInitiator.php @@ -14,12 +14,12 @@ use Symfony\Component\Process\Exception\ProcessTimedOutException; use Symfony\Component\Process\Process; -require \dirname(__DIR__).'/vendor/autoload.php'; +require is_file(\dirname(__DIR__).'/vendor/autoload.php') ? \dirname(__DIR__).'/vendor/autoload.php' : \dirname(__DIR__, 5).'/vendor/autoload.php'; ['e' => $php] = getopt('e:') + ['e' => 'php']; try { - $process = new Process("exec $php -r \"echo 'ready'; trigger_error('error', E_USER_ERROR);\""); + $process = new Process([$php, '-r', "echo 'ready'; trigger_error('error', E_USER_ERROR);"]); $process->start(); $process->setTimeout(0.5); while (!str_contains($process->getOutput(), 'ready')) { diff --git a/src/Symfony/Component/Process/Tests/ProcessTest.php b/src/Symfony/Component/Process/Tests/ProcessTest.php index 6e6ee8a41a029..827c723969c76 100644 --- a/src/Symfony/Component/Process/Tests/ProcessTest.php +++ b/src/Symfony/Component/Process/Tests/ProcessTest.php @@ -1523,6 +1523,10 @@ public function testWaitStoppedDeadProcess() $process->setTimeout(2); $process->wait(); $this->assertFalse($process->isRunning()); + + if ('\\' !== \DIRECTORY_SEPARATOR) { + $this->assertSame(0, $process->getExitCode()); + } } public function testEnvCaseInsensitiveOnWindows() From 56166afcb108ccdaed820e2eccde742045f38dcc Mon Sep 17 00:00:00 2001 From: Antoine Lamirault Date: Tue, 1 Aug 2023 19:52:17 +0200 Subject: [PATCH 13/67] [Notifier] Document Amazon Notifier options --- src/Symfony/Component/Notifier/Bridge/AmazonSns/README.md | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/Symfony/Component/Notifier/Bridge/AmazonSns/README.md b/src/Symfony/Component/Notifier/Bridge/AmazonSns/README.md index db4759327f502..85cf8f271936d 100644 --- a/src/Symfony/Component/Notifier/Bridge/AmazonSns/README.md +++ b/src/Symfony/Component/Notifier/Bridge/AmazonSns/README.md @@ -7,9 +7,15 @@ DSN example ----------- ``` -AMAZON_SNS_DSN=sns://ACCESS_ID:ACCESS_KEY@default?region=REGION +AMAZON_SNS_DSN=sns://ACCESS_ID:ACCESS_KEY@default?region=REGION&profile=PROFILE ``` +where: + - `ACCESS_ID` is your AWS access key id + - `ACCESS_KEY` is your AWS access key secret + - `REGION` is the AWS region targeted (optional, default: `us-east-1`) + - `PROFILE` is the name of your AWS configured profile (optional, default: `default`) + Adding Options to a Chat Message -------------------------------- From 64f788d825d6d0b8fe25ad3111ee1749d0d9f86b Mon Sep 17 00:00:00 2001 From: HypeMC Date: Tue, 1 Aug 2023 21:26:45 +0200 Subject: [PATCH 14/67] [DependencyInjection][HttpKernel] Fix using `#[AutowireCallable]` with controller arguments --- .../Attribute/AutowireCallable.php | 9 +++++++++ .../DependencyInjection/Compiler/AutowirePass.php | 5 +---- .../RegisterControllerArgumentLocatorsPass.php | 8 +++++++- .../RegisterControllerArgumentLocatorsPassTest.php | 14 +++++++++++++- src/Symfony/Component/HttpKernel/composer.json | 4 ++-- 5 files changed, 32 insertions(+), 8 deletions(-) diff --git a/src/Symfony/Component/DependencyInjection/Attribute/AutowireCallable.php b/src/Symfony/Component/DependencyInjection/Attribute/AutowireCallable.php index c472cb776e2bb..87e119746d84d 100644 --- a/src/Symfony/Component/DependencyInjection/Attribute/AutowireCallable.php +++ b/src/Symfony/Component/DependencyInjection/Attribute/AutowireCallable.php @@ -11,6 +11,7 @@ namespace Symfony\Component\DependencyInjection\Attribute; +use Symfony\Component\DependencyInjection\Definition; use Symfony\Component\DependencyInjection\Exception\LogicException; use Symfony\Component\DependencyInjection\Reference; @@ -38,4 +39,12 @@ public function __construct( parent::__construct($callable ?? [new Reference($service), $method ?? '__invoke'], lazy: $lazy); } + + public function buildDefinition(mixed $value, ?string $type, \ReflectionParameter $parameter): Definition + { + return (new Definition($type = \is_string($this->lazy) ? $this->lazy : ($type ?: 'Closure'))) + ->setFactory(['Closure', 'fromCallable']) + ->setArguments([\is_array($value) ? $value + [1 => '__invoke'] : $value]) + ->setLazy($this->lazy || 'Closure' !== $type && 'callable' !== (string) $parameter->getType()); + } } diff --git a/src/Symfony/Component/DependencyInjection/Compiler/AutowirePass.php b/src/Symfony/Component/DependencyInjection/Compiler/AutowirePass.php index f84a7faff07ec..f0a58c2b06197 100644 --- a/src/Symfony/Component/DependencyInjection/Compiler/AutowirePass.php +++ b/src/Symfony/Component/DependencyInjection/Compiler/AutowirePass.php @@ -314,10 +314,7 @@ private function autowireMethod(\ReflectionFunctionAbstract $reflectionMethod, a } if ($attribute instanceof AutowireCallable) { - $value = (new Definition($type = \is_string($attribute->lazy) ? $attribute->lazy : ($type ?: 'Closure'))) - ->setFactory(['Closure', 'fromCallable']) - ->setArguments([\is_array($value) ? $value + [1 => '__invoke'] : $value]) - ->setLazy($attribute->lazy || 'Closure' !== $type && 'callable' !== (string) $parameter->getType()); + $value = $attribute->buildDefinition($value, $type, $parameter); } elseif ($lazy = $attribute->lazy) { $definition = (new Definition($type)) ->setFactory('current') diff --git a/src/Symfony/Component/HttpKernel/DependencyInjection/RegisterControllerArgumentLocatorsPass.php b/src/Symfony/Component/HttpKernel/DependencyInjection/RegisterControllerArgumentLocatorsPass.php index d0e05340d8c6a..d43c6a3aef11f 100644 --- a/src/Symfony/Component/HttpKernel/DependencyInjection/RegisterControllerArgumentLocatorsPass.php +++ b/src/Symfony/Component/HttpKernel/DependencyInjection/RegisterControllerArgumentLocatorsPass.php @@ -12,6 +12,7 @@ namespace Symfony\Component\HttpKernel\DependencyInjection; use Symfony\Component\DependencyInjection\Attribute\Autowire; +use Symfony\Component\DependencyInjection\Attribute\AutowireCallable; use Symfony\Component\DependencyInjection\Attribute\Target; use Symfony\Component\DependencyInjection\ChildDefinition; use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface; @@ -160,7 +161,12 @@ public function process(ContainerBuilder $container) } if ($autowireAttributes) { - $value = $autowireAttributes[0]->newInstance()->value; + $attribute = $autowireAttributes[0]->newInstance(); + $value = $parameterBag->resolveValue($attribute->value); + + if ($attribute instanceof AutowireCallable) { + $value = $attribute->buildDefinition($value, $type, $p); + } if ($value instanceof Reference) { $args[$p->name] = $type ? new TypedReference($value, $type, $invalidBehavior, $p->name) : new Reference($value, $invalidBehavior); diff --git a/src/Symfony/Component/HttpKernel/Tests/DependencyInjection/RegisterControllerArgumentLocatorsPassTest.php b/src/Symfony/Component/HttpKernel/Tests/DependencyInjection/RegisterControllerArgumentLocatorsPassTest.php index cc2f37b9711cb..82577d27570fe 100644 --- a/src/Symfony/Component/HttpKernel/Tests/DependencyInjection/RegisterControllerArgumentLocatorsPassTest.php +++ b/src/Symfony/Component/HttpKernel/Tests/DependencyInjection/RegisterControllerArgumentLocatorsPassTest.php @@ -12,9 +12,11 @@ namespace Symfony\Component\HttpKernel\Tests\DependencyInjection; use PHPUnit\Framework\TestCase; +use Symfony\Component\DependencyInjection\Argument\LazyClosure; use Symfony\Component\DependencyInjection\Argument\RewindableGenerator; use Symfony\Component\DependencyInjection\Argument\ServiceClosureArgument; use Symfony\Component\DependencyInjection\Attribute\Autowire; +use Symfony\Component\DependencyInjection\Attribute\AutowireCallable; use Symfony\Component\DependencyInjection\Attribute\TaggedIterator; use Symfony\Component\DependencyInjection\Attribute\TaggedLocator; use Symfony\Component\DependencyInjection\Attribute\Target; @@ -481,7 +483,7 @@ public function testAutowireAttribute() $locator = $container->get($locatorId)->get('foo::fooAction'); - $this->assertCount(8, $locator->getProvidedServices()); + $this->assertCount(9, $locator->getProvidedServices()); $this->assertInstanceOf(\stdClass::class, $locator->get('service1')); $this->assertSame('foo/bar', $locator->get('value')); $this->assertSame('foo', $locator->get('expression')); @@ -490,6 +492,9 @@ public function testAutowireAttribute() $this->assertSame('bar', $locator->get('rawValue')); $this->assertSame('@bar', $locator->get('escapedRawValue')); $this->assertSame('foo', $locator->get('customAutowire')); + $this->assertInstanceOf(FooInterface::class, $autowireCallable = $locator->get('autowireCallable')); + $this->assertInstanceOf(LazyClosure::class, $autowireCallable); + $this->assertInstanceOf(\stdClass::class, $autowireCallable->service); $this->assertFalse($locator->has('service2')); } @@ -625,6 +630,11 @@ public function __construct(string $parameter) } } +interface FooInterface +{ + public function foo(); +} + class WithAutowireAttribute { public function fooAction( @@ -644,6 +654,8 @@ public function fooAction( string $escapedRawValue, #[CustomAutowire('some.parameter')] string $customAutowire, + #[AutowireCallable(service: 'some.id', method: 'bar')] + FooInterface $autowireCallable, #[Autowire(service: 'invalid.id')] \stdClass $service2 = null, ) { diff --git a/src/Symfony/Component/HttpKernel/composer.json b/src/Symfony/Component/HttpKernel/composer.json index bf8be24d05ab4..7a989c40bd957 100644 --- a/src/Symfony/Component/HttpKernel/composer.json +++ b/src/Symfony/Component/HttpKernel/composer.json @@ -30,7 +30,7 @@ "symfony/config": "^6.1", "symfony/console": "^5.4|^6.0", "symfony/css-selector": "^5.4|^6.0", - "symfony/dependency-injection": "^6.3", + "symfony/dependency-injection": "^6.3.4", "symfony/dom-crawler": "^5.4|^6.0", "symfony/expression-language": "^5.4|^6.0", "symfony/finder": "^5.4|^6.0", @@ -57,7 +57,7 @@ "symfony/config": "<6.1", "symfony/console": "<5.4", "symfony/form": "<5.4", - "symfony/dependency-injection": "<6.3", + "symfony/dependency-injection": "<6.3.4", "symfony/doctrine-bridge": "<5.4", "symfony/http-client": "<5.4", "symfony/http-client-contracts": "<2.5", From 269eb100c1192ab483538c254dc9984940919ce3 Mon Sep 17 00:00:00 2001 From: Oskar Stark Date: Wed, 2 Aug 2023 11:26:36 +0200 Subject: [PATCH 15/67] [Notifier][AmazonSns] README update --- src/Symfony/Component/Notifier/Bridge/AmazonSns/README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/Symfony/Component/Notifier/Bridge/AmazonSns/README.md b/src/Symfony/Component/Notifier/Bridge/AmazonSns/README.md index 85cf8f271936d..9dd4bfdcccaa6 100644 --- a/src/Symfony/Component/Notifier/Bridge/AmazonSns/README.md +++ b/src/Symfony/Component/Notifier/Bridge/AmazonSns/README.md @@ -13,7 +13,7 @@ AMAZON_SNS_DSN=sns://ACCESS_ID:ACCESS_KEY@default?region=REGION&profile=PROFILE where: - `ACCESS_ID` is your AWS access key id - `ACCESS_KEY` is your AWS access key secret - - `REGION` is the AWS region targeted (optional, default: `us-east-1`) + - `REGION` is the targeted AWS region (optional, default: `us-east-1`) - `PROFILE` is the name of your AWS configured profile (optional, default: `default`) Adding Options to a Chat Message @@ -43,6 +43,7 @@ $chatter->send($chatMessage); Resources --------- + * [AsyncAws Documentation](https://async-aws.com/configuration.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) From 692704e133726ba9ff8ecf12f845cac1ed96c19a Mon Sep 17 00:00:00 2001 From: Ruud Kamphuis Date: Thu, 3 Aug 2023 13:01:09 +0200 Subject: [PATCH 16/67] [DependencyInjection] Do not add `return` in `LazyClosure` when return type of closure is `void` --- .../Argument/LazyClosure.php | 5 +++-- .../Tests/Dumper/PhpDumperTest.php | 22 +++++++++++++++---- .../Fixtures/includes/autowiring_classes.php | 10 +++++++++ .../Tests/Fixtures/php/lazy_closure.php | 20 +++++++++++++---- 4 files changed, 47 insertions(+), 10 deletions(-) diff --git a/src/Symfony/Component/DependencyInjection/Argument/LazyClosure.php b/src/Symfony/Component/DependencyInjection/Argument/LazyClosure.php index 234ed622db74b..230363a95bf3a 100644 --- a/src/Symfony/Component/DependencyInjection/Argument/LazyClosure.php +++ b/src/Symfony/Component/DependencyInjection/Argument/LazyClosure.php @@ -78,7 +78,8 @@ public static function getCode(string $initializer, array $callable, Definition throw new RuntimeException("Cannot create lazy closure{$id} because its corresponding callable is invalid."); } - $code = ProxyHelper::exportSignature($r->getMethod($method), true, $args); + $methodReflector = $r->getMethod($method); + $code = ProxyHelper::exportSignature($methodReflector, true, $args); if ($asClosure) { $code = ' { '.preg_replace('/: static$/', ': \\'.$r->name, $code); @@ -87,7 +88,7 @@ public static function getCode(string $initializer, array $callable, Definition } $code = 'new class('.$initializer.') extends \\'.self::class - .$code.' { return $this->service->'.$callable[1].'('.$args.'); } ' + .$code.' { '.($methodReflector->hasReturnType() && 'void' === (string) $methodReflector->getReturnType() ? '' : 'return ').'$this->service->'.$callable[1].'('.$args.'); } ' .'}'; return $asClosure ? '('.$code.')->'.$method.'(...)' : $code; diff --git a/src/Symfony/Component/DependencyInjection/Tests/Dumper/PhpDumperTest.php b/src/Symfony/Component/DependencyInjection/Tests/Dumper/PhpDumperTest.php index 91f8a20dcc224..ae3d1bbe04067 100644 --- a/src/Symfony/Component/DependencyInjection/Tests/Dumper/PhpDumperTest.php +++ b/src/Symfony/Component/DependencyInjection/Tests/Dumper/PhpDumperTest.php @@ -48,6 +48,7 @@ use Symfony\Component\DependencyInjection\Tests\Compiler\AInterface; use Symfony\Component\DependencyInjection\Tests\Compiler\Foo; use Symfony\Component\DependencyInjection\Tests\Compiler\FooAnnotation; +use Symfony\Component\DependencyInjection\Tests\Compiler\FooVoid; use Symfony\Component\DependencyInjection\Tests\Compiler\IInterface; use Symfony\Component\DependencyInjection\Tests\Compiler\MyCallable; use Symfony\Component\DependencyInjection\Tests\Compiler\SingleMethodInterface; @@ -1874,12 +1875,18 @@ public function testAutowireClosure() public function testLazyClosure() { $container = new ContainerBuilder(); - $container->register('closure', 'Closure') + $container->register('closure1', 'Closure') ->setPublic('true') ->setFactory(['Closure', 'fromCallable']) ->setLazy(true) ->setArguments([[new Reference('foo'), 'cloneFoo']]); + $container->register('closure2', 'Closure') + ->setPublic('true') + ->setFactory(['Closure', 'fromCallable']) + ->setLazy(true) + ->setArguments([[new Reference('foo_void'), '__invoke']]); $container->register('foo', Foo::class); + $container->register('foo_void', FooVoid::class); $container->compile(); $dumper = new PhpDumper($container); @@ -1890,11 +1897,18 @@ public function testLazyClosure() $container = new \Symfony_DI_PhpDumper_Test_Lazy_Closure(); $cloned = Foo::$counter; - $this->assertInstanceOf(\Closure::class, $container->get('closure')); + $this->assertInstanceOf(\Closure::class, $container->get('closure1')); $this->assertSame($cloned, Foo::$counter); - $this->assertInstanceOf(Foo::class, $container->get('closure')()); + $this->assertInstanceOf(Foo::class, $container->get('closure1')()); $this->assertSame(1 + $cloned, Foo::$counter); - $this->assertSame(1, (new \ReflectionFunction($container->get('closure')))->getNumberOfParameters()); + $this->assertSame(1, (new \ReflectionFunction($container->get('closure1')))->getNumberOfParameters()); + + $counter = FooVoid::$counter; + $this->assertInstanceOf(\Closure::class, $container->get('closure2')); + $this->assertSame($counter, FooVoid::$counter); + $container->get('closure2')('Hello'); + $this->assertSame(1 + $counter, FooVoid::$counter); + $this->assertSame(1, (new \ReflectionFunction($container->get('closure2')))->getNumberOfParameters()); } public function testLazyAutowireAttribute() diff --git a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/includes/autowiring_classes.php b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/includes/autowiring_classes.php index 31eb9d9bb68a5..d75b20bb77315 100644 --- a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/includes/autowiring_classes.php +++ b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/includes/autowiring_classes.php @@ -38,6 +38,16 @@ public function cloneFoo(\stdClass $bar = null): static } } +class FooVoid +{ + public static int $counter = 0; + + public function __invoke(string $name): void + { + ++self::$counter; + } +} + class Bar { public function __construct(Foo $foo) diff --git a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/php/lazy_closure.php b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/php/lazy_closure.php index 3623366544fa0..0af28f2650147 100644 --- a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/php/lazy_closure.php +++ b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/php/lazy_closure.php @@ -20,7 +20,8 @@ public function __construct() { $this->services = $this->privates = []; $this->methodMap = [ - 'closure' => 'getClosureService', + 'closure1' => 'getClosure1Service', + 'closure2' => 'getClosure2Service', ]; $this->aliases = []; @@ -40,6 +41,7 @@ public function getRemovedIds(): array { return [ 'foo' => true, + 'foo_void' => true, ]; } @@ -49,12 +51,22 @@ protected function createProxy($class, \Closure $factory) } /** - * Gets the public 'closure' shared service. + * Gets the public 'closure1' shared service. * * @return \Closure */ - protected static function getClosureService($container, $lazyLoad = true) + protected static function getClosure1Service($container, $lazyLoad = true) { - return $container->services['closure'] = (new class(fn () => new \Symfony\Component\DependencyInjection\Tests\Compiler\Foo()) extends \Symfony\Component\DependencyInjection\Argument\LazyClosure { public function cloneFoo(?\stdClass $bar = null): \Symfony\Component\DependencyInjection\Tests\Compiler\Foo { return $this->service->cloneFoo(...\func_get_args()); } })->cloneFoo(...); + return $container->services['closure1'] = (new class(fn () => new \Symfony\Component\DependencyInjection\Tests\Compiler\Foo()) extends \Symfony\Component\DependencyInjection\Argument\LazyClosure { public function cloneFoo(?\stdClass $bar = null): \Symfony\Component\DependencyInjection\Tests\Compiler\Foo { return $this->service->cloneFoo(...\func_get_args()); } })->cloneFoo(...); + } + + /** + * Gets the public 'closure2' shared service. + * + * @return \Closure + */ + protected static function getClosure2Service($container, $lazyLoad = true) + { + return $container->services['closure2'] = (new class(fn () => new \Symfony\Component\DependencyInjection\Tests\Compiler\FooVoid()) extends \Symfony\Component\DependencyInjection\Argument\LazyClosure { public function __invoke(string $name): void { $this->service->__invoke(...\func_get_args()); } })->__invoke(...); } } From 74401f106cc40a687f03c0bdc96061d5695131ec Mon Sep 17 00:00:00 2001 From: "Alexander M. Turek" Date: Fri, 4 Aug 2023 10:05:04 +0200 Subject: [PATCH 17/67] Psalm: Suppress UnusedConstructor errors --- psalm.xml | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/psalm.xml b/psalm.xml index c74733de4e714..4d9f6743bd3b8 100644 --- a/psalm.xml +++ b/psalm.xml @@ -36,5 +36,14 @@ + + + + + + From 98fe0a21b5a8f4d98ab1d55b9e25a309e1e5b8d2 Mon Sep 17 00:00:00 2001 From: Christian Flothmann Date: Sat, 5 Aug 2023 10:32:42 +0200 Subject: [PATCH 18/67] harden LockRegistry tests, consider PHP files only --- src/Symfony/Component/Cache/Tests/LockRegistryTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Symfony/Component/Cache/Tests/LockRegistryTest.php b/src/Symfony/Component/Cache/Tests/LockRegistryTest.php index 30ff6774047a5..7666279b9491e 100644 --- a/src/Symfony/Component/Cache/Tests/LockRegistryTest.php +++ b/src/Symfony/Component/Cache/Tests/LockRegistryTest.php @@ -23,7 +23,7 @@ public function testFiles() } $lockFiles = LockRegistry::setFiles([]); LockRegistry::setFiles($lockFiles); - $expected = array_map('realpath', glob(__DIR__.'/../Adapter/*')); + $expected = array_map('realpath', glob(__DIR__.'/../Adapter/*.php')); $this->assertSame($expected, $lockFiles); } } From 6157e3c8b6ee436f04b0546b18ce3fd085aadcde Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Sat, 5 Aug 2023 11:11:10 +0200 Subject: [PATCH 19/67] Sync .github/expected-missing-return-types.diff --- .github/expected-missing-return-types.diff | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/expected-missing-return-types.diff b/.github/expected-missing-return-types.diff index 1dc86d5c94d2e..a8d626bae0833 100644 --- a/.github/expected-missing-return-types.diff +++ b/.github/expected-missing-return-types.diff @@ -8165,7 +8165,7 @@ diff --git a/src/Symfony/Component/HttpKernel/DependencyInjection/MergeExtension diff --git a/src/Symfony/Component/HttpKernel/DependencyInjection/RegisterControllerArgumentLocatorsPass.php b/src/Symfony/Component/HttpKernel/DependencyInjection/RegisterControllerArgumentLocatorsPass.php --- a/src/Symfony/Component/HttpKernel/DependencyInjection/RegisterControllerArgumentLocatorsPass.php +++ b/src/Symfony/Component/HttpKernel/DependencyInjection/RegisterControllerArgumentLocatorsPass.php -@@ -37,5 +37,5 @@ class RegisterControllerArgumentLocatorsPass implements CompilerPassInterface +@@ -38,5 +38,5 @@ class RegisterControllerArgumentLocatorsPass implements CompilerPassInterface * @return void */ - public function process(ContainerBuilder $container) From c5e5391d4fe825c07b83ca9173626a0b668eb5b5 Mon Sep 17 00:00:00 2001 From: Wouter de Jong Date: Sat, 5 Aug 2023 14:53:29 +0200 Subject: [PATCH 20/67] Add before/after examples to 6.3 UPGRADE guide --- UPGRADE-6.3.md | 140 +++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 129 insertions(+), 11 deletions(-) diff --git a/UPGRADE-6.3.md b/UPGRADE-6.3.md index 0ad0f71de74e8..cf66a462ed78d 100644 --- a/UPGRADE-6.3.md +++ b/UPGRADE-6.3.md @@ -24,6 +24,44 @@ DoctrineBridge -------------- * Deprecate passing Doctrine subscribers to `ContainerAwareEventManager` class, use listeners instead + + *Before* + ```php + use Doctrine\Bundle\DoctrineBundle\EventSubscriber\EventSubscriberInterface; + use Doctrine\ORM\Event\PostFlushEventArgs; + use Doctrine\ORM\Events; + + class InvalidateCacheSubscriber implements EventSubscriberInterface + { + public function getSubscribedEvents(): array + { + return [Events::postFlush]; + } + + public function postFlush(PostFlushEventArgs $args): void + { + // ... + } + } + ``` + + *After* + ```php + use Doctrine\Bundle\DoctrineBundle\Attribute\AsDoctrineListener; + use Doctrine\ORM\Event\PostFlushEventArgs; + use Doctrine\ORM\Events; + + // Instead of PHP attributes, you can also tag this service with "doctrine.event_listener" + #[AsDoctrineListener(event: Events::postFlush)] + class InvalidateCacheSubscriber + { + public function postFlush(PostFlushEventArgs $args): void + { + // ... + } + } + ``` + * Deprecate `DoctrineDbalCacheAdapterSchemaSubscriber` in favor of `DoctrineDbalCacheAdapterSchemaListener` * Deprecate `MessengerTransportDoctrineSchemaSubscriber` in favor of `MessengerTransportDoctrineSchemaListener` * Deprecate `RememberMeTokenProviderDoctrineSchemaSubscriber` in favor of `RememberMeTokenProviderDoctrineSchemaListener` @@ -65,10 +103,6 @@ FrameworkBundle /> ``` - -FrameworkBundle ---------------- - * Deprecate the `notifier.logger_notification_listener` service, use the `notifier.notification_logger_listener` service instead * Deprecate the `Http\Client\HttpClient` service, use `Psr\Http\Client\ClientInterface` instead @@ -126,19 +160,57 @@ Security SecurityBundle -------------- - * Deprecate enabling bundle and not configuring it + * Deprecate enabling bundle and not configuring it, either remove the bundle or configure at least one firewall * Deprecate the `security.firewalls.logout.csrf_token_generator` config option, use `security.firewalls.logout.csrf_token_manager` instead -Validator ---------- - - * Implementing the `ConstraintViolationInterface` without implementing the `getConstraint()` method is deprecated - Serializer ---------- * Deprecate `CacheableSupportsMethodInterface` in favor of the new `getSupportedTypes(?string $format)` methods - * The following Normalizer classes will become final in 7.0: + + *Before* + ```php + use Symfony\Component\Serializer\Normalizer\NormalizerInterface; + use Symfony\Component\Serializer\Normalizer\CacheableSupportsMethodInterface; + + class TopicNormalizer implements NormalizerInterface, CacheableSupportsMethodInterface + { + public function supportsNormalization($data, string $format = null, array $context = []): bool + { + return $data instanceof Topic; + } + + public function hasCacheableSupportsMethod(): bool + { + return true; + } + + // ... + } + ``` + + *After* + ```php + use Symfony\Component\Serializer\Normalizer\NormalizerInterface; + + class TopicNormalizer implements NormalizerInterface + { + public function supportsNormalization($data, string $format = null, array $context = []): bool + { + return $data instanceof Topic; + } + + public function getSupportedTypes(?string $format): array + { + return [ + Topic::class => true, + ]; + } + + // ... + } + ``` + * The following Normalizer classes will become final in 7.0, use decoration instead of inheritance: * `ConstraintViolationListNormalizer` * `CustomNormalizer` * `DataUriNormalizer` @@ -149,3 +221,49 @@ Serializer * `JsonSerializableNormalizer` * `ObjectNormalizer` * `PropertyNormalizer` + + *Before* + ```php + use Symfony\Component\Serializer\Normalizer\ObjectNormalizer; + + class TopicNormalizer extends ObjectNormalizer + { + // ... + + public function normalize($topic, string $format = null, array $context = []): array + { + $data = parent::normalize($topic, $format, $context); + + // ... + } + } + ``` + + *After* + ```php + use Symfony\Component\DependencyInjection\Attribute\Autowire; + use Symfony\Component\Serializer\Normalizer\DenormalizerInterface; + use Symfony\Component\Serializer\Normalizer\NormalizerInterface; + + class TopicNormalizer implements NormalizerInterface + { + public function __construct( + #[Autowire(service: 'serializer.normalizer.object')] private NormalizerInterface&DenormalizerInterface $objectNormalizer, + ) { + } + + public function normalize($topic, string $format = null, array $context = []): array + { + $data = $this->objectNormalizer->normalize($topic, $format, $context); + + // ... + } + + // ... + } + ``` + +Validator +--------- + + * Implementing the `ConstraintViolationInterface` without implementing the `getConstraint()` method is deprecated From 9f86e7f6aaba409d2d8dfcf4641583ba4d9c1e04 Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Sat, 5 Aug 2023 16:21:36 +0200 Subject: [PATCH 21/67] [Serializer] Make deprecation message more actionable --- src/Symfony/Component/Serializer/Debug/TraceableNormalizer.php | 2 +- .../Component/Serializer/Normalizer/AbstractNormalizer.php | 2 +- .../Serializer/Normalizer/ConstraintViolationListNormalizer.php | 2 +- .../Component/Serializer/Normalizer/CustomNormalizer.php | 2 +- .../Component/Serializer/Normalizer/DataUriNormalizer.php | 2 +- .../Component/Serializer/Normalizer/DateIntervalNormalizer.php | 2 +- .../Component/Serializer/Normalizer/DateTimeNormalizer.php | 2 +- .../Component/Serializer/Normalizer/DateTimeZoneNormalizer.php | 2 +- .../Component/Serializer/Normalizer/GetSetMethodNormalizer.php | 2 +- .../Serializer/Normalizer/JsonSerializableNormalizer.php | 2 +- .../Component/Serializer/Normalizer/MimeMessageNormalizer.php | 2 +- .../Component/Serializer/Normalizer/ObjectNormalizer.php | 2 +- .../Component/Serializer/Normalizer/ProblemNormalizer.php | 2 +- .../Component/Serializer/Normalizer/PropertyNormalizer.php | 2 +- 14 files changed, 14 insertions(+), 14 deletions(-) diff --git a/src/Symfony/Component/Serializer/Debug/TraceableNormalizer.php b/src/Symfony/Component/Serializer/Debug/TraceableNormalizer.php index d4cf6fcbd2496..4bdd3f7b44aa4 100644 --- a/src/Symfony/Component/Serializer/Debug/TraceableNormalizer.php +++ b/src/Symfony/Component/Serializer/Debug/TraceableNormalizer.php @@ -132,7 +132,7 @@ public function setDenormalizer(DenormalizerInterface $denormalizer): void */ public function hasCacheableSupportsMethod(): bool { - trigger_deprecation('symfony/serializer', '6.3', 'The "%s()" method is deprecated, use "getSupportedTypes()" instead.', __METHOD__); + trigger_deprecation('symfony/serializer', '6.3', 'The "%s()" method is deprecated, implement "%s::getSupportedTypes()" instead.', __METHOD__, get_debug_type($this->normalizer)); return $this->normalizer instanceof CacheableSupportsMethodInterface && $this->normalizer->hasCacheableSupportsMethod(); } diff --git a/src/Symfony/Component/Serializer/Normalizer/AbstractNormalizer.php b/src/Symfony/Component/Serializer/Normalizer/AbstractNormalizer.php index fc5322fa2971a..39d91bbc76e44 100644 --- a/src/Symfony/Component/Serializer/Normalizer/AbstractNormalizer.php +++ b/src/Symfony/Component/Serializer/Normalizer/AbstractNormalizer.php @@ -161,7 +161,7 @@ public function __construct(ClassMetadataFactoryInterface $classMetadataFactory */ public function hasCacheableSupportsMethod(): bool { - trigger_deprecation('symfony/serializer', '6.3', 'The "%s()" method is deprecated, use "getSupportedTypes()" instead.', __METHOD__); + trigger_deprecation('symfony/serializer', '6.3', 'The "%s()" method is deprecated, implement "%s::getSupportedTypes()" instead.', __METHOD__, get_debug_type($this)); return false; } diff --git a/src/Symfony/Component/Serializer/Normalizer/ConstraintViolationListNormalizer.php b/src/Symfony/Component/Serializer/Normalizer/ConstraintViolationListNormalizer.php index 1fdf8420dbb9a..2b6a8ec2e777c 100644 --- a/src/Symfony/Component/Serializer/Normalizer/ConstraintViolationListNormalizer.php +++ b/src/Symfony/Component/Serializer/Normalizer/ConstraintViolationListNormalizer.php @@ -121,7 +121,7 @@ public function supportsNormalization(mixed $data, string $format = null /* , ar */ public function hasCacheableSupportsMethod(): bool { - trigger_deprecation('symfony/serializer', '6.3', 'The "%s()" method is deprecated, use "getSupportedTypes()" instead.', __METHOD__); + trigger_deprecation('symfony/serializer', '6.3', 'The "%s()" method is deprecated, implement "%s::getSupportedTypes()" instead.', __METHOD__, get_debug_type($this)); return __CLASS__ === static::class; } diff --git a/src/Symfony/Component/Serializer/Normalizer/CustomNormalizer.php b/src/Symfony/Component/Serializer/Normalizer/CustomNormalizer.php index 7e67a31a91ce7..f45f36296f17b 100644 --- a/src/Symfony/Component/Serializer/Normalizer/CustomNormalizer.php +++ b/src/Symfony/Component/Serializer/Normalizer/CustomNormalizer.php @@ -75,7 +75,7 @@ public function supportsDenormalization(mixed $data, string $type, string $forma */ public function hasCacheableSupportsMethod(): bool { - trigger_deprecation('symfony/serializer', '6.3', 'The "%s()" method is deprecated, use "getSupportedTypes()" instead.', __METHOD__); + trigger_deprecation('symfony/serializer', '6.3', 'The "%s()" method is deprecated, implement "%s::getSupportedTypes()" instead.', __METHOD__, get_debug_type($this)); return __CLASS__ === static::class; } diff --git a/src/Symfony/Component/Serializer/Normalizer/DataUriNormalizer.php b/src/Symfony/Component/Serializer/Normalizer/DataUriNormalizer.php index 1bcf81f9ba892..0b4d0b2733475 100644 --- a/src/Symfony/Component/Serializer/Normalizer/DataUriNormalizer.php +++ b/src/Symfony/Component/Serializer/Normalizer/DataUriNormalizer.php @@ -133,7 +133,7 @@ public function supportsDenormalization(mixed $data, string $type, string $forma */ public function hasCacheableSupportsMethod(): bool { - trigger_deprecation('symfony/serializer', '6.3', 'The "%s()" method is deprecated, use "getSupportedTypes()" instead.', __METHOD__); + trigger_deprecation('symfony/serializer', '6.3', 'The "%s()" method is deprecated, implement "%s::getSupportedTypes()" instead.', __METHOD__, get_debug_type($this)); return __CLASS__ === static::class; } diff --git a/src/Symfony/Component/Serializer/Normalizer/DateIntervalNormalizer.php b/src/Symfony/Component/Serializer/Normalizer/DateIntervalNormalizer.php index 3cf5b887f9dbe..f0bcfc7e604c1 100644 --- a/src/Symfony/Component/Serializer/Normalizer/DateIntervalNormalizer.php +++ b/src/Symfony/Component/Serializer/Normalizer/DateIntervalNormalizer.php @@ -67,7 +67,7 @@ public function supportsNormalization(mixed $data, string $format = null /* , ar */ public function hasCacheableSupportsMethod(): bool { - trigger_deprecation('symfony/serializer', '6.3', 'The "%s()" method is deprecated, use "getSupportedTypes()" instead.', __METHOD__); + trigger_deprecation('symfony/serializer', '6.3', 'The "%s()" method is deprecated, implement "%s::getSupportedTypes()" instead.', __METHOD__, get_debug_type($this)); return __CLASS__ === static::class; } diff --git a/src/Symfony/Component/Serializer/Normalizer/DateTimeNormalizer.php b/src/Symfony/Component/Serializer/Normalizer/DateTimeNormalizer.php index df222b3813699..e6be88289f880 100644 --- a/src/Symfony/Component/Serializer/Normalizer/DateTimeNormalizer.php +++ b/src/Symfony/Component/Serializer/Normalizer/DateTimeNormalizer.php @@ -151,7 +151,7 @@ public function supportsDenormalization(mixed $data, string $type, string $forma */ public function hasCacheableSupportsMethod(): bool { - trigger_deprecation('symfony/serializer', '6.3', 'The "%s()" method is deprecated, use "getSupportedTypes()" instead.', __METHOD__); + trigger_deprecation('symfony/serializer', '6.3', 'The "%s()" method is deprecated, implement "%s::getSupportedTypes()" instead.', __METHOD__, get_debug_type($this)); return __CLASS__ === static::class; } diff --git a/src/Symfony/Component/Serializer/Normalizer/DateTimeZoneNormalizer.php b/src/Symfony/Component/Serializer/Normalizer/DateTimeZoneNormalizer.php index 472f64fc8b1bc..b4e1584adf61e 100644 --- a/src/Symfony/Component/Serializer/Normalizer/DateTimeZoneNormalizer.php +++ b/src/Symfony/Component/Serializer/Normalizer/DateTimeZoneNormalizer.php @@ -80,7 +80,7 @@ public function supportsDenormalization(mixed $data, string $type, string $forma */ public function hasCacheableSupportsMethod(): bool { - trigger_deprecation('symfony/serializer', '6.3', 'The "%s()" method is deprecated, use "getSupportedTypes()" instead.', __METHOD__); + trigger_deprecation('symfony/serializer', '6.3', 'The "%s()" method is deprecated, implement "%s::getSupportedTypes()" instead.', __METHOD__, get_debug_type($this)); return __CLASS__ === static::class; } diff --git a/src/Symfony/Component/Serializer/Normalizer/GetSetMethodNormalizer.php b/src/Symfony/Component/Serializer/Normalizer/GetSetMethodNormalizer.php index 063d34ea59177..9a412ff23e0ed 100644 --- a/src/Symfony/Component/Serializer/Normalizer/GetSetMethodNormalizer.php +++ b/src/Symfony/Component/Serializer/Normalizer/GetSetMethodNormalizer.php @@ -66,7 +66,7 @@ public function supportsDenormalization(mixed $data, string $type, string $forma */ public function hasCacheableSupportsMethod(): bool { - trigger_deprecation('symfony/serializer', '6.3', 'The "%s()" method is deprecated, use "getSupportedTypes()" instead.', __METHOD__); + trigger_deprecation('symfony/serializer', '6.3', 'The "%s()" method is deprecated, implement "%s::getSupportedTypes()" instead.', __METHOD__, get_debug_type($this)); return __CLASS__ === static::class; } diff --git a/src/Symfony/Component/Serializer/Normalizer/JsonSerializableNormalizer.php b/src/Symfony/Component/Serializer/Normalizer/JsonSerializableNormalizer.php index 1c8bbfe4ae0da..238cffa1ea764 100644 --- a/src/Symfony/Component/Serializer/Normalizer/JsonSerializableNormalizer.php +++ b/src/Symfony/Component/Serializer/Normalizer/JsonSerializableNormalizer.php @@ -73,7 +73,7 @@ public function denormalize(mixed $data, string $type, string $format = null, ar */ public function hasCacheableSupportsMethod(): bool { - trigger_deprecation('symfony/serializer', '6.3', 'The "%s()" method is deprecated, use "getSupportedTypes()" instead.', __METHOD__); + trigger_deprecation('symfony/serializer', '6.3', 'The "%s()" method is deprecated, implement "%s::getSupportedTypes()" instead.', __METHOD__, get_debug_type($this)); return __CLASS__ === static::class; } diff --git a/src/Symfony/Component/Serializer/Normalizer/MimeMessageNormalizer.php b/src/Symfony/Component/Serializer/Normalizer/MimeMessageNormalizer.php index ddeade33f982a..ab9544bf23267 100644 --- a/src/Symfony/Component/Serializer/Normalizer/MimeMessageNormalizer.php +++ b/src/Symfony/Component/Serializer/Normalizer/MimeMessageNormalizer.php @@ -122,7 +122,7 @@ public function supportsDenormalization(mixed $data, string $type, string $forma */ public function hasCacheableSupportsMethod(): bool { - trigger_deprecation('symfony/serializer', '6.3', 'The "%s()" method is deprecated, use "getSupportedTypes()" instead.', __METHOD__); + trigger_deprecation('symfony/serializer', '6.3', 'The "%s()" method is deprecated, implement "%s::getSupportedTypes()" instead.', __METHOD__, get_debug_type($this)); return true; } diff --git a/src/Symfony/Component/Serializer/Normalizer/ObjectNormalizer.php b/src/Symfony/Component/Serializer/Normalizer/ObjectNormalizer.php index 357c36426e50a..dd601b828b6b8 100644 --- a/src/Symfony/Component/Serializer/Normalizer/ObjectNormalizer.php +++ b/src/Symfony/Component/Serializer/Normalizer/ObjectNormalizer.php @@ -60,7 +60,7 @@ public function getSupportedTypes(?string $format): array */ public function hasCacheableSupportsMethod(): bool { - trigger_deprecation('symfony/serializer', '6.3', 'The "%s()" method is deprecated, use "getSupportedTypes()" instead.', __METHOD__); + trigger_deprecation('symfony/serializer', '6.3', 'The "%s()" method is deprecated, implement "%s::getSupportedTypes()" instead.', __METHOD__, get_debug_type($this)); return __CLASS__ === static::class; } diff --git a/src/Symfony/Component/Serializer/Normalizer/ProblemNormalizer.php b/src/Symfony/Component/Serializer/Normalizer/ProblemNormalizer.php index 4161d0b1cb989..f7a8077ec7e51 100644 --- a/src/Symfony/Component/Serializer/Normalizer/ProblemNormalizer.php +++ b/src/Symfony/Component/Serializer/Normalizer/ProblemNormalizer.php @@ -119,7 +119,7 @@ public function supportsNormalization(mixed $data, string $format = null /* , ar */ public function hasCacheableSupportsMethod(): bool { - trigger_deprecation('symfony/serializer', '6.3', 'The "%s()" method is deprecated, use "getSupportedTypes()" instead.', __METHOD__); + trigger_deprecation('symfony/serializer', '6.3', 'The "%s()" method is deprecated, implement "%s::getSupportedTypes()" instead.', __METHOD__, get_debug_type($this)); return true; } diff --git a/src/Symfony/Component/Serializer/Normalizer/PropertyNormalizer.php b/src/Symfony/Component/Serializer/Normalizer/PropertyNormalizer.php index ec12db9bb20ac..7e7743f5e2865 100644 --- a/src/Symfony/Component/Serializer/Normalizer/PropertyNormalizer.php +++ b/src/Symfony/Component/Serializer/Normalizer/PropertyNormalizer.php @@ -82,7 +82,7 @@ public function supportsDenormalization(mixed $data, string $type, string $forma */ public function hasCacheableSupportsMethod(): bool { - trigger_deprecation('symfony/serializer', '6.3', 'The "%s()" method is deprecated, use "getSupportedTypes()" instead.', __METHOD__); + trigger_deprecation('symfony/serializer', '6.3', 'The "%s()" method is deprecated, implement "%s::getSupportedTypes()" instead.', __METHOD__, get_debug_type($this)); return __CLASS__ === static::class; } From fcf86b395bd05590be6312a8bb9ba2bc5e261275 Mon Sep 17 00:00:00 2001 From: Maximilian Beckers Date: Mon, 7 Aug 2023 08:12:30 +0200 Subject: [PATCH 22/67] [Console] Fix linewraps in OutputFormatter --- .../Console/Formatter/OutputFormatter.php | 11 ++- .../Tests/Formatter/OutputFormatterTest.php | 14 ++-- .../Console/Tests/Helper/TableTest.php | 75 ++++++++++--------- 3 files changed, 57 insertions(+), 43 deletions(-) diff --git a/src/Symfony/Component/Console/Formatter/OutputFormatter.php b/src/Symfony/Component/Console/Formatter/OutputFormatter.php index 603e5dca0b1dc..4ec600244d656 100644 --- a/src/Symfony/Component/Console/Formatter/OutputFormatter.php +++ b/src/Symfony/Component/Console/Formatter/OutputFormatter.php @@ -13,6 +13,8 @@ use Symfony\Component\Console\Exception\InvalidArgumentException; +use function Symfony\Component\String\b; + /** * Formatter class for console output. * @@ -258,7 +260,7 @@ private function applyCurrentStyle(string $text, string $current, int $width, in } preg_match('~(\\n)$~', $text, $matches); - $text = $prefix.preg_replace('~([^\\n]{'.$width.'})\\ *~', "\$1\n", $text); + $text = $prefix.$this->addLineBreaks($text, $width); $text = rtrim($text, "\n").($matches[1] ?? ''); if (!$currentLineLength && '' !== $current && "\n" !== substr($current, -1)) { @@ -282,4 +284,11 @@ private function applyCurrentStyle(string $text, string $current, int $width, in return implode("\n", $lines); } + + private function addLineBreaks(string $text, int $width): string + { + $encoding = mb_detect_encoding($text, null, true) ?: 'UTF-8'; + + return b($text)->toCodePointString($encoding)->wordwrap($width, "\n", true)->toByteString($encoding); + } } diff --git a/src/Symfony/Component/Console/Tests/Formatter/OutputFormatterTest.php b/src/Symfony/Component/Console/Tests/Formatter/OutputFormatterTest.php index 203f5a3caf0ab..0b1772107bbd7 100644 --- a/src/Symfony/Component/Console/Tests/Formatter/OutputFormatterTest.php +++ b/src/Symfony/Component/Console/Tests/Formatter/OutputFormatterTest.php @@ -367,10 +367,10 @@ public function testFormatAndWrap() $formatter = new OutputFormatter(true); $this->assertSame("fo\no\e[37;41mb\e[39;49m\n\e[37;41mar\e[39;49m\nba\nz", $formatter->formatAndWrap('foobar baz', 2)); - $this->assertSame("pr\ne \e[37;41m\e[39;49m\n\e[37;41mfo\e[39;49m\n\e[37;41mo \e[39;49m\n\e[37;41mba\e[39;49m\n\e[37;41mr \e[39;49m\n\e[37;41mba\e[39;49m\n\e[37;41mz\e[39;49m \npo\nst", $formatter->formatAndWrap('pre foo bar baz post', 2)); + $this->assertSame("pr\ne \e[37;41m\e[39;49m\n\e[37;41mfo\e[39;49m\n\e[37;41mo\e[39;49m\n\e[37;41mba\e[39;49m\n\e[37;41mr\e[39;49m\n\e[37;41mba\e[39;49m\n\e[37;41mz\e[39;49m \npo\nst", $formatter->formatAndWrap('pre foo bar baz post', 2)); $this->assertSame("pre\e[37;41m\e[39;49m\n\e[37;41mfoo\e[39;49m\n\e[37;41mbar\e[39;49m\n\e[37;41mbaz\e[39;49m\npos\nt", $formatter->formatAndWrap('pre foo bar baz post', 3)); - $this->assertSame("pre \e[37;41m\e[39;49m\n\e[37;41mfoo \e[39;49m\n\e[37;41mbar \e[39;49m\n\e[37;41mbaz\e[39;49m \npost", $formatter->formatAndWrap('pre foo bar baz post', 4)); - $this->assertSame("pre \e[37;41mf\e[39;49m\n\e[37;41moo ba\e[39;49m\n\e[37;41mr baz\e[39;49m\npost", $formatter->formatAndWrap('pre foo bar baz post', 5)); + $this->assertSame("pre \e[37;41m\e[39;49m\n\e[37;41mfoo\e[39;49m\n\e[37;41mbar\e[39;49m\n\e[37;41mbaz\e[39;49m \npost", $formatter->formatAndWrap('pre foo bar baz post', 4)); + $this->assertSame("pre \e[37;41mf\e[39;49m\n\e[37;41moo\e[39;49m\n\e[37;41mbar\e[39;49m\n\e[37;41mbaz\e[39;49m p\nost", $formatter->formatAndWrap('pre foo bar baz post', 5)); $this->assertSame("Lore\nm \e[37;41mip\e[39;49m\n\e[37;41msum\e[39;49m \ndolo\nr \e[32msi\e[39m\n\e[32mt\e[39m am\net", $formatter->formatAndWrap('Lorem ipsum dolor sit amet', 4)); $this->assertSame("Lorem \e[37;41mip\e[39;49m\n\e[37;41msum\e[39;49m dolo\nr \e[32msit\e[39m am\net", $formatter->formatAndWrap('Lorem ipsum dolor sit amet', 8)); $this->assertSame("Lorem \e[37;41mipsum\e[39;49m dolor \e[32m\e[39m\n\e[32msit\e[39m, \e[37;41mamet\e[39;49m et \e[32mlauda\e[39m\n\e[32mntium\e[39m architecto", $formatter->formatAndWrap('Lorem ipsum dolor sit, amet et laudantium architecto', 18)); @@ -378,10 +378,12 @@ public function testFormatAndWrap() $formatter = new OutputFormatter(); $this->assertSame("fo\nob\nar\nba\nz", $formatter->formatAndWrap('foobar baz', 2)); - $this->assertSame("pr\ne \nfo\no \nba\nr \nba\nz \npo\nst", $formatter->formatAndWrap('pre foo bar baz post', 2)); + $this->assertSame("pr\ne \nfo\no\nba\nr\nba\nz \npo\nst", $formatter->formatAndWrap('pre foo bar baz post', 2)); $this->assertSame("pre\nfoo\nbar\nbaz\npos\nt", $formatter->formatAndWrap('pre foo bar baz post', 3)); - $this->assertSame("pre \nfoo \nbar \nbaz \npost", $formatter->formatAndWrap('pre foo bar baz post', 4)); - $this->assertSame("pre f\noo ba\nr baz\npost", $formatter->formatAndWrap('pre foo bar baz post', 5)); + $this->assertSame("pre \nfoo\nbar\nbaz \npost", $formatter->formatAndWrap('pre foo bar baz post', 4)); + $this->assertSame("pre f\noo\nbar\nbaz p\nost", $formatter->formatAndWrap('pre foo bar baz post', 5)); + $this->assertSame("Â rèälly\nlöng tîtlè\nthät cöüld\nnèêd\nmúltîplê\nlínès", $formatter->formatAndWrap('Â rèälly löng tîtlè thät cöüld nèêd múltîplê línès', 10)); + $this->assertSame("Â rèälly\nlöng tîtlè\nthät cöüld\nnèêd\nmúltîplê\n línès", $formatter->formatAndWrap("Â rèälly löng tîtlè thät cöüld nèêd múltîplê\n línès", 10)); $this->assertSame('', $formatter->formatAndWrap(null, 5)); } } diff --git a/src/Symfony/Component/Console/Tests/Helper/TableTest.php b/src/Symfony/Component/Console/Tests/Helper/TableTest.php index e9c94b10780dc..1f313a680f04a 100644 --- a/src/Symfony/Component/Console/Tests/Helper/TableTest.php +++ b/src/Symfony/Component/Console/Tests/Helper/TableTest.php @@ -118,30 +118,30 @@ public static function renderProvider() ['ISBN', 'Title', 'Author'], $books, 'compact', -<<<'TABLE' -ISBN Title Author -99921-58-10-7 Divine Comedy Dante Alighieri -9971-5-0210-0 A Tale of Two Cities Charles Dickens -960-425-059-0 The Lord of the Rings J. R. R. Tolkien -80-902734-1-6 And Then There Were None Agatha Christie - -TABLE + implode("\n", [ + 'ISBN Title Author ', + '99921-58-10-7 Divine Comedy Dante Alighieri ', + '9971-5-0210-0 A Tale of Two Cities Charles Dickens ', + '960-425-059-0 The Lord of the Rings J. R. R. Tolkien ', + '80-902734-1-6 And Then There Were None Agatha Christie ', + '', + ]), ], [ ['ISBN', 'Title', 'Author'], $books, 'borderless', -<<<'TABLE' - =============== ========================== ================== - ISBN Title Author - =============== ========================== ================== - 99921-58-10-7 Divine Comedy Dante Alighieri - 9971-5-0210-0 A Tale of Two Cities Charles Dickens - 960-425-059-0 The Lord of the Rings J. R. R. Tolkien - 80-902734-1-6 And Then There Were None Agatha Christie - =============== ========================== ================== - -TABLE + implode("\n", [ + ' =============== ========================== ================== ', + ' ISBN Title Author ', + ' =============== ========================== ================== ', + ' 99921-58-10-7 Divine Comedy Dante Alighieri ', + ' 9971-5-0210-0 A Tale of Two Cities Charles Dickens ', + ' 960-425-059-0 The Lord of the Rings J. R. R. Tolkien ', + ' 80-902734-1-6 And Then There Were None Agatha Christie ', + ' =============== ========================== ================== ', + '', + ]), ], [ ['ISBN', 'Title', 'Author'], @@ -1378,12 +1378,14 @@ public function testColumnMaxWidths() $expected = << Date: Mon, 7 Aug 2023 11:52:08 +0200 Subject: [PATCH 23/67] [Process] Fix silencing `wait` when using a sigchild-enabled binary --- src/Symfony/Component/Process/Process.php | 2 +- src/Symfony/Component/Process/Tests/ProcessTest.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Symfony/Component/Process/Process.php b/src/Symfony/Component/Process/Process.php index 9b19475ac5d78..30ebeb6b58e18 100644 --- a/src/Symfony/Component/Process/Process.php +++ b/src/Symfony/Component/Process/Process.php @@ -331,7 +331,7 @@ public function start(callable $callback = null, array $env = []) // See https://unix.stackexchange.com/questions/71205/background-process-pipe-input $commandline = '{ ('.$commandline.') <&3 3<&- 3>/dev/null & } 3<&0;'; - $commandline .= 'pid=$!; echo $pid >&3; wait $pid; code=$?; echo $code >&3; exit $code'; + $commandline .= 'pid=$!; echo $pid >&3; wait $pid 2>/dev/null; code=$?; echo $code >&3; exit $code'; // Workaround for the bug, when PTS functionality is enabled. // @see : https://bugs.php.net/69442 diff --git a/src/Symfony/Component/Process/Tests/ProcessTest.php b/src/Symfony/Component/Process/Tests/ProcessTest.php index 827c723969c76..804937999a5f6 100644 --- a/src/Symfony/Component/Process/Tests/ProcessTest.php +++ b/src/Symfony/Component/Process/Tests/ProcessTest.php @@ -1524,7 +1524,7 @@ public function testWaitStoppedDeadProcess() $process->wait(); $this->assertFalse($process->isRunning()); - if ('\\' !== \DIRECTORY_SEPARATOR) { + if ('\\' !== \DIRECTORY_SEPARATOR && !\Closure::bind(function () { return $this->isSigchildEnabled(); }, $process, $process)()) { $this->assertSame(0, $process->getExitCode()); } } From a6a3faee4d2497a974a17028229ebee3e3940cad Mon Sep 17 00:00:00 2001 From: Christian Flothmann Date: Mon, 7 Aug 2023 16:20:23 +0200 Subject: [PATCH 24/67] add missing default-doctrine-dbal-provider cache pool attribute to XSD --- .../FrameworkBundle/Resources/config/schema/symfony-1.0.xsd | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Symfony/Bundle/FrameworkBundle/Resources/config/schema/symfony-1.0.xsd b/src/Symfony/Bundle/FrameworkBundle/Resources/config/schema/symfony-1.0.xsd index 3a1a9a6d70a65..857c3c57fb7f2 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Resources/config/schema/symfony-1.0.xsd +++ b/src/Symfony/Bundle/FrameworkBundle/Resources/config/schema/symfony-1.0.xsd @@ -290,6 +290,7 @@ + From f42e2c146ed50d708bfc359fd9c2139575b5f2f5 Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Tue, 8 Aug 2023 11:57:41 +0200 Subject: [PATCH 25/67] [DoctrineBridge] Silence ORM deprecation --- .github/deprecations-baseline.json | 147 +++++++++++++++++- .github/workflows/unit-tests.yml | 1 + .../Doctrine/Test/DoctrineTestHelper.php | 5 + 3 files changed, 152 insertions(+), 1 deletion(-) diff --git a/.github/deprecations-baseline.json b/.github/deprecations-baseline.json index bc8adfb354f19..fdd35496c22c2 100644 --- a/.github/deprecations-baseline.json +++ b/.github/deprecations-baseline.json @@ -8,5 +8,150 @@ "location": "Symfony\\Component\\Messenger\\Bridge\\Doctrine\\Tests\\Transport\\DoctrinePostgreSqlIntegrationTest::setUp", "message": "Connection::query() is deprecated, use Connection::executeQuery() instead. (Connection.php:1436 called by AbstractPostgreSQLDriver.php:149, https://github.com/doctrine/dbal/pull/4163, package doctrine/dbal)", "count": 1 + }, + { + "location": "Symfony\\Bridge\\Doctrine\\Tests\\Form\\ChoiceList\\ORMQueryBuilderLoaderTest::testIdentifierTypeIsStringArray", + "message": "Not enabling lazy ghost objects is deprecated and will not be supported in Doctrine ORM 3.0. Ensure Doctrine\\ORM\\Configuration::setLazyGhostObjectEnabled(true) is called to enable them. (ProxyFactory.php:166 called by EntityManager.php:178, https://github.com/doctrine/orm/pull/10837/, package doctrine/orm)", + "count": 1 + }, + { + "location": "Symfony\\Bridge\\Doctrine\\Tests\\Form\\ChoiceList\\ORMQueryBuilderLoaderTest::testIdentifierTypeIsIntegerArray", + "message": "Not enabling lazy ghost objects is deprecated and will not be supported in Doctrine ORM 3.0. Ensure Doctrine\\ORM\\Configuration::setLazyGhostObjectEnabled(true) is called to enable them. (ProxyFactory.php:166 called by EntityManager.php:178, https://github.com/doctrine/orm/pull/10837/, package doctrine/orm)", + "count": 1 + }, + { + "location": "Symfony\\Bridge\\Doctrine\\Tests\\Form\\ChoiceList\\ORMQueryBuilderLoaderTest::testFilterNonIntegerValues", + "message": "Not enabling lazy ghost objects is deprecated and will not be supported in Doctrine ORM 3.0. Ensure Doctrine\\ORM\\Configuration::setLazyGhostObjectEnabled(true) is called to enable them. (ProxyFactory.php:166 called by EntityManager.php:178, https://github.com/doctrine/orm/pull/10837/, package doctrine/orm)", + "count": 1 + }, + { + "location": "Symfony\\Bridge\\Doctrine\\Tests\\Form\\ChoiceList\\ORMQueryBuilderLoaderTest::testFilterEmptyUuids", + "message": "Not enabling lazy ghost objects is deprecated and will not be supported in Doctrine ORM 3.0. Ensure Doctrine\\ORM\\Configuration::setLazyGhostObjectEnabled(true) is called to enable them. (ProxyFactory.php:166 called by EntityManager.php:178, https://github.com/doctrine/orm/pull/10837/, package doctrine/orm)", + "count": 2 + }, + { + "location": "Symfony\\Bridge\\Doctrine\\Tests\\Form\\ChoiceList\\ORMQueryBuilderLoaderTest::testFilterUid", + "message": "Not enabling lazy ghost objects is deprecated and will not be supported in Doctrine ORM 3.0. Ensure Doctrine\\ORM\\Configuration::setLazyGhostObjectEnabled(true) is called to enable them. (ProxyFactory.php:166 called by EntityManager.php:178, https://github.com/doctrine/orm/pull/10837/, package doctrine/orm)", + "count": 2 + }, + { + "location": "Symfony\\Bridge\\Doctrine\\Tests\\Form\\ChoiceList\\ORMQueryBuilderLoaderTest::testUidThrowProperException", + "message": "Not enabling lazy ghost objects is deprecated and will not be supported in Doctrine ORM 3.0. Ensure Doctrine\\ORM\\Configuration::setLazyGhostObjectEnabled(true) is called to enable them. (ProxyFactory.php:166 called by EntityManager.php:178, https://github.com/doctrine/orm/pull/10837/, package doctrine/orm)", + "count": 2 + }, + { + "location": "Symfony\\Bridge\\Doctrine\\Tests\\Form\\ChoiceList\\ORMQueryBuilderLoaderTest::testEmbeddedIdentifierName", + "message": "Not enabling lazy ghost objects is deprecated and will not be supported in Doctrine ORM 3.0. Ensure Doctrine\\ORM\\Configuration::setLazyGhostObjectEnabled(true) is called to enable them. (ProxyFactory.php:166 called by EntityManager.php:178, https://github.com/doctrine/orm/pull/10837/, package doctrine/orm)", + "count": 1 + }, + { + "location": "Symfony\\Bridge\\Doctrine\\Tests\\Form\\Type\\EntityTypeTest::setUp", + "message": "Not enabling lazy ghost objects is deprecated and will not be supported in Doctrine ORM 3.0. Ensure Doctrine\\ORM\\Configuration::setLazyGhostObjectEnabled(true) is called to enable them. (ProxyFactory.php:166 called by EntityManager.php:178, https://github.com/doctrine/orm/pull/10837/, package doctrine/orm)", + "count": 83 + }, + { + "location": "Symfony\\Bridge\\Doctrine\\Tests\\PropertyInfo\\DoctrineExtractorTest::testGetProperties", + "message": "Not enabling lazy ghost objects is deprecated and will not be supported in Doctrine ORM 3.0. Ensure Doctrine\\ORM\\Configuration::setLazyGhostObjectEnabled(true) is called to enable them. (ProxyFactory.php:166 called by EntityManager.php:178, https://github.com/doctrine/orm/pull/10837/, package doctrine/orm)", + "count": 1 + }, + { + "location": "Symfony\\Bridge\\Doctrine\\Tests\\PropertyInfo\\DoctrineExtractorTest::testTestGetPropertiesWithEmbedded", + "message": "Not enabling lazy ghost objects is deprecated and will not be supported in Doctrine ORM 3.0. Ensure Doctrine\\ORM\\Configuration::setLazyGhostObjectEnabled(true) is called to enable them. (ProxyFactory.php:166 called by EntityManager.php:178, https://github.com/doctrine/orm/pull/10837/, package doctrine/orm)", + "count": 1 + }, + { + "location": "Symfony\\Bridge\\Doctrine\\Tests\\PropertyInfo\\DoctrineExtractorTest::testExtract", + "message": "Not enabling lazy ghost objects is deprecated and will not be supported in Doctrine ORM 3.0. Ensure Doctrine\\ORM\\Configuration::setLazyGhostObjectEnabled(true) is called to enable them. (ProxyFactory.php:166 called by EntityManager.php:178, https://github.com/doctrine/orm/pull/10837/, package doctrine/orm)", + "count": 25 + }, + { + "location": "Symfony\\Bridge\\Doctrine\\Tests\\PropertyInfo\\DoctrineExtractorTest::testExtractWithEmbedded", + "message": "Not enabling lazy ghost objects is deprecated and will not be supported in Doctrine ORM 3.0. Ensure Doctrine\\ORM\\Configuration::setLazyGhostObjectEnabled(true) is called to enable them. (ProxyFactory.php:166 called by EntityManager.php:178, https://github.com/doctrine/orm/pull/10837/, package doctrine/orm)", + "count": 1 + }, + { + "location": "Symfony\\Bridge\\Doctrine\\Tests\\PropertyInfo\\DoctrineExtractorTest::testExtractEnum", + "message": "Not enabling lazy ghost objects is deprecated and will not be supported in Doctrine ORM 3.0. Ensure Doctrine\\ORM\\Configuration::setLazyGhostObjectEnabled(true) is called to enable them. (ProxyFactory.php:166 called by EntityManager.php:178, https://github.com/doctrine/orm/pull/10837/, package doctrine/orm)", + "count": 5 + }, + { + "location": "Symfony\\Bridge\\Doctrine\\Tests\\PropertyInfo\\DoctrineExtractorTest::testGetPropertiesCatchException", + "message": "Not enabling lazy ghost objects is deprecated and will not be supported in Doctrine ORM 3.0. Ensure Doctrine\\ORM\\Configuration::setLazyGhostObjectEnabled(true) is called to enable them. (ProxyFactory.php:166 called by EntityManager.php:178, https://github.com/doctrine/orm/pull/10837/, package doctrine/orm)", + "count": 1 + }, + { + "location": "Symfony\\Bridge\\Doctrine\\Tests\\PropertyInfo\\DoctrineExtractorTest::testGetTypesCatchException", + "message": "Not enabling lazy ghost objects is deprecated and will not be supported in Doctrine ORM 3.0. Ensure Doctrine\\ORM\\Configuration::setLazyGhostObjectEnabled(true) is called to enable them. (ProxyFactory.php:166 called by EntityManager.php:178, https://github.com/doctrine/orm/pull/10837/, package doctrine/orm)", + "count": 1 + }, + { + "location": "Symfony\\Bridge\\Doctrine\\Tests\\PropertyInfo\\DoctrineExtractorTest::testGeneratedValueNotWritable", + "message": "Not enabling lazy ghost objects is deprecated and will not be supported in Doctrine ORM 3.0. Ensure Doctrine\\ORM\\Configuration::setLazyGhostObjectEnabled(true) is called to enable them. (ProxyFactory.php:166 called by EntityManager.php:178, https://github.com/doctrine/orm/pull/10837/, package doctrine/orm)", + "count": 1 + }, + { + "location": "Symfony\\Bridge\\Doctrine\\Tests\\Security\\User\\EntityUserProviderTest::testRefreshUserGetsUserByPrimaryKey", + "message": "Not enabling lazy ghost objects is deprecated and will not be supported in Doctrine ORM 3.0. Ensure Doctrine\\ORM\\Configuration::setLazyGhostObjectEnabled(true) is called to enable them. (ProxyFactory.php:166 called by EntityManager.php:178, https://github.com/doctrine/orm/pull/10837/, package doctrine/orm)", + "count": 1 + }, + { + "location": "Symfony\\Bridge\\Doctrine\\Tests\\Security\\User\\EntityUserProviderTest::testLoadUserByUsername", + "message": "Not enabling lazy ghost objects is deprecated and will not be supported in Doctrine ORM 3.0. Ensure Doctrine\\ORM\\Configuration::setLazyGhostObjectEnabled(true) is called to enable them. (ProxyFactory.php:166 called by EntityManager.php:178, https://github.com/doctrine/orm/pull/10837/, package doctrine/orm)", + "count": 1 + }, + { + "location": "Symfony\\Bridge\\Doctrine\\Tests\\Security\\User\\EntityUserProviderTest::testLoadUserByUsernameWithNonUserLoaderRepositoryAndWithoutProperty", + "message": "Not enabling lazy ghost objects is deprecated and will not be supported in Doctrine ORM 3.0. Ensure Doctrine\\ORM\\Configuration::setLazyGhostObjectEnabled(true) is called to enable them. (ProxyFactory.php:166 called by EntityManager.php:178, https://github.com/doctrine/orm/pull/10837/, package doctrine/orm)", + "count": 1 + }, + { + "location": "Symfony\\Bridge\\Doctrine\\Tests\\Security\\User\\EntityUserProviderTest::testRefreshUserRequiresId", + "message": "Not enabling lazy ghost objects is deprecated and will not be supported in Doctrine ORM 3.0. Ensure Doctrine\\ORM\\Configuration::setLazyGhostObjectEnabled(true) is called to enable them. (ProxyFactory.php:166 called by EntityManager.php:178, https://github.com/doctrine/orm/pull/10837/, package doctrine/orm)", + "count": 1 + }, + { + "location": "Symfony\\Bridge\\Doctrine\\Tests\\Security\\User\\EntityUserProviderTest::testRefreshInvalidUser", + "message": "Not enabling lazy ghost objects is deprecated and will not be supported in Doctrine ORM 3.0. Ensure Doctrine\\ORM\\Configuration::setLazyGhostObjectEnabled(true) is called to enable them. (ProxyFactory.php:166 called by EntityManager.php:178, https://github.com/doctrine/orm/pull/10837/, package doctrine/orm)", + "count": 1 + }, + { + "location": "Symfony\\Bridge\\Doctrine\\Tests\\Security\\User\\EntityUserProviderTest::testSupportProxy", + "message": "Not enabling lazy ghost objects is deprecated and will not be supported in Doctrine ORM 3.0. Ensure Doctrine\\ORM\\Configuration::setLazyGhostObjectEnabled(true) is called to enable them. (ProxyFactory.php:166 called by EntityManager.php:178, https://github.com/doctrine/orm/pull/10837/, package doctrine/orm)", + "count": 1 + }, + { + "location": "Symfony\\Bridge\\Doctrine\\Tests\\Security\\User\\EntityUserProviderTest::testRefreshedUserProxyIsLoaded", + "message": "Not enabling lazy ghost objects is deprecated and will not be supported in Doctrine ORM 3.0. Ensure Doctrine\\ORM\\Configuration::setLazyGhostObjectEnabled(true) is called to enable them. (ProxyFactory.php:166 called by EntityManager.php:178, https://github.com/doctrine/orm/pull/10837/, package doctrine/orm)", + "count": 1 + }, + { + "location": "Symfony\\Bridge\\Doctrine\\Tests\\Validator\\Constraints\\UniqueEntityValidatorTest::setUp", + "message": "Not enabling lazy ghost objects is deprecated and will not be supported in Doctrine ORM 3.0. Ensure Doctrine\\ORM\\Configuration::setLazyGhostObjectEnabled(true) is called to enable them. (ProxyFactory.php:166 called by EntityManager.php:178, https://github.com/doctrine/orm/pull/10837/, package doctrine/orm)", + "count": 36 + }, + { + "location": "Symfony\\Bridge\\Doctrine\\Tests\\Validator\\DoctrineLoaderTest::testLoadClassMetadata", + "message": "Not enabling lazy ghost objects is deprecated and will not be supported in Doctrine ORM 3.0. Ensure Doctrine\\ORM\\Configuration::setLazyGhostObjectEnabled(true) is called to enable them. (ProxyFactory.php:166 called by EntityManager.php:178, https://github.com/doctrine/orm/pull/10837/, package doctrine/orm)", + "count": 1 + }, + { + "location": "Symfony\\Bridge\\Doctrine\\Tests\\Validator\\DoctrineLoaderTest::testExtractEnum", + "message": "Not enabling lazy ghost objects is deprecated and will not be supported in Doctrine ORM 3.0. Ensure Doctrine\\ORM\\Configuration::setLazyGhostObjectEnabled(true) is called to enable them. (ProxyFactory.php:166 called by EntityManager.php:178, https://github.com/doctrine/orm/pull/10837/, package doctrine/orm)", + "count": 1 + }, + { + "location": "Symfony\\Bridge\\Doctrine\\Tests\\Validator\\DoctrineLoaderTest::testFieldMappingsConfiguration", + "message": "Not enabling lazy ghost objects is deprecated and will not be supported in Doctrine ORM 3.0. Ensure Doctrine\\ORM\\Configuration::setLazyGhostObjectEnabled(true) is called to enable them. (ProxyFactory.php:166 called by EntityManager.php:178, https://github.com/doctrine/orm/pull/10837/, package doctrine/orm)", + "count": 1 + }, + { + "location": "Symfony\\Bridge\\Doctrine\\Tests\\Validator\\DoctrineLoaderTest::testClassValidator", + "message": "Not enabling lazy ghost objects is deprecated and will not be supported in Doctrine ORM 3.0. Ensure Doctrine\\ORM\\Configuration::setLazyGhostObjectEnabled(true) is called to enable them. (ProxyFactory.php:166 called by EntityManager.php:178, https://github.com/doctrine/orm/pull/10837/, package doctrine/orm)", + "count": 4 + }, + { + "location": "Symfony\\Bridge\\Doctrine\\Tests\\Validator\\DoctrineLoaderTest::testClassNoAutoMapping", + "message": "Not enabling lazy ghost objects is deprecated and will not be supported in Doctrine ORM 3.0. Ensure Doctrine\\ORM\\Configuration::setLazyGhostObjectEnabled(true) is called to enable them. (ProxyFactory.php:166 called by EntityManager.php:178, https://github.com/doctrine/orm/pull/10837/, package doctrine/orm)", + "count": 1 } -] \ No newline at end of file +] diff --git a/.github/workflows/unit-tests.yml b/.github/workflows/unit-tests.yml index 7846507f86101..199887754e036 100644 --- a/.github/workflows/unit-tests.yml +++ b/.github/workflows/unit-tests.yml @@ -66,6 +66,7 @@ jobs: echo COLUMNS=120 >> $GITHUB_ENV echo PHPUNIT="$(pwd)/phpunit --exclude-group tty,benchmark,intl-data,integration" >> $GITHUB_ENV echo COMPOSER_UP='composer update --no-progress --ansi'$([[ "${{ matrix.mode }}" != low-deps ]] && echo ' --ignore-platform-req=php+') >> $GITHUB_ENV + echo SYMFONY_DEPRECATIONS_HELPER="baselineFile=$(pwd)/.github/deprecations-baseline.json" >> $GITHUB_ENV SYMFONY_VERSIONS=$(git ls-remote -q --heads | cut -f2 | grep -o '/[1-9][0-9]*\.[0-9].*' | sort -V) SYMFONY_VERSION=$(grep ' VERSION = ' src/Symfony/Component/HttpKernel/Kernel.php | cut -d "'" -f2 | cut -d '.' -f 1-2) diff --git a/src/Symfony/Bridge/Doctrine/Test/DoctrineTestHelper.php b/src/Symfony/Bridge/Doctrine/Test/DoctrineTestHelper.php index b9597cfaed345..0de248b1efdf0 100644 --- a/src/Symfony/Bridge/Doctrine/Test/DoctrineTestHelper.php +++ b/src/Symfony/Bridge/Doctrine/Test/DoctrineTestHelper.php @@ -24,6 +24,7 @@ use Doctrine\Persistence\Mapping\Driver\MappingDriverChain; use Doctrine\Persistence\Mapping\Driver\SymfonyFileLocator; use PHPUnit\Framework\TestCase; +use Symfony\Component\VarExporter\LazyGhostTrait; /** * Provides utility functions needed in tests. @@ -90,6 +91,10 @@ public static function createTestConfiguration() $config->setSchemaManagerFactory(new DefaultSchemaManagerFactory()); } + if (\PHP_VERSION_ID >= 80100 && method_exists(Configuration::class, 'setLazyGhostObjectEnabled') && trait_exists(LazyGhostTrait::class)) { + $config->setLazyGhostObjectEnabled(true); + } + return $config; } From 48ac0e5537f74b375cec4d0e65711a919e009597 Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Tue, 8 Aug 2023 12:40:25 +0200 Subject: [PATCH 26/67] Fix merge --- src/Symfony/Bridge/Doctrine/Tests/DoctrineTestHelper.php | 5 ++--- .../Doctrine/Tests/Middleware/Debug/MiddlewareTest.php | 6 ++++-- .../Doctrine/Tests/PropertyInfo/DoctrineExtractorTest.php | 4 ++++ .../Security/RememberMe/DoctrineTokenProviderTest.php | 7 +++++-- 4 files changed, 15 insertions(+), 7 deletions(-) diff --git a/src/Symfony/Bridge/Doctrine/Tests/DoctrineTestHelper.php b/src/Symfony/Bridge/Doctrine/Tests/DoctrineTestHelper.php index a3d13740734ff..a54319de9f47b 100644 --- a/src/Symfony/Bridge/Doctrine/Tests/DoctrineTestHelper.php +++ b/src/Symfony/Bridge/Doctrine/Tests/DoctrineTestHelper.php @@ -59,7 +59,7 @@ public static function createTestEntityManager(Configuration $config = null): En public static function createTestConfiguration(): Configuration { - $config = class_exists(ORMSetup::class) ? ORMSetup::createConfiguration(true) : new Configuration(); + $config = ORMSetup::createConfiguration(true); $config->setEntityNamespaces(['SymfonyTestsDoctrine' => 'Symfony\Bridge\Doctrine\Tests\Fixtures']); $config->setAutoGenerateProxyClasses(true); $config->setProxyDir(sys_get_temp_dir()); @@ -72,8 +72,7 @@ public static function createTestConfiguration(): Configuration if (class_exists(DefaultSchemaManagerFactory::class)) { $config->setSchemaManagerFactory(new DefaultSchemaManagerFactory()); } - - if (method_exists(Configuration::class, 'setLazyGhostObjectEnabled')) { + if (method_exists($config, 'setLazyGhostObjectEnabled')) { $config->setLazyGhostObjectEnabled(true); } diff --git a/src/Symfony/Bridge/Doctrine/Tests/Middleware/Debug/MiddlewareTest.php b/src/Symfony/Bridge/Doctrine/Tests/Middleware/Debug/MiddlewareTest.php index b1096fbf60cb5..deeef93e7e13e 100644 --- a/src/Symfony/Bridge/Doctrine/Tests/Middleware/Debug/MiddlewareTest.php +++ b/src/Symfony/Bridge/Doctrine/Tests/Middleware/Debug/MiddlewareTest.php @@ -11,7 +11,6 @@ namespace Symfony\Bridge\Doctrine\Tests\Middleware\Debug; -use Doctrine\DBAL\Configuration; use Doctrine\DBAL\Connection; use Doctrine\DBAL\Driver\Middleware as MiddlewareInterface; use Doctrine\DBAL\DriverManager; @@ -51,10 +50,13 @@ private function init(bool $withStopwatch = true): void { $this->stopwatch = $withStopwatch ? new Stopwatch() : null; - $config = class_exists(ORMSetup::class) ? ORMSetup::createConfiguration(true) : new Configuration(); + $config = ORMSetup::createConfiguration(true); if (class_exists(DefaultSchemaManagerFactory::class)) { $config->setSchemaManagerFactory(new DefaultSchemaManagerFactory()); } + if (method_exists($config, 'setLazyGhostObjectEnabled')) { + $config->setLazyGhostObjectEnabled(true); + } $this->debugDataHolder = new DebugDataHolder(); $config->setMiddlewares([new Middleware($this->debugDataHolder, $this->stopwatch)]); diff --git a/src/Symfony/Bridge/Doctrine/Tests/PropertyInfo/DoctrineExtractorTest.php b/src/Symfony/Bridge/Doctrine/Tests/PropertyInfo/DoctrineExtractorTest.php index 5ca97f6f0b64a..296fbcc7dca59 100644 --- a/src/Symfony/Bridge/Doctrine/Tests/PropertyInfo/DoctrineExtractorTest.php +++ b/src/Symfony/Bridge/Doctrine/Tests/PropertyInfo/DoctrineExtractorTest.php @@ -43,6 +43,10 @@ private function createExtractor() $config->setSchemaManagerFactory(new DefaultSchemaManagerFactory()); } + if (method_exists($config, 'setLazyGhostObjectEnabled')) { + $config->setLazyGhostObjectEnabled(true); + } + if (!(new \ReflectionMethod(EntityManager::class, '__construct'))->isPublic()) { $entityManager = EntityManager::create(['driver' => 'pdo_sqlite'], $config); } else { diff --git a/src/Symfony/Bridge/Doctrine/Tests/Security/RememberMe/DoctrineTokenProviderTest.php b/src/Symfony/Bridge/Doctrine/Tests/Security/RememberMe/DoctrineTokenProviderTest.php index eb387e424cd09..de9ae48e041d1 100644 --- a/src/Symfony/Bridge/Doctrine/Tests/Security/RememberMe/DoctrineTokenProviderTest.php +++ b/src/Symfony/Bridge/Doctrine/Tests/Security/RememberMe/DoctrineTokenProviderTest.php @@ -11,7 +11,6 @@ namespace Security\RememberMe; -use Doctrine\DBAL\Configuration; use Doctrine\DBAL\DriverManager; use Doctrine\DBAL\Schema\DefaultSchemaManagerFactory; use Doctrine\ORM\ORMSetup; @@ -123,11 +122,15 @@ public function testVerifyOutdatedTokenAfterParallelRequestFailsAfter60Seconds() */ private function bootstrapProvider() { - $config = class_exists(ORMSetup::class) ? ORMSetup::createConfiguration(true) : new Configuration(); + $config = ORMSetup::createConfiguration(true); if (class_exists(DefaultSchemaManagerFactory::class)) { $config->setSchemaManagerFactory(new DefaultSchemaManagerFactory()); } + if (method_exists($config, 'setLazyGhostObjectEnabled')) { + $config->setLazyGhostObjectEnabled(true); + } + $connection = DriverManager::getConnection([ 'driver' => 'pdo_sqlite', 'memory' => true, From e8a2e862dddd597cdc339d17832947e893e70b33 Mon Sep 17 00:00:00 2001 From: Christian Flothmann Date: Tue, 8 Aug 2023 13:21:07 +0200 Subject: [PATCH 27/67] change default doctrine DBAL provider to XML attribute --- .../FrameworkBundle/Resources/config/schema/symfony-1.0.xsd | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Symfony/Bundle/FrameworkBundle/Resources/config/schema/symfony-1.0.xsd b/src/Symfony/Bundle/FrameworkBundle/Resources/config/schema/symfony-1.0.xsd index 857c3c57fb7f2..29f64dad9bed9 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Resources/config/schema/symfony-1.0.xsd +++ b/src/Symfony/Bundle/FrameworkBundle/Resources/config/schema/symfony-1.0.xsd @@ -290,7 +290,6 @@ - @@ -302,6 +301,7 @@ + From c85892cfac78c6126b09eac65f1b6d94ffec257d Mon Sep 17 00:00:00 2001 From: Bastien THOMAS Date: Mon, 7 Aug 2023 00:46:00 +0200 Subject: [PATCH 28/67] [Mailer] update Brevo SMTP host --- .../Bridge/Sendinblue/Transport/SendinblueSmtpTransport.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Symfony/Component/Mailer/Bridge/Sendinblue/Transport/SendinblueSmtpTransport.php b/src/Symfony/Component/Mailer/Bridge/Sendinblue/Transport/SendinblueSmtpTransport.php index 85c05f49b6a3c..b0e90230a0fb4 100644 --- a/src/Symfony/Component/Mailer/Bridge/Sendinblue/Transport/SendinblueSmtpTransport.php +++ b/src/Symfony/Component/Mailer/Bridge/Sendinblue/Transport/SendinblueSmtpTransport.php @@ -22,7 +22,7 @@ final class SendinblueSmtpTransport extends EsmtpTransport { public function __construct(string $username, string $password, EventDispatcherInterface $dispatcher = null, LoggerInterface $logger = null) { - parent::__construct('smtp-relay.sendinblue.com', 465, true, $dispatcher, $logger); + parent::__construct('smtp-relay.brevo.com', 465, true, $dispatcher, $logger); $this->setUsername($username); $this->setPassword($password); From 81acb105de19b045f861a94830c7dd0aabe3dccf Mon Sep 17 00:00:00 2001 From: "hubert.lenoir" Date: Wed, 9 Aug 2023 16:21:20 +0200 Subject: [PATCH 29/67] [FrameworkBundle] Fix xsd handle-all-throwables --- .../FrameworkBundle/Resources/config/schema/symfony-1.0.xsd | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Symfony/Bundle/FrameworkBundle/Resources/config/schema/symfony-1.0.xsd b/src/Symfony/Bundle/FrameworkBundle/Resources/config/schema/symfony-1.0.xsd index 2cc47238c2053..324c41b3e705d 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Resources/config/schema/symfony-1.0.xsd +++ b/src/Symfony/Bundle/FrameworkBundle/Resources/config/schema/symfony-1.0.xsd @@ -49,6 +49,7 @@ + From 33f515672d7aa578bb82a82c4f75020fea6b07a5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Str=C3=B8m?= Date: Wed, 9 Aug 2023 19:16:27 +0200 Subject: [PATCH 30/67] Always return bool from messenger amqp conncetion nack --- .../Component/Messenger/Bridge/Amqp/Transport/Connection.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Symfony/Component/Messenger/Bridge/Amqp/Transport/Connection.php b/src/Symfony/Component/Messenger/Bridge/Amqp/Transport/Connection.php index ece0c1716b69b..166031b3aea90 100644 --- a/src/Symfony/Component/Messenger/Bridge/Amqp/Transport/Connection.php +++ b/src/Symfony/Component/Messenger/Bridge/Amqp/Transport/Connection.php @@ -461,7 +461,7 @@ public function ack(\AMQPEnvelope $message, string $queueName): bool public function nack(\AMQPEnvelope $message, string $queueName, int $flags = \AMQP_NOPARAM): bool { - return $this->queue($queueName)->nack($message->getDeliveryTag(), $flags); + return $this->queue($queueName)->nack($message->getDeliveryTag(), $flags) ?? true; } public function setup(): void From ccafda38d5e77e107db358d14e5c236296fd4dbc Mon Sep 17 00:00:00 2001 From: Ahmed Ghanem Date: Thu, 10 Aug 2023 06:35:35 +0300 Subject: [PATCH 31/67] Fix invalid method call + improve exception message --- .../Component/Notifier/Bridge/Pushover/PushoverTransport.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Symfony/Component/Notifier/Bridge/Pushover/PushoverTransport.php b/src/Symfony/Component/Notifier/Bridge/Pushover/PushoverTransport.php index cf96f7757ae70..900dcf84e4248 100644 --- a/src/Symfony/Component/Notifier/Bridge/Pushover/PushoverTransport.php +++ b/src/Symfony/Component/Notifier/Bridge/Pushover/PushoverTransport.php @@ -77,7 +77,7 @@ protected function doSend(MessageInterface $message): SentMessage $result = $response->toArray(false); if (!isset($result['request'])) { - throw new TransportException(sprintf('Unable to send the Pushover push notification: "%s".', $result->getContent(false)), $response); + throw new TransportException(sprintf('Unable to find the message id within the Pushover response: "%s".', $response->getContent(false)), $response); } $sentMessage = new SentMessage($message, (string) $this); From 55d7e227cf430d51ae2801c5dec7d78ca9036074 Mon Sep 17 00:00:00 2001 From: Wouter de Jong Date: Thu, 10 Aug 2023 15:09:58 +0200 Subject: [PATCH 32/67] Remove me from CODEOWNERS Imho, this created more noise than being useful in GitHub notification management. --- .github/CODEOWNERS | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 19e868793ac36..b9e28a90c6196 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -38,10 +38,10 @@ # Serializer /src/Symfony/Component/Serializer/ @dunglas # Security -/src/Symfony/Bridge/Doctrine/Security/ @wouterj @chalasr -/src/Symfony/Bundle/SecurityBundle/ @wouterj @chalasr -/src/Symfony/Component/Security/ @wouterj @chalasr -/src/Symfony/Component/Ldap/Security/ @wouterj @chalasr +/src/Symfony/Bridge/Doctrine/Security/ @chalasr +/src/Symfony/Bundle/SecurityBundle/ @chalasr +/src/Symfony/Component/Security/ @chalasr +/src/Symfony/Component/Ldap/Security/ @chalasr # TwigBundle /src/Symfony/Bundle/TwigBundle/ @yceruto # WebLink From 28e9da6a0dd1f31471b6d61091d56242b78a68e7 Mon Sep 17 00:00:00 2001 From: Joel Wurtz Date: Fri, 11 Aug 2023 14:16:05 +0200 Subject: [PATCH 33/67] fix(console): fix section output when multiples section with max height --- .../Console/Output/ConsoleSectionOutput.php | 6 ++-- .../Tests/Output/ConsoleSectionOutputTest.php | 34 +++++++++++++++++++ 2 files changed, 37 insertions(+), 3 deletions(-) diff --git a/src/Symfony/Component/Console/Output/ConsoleSectionOutput.php b/src/Symfony/Component/Console/Output/ConsoleSectionOutput.php index 3f3f1434be46c..3d499bbcc9e37 100644 --- a/src/Symfony/Component/Console/Output/ConsoleSectionOutput.php +++ b/src/Symfony/Component/Console/Output/ConsoleSectionOutput.php @@ -48,9 +48,9 @@ public function __construct($stream, array &$sections, int $verbosity, bool $dec public function setMaxHeight(int $maxHeight): void { // when changing max height, clear output of current section and redraw again with the new height - $existingContent = $this->popStreamContentUntilCurrentSection($this->maxHeight ? min($this->maxHeight, $this->lines) : $this->lines); - + $previousMaxHeight = $this->maxHeight; $this->maxHeight = $maxHeight; + $existingContent = $this->popStreamContentUntilCurrentSection($previousMaxHeight ? min($previousMaxHeight, $this->lines) : $this->lines); parent::doWrite($this->getVisibleContent(), false); parent::doWrite($existingContent, false); @@ -213,7 +213,7 @@ private function popStreamContentUntilCurrentSection(int $numberOfLinesToClearFr break; } - $numberOfLinesToClear += $section->lines; + $numberOfLinesToClear += $section->maxHeight ? min($section->lines, $section->maxHeight) : $section->lines; if ('' !== $sectionContent = $section->getVisibleContent()) { if (!str_ends_with($sectionContent, \PHP_EOL)) { $sectionContent .= \PHP_EOL; diff --git a/src/Symfony/Component/Console/Tests/Output/ConsoleSectionOutputTest.php b/src/Symfony/Component/Console/Tests/Output/ConsoleSectionOutputTest.php index 984ade26608a7..0a775fd68e4f9 100644 --- a/src/Symfony/Component/Console/Tests/Output/ConsoleSectionOutputTest.php +++ b/src/Symfony/Component/Console/Tests/Output/ConsoleSectionOutputTest.php @@ -133,6 +133,40 @@ public function testMaxHeight() $this->assertEquals($expected, stream_get_contents($output->getStream())); } + public function testMaxHeightMultipleSections() + { + $expected = ''; + $sections = []; + + $firstSection = new ConsoleSectionOutput($this->stream, $sections, OutputInterface::VERBOSITY_NORMAL, true, new OutputFormatter()); + $firstSection->setMaxHeight(3); + + $secondSection = new ConsoleSectionOutput($this->stream, $sections, OutputInterface::VERBOSITY_NORMAL, true, new OutputFormatter()); + $secondSection->setMaxHeight(3); + + // fill the first section + $firstSection->writeln(['One', 'Two', 'Three']); + $expected .= 'One'.\PHP_EOL.'Two'.\PHP_EOL.'Three'.\PHP_EOL; + + // fill the second section + $secondSection->writeln(['One', 'Two', 'Three']); + $expected .= 'One'.\PHP_EOL.'Two'.\PHP_EOL.'Three'.\PHP_EOL; + + // cause overflow of second section (redraw whole section, without first line) + $secondSection->writeln('Four'); + $expected .= "\x1b[3A\x1b[0J"; + $expected .= 'Two'.\PHP_EOL.'Three'.\PHP_EOL.'Four'.\PHP_EOL; + + // cause overflow of first section (redraw whole section, without first line) + $firstSection->writeln("Four\nFive\nSix"); + $expected .= "\x1b[6A\x1b[0J"; + $expected .= 'Four'.\PHP_EOL.'Five'.\PHP_EOL.'Six'.\PHP_EOL; + $expected .= 'Two'.\PHP_EOL.'Three'.\PHP_EOL.'Four'.\PHP_EOL; + + rewind($this->stream); + $this->assertEquals(escapeshellcmd($expected), escapeshellcmd(stream_get_contents($this->stream))); + } + public function testMaxHeightWithoutNewLine() { $expected = ''; From a22e891812463a252ede82c431e660a63c1b2922 Mon Sep 17 00:00:00 2001 From: Baptiste CONTRERAS <38988658+BaptisteContreras@users.noreply.github.com> Date: Fri, 11 Aug 2023 17:08:23 +0200 Subject: [PATCH 34/67] [Security] Fix error with lock_factory in login_throttling --- .../Security/Factory/LoginThrottlingFactory.php | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/Symfony/Bundle/SecurityBundle/DependencyInjection/Security/Factory/LoginThrottlingFactory.php b/src/Symfony/Bundle/SecurityBundle/DependencyInjection/Security/Factory/LoginThrottlingFactory.php index 4092f3e837f4c..b696f9e02d91c 100644 --- a/src/Symfony/Bundle/SecurityBundle/DependencyInjection/Security/Factory/LoginThrottlingFactory.php +++ b/src/Symfony/Bundle/SecurityBundle/DependencyInjection/Security/Factory/LoginThrottlingFactory.php @@ -98,9 +98,6 @@ private function registerRateLimiter(ContainerBuilder $container, string $name, if (!interface_exists(LockInterface::class)) { throw new LogicException(sprintf('Rate limiter "%s" requires the Lock component to be installed. Try running "composer require symfony/lock".', $name)); } - if (!$container->hasDefinition('lock.factory.abstract')) { - throw new LogicException(sprintf('Rate limiter "%s" requires the Lock component to be configured.', $name)); - } $limiter->replaceArgument(2, new Reference($limiterConfig['lock_factory'])); } From 724ccf8b8fad68008ba22e0f91d5c2b1a5437158 Mon Sep 17 00:00:00 2001 From: Ruud Kamphuis Date: Fri, 11 Aug 2023 08:51:27 +0200 Subject: [PATCH 35/67] Allow passing an `inline_service` to a `service_locator` Something, you want to include an inline service to a service locator. This works fine. Except that the PHPDoc doesn't allow it causing PHPStan to fail. --- .../Loader/Configurator/ContainerConfigurator.php | 2 +- .../Tests/Compiler/ServiceLocatorTagPassTest.php | 2 ++ .../config/services_with_service_locator_argument.php | 6 ++++++ .../xml/services_with_service_locator_argument.xml | 11 +++++++++++ .../yaml/services_with_service_locator_argument.yml | 11 +++++++++++ .../Tests/Loader/PhpFileLoaderTest.php | 4 ++++ .../Tests/Loader/XmlFileLoaderTest.php | 4 ++++ .../Tests/Loader/YamlFileLoaderTest.php | 4 ++++ 8 files changed, 43 insertions(+), 1 deletion(-) diff --git a/src/Symfony/Component/DependencyInjection/Loader/Configurator/ContainerConfigurator.php b/src/Symfony/Component/DependencyInjection/Loader/Configurator/ContainerConfigurator.php index 28f823746d998..52d03fb093a09 100644 --- a/src/Symfony/Component/DependencyInjection/Loader/Configurator/ContainerConfigurator.php +++ b/src/Symfony/Component/DependencyInjection/Loader/Configurator/ContainerConfigurator.php @@ -119,7 +119,7 @@ function inline_service(string $class = null): InlineServiceConfigurator /** * Creates a service locator. * - * @param ReferenceConfigurator[] $values + * @param array $values */ function service_locator(array $values): ServiceLocatorArgument { diff --git a/src/Symfony/Component/DependencyInjection/Tests/Compiler/ServiceLocatorTagPassTest.php b/src/Symfony/Component/DependencyInjection/Tests/Compiler/ServiceLocatorTagPassTest.php index 10f9bff443919..27e363a95dda8 100644 --- a/src/Symfony/Component/DependencyInjection/Tests/Compiler/ServiceLocatorTagPassTest.php +++ b/src/Symfony/Component/DependencyInjection/Tests/Compiler/ServiceLocatorTagPassTest.php @@ -70,6 +70,7 @@ public function testProcessValue() new Reference('bar'), new Reference('baz'), 'some.service' => new Reference('bar'), + 'inlines.service' => new Definition(CustomDefinition::class), ]]) ->addTag('container.service_locator') ; @@ -82,6 +83,7 @@ public function testProcessValue() $this->assertSame(CustomDefinition::class, $locator('bar')::class); $this->assertSame(CustomDefinition::class, $locator('baz')::class); $this->assertSame(CustomDefinition::class, $locator('some.service')::class); + $this->assertSame(CustomDefinition::class, \get_class($locator('inlines.service'))); } public function testServiceWithKeyOverwritesPreviousInheritedKey() diff --git a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/config/services_with_service_locator_argument.php b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/config/services_with_service_locator_argument.php index 58757abc4b326..cffc716f5e1d9 100644 --- a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/config/services_with_service_locator_argument.php +++ b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/config/services_with_service_locator_argument.php @@ -26,4 +26,10 @@ 'foo' => service('foo_service'), service('bar_service'), ])]); + + $services->set('locator_dependent_inline_service', \ArrayObject::class) + ->args([service_locator([ + 'foo' => inline_service(\stdClass::class), + 'bar' => inline_service(\stdClass::class), + ])]); }; diff --git a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/xml/services_with_service_locator_argument.xml b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/xml/services_with_service_locator_argument.xml index f98ca9e5a01d9..773bad5187b72 100644 --- a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/xml/services_with_service_locator_argument.xml +++ b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/xml/services_with_service_locator_argument.xml @@ -25,5 +25,16 @@ + + + + + + + + + + + diff --git a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/yaml/services_with_service_locator_argument.yml b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/yaml/services_with_service_locator_argument.yml index b0309d3eeab9a..57570c2d01efa 100644 --- a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/yaml/services_with_service_locator_argument.yml +++ b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/yaml/services_with_service_locator_argument.yml @@ -26,3 +26,14 @@ services: - !service_locator 'foo': '@foo_service' '0': '@bar_service' + + locator_dependent_inline_service: + class: ArrayObject + arguments: + - !service_locator + 'foo': + - !service + class: stdClass + 'bar': + - !service + class: stdClass diff --git a/src/Symfony/Component/DependencyInjection/Tests/Loader/PhpFileLoaderTest.php b/src/Symfony/Component/DependencyInjection/Tests/Loader/PhpFileLoaderTest.php index 7b24f5e2248e6..ec193bce005ec 100644 --- a/src/Symfony/Component/DependencyInjection/Tests/Loader/PhpFileLoaderTest.php +++ b/src/Symfony/Component/DependencyInjection/Tests/Loader/PhpFileLoaderTest.php @@ -19,6 +19,7 @@ use Symfony\Component\Config\FileLocator; use Symfony\Component\DependencyInjection\Argument\ServiceLocatorArgument; use Symfony\Component\DependencyInjection\ContainerBuilder; +use Symfony\Component\DependencyInjection\Definition; use Symfony\Component\DependencyInjection\Dumper\PhpDumper; use Symfony\Component\DependencyInjection\Dumper\YamlDumper; use Symfony\Component\DependencyInjection\Exception\InvalidArgumentException; @@ -231,5 +232,8 @@ public function testServiceWithServiceLocatorArgument() $values = ['foo' => new Reference('foo_service'), 0 => new Reference('bar_service')]; $this->assertEquals([new ServiceLocatorArgument($values)], $container->getDefinition('locator_dependent_service_mixed')->getArguments()); + + $values = ['foo' => new Definition(\stdClass::class), 'bar' => new Definition(\stdClass::class)]; + $this->assertEquals([new ServiceLocatorArgument($values)], $container->getDefinition('locator_dependent_inline_service')->getArguments()); } } diff --git a/src/Symfony/Component/DependencyInjection/Tests/Loader/XmlFileLoaderTest.php b/src/Symfony/Component/DependencyInjection/Tests/Loader/XmlFileLoaderTest.php index a7c6df66fec3d..7b398277bfda2 100644 --- a/src/Symfony/Component/DependencyInjection/Tests/Loader/XmlFileLoaderTest.php +++ b/src/Symfony/Component/DependencyInjection/Tests/Loader/XmlFileLoaderTest.php @@ -447,6 +447,10 @@ public function testServiceWithServiceLocatorArgument() $values = ['foo' => new Reference('foo_service'), 0 => new Reference('bar_service')]; $this->assertEquals([new ServiceLocatorArgument($values)], $container->getDefinition('locator_dependent_service_mixed')->getArguments()); + + $inlinedServiceArguments = $container->getDefinition('locator_dependent_inline_service')->getArguments(); + $this->assertEquals((new Definition(\stdClass::class))->setPublic(false), $container->getDefinition((string) $inlinedServiceArguments[0]->getValues()['foo'])); + $this->assertEquals((new Definition(\stdClass::class))->setPublic(false), $container->getDefinition((string) $inlinedServiceArguments[0]->getValues()['bar'])); } public function testParseServiceClosure() diff --git a/src/Symfony/Component/DependencyInjection/Tests/Loader/YamlFileLoaderTest.php b/src/Symfony/Component/DependencyInjection/Tests/Loader/YamlFileLoaderTest.php index 7027cdb232e3c..2b51ffcca524b 100644 --- a/src/Symfony/Component/DependencyInjection/Tests/Loader/YamlFileLoaderTest.php +++ b/src/Symfony/Component/DependencyInjection/Tests/Loader/YamlFileLoaderTest.php @@ -441,6 +441,10 @@ public function testServiceWithServiceLocatorArgument() $values = ['foo' => new Reference('foo_service'), 0 => new Reference('bar_service')]; $this->assertEquals([new ServiceLocatorArgument($values)], $container->getDefinition('locator_dependent_service_mixed')->getArguments()); + + $inlinedServiceArguments = $container->getDefinition('locator_dependent_inline_service')->getArguments(); + $this->assertEquals(new Definition(\stdClass::class), $container->getDefinition((string) $inlinedServiceArguments[0]->getValues()['foo'][0])); + $this->assertEquals(new Definition(\stdClass::class), $container->getDefinition((string) $inlinedServiceArguments[0]->getValues()['bar'][0])); } public function testParseServiceClosure() From 232317f64601eb0806ebf7ad2a517ecb123785a9 Mon Sep 17 00:00:00 2001 From: Antoine Lamirault Date: Fri, 11 Aug 2023 20:59:51 +0200 Subject: [PATCH 36/67] [SecurityBundle] Remove unused test files --- .../php/legacy_remember_me_options.php | 18 ----------- .../Fixtures/php/logout_delete_cookies.php | 21 ------------- .../xml/legacy_remember_me_options.xml | 21 ------------- .../Fixtures/xml/logout_delete_cookies.xml | 23 -------------- .../yml/legacy_remember_me_options.yml | 12 ------- .../Fixtures/yml/logout_delete_cookies.yml | 15 --------- .../legacy_config.yml | 30 ------------------ .../app/AutowiringTypes/legacy_config.yml | 15 --------- .../app/JsonLogin/legacy_config.yml | 27 ---------------- .../app/JsonLogin/legacy_custom_handlers.yml | 31 ------------------- .../app/SecurityHelper/legacy_config.yml | 22 ------------- 11 files changed, 235 deletions(-) delete mode 100644 src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/Fixtures/php/legacy_remember_me_options.php delete mode 100644 src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/Fixtures/php/logout_delete_cookies.php delete mode 100644 src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/Fixtures/xml/legacy_remember_me_options.xml delete mode 100644 src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/Fixtures/xml/logout_delete_cookies.xml delete mode 100644 src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/Fixtures/yml/legacy_remember_me_options.yml delete mode 100644 src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/Fixtures/yml/logout_delete_cookies.yml delete mode 100644 src/Symfony/Bundle/SecurityBundle/Tests/Functional/app/AbstractTokenCompareRoles/legacy_config.yml delete mode 100644 src/Symfony/Bundle/SecurityBundle/Tests/Functional/app/AutowiringTypes/legacy_config.yml delete mode 100644 src/Symfony/Bundle/SecurityBundle/Tests/Functional/app/JsonLogin/legacy_config.yml delete mode 100644 src/Symfony/Bundle/SecurityBundle/Tests/Functional/app/JsonLogin/legacy_custom_handlers.yml delete mode 100644 src/Symfony/Bundle/SecurityBundle/Tests/Functional/app/SecurityHelper/legacy_config.yml diff --git a/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/Fixtures/php/legacy_remember_me_options.php b/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/Fixtures/php/legacy_remember_me_options.php deleted file mode 100644 index cfbef609a18db..0000000000000 --- a/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/Fixtures/php/legacy_remember_me_options.php +++ /dev/null @@ -1,18 +0,0 @@ -loadFromExtension('security', [ - 'providers' => [ - 'default' => ['id' => 'foo'], - ], - - 'firewalls' => [ - 'main' => [ - 'form_login' => true, - 'remember_me' => [ - 'secret' => 'TheSecret', - 'catch_exceptions' => false, - 'token_provider' => 'token_provider_id', - ], - ], - ], -]); diff --git a/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/Fixtures/php/logout_delete_cookies.php b/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/Fixtures/php/logout_delete_cookies.php deleted file mode 100644 index 8ffe12e3eb929..0000000000000 --- a/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/Fixtures/php/logout_delete_cookies.php +++ /dev/null @@ -1,21 +0,0 @@ -loadFromExtension('security', [ - 'providers' => [ - 'default' => ['id' => 'foo'], - ], - - 'firewalls' => [ - 'main' => [ - 'provider' => 'default', - 'form_login' => true, - 'logout' => [ - 'delete_cookies' => [ - 'cookie1-name' => true, - 'cookie2_name' => true, - 'cookie3-long_name' => ['path' => '/'], - ], - ], - ], - ], -]); diff --git a/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/Fixtures/xml/legacy_remember_me_options.xml b/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/Fixtures/xml/legacy_remember_me_options.xml deleted file mode 100644 index 767397ada3515..0000000000000 --- a/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/Fixtures/xml/legacy_remember_me_options.xml +++ /dev/null @@ -1,21 +0,0 @@ - - - - - - - - - - - - - - - diff --git a/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/Fixtures/xml/logout_delete_cookies.xml b/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/Fixtures/xml/logout_delete_cookies.xml deleted file mode 100644 index e66043c359a15..0000000000000 --- a/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/Fixtures/xml/logout_delete_cookies.xml +++ /dev/null @@ -1,23 +0,0 @@ - - - - - - - - - - - - - - - - - diff --git a/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/Fixtures/yml/legacy_remember_me_options.yml b/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/Fixtures/yml/legacy_remember_me_options.yml deleted file mode 100644 index a521c8c6a803d..0000000000000 --- a/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/Fixtures/yml/legacy_remember_me_options.yml +++ /dev/null @@ -1,12 +0,0 @@ -security: - providers: - default: - id: foo - - firewalls: - main: - form_login: true - remember_me: - secret: TheSecret - catch_exceptions: false - token_provider: token_provider_id diff --git a/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/Fixtures/yml/logout_delete_cookies.yml b/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/Fixtures/yml/logout_delete_cookies.yml deleted file mode 100644 index 09bea8c13ab37..0000000000000 --- a/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/Fixtures/yml/logout_delete_cookies.yml +++ /dev/null @@ -1,15 +0,0 @@ -security: - providers: - default: - id: foo - - firewalls: - main: - provider: default - form_login: true - logout: - delete_cookies: - cookie1-name: ~ - cookie2_name: ~ - cookie3-long_name: - path: '/' diff --git a/src/Symfony/Bundle/SecurityBundle/Tests/Functional/app/AbstractTokenCompareRoles/legacy_config.yml b/src/Symfony/Bundle/SecurityBundle/Tests/Functional/app/AbstractTokenCompareRoles/legacy_config.yml deleted file mode 100644 index 54bfaf89cb6c7..0000000000000 --- a/src/Symfony/Bundle/SecurityBundle/Tests/Functional/app/AbstractTokenCompareRoles/legacy_config.yml +++ /dev/null @@ -1,30 +0,0 @@ -imports: - - { resource: ./../config/framework.yml } - -services: - _defaults: { public: true } - - security.user.provider.array: - class: Symfony\Bundle\SecurityBundle\Tests\Functional\Bundle\SecuredPageBundle\Security\Core\User\ArrayUserProvider - -security: - password_hashers: - \Symfony\Component\Security\Core\User\UserInterface: plaintext - - providers: - array: - id: security.user.provider.array - - firewalls: - default: - form_login: - check_path: login - remember_me: true - require_previous_session: false - logout: ~ - stateless: false - - access_control: - - { path: ^/admin$, roles: ROLE_ADMIN } - - { path: ^/login$, roles: IS_AUTHENTICATED_ANONYMOUSLY } - - { path: .*, roles: IS_AUTHENTICATED_FULLY } diff --git a/src/Symfony/Bundle/SecurityBundle/Tests/Functional/app/AutowiringTypes/legacy_config.yml b/src/Symfony/Bundle/SecurityBundle/Tests/Functional/app/AutowiringTypes/legacy_config.yml deleted file mode 100644 index 2045118e1b9f1..0000000000000 --- a/src/Symfony/Bundle/SecurityBundle/Tests/Functional/app/AutowiringTypes/legacy_config.yml +++ /dev/null @@ -1,15 +0,0 @@ -imports: - - { resource: ../config/framework.yml } - -services: - _defaults: { public: true } - test.autowiring_types.autowired_services: - class: Symfony\Bundle\SecurityBundle\Tests\Functional\Bundle\AutowiringBundle\AutowiredServices - autowire: true -security: - providers: - dummy: - memory: ~ - firewalls: - dummy: - security: false diff --git a/src/Symfony/Bundle/SecurityBundle/Tests/Functional/app/JsonLogin/legacy_config.yml b/src/Symfony/Bundle/SecurityBundle/Tests/Functional/app/JsonLogin/legacy_config.yml deleted file mode 100644 index 022263a978e6d..0000000000000 --- a/src/Symfony/Bundle/SecurityBundle/Tests/Functional/app/JsonLogin/legacy_config.yml +++ /dev/null @@ -1,27 +0,0 @@ -imports: - - { resource: ./../config/framework.yml } - -framework: - http_method_override: false - serializer: ~ - -security: - password_hashers: - Symfony\Component\Security\Core\User\InMemoryUser: plaintext - - providers: - in_memory: - memory: - users: - dunglas: { password: foo, roles: [ROLE_USER] } - - firewalls: - main: - pattern: ^/ - json_login: - check_path: /chk - username_path: user.login - password_path: user.password - - access_control: - - { path: ^/foo, roles: ROLE_USER } diff --git a/src/Symfony/Bundle/SecurityBundle/Tests/Functional/app/JsonLogin/legacy_custom_handlers.yml b/src/Symfony/Bundle/SecurityBundle/Tests/Functional/app/JsonLogin/legacy_custom_handlers.yml deleted file mode 100644 index f1f1a93ab0c0b..0000000000000 --- a/src/Symfony/Bundle/SecurityBundle/Tests/Functional/app/JsonLogin/legacy_custom_handlers.yml +++ /dev/null @@ -1,31 +0,0 @@ -imports: - - { resource: ./../config/framework.yml } - -security: - password_hashers: - Symfony\Component\Security\Core\User\InMemoryUser: plaintext - - providers: - in_memory: - memory: - users: - dunglas: { password: foo, roles: [ROLE_USER] } - - firewalls: - main: - pattern: ^/ - json_login: - check_path: /chk - username_path: user.login - password_path: user.password - success_handler: json_login.success_handler - failure_handler: json_login.failure_handler - - access_control: - - { path: ^/foo, roles: ROLE_USER } - -services: - json_login.success_handler: - class: Symfony\Bundle\SecurityBundle\Tests\Functional\Bundle\JsonLoginBundle\Security\Http\JsonAuthenticationSuccessHandler - json_login.failure_handler: - class: Symfony\Bundle\SecurityBundle\Tests\Functional\Bundle\JsonLoginBundle\Security\Http\JsonAuthenticationFailureHandler diff --git a/src/Symfony/Bundle/SecurityBundle/Tests/Functional/app/SecurityHelper/legacy_config.yml b/src/Symfony/Bundle/SecurityBundle/Tests/Functional/app/SecurityHelper/legacy_config.yml deleted file mode 100644 index 01aa24889faf0..0000000000000 --- a/src/Symfony/Bundle/SecurityBundle/Tests/Functional/app/SecurityHelper/legacy_config.yml +++ /dev/null @@ -1,22 +0,0 @@ -imports: - - { resource: ./../config/framework.yml } - -services: - # alias the service so we can access it in the tests - functional_test.security.helper: - alias: security.helper - public: true - - functional.test.security.token_storage: - alias: security.token_storage - public: true - -security: - providers: - in_memory: - memory: - users: [] - - firewalls: - default: - anonymous: ~ From d571a07662f8b5462ec1f895f6185752b5e3ea75 Mon Sep 17 00:00:00 2001 From: Zbigniew Malcherczyk <124783578+zbigniew-malcherczyk-tg@users.noreply.github.com> Date: Fri, 11 Aug 2023 16:45:12 +0200 Subject: [PATCH 37/67] [Messenger] BatchHandlerTrait - fix phpdoc typo --- src/Symfony/Component/Messenger/Handler/BatchHandlerTrait.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Symfony/Component/Messenger/Handler/BatchHandlerTrait.php b/src/Symfony/Component/Messenger/Handler/BatchHandlerTrait.php index be7124dd38893..539956ec8da6b 100644 --- a/src/Symfony/Component/Messenger/Handler/BatchHandlerTrait.php +++ b/src/Symfony/Component/Messenger/Handler/BatchHandlerTrait.php @@ -66,7 +66,7 @@ private function shouldFlush(): bool /** * Completes the jobs in the list. * - * @list $jobs A list of pairs of messages and their corresponding acknowledgers + * @param list $jobs A list of pairs of messages and their corresponding acknowledgers */ private function process(array $jobs): void { From 28451b2951c04b74245470ffcb733ab7337317d8 Mon Sep 17 00:00:00 2001 From: Fabien Potencier Date: Sat, 12 Aug 2023 18:38:40 +0200 Subject: [PATCH 38/67] [HttpFoundation] Add a slightly more verbose comment about a warning on UploadedFile --- src/Symfony/Component/HttpFoundation/File/UploadedFile.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Symfony/Component/HttpFoundation/File/UploadedFile.php b/src/Symfony/Component/HttpFoundation/File/UploadedFile.php index fcc6299138eb7..1161556c4fea7 100644 --- a/src/Symfony/Component/HttpFoundation/File/UploadedFile.php +++ b/src/Symfony/Component/HttpFoundation/File/UploadedFile.php @@ -74,7 +74,7 @@ public function __construct(string $path, string $originalName, string $mimeType * Returns the original file name. * * It is extracted from the request from which the file has been uploaded. - * Then it should not be considered as a safe value. + * This should not be considered as a safe value to use for a file name on your servers. * * @return string */ @@ -87,7 +87,7 @@ public function getClientOriginalName() * Returns the original file extension. * * It is extracted from the original file name that was uploaded. - * Then it should not be considered as a safe value. + * This should not be considered as a safe value to use for a file name on your servers. * * @return string */ From ddc699a41292ce3dfb91fa790e9ad85060c836a0 Mon Sep 17 00:00:00 2001 From: "hubert.lenoir" Date: Tue, 8 Aug 2023 10:16:09 +0200 Subject: [PATCH 39/67] [DependencyInjection] fix dump xml with array/object/enum default value --- .../Compiler/AutowirePass.php | 7 ++-- .../Tests/Dumper/XmlDumperTest.php | 32 +++++++++++++++++++ .../Tests/Dumper/YamlDumperTest.php | 32 +++++++++++++++++++ .../FooClassWithDefaultArrayAttribute.php | 12 +++++++ .../FooClassWithDefaultEnumAttribute.php | 12 +++++++ .../FooClassWithDefaultObjectAttribute.php | 12 +++++++ .../xml/services_with_default_array.xml | 15 +++++++++ .../xml/services_with_default_enumeration.xml | 15 +++++++++ .../xml/services_with_default_object.xml | 15 +++++++++ .../yaml/services_with_default_array.yml | 23 +++++++++++++ .../services_with_default_enumeration.yml | 23 +++++++++++++ .../yaml/services_with_default_object.yml | 23 +++++++++++++ 12 files changed, 219 insertions(+), 2 deletions(-) create mode 100644 src/Symfony/Component/DependencyInjection/Tests/Fixtures/FooClassWithDefaultArrayAttribute.php create mode 100644 src/Symfony/Component/DependencyInjection/Tests/Fixtures/FooClassWithDefaultEnumAttribute.php create mode 100644 src/Symfony/Component/DependencyInjection/Tests/Fixtures/FooClassWithDefaultObjectAttribute.php create mode 100644 src/Symfony/Component/DependencyInjection/Tests/Fixtures/xml/services_with_default_array.xml create mode 100644 src/Symfony/Component/DependencyInjection/Tests/Fixtures/xml/services_with_default_enumeration.xml create mode 100644 src/Symfony/Component/DependencyInjection/Tests/Fixtures/xml/services_with_default_object.xml create mode 100644 src/Symfony/Component/DependencyInjection/Tests/Fixtures/yaml/services_with_default_array.yml create mode 100644 src/Symfony/Component/DependencyInjection/Tests/Fixtures/yaml/services_with_default_enumeration.yml create mode 100644 src/Symfony/Component/DependencyInjection/Tests/Fixtures/yaml/services_with_default_object.yml diff --git a/src/Symfony/Component/DependencyInjection/Compiler/AutowirePass.php b/src/Symfony/Component/DependencyInjection/Compiler/AutowirePass.php index 845f09c116fe1..0e679d21826ed 100644 --- a/src/Symfony/Component/DependencyInjection/Compiler/AutowirePass.php +++ b/src/Symfony/Component/DependencyInjection/Compiler/AutowirePass.php @@ -212,13 +212,16 @@ private function autowireCalls(\ReflectionClass $reflectionClass, bool $isRoot, unset($arguments[$j]); $arguments[$namedArguments[$j]] = $value; } - if ($namedArguments || !$value instanceof $this->defaultArgument) { + if (!$value instanceof $this->defaultArgument) { continue; } if (\PHP_VERSION_ID >= 80100 && (\is_array($value->value) ? $value->value : \is_object($value->value))) { - unset($arguments[$j]); $namedArguments = $value->names; + } + + if ($namedArguments) { + unset($arguments[$j]); } else { $arguments[$j] = $value->value; } diff --git a/src/Symfony/Component/DependencyInjection/Tests/Dumper/XmlDumperTest.php b/src/Symfony/Component/DependencyInjection/Tests/Dumper/XmlDumperTest.php index 9e2547cc244e6..3011444f757e9 100644 --- a/src/Symfony/Component/DependencyInjection/Tests/Dumper/XmlDumperTest.php +++ b/src/Symfony/Component/DependencyInjection/Tests/Dumper/XmlDumperTest.php @@ -17,11 +17,15 @@ use Symfony\Component\DependencyInjection\Argument\ServiceClosureArgument; use Symfony\Component\DependencyInjection\Argument\ServiceLocatorArgument; use Symfony\Component\DependencyInjection\Argument\TaggedIteratorArgument; +use Symfony\Component\DependencyInjection\Compiler\AutowirePass; use Symfony\Component\DependencyInjection\ContainerBuilder; use Symfony\Component\DependencyInjection\ContainerInterface; use Symfony\Component\DependencyInjection\Dumper\XmlDumper; use Symfony\Component\DependencyInjection\Loader\XmlFileLoader; use Symfony\Component\DependencyInjection\Reference; +use Symfony\Component\DependencyInjection\Tests\Fixtures\FooClassWithDefaultArrayAttribute; +use Symfony\Component\DependencyInjection\Tests\Fixtures\FooClassWithDefaultEnumAttribute; +use Symfony\Component\DependencyInjection\Tests\Fixtures\FooClassWithDefaultObjectAttribute; use Symfony\Component\DependencyInjection\Tests\Fixtures\FooClassWithEnumAttribute; use Symfony\Component\DependencyInjection\Tests\Fixtures\FooUnitEnum; use Symfony\Component\DependencyInjection\Tests\Fixtures\FooWithAbstractArgument; @@ -287,6 +291,34 @@ public function testDumpHandlesEnumeration() $this->assertEquals(file_get_contents(self::$fixturesPath.'/xml/services_with_enumeration.xml'), $dumper->dump()); } + /** + * @requires PHP 8.1 + * + * @dataProvider provideDefaultClasses + */ + public function testDumpHandlesDefaultAttribute($class, $expectedFile) + { + $container = new ContainerBuilder(); + $container + ->register('foo', $class) + ->setPublic(true) + ->setAutowired(true) + ->setArguments([2 => true]); + + (new AutowirePass())->process($container); + + $dumper = new XmlDumper($container); + + $this->assertSame(file_get_contents(self::$fixturesPath.'/xml/'.$expectedFile), $dumper->dump()); + } + + public static function provideDefaultClasses() + { + yield [FooClassWithDefaultArrayAttribute::class, 'services_with_default_array.xml']; + yield [FooClassWithDefaultObjectAttribute::class, 'services_with_default_object.xml']; + yield [FooClassWithDefaultEnumAttribute::class, 'services_with_default_enumeration.xml']; + } + public function testDumpServiceWithAbstractArgument() { $container = new ContainerBuilder(); diff --git a/src/Symfony/Component/DependencyInjection/Tests/Dumper/YamlDumperTest.php b/src/Symfony/Component/DependencyInjection/Tests/Dumper/YamlDumperTest.php index 1bfd222ed1ac1..90376c15f1842 100644 --- a/src/Symfony/Component/DependencyInjection/Tests/Dumper/YamlDumperTest.php +++ b/src/Symfony/Component/DependencyInjection/Tests/Dumper/YamlDumperTest.php @@ -17,12 +17,16 @@ use Symfony\Component\DependencyInjection\Argument\ServiceClosureArgument; use Symfony\Component\DependencyInjection\Argument\ServiceLocatorArgument; use Symfony\Component\DependencyInjection\Argument\TaggedIteratorArgument; +use Symfony\Component\DependencyInjection\Compiler\AutowirePass; use Symfony\Component\DependencyInjection\ContainerBuilder; use Symfony\Component\DependencyInjection\ContainerInterface; use Symfony\Component\DependencyInjection\Definition; use Symfony\Component\DependencyInjection\Dumper\YamlDumper; use Symfony\Component\DependencyInjection\Loader\YamlFileLoader; use Symfony\Component\DependencyInjection\Reference; +use Symfony\Component\DependencyInjection\Tests\Fixtures\FooClassWithDefaultArrayAttribute; +use Symfony\Component\DependencyInjection\Tests\Fixtures\FooClassWithDefaultEnumAttribute; +use Symfony\Component\DependencyInjection\Tests\Fixtures\FooClassWithDefaultObjectAttribute; use Symfony\Component\DependencyInjection\Tests\Fixtures\FooClassWithEnumAttribute; use Symfony\Component\DependencyInjection\Tests\Fixtures\FooUnitEnum; use Symfony\Component\DependencyInjection\Tests\Fixtures\FooWithAbstractArgument; @@ -153,6 +157,34 @@ public function testDumpHandlesEnumeration() $this->assertEquals(file_get_contents(self::$fixturesPath.'/yaml/services_with_enumeration.yml'), $dumper->dump()); } + /** + * @requires PHP 8.1 + * + * @dataProvider provideDefaultClasses + */ + public function testDumpHandlesDefaultAttribute($class, $expectedFile) + { + $container = new ContainerBuilder(); + $container + ->register('foo', $class) + ->setPublic(true) + ->setAutowired(true) + ->setArguments([2 => true]); + + (new AutowirePass())->process($container); + + $dumper = new YamlDumper($container); + + $this->assertSame(file_get_contents(self::$fixturesPath.'/yaml/'.$expectedFile), $dumper->dump()); + } + + public static function provideDefaultClasses() + { + yield [FooClassWithDefaultArrayAttribute::class, 'services_with_default_array.yml']; + yield [FooClassWithDefaultObjectAttribute::class, 'services_with_default_object.yml']; + yield [FooClassWithDefaultEnumAttribute::class, 'services_with_default_enumeration.yml']; + } + public function testDumpServiceWithAbstractArgument() { $container = new ContainerBuilder(); diff --git a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/FooClassWithDefaultArrayAttribute.php b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/FooClassWithDefaultArrayAttribute.php new file mode 100644 index 0000000000000..49275212281f1 --- /dev/null +++ b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/FooClassWithDefaultArrayAttribute.php @@ -0,0 +1,12 @@ + + + + + + true + + + The "%alias_id%" autowiring alias is deprecated. Define it explicitly in your app if you want to keep using it. + + + The "%alias_id%" autowiring alias is deprecated. Define it explicitly in your app if you want to keep using it. + + + diff --git a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/xml/services_with_default_enumeration.xml b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/xml/services_with_default_enumeration.xml new file mode 100644 index 0000000000000..5fc112c8bf5d4 --- /dev/null +++ b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/xml/services_with_default_enumeration.xml @@ -0,0 +1,15 @@ + + + + + + true + + + The "%alias_id%" autowiring alias is deprecated. Define it explicitly in your app if you want to keep using it. + + + The "%alias_id%" autowiring alias is deprecated. Define it explicitly in your app if you want to keep using it. + + + diff --git a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/xml/services_with_default_object.xml b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/xml/services_with_default_object.xml new file mode 100644 index 0000000000000..09dad58c36425 --- /dev/null +++ b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/xml/services_with_default_object.xml @@ -0,0 +1,15 @@ + + + + + + true + + + The "%alias_id%" autowiring alias is deprecated. Define it explicitly in your app if you want to keep using it. + + + The "%alias_id%" autowiring alias is deprecated. Define it explicitly in your app if you want to keep using it. + + + diff --git a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/yaml/services_with_default_array.yml b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/yaml/services_with_default_array.yml new file mode 100644 index 0000000000000..3349a92673f05 --- /dev/null +++ b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/yaml/services_with_default_array.yml @@ -0,0 +1,23 @@ + +services: + service_container: + class: Symfony\Component\DependencyInjection\ContainerInterface + public: true + synthetic: true + foo: + class: Symfony\Component\DependencyInjection\Tests\Fixtures\FooClassWithDefaultArrayAttribute + public: true + autowire: true + arguments: { secondOptional: true } + Psr\Container\ContainerInterface: + alias: service_container + deprecated: + package: symfony/dependency-injection + version: 5.1 + message: The "%alias_id%" autowiring alias is deprecated. Define it explicitly in your app if you want to keep using it. + Symfony\Component\DependencyInjection\ContainerInterface: + alias: service_container + deprecated: + package: symfony/dependency-injection + version: 5.1 + message: The "%alias_id%" autowiring alias is deprecated. Define it explicitly in your app if you want to keep using it. diff --git a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/yaml/services_with_default_enumeration.yml b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/yaml/services_with_default_enumeration.yml new file mode 100644 index 0000000000000..66113708ad2c8 --- /dev/null +++ b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/yaml/services_with_default_enumeration.yml @@ -0,0 +1,23 @@ + +services: + service_container: + class: Symfony\Component\DependencyInjection\ContainerInterface + public: true + synthetic: true + foo: + class: Symfony\Component\DependencyInjection\Tests\Fixtures\FooClassWithDefaultEnumAttribute + public: true + autowire: true + arguments: { secondOptional: true } + Psr\Container\ContainerInterface: + alias: service_container + deprecated: + package: symfony/dependency-injection + version: 5.1 + message: The "%alias_id%" autowiring alias is deprecated. Define it explicitly in your app if you want to keep using it. + Symfony\Component\DependencyInjection\ContainerInterface: + alias: service_container + deprecated: + package: symfony/dependency-injection + version: 5.1 + message: The "%alias_id%" autowiring alias is deprecated. Define it explicitly in your app if you want to keep using it. diff --git a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/yaml/services_with_default_object.yml b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/yaml/services_with_default_object.yml new file mode 100644 index 0000000000000..547f6919ff26c --- /dev/null +++ b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/yaml/services_with_default_object.yml @@ -0,0 +1,23 @@ + +services: + service_container: + class: Symfony\Component\DependencyInjection\ContainerInterface + public: true + synthetic: true + foo: + class: Symfony\Component\DependencyInjection\Tests\Fixtures\FooClassWithDefaultObjectAttribute + public: true + autowire: true + arguments: { secondOptional: true } + Psr\Container\ContainerInterface: + alias: service_container + deprecated: + package: symfony/dependency-injection + version: 5.1 + message: The "%alias_id%" autowiring alias is deprecated. Define it explicitly in your app if you want to keep using it. + Symfony\Component\DependencyInjection\ContainerInterface: + alias: service_container + deprecated: + package: symfony/dependency-injection + version: 5.1 + message: The "%alias_id%" autowiring alias is deprecated. Define it explicitly in your app if you want to keep using it. From a99b70741543e1db51044a4726b4cc8daaf5deb0 Mon Sep 17 00:00:00 2001 From: Jean-Baptiste Nahan <814683+macintoshplus@users.noreply.github.com> Date: Sat, 31 Dec 2022 21:26:59 +0100 Subject: [PATCH 40/67] Dump Valid constaints on debug command #46544 --- .../Validator/Command/DebugCommand.php | 29 +++ .../Tests/Command/DebugCommandTest.php | 177 +++++++++++------- .../Validator/Tests/Dummy/DummyClassOne.php | 7 + .../Validator/Tests/Dummy/DummyClassTwo.php | 7 + 4 files changed, 154 insertions(+), 66 deletions(-) diff --git a/src/Symfony/Component/Validator/Command/DebugCommand.php b/src/Symfony/Component/Validator/Command/DebugCommand.php index be2c3fe96337e..bd892c5ecb323 100644 --- a/src/Symfony/Component/Validator/Command/DebugCommand.php +++ b/src/Symfony/Component/Validator/Command/DebugCommand.php @@ -22,8 +22,12 @@ use Symfony\Component\Finder\Exception\DirectoryNotFoundException; use Symfony\Component\Finder\Finder; use Symfony\Component\Validator\Constraint; +use Symfony\Component\Validator\Mapping\AutoMappingStrategy; +use Symfony\Component\Validator\Mapping\CascadingStrategy; use Symfony\Component\Validator\Mapping\ClassMetadataInterface; use Symfony\Component\Validator\Mapping\Factory\MetadataFactoryInterface; +use Symfony\Component\Validator\Mapping\GenericMetadata; +use Symfony\Component\Validator\Mapping\TraversalStrategy; /** * A console command to debug Validators information. @@ -161,6 +165,31 @@ private function getPropertyData(ClassMetadataInterface $classMetadata, string $ $propertyMetadata = $classMetadata->getPropertyMetadata($constrainedProperty); foreach ($propertyMetadata as $metadata) { + $autoMapingStrategy = 'Not supported'; + if ($metadata instanceof GenericMetadata) { + switch ($metadata->getAutoMappingStrategy()) { + case AutoMappingStrategy::ENABLED: $autoMapingStrategy = 'Enabled'; break; + case AutoMappingStrategy::DISABLED: $autoMapingStrategy = 'Disabled'; break; + case AutoMappingStrategy::NONE: $autoMapingStrategy = 'None'; break; + } + } + $traversalStrategy = 'None'; + if (TraversalStrategy::TRAVERSE === $metadata->getTraversalStrategy()) { + $traversalStrategy = 'Traverse'; + } + if (TraversalStrategy::IMPLICIT === $metadata->getTraversalStrategy()) { + $traversalStrategy = 'Implicit'; + } + + $data[] = [ + 'class' => 'property options', + 'groups' => [], + 'options' => [ + 'cascadeStrategy' => CascadingStrategy::CASCADE === $metadata->getCascadingStrategy() ? 'Cascade' : 'None', + 'autoMappingStrategy' => $autoMapingStrategy, + 'traversalStrategy' => $traversalStrategy, + ], + ]; foreach ($metadata->getConstraints() as $constraint) { $data[] = [ 'class' => \get_class($constraint), diff --git a/src/Symfony/Component/Validator/Tests/Command/DebugCommandTest.php b/src/Symfony/Component/Validator/Tests/Command/DebugCommandTest.php index 87cfc68b89995..54dcb07cb08b0 100644 --- a/src/Symfony/Component/Validator/Tests/Command/DebugCommandTest.php +++ b/src/Symfony/Component/Validator/Tests/Command/DebugCommandTest.php @@ -37,28 +37,43 @@ public function testOutputWithClassArgument() Symfony\Component\Validator\Tests\Dummy\DummyClassOne ----------------------------------------------------- -+----------+----------------------------------------------------+------------------------+------------------------------------------------------------+ -| Property | Name | Groups | Options | -+----------+----------------------------------------------------+------------------------+------------------------------------------------------------+ -| - | Symfony\Component\Validator\Constraints\Expression | Default, DummyClassOne | [ | -| | | | "expression" => "1 + 1 = 2", | -| | | | "message" => "This value is not valid.", | -| | | | "payload" => null, | -| | | | "values" => [] | -| | | | ] | -| code | Symfony\Component\Validator\Constraints\NotBlank | Default, DummyClassOne | [ | -| | | | "allowNull" => false, | -| | | | "message" => "This value should not be blank.", | -| | | | "normalizer" => null, | -| | | | "payload" => null | -| | | | ] | -| email | Symfony\Component\Validator\Constraints\Email | Default, DummyClassOne | [ | -| | | | "message" => "This value is not a valid email address.", | -| | | | "mode" => null, | -| | | | "normalizer" => null, | -| | | | "payload" => null | -| | | | ] | -+----------+----------------------------------------------------+------------------------+------------------------------------------------------------+ ++---------------+----------------------------------------------------+------------------------+------------------------------------------------------------+ +| Property | Name | Groups | Options | ++---------------+----------------------------------------------------+------------------------+------------------------------------------------------------+ +| - | Symfony\Component\Validator\Constraints\Expression | Default, DummyClassOne | [ | +| | | | "expression" => "1 + 1 = 2", | +| | | | "message" => "This value is not valid.", | +| | | | "payload" => null, | +| | | | "values" => [] | +| | | | ] | +| code | property options | | [ | +| | | | "cascadeStrategy" => "None", | +| | | | "autoMappingStrategy" => "None", | +| | | | "traversalStrategy" => "None" | +| | | | ] | +| code | Symfony\Component\Validator\Constraints\NotBlank | Default, DummyClassOne | [ | +| | | | "allowNull" => false, | +| | | | "message" => "This value should not be blank.", | +| | | | "normalizer" => null, | +| | | | "payload" => null | +| | | | ] | +| email | property options | | [ | +| | | | "cascadeStrategy" => "None", | +| | | | "autoMappingStrategy" => "None", | +| | | | "traversalStrategy" => "None" | +| | | | ] | +| email | Symfony\Component\Validator\Constraints\Email | Default, DummyClassOne | [ | +| | | | "message" => "This value is not a valid email address.", | +| | | | "mode" => null, | +| | | | "normalizer" => null, | +| | | | "payload" => null | +| | | | ] | +| dummyClassTwo | property options | | [ | +| | | | "cascadeStrategy" => "Cascade", | +| | | | "autoMappingStrategy" => "None", | +| | | | "traversalStrategy" => "Implicit" | +| | | | ] | ++---------------+----------------------------------------------------+------------------------+------------------------------------------------------------+ TXT , $tester->getDisplay(true) @@ -77,54 +92,84 @@ public function testOutputWithPathArgument() Symfony\Component\Validator\Tests\Dummy\DummyClassOne ----------------------------------------------------- -+----------+----------------------------------------------------+------------------------+------------------------------------------------------------+ -| Property | Name | Groups | Options | -+----------+----------------------------------------------------+------------------------+------------------------------------------------------------+ -| - | Symfony\Component\Validator\Constraints\Expression | Default, DummyClassOne | [ | -| | | | "expression" => "1 + 1 = 2", | -| | | | "message" => "This value is not valid.", | -| | | | "payload" => null, | -| | | | "values" => [] | -| | | | ] | -| code | Symfony\Component\Validator\Constraints\NotBlank | Default, DummyClassOne | [ | -| | | | "allowNull" => false, | -| | | | "message" => "This value should not be blank.", | -| | | | "normalizer" => null, | -| | | | "payload" => null | -| | | | ] | -| email | Symfony\Component\Validator\Constraints\Email | Default, DummyClassOne | [ | -| | | | "message" => "This value is not a valid email address.", | -| | | | "mode" => null, | -| | | | "normalizer" => null, | -| | | | "payload" => null | -| | | | ] | -+----------+----------------------------------------------------+------------------------+------------------------------------------------------------+ ++---------------+----------------------------------------------------+------------------------+------------------------------------------------------------+ +| Property | Name | Groups | Options | ++---------------+----------------------------------------------------+------------------------+------------------------------------------------------------+ +| - | Symfony\Component\Validator\Constraints\Expression | Default, DummyClassOne | [ | +| | | | "expression" => "1 + 1 = 2", | +| | | | "message" => "This value is not valid.", | +| | | | "payload" => null, | +| | | | "values" => [] | +| | | | ] | +| code | property options | | [ | +| | | | "cascadeStrategy" => "None", | +| | | | "autoMappingStrategy" => "None", | +| | | | "traversalStrategy" => "None" | +| | | | ] | +| code | Symfony\Component\Validator\Constraints\NotBlank | Default, DummyClassOne | [ | +| | | | "allowNull" => false, | +| | | | "message" => "This value should not be blank.", | +| | | | "normalizer" => null, | +| | | | "payload" => null | +| | | | ] | +| email | property options | | [ | +| | | | "cascadeStrategy" => "None", | +| | | | "autoMappingStrategy" => "None", | +| | | | "traversalStrategy" => "None" | +| | | | ] | +| email | Symfony\Component\Validator\Constraints\Email | Default, DummyClassOne | [ | +| | | | "message" => "This value is not a valid email address.", | +| | | | "mode" => null, | +| | | | "normalizer" => null, | +| | | | "payload" => null | +| | | | ] | +| dummyClassTwo | property options | | [ | +| | | | "cascadeStrategy" => "Cascade", | +| | | | "autoMappingStrategy" => "None", | +| | | | "traversalStrategy" => "Implicit" | +| | | | ] | ++---------------+----------------------------------------------------+------------------------+------------------------------------------------------------+ Symfony\Component\Validator\Tests\Dummy\DummyClassTwo ----------------------------------------------------- -+----------+----------------------------------------------------+------------------------+------------------------------------------------------------+ -| Property | Name | Groups | Options | -+----------+----------------------------------------------------+------------------------+------------------------------------------------------------+ -| - | Symfony\Component\Validator\Constraints\Expression | Default, DummyClassTwo | [ | -| | | | "expression" => "1 + 1 = 2", | -| | | | "message" => "This value is not valid.", | -| | | | "payload" => null, | -| | | | "values" => [] | -| | | | ] | -| code | Symfony\Component\Validator\Constraints\NotBlank | Default, DummyClassTwo | [ | -| | | | "allowNull" => false, | -| | | | "message" => "This value should not be blank.", | -| | | | "normalizer" => null, | -| | | | "payload" => null | -| | | | ] | -| email | Symfony\Component\Validator\Constraints\Email | Default, DummyClassTwo | [ | -| | | | "message" => "This value is not a valid email address.", | -| | | | "mode" => null, | -| | | | "normalizer" => null, | -| | | | "payload" => null | -| | | | ] | -+----------+----------------------------------------------------+------------------------+------------------------------------------------------------+ ++---------------+----------------------------------------------------+------------------------+------------------------------------------------------------+ +| Property | Name | Groups | Options | ++---------------+----------------------------------------------------+------------------------+------------------------------------------------------------+ +| - | Symfony\Component\Validator\Constraints\Expression | Default, DummyClassTwo | [ | +| | | | "expression" => "1 + 1 = 2", | +| | | | "message" => "This value is not valid.", | +| | | | "payload" => null, | +| | | | "values" => [] | +| | | | ] | +| code | property options | | [ | +| | | | "cascadeStrategy" => "None", | +| | | | "autoMappingStrategy" => "None", | +| | | | "traversalStrategy" => "None" | +| | | | ] | +| code | Symfony\Component\Validator\Constraints\NotBlank | Default, DummyClassTwo | [ | +| | | | "allowNull" => false, | +| | | | "message" => "This value should not be blank.", | +| | | | "normalizer" => null, | +| | | | "payload" => null | +| | | | ] | +| email | property options | | [ | +| | | | "cascadeStrategy" => "None", | +| | | | "autoMappingStrategy" => "None", | +| | | | "traversalStrategy" => "None" | +| | | | ] | +| email | Symfony\Component\Validator\Constraints\Email | Default, DummyClassTwo | [ | +| | | | "message" => "This value is not a valid email address.", | +| | | | "mode" => null, | +| | | | "normalizer" => null, | +| | | | "payload" => null | +| | | | ] | +| dummyClassOne | property options | | [ | +| | | | "cascadeStrategy" => "None", | +| | | | "autoMappingStrategy" => "Disabled", | +| | | | "traversalStrategy" => "None" | +| | | | ] | ++---------------+----------------------------------------------------+------------------------+------------------------------------------------------------+ TXT , $tester->getDisplay(true) diff --git a/src/Symfony/Component/Validator/Tests/Dummy/DummyClassOne.php b/src/Symfony/Component/Validator/Tests/Dummy/DummyClassOne.php index 92def37e0e9fe..169034fefceb0 100644 --- a/src/Symfony/Component/Validator/Tests/Dummy/DummyClassOne.php +++ b/src/Symfony/Component/Validator/Tests/Dummy/DummyClassOne.php @@ -31,4 +31,11 @@ class DummyClassOne * @Assert\Email */ public $email; + + /** + * @var DummyClassTwo|null + * + * @Assert\Valid() + */ + public $dummyClassTwo; } diff --git a/src/Symfony/Component/Validator/Tests/Dummy/DummyClassTwo.php b/src/Symfony/Component/Validator/Tests/Dummy/DummyClassTwo.php index cd136a9dd301e..01bc5fed873ec 100644 --- a/src/Symfony/Component/Validator/Tests/Dummy/DummyClassTwo.php +++ b/src/Symfony/Component/Validator/Tests/Dummy/DummyClassTwo.php @@ -31,4 +31,11 @@ class DummyClassTwo * @Assert\Email */ public $email; + + /** + * @var DummyClassOne|null + * + * @Assert\DisableAutoMapping() + */ + public $dummyClassOne; } From 63b9635d308f7bc82819d78a2e2645a5be4a898c Mon Sep 17 00:00:00 2001 From: Ryan Weaver Date: Thu, 10 Aug 2023 10:46:07 -0400 Subject: [PATCH 41/67] [AssetMapper] Fixing bug where a circular exception could be thrown while making error message --- .../Compiler/JavaScriptImportPathCompiler.php | 9 +++++-- .../Exception/CircularAssetsException.php | 19 ++++++++++++++ .../Factory/MappedAssetFactory.php | 3 ++- .../JavaScriptImportPathCompilerTest.php | 26 +++++++++++++++++++ 4 files changed, 54 insertions(+), 3 deletions(-) create mode 100644 src/Symfony/Component/AssetMapper/Exception/CircularAssetsException.php diff --git a/src/Symfony/Component/AssetMapper/Compiler/JavaScriptImportPathCompiler.php b/src/Symfony/Component/AssetMapper/Compiler/JavaScriptImportPathCompiler.php index 8ca018f0f13c4..5d011f9edc39a 100644 --- a/src/Symfony/Component/AssetMapper/Compiler/JavaScriptImportPathCompiler.php +++ b/src/Symfony/Component/AssetMapper/Compiler/JavaScriptImportPathCompiler.php @@ -15,6 +15,7 @@ use Psr\Log\NullLogger; use Symfony\Component\AssetMapper\AssetDependency; use Symfony\Component\AssetMapper\AssetMapperInterface; +use Symfony\Component\AssetMapper\Exception\CircularAssetsException; use Symfony\Component\AssetMapper\Exception\RuntimeException; use Symfony\Component\AssetMapper\MappedAsset; @@ -57,8 +58,12 @@ public function compile(string $content, MappedAsset $asset, AssetMapperInterfac if (!$dependentAsset) { $message = sprintf('Unable to find asset "%s" imported from "%s".', $matches[1], $asset->sourcePath); - if (null !== $assetMapper->getAsset(sprintf('%s.js', $resolvedPath))) { - $message .= sprintf(' Try adding ".js" to the end of the import - i.e. "%s.js".', $matches[1]); + try { + if (null !== $assetMapper->getAsset(sprintf('%s.js', $resolvedPath))) { + $message .= sprintf(' Try adding ".js" to the end of the import - i.e. "%s.js".', $matches[1]); + } + } catch (CircularAssetsException $e) { + // avoid circular error if there is self-referencing import comments } $this->handleMissingImport($message); diff --git a/src/Symfony/Component/AssetMapper/Exception/CircularAssetsException.php b/src/Symfony/Component/AssetMapper/Exception/CircularAssetsException.php new file mode 100644 index 0000000000000..da412e63123ee --- /dev/null +++ b/src/Symfony/Component/AssetMapper/Exception/CircularAssetsException.php @@ -0,0 +1,19 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\AssetMapper\Exception; + +/** + * Thrown when a circular reference is detected while creating an asset. + */ +class CircularAssetsException extends RuntimeException +{ +} diff --git a/src/Symfony/Component/AssetMapper/Factory/MappedAssetFactory.php b/src/Symfony/Component/AssetMapper/Factory/MappedAssetFactory.php index b6fdb3debaa2d..4c19ab7677d51 100644 --- a/src/Symfony/Component/AssetMapper/Factory/MappedAssetFactory.php +++ b/src/Symfony/Component/AssetMapper/Factory/MappedAssetFactory.php @@ -12,6 +12,7 @@ namespace Symfony\Component\AssetMapper\Factory; use Symfony\Component\AssetMapper\AssetMapperCompiler; +use Symfony\Component\AssetMapper\Exception\CircularAssetsException; use Symfony\Component\AssetMapper\Exception\RuntimeException; use Symfony\Component\AssetMapper\MappedAsset; use Symfony\Component\AssetMapper\Path\PublicAssetsPathResolverInterface; @@ -36,7 +37,7 @@ public function __construct( public function createMappedAsset(string $logicalPath, string $sourcePath): ?MappedAsset { if (\in_array($logicalPath, $this->assetsBeingCreated, true)) { - throw new RuntimeException(sprintf('Circular reference detected while creating asset for "%s": "%s".', $logicalPath, implode(' -> ', $this->assetsBeingCreated).' -> '.$logicalPath)); + throw new CircularAssetsException(sprintf('Circular reference detected while creating asset for "%s": "%s".', $logicalPath, implode(' -> ', $this->assetsBeingCreated).' -> '.$logicalPath)); } if (!isset($this->assetsCache[$logicalPath])) { diff --git a/src/Symfony/Component/AssetMapper/Tests/Compiler/JavaScriptImportPathCompilerTest.php b/src/Symfony/Component/AssetMapper/Tests/Compiler/JavaScriptImportPathCompilerTest.php index 4c04a70ba78b4..cf290e5ef0c90 100644 --- a/src/Symfony/Component/AssetMapper/Tests/Compiler/JavaScriptImportPathCompilerTest.php +++ b/src/Symfony/Component/AssetMapper/Tests/Compiler/JavaScriptImportPathCompilerTest.php @@ -16,6 +16,7 @@ use Symfony\Component\AssetMapper\AssetMapperInterface; use Symfony\Component\AssetMapper\Compiler\AssetCompilerInterface; use Symfony\Component\AssetMapper\Compiler\JavaScriptImportPathCompiler; +use Symfony\Component\AssetMapper\Exception\CircularAssetsException; use Symfony\Component\AssetMapper\Exception\RuntimeException; use Symfony\Component\AssetMapper\MappedAsset; @@ -277,6 +278,31 @@ public static function provideMissingImportModeTests(): iterable ]; } + public function testErrorMessageAvoidsCircularException() + { + $assetMapper = $this->createMock(AssetMapperInterface::class); + $assetMapper->expects($this->any()) + ->method('getAsset') + ->willReturnCallback(function ($logicalPath) { + if ('htmx' === $logicalPath) { + return null; + } + + if ('htmx.js' === $logicalPath) { + throw new CircularAssetsException(); + } + }); + + $asset = new MappedAsset('htmx.js', '/path/to/app.js'); + $compiler = new JavaScriptImportPathCompiler(); + $content = '//** @type {import("./htmx").HtmxApi} */'; + $compiled = $compiler->compile($content, $asset, $assetMapper); + // To form a good exception message, the compiler will check for the + // htmx.js asset, which will throw a CircularAssetsException. This + // should not be caught. + $this->assertSame($content, $compiled); + } + private function createAssetMapper(): AssetMapperInterface { $assetMapper = $this->createMock(AssetMapperInterface::class); From 9c90ac8d5d4aa3a921bc9327b6c6821ccadfad28 Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Mon, 14 Aug 2023 18:40:48 +0200 Subject: [PATCH 42/67] [GHA] Disable composer cache-vcs-dir --- .github/composer-config.json | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/composer-config.json b/.github/composer-config.json index 2bdec1a826251..8fa24e783b4e7 100644 --- a/.github/composer-config.json +++ b/.github/composer-config.json @@ -1,5 +1,6 @@ { "config": { + "cache-vcs-dir": "/dev/null", "platform-check": false, "preferred-install": { "symfony/form": "source", From 1f20f726406cc7d8562155277cd17f5c6afa7108 Mon Sep 17 00:00:00 2001 From: Joel Wurtz Date: Mon, 14 Aug 2023 10:15:15 +0200 Subject: [PATCH 43/67] fix(console): avoid multiple new line when message already ends with a new line --- .../Console/Output/ConsoleSectionOutput.php | 9 +++++++-- .../Tests/Output/ConsoleSectionOutputTest.php | 14 +++++++++++++- .../Console/Tests/Style/SymfonyStyleTest.php | 10 +++++----- 3 files changed, 25 insertions(+), 8 deletions(-) diff --git a/src/Symfony/Component/Console/Output/ConsoleSectionOutput.php b/src/Symfony/Component/Console/Output/ConsoleSectionOutput.php index 3d499bbcc9e37..21c4a44a8eb25 100644 --- a/src/Symfony/Component/Console/Output/ConsoleSectionOutput.php +++ b/src/Symfony/Component/Console/Output/ConsoleSectionOutput.php @@ -119,8 +119,7 @@ public function addContent(string $input, bool $newline = true): int // re-add the line break (that has been removed in the above `explode()` for // - every line that is not the last line // - if $newline is required, also add it to the last line - // - if it's not new line, but input ending with `\PHP_EOL` - if ($i < $count || $newline || str_ends_with($input, \PHP_EOL)) { + if ($i < $count || $newline) { $lineContent .= \PHP_EOL; } @@ -168,6 +167,12 @@ public function addNewLineOfInputSubmit(): void */ protected function doWrite(string $message, bool $newline) { + // Simulate newline behavior for consistent output formatting, avoiding extra logic + if (!$newline && str_ends_with($message, \PHP_EOL)) { + $message = substr($message, 0, -\strlen(\PHP_EOL)); + $newline = true; + } + if (!$this->isDecorated()) { parent::doWrite($message, $newline); diff --git a/src/Symfony/Component/Console/Tests/Output/ConsoleSectionOutputTest.php b/src/Symfony/Component/Console/Tests/Output/ConsoleSectionOutputTest.php index 0a775fd68e4f9..b653b75c1eed2 100644 --- a/src/Symfony/Component/Console/Tests/Output/ConsoleSectionOutputTest.php +++ b/src/Symfony/Component/Console/Tests/Output/ConsoleSectionOutputTest.php @@ -158,7 +158,7 @@ public function testMaxHeightMultipleSections() $expected .= 'Two'.\PHP_EOL.'Three'.\PHP_EOL.'Four'.\PHP_EOL; // cause overflow of first section (redraw whole section, without first line) - $firstSection->writeln("Four\nFive\nSix"); + $firstSection->writeln('Four'.\PHP_EOL.'Five'.\PHP_EOL.'Six'); $expected .= "\x1b[6A\x1b[0J"; $expected .= 'Four'.\PHP_EOL.'Five'.\PHP_EOL.'Six'.\PHP_EOL; $expected .= 'Two'.\PHP_EOL.'Three'.\PHP_EOL.'Four'.\PHP_EOL; @@ -290,4 +290,16 @@ public function testClearSectionContainingQuestion() rewind($output->getStream()); $this->assertSame('What\'s your favorite super hero?'.\PHP_EOL."\x1b[2A\x1b[0J", stream_get_contents($output->getStream())); } + + public function testWriteWithoutNewLine() + { + $sections = []; + $output = new ConsoleSectionOutput($this->stream, $sections, OutputInterface::VERBOSITY_NORMAL, true, new OutputFormatter()); + + $output->write('Foo'.\PHP_EOL); + $output->write('Bar'); + + rewind($output->getStream()); + $this->assertEquals(escapeshellcmd('Foo'.\PHP_EOL.'Bar'.\PHP_EOL), escapeshellcmd(stream_get_contents($output->getStream()))); + } } diff --git a/src/Symfony/Component/Console/Tests/Style/SymfonyStyleTest.php b/src/Symfony/Component/Console/Tests/Style/SymfonyStyleTest.php index f053b60f84335..a56dc38706a05 100644 --- a/src/Symfony/Component/Console/Tests/Style/SymfonyStyleTest.php +++ b/src/Symfony/Component/Console/Tests/Style/SymfonyStyleTest.php @@ -212,15 +212,15 @@ public function testAskAndClearExpectFullSectionCleared() rewind($output->getStream()); $this->assertEquals($answer, $givenAnswer); - $this->assertEquals( + $this->assertEquals(escapeshellcmd( 'start'.\PHP_EOL. // write start 'foo'.\PHP_EOL. // write foo "\x1b[1A\x1b[0Jfoo and bar".\PHP_EOL. // complete line - \PHP_EOL.\PHP_EOL." \033[32mDummy question?\033[39m:".\PHP_EOL.' > '.\PHP_EOL.\PHP_EOL.\PHP_EOL. // question - 'foo2'.\PHP_EOL.\PHP_EOL. // write foo2 + \PHP_EOL." \033[32mDummy question?\033[39m:".\PHP_EOL.' > '.\PHP_EOL.\PHP_EOL. // question + 'foo2'.\PHP_EOL. // write foo2 'bar2'.\PHP_EOL. // write bar - "\033[12A\033[0J", // clear 12 lines (11 output lines and one from the answer input return) - stream_get_contents($output->getStream()) + "\033[9A\033[0J"), // clear 9 lines (8 output lines and one from the answer input return) + escapeshellcmd(stream_get_contents($output->getStream())) ); } } From 12beb97513ce1ed2d5060b97bccfe5e008c20bfc Mon Sep 17 00:00:00 2001 From: "Alexander M. Turek" Date: Wed, 16 Aug 2023 09:35:26 +0200 Subject: [PATCH 44/67] Psalm: Ignore UnusedClass errors --- psalm.xml | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/psalm.xml b/psalm.xml index 4d9f6743bd3b8..0f04bcf070170 100644 --- a/psalm.xml +++ b/psalm.xml @@ -36,6 +36,15 @@ + + + + + +