From c12039b1c3b3ee267b6fa01118ee3bfdc60421f9 Mon Sep 17 00:00:00 2001 From: Vladimir Vasilev Date: Tue, 17 May 2022 00:33:45 +0300 Subject: [PATCH 01/44] Fix for missing sender name in case with usage of the EnvelopeListener --- src/Symfony/Component/Mailer/EventListener/EnvelopeListener.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Symfony/Component/Mailer/EventListener/EnvelopeListener.php b/src/Symfony/Component/Mailer/EventListener/EnvelopeListener.php index b439b2f0bf41d..b2980bc5cf6bc 100644 --- a/src/Symfony/Component/Mailer/EventListener/EnvelopeListener.php +++ b/src/Symfony/Component/Mailer/EventListener/EnvelopeListener.php @@ -48,7 +48,7 @@ public function onMessage(MessageEvent $event): void $message = $event->getMessage(); if ($message instanceof Message) { if (!$message->getHeaders()->has('Sender') && !$message->getHeaders()->has('From')) { - $message->getHeaders()->addMailboxHeader('Sender', $this->sender->getAddress()); + $message->getHeaders()->addMailboxHeader('Sender', $this->sender); } } } From 3bebc645bc654740cf5ece0829af10a302a03da8 Mon Sep 17 00:00:00 2001 From: Paul Oms Date: Mon, 6 Jun 2022 16:49:04 +0100 Subject: [PATCH 02/44] [Mailer] Fix Error Handling for OhMySMTP Bridge --- .../Transport/OhMySmtpApiTransportTest.php | 28 +++++++++++++++++-- .../Transport/OhMySmtpApiTransport.php | 2 +- 2 files changed, 27 insertions(+), 3 deletions(-) diff --git a/src/Symfony/Component/Mailer/Bridge/OhMySmtp/Tests/Transport/OhMySmtpApiTransportTest.php b/src/Symfony/Component/Mailer/Bridge/OhMySmtp/Tests/Transport/OhMySmtpApiTransportTest.php index 7f64a8c997fdb..6fc5c5ba9d215 100644 --- a/src/Symfony/Component/Mailer/Bridge/OhMySmtp/Tests/Transport/OhMySmtpApiTransportTest.php +++ b/src/Symfony/Component/Mailer/Bridge/OhMySmtp/Tests/Transport/OhMySmtpApiTransportTest.php @@ -101,7 +101,7 @@ public function testSend() public function testSendThrowsForErrorResponse() { $client = new MockHttpClient(static function (string $method, string $url, array $options): ResponseInterface { - return new MockResponse(json_encode(['Message' => 'i\'m a teapot', 'ErrorCode' => 418]), [ + return new MockResponse(json_encode(['error' => 'i\'m a teapot']), [ 'http_code' => 418, 'response_headers' => [ 'content-type' => 'application/json', @@ -118,7 +118,31 @@ public function testSendThrowsForErrorResponse() ->text('Hello There!'); $this->expectException(HttpTransportException::class); - $this->expectExceptionMessage('Unable to send an email: i\'m a teapot (code 418).'); + $this->expectExceptionMessage('Unable to send an email: {"error":"i\'m a teapot"}'); + $transport->send($mail); + } + + public function testSendThrowsForMultipleErrorResponses() + { + $client = new MockHttpClient(static function (string $method, string $url, array $options): ResponseInterface { + return new MockResponse(json_encode(['errors' => ["to" => "undefined field" ]]), [ + 'http_code' => 418, + 'response_headers' => [ + 'content-type' => 'application/json', + ], + ]); + }); + $transport = new OhMySmtpApiTransport('KEY', $client); + $transport->setPort(8984); + + $mail = new Email(); + $mail->subject('Hello!') + ->to(new Address('saif.gmati@symfony.com', 'Saif Eddin')) + ->from(new Address('fabpot@symfony.com', 'Fabien')) + ->text('Hello There!'); + + $this->expectException(HttpTransportException::class); + $this->expectExceptionMessage('Unable to send an email: {"errors":{"to":"undefined field"}}'); $transport->send($mail); } diff --git a/src/Symfony/Component/Mailer/Bridge/OhMySmtp/Transport/OhMySmtpApiTransport.php b/src/Symfony/Component/Mailer/Bridge/OhMySmtp/Transport/OhMySmtpApiTransport.php index a70fc3448e1c2..e4e6bddfc103d 100644 --- a/src/Symfony/Component/Mailer/Bridge/OhMySmtp/Transport/OhMySmtpApiTransport.php +++ b/src/Symfony/Component/Mailer/Bridge/OhMySmtp/Transport/OhMySmtpApiTransport.php @@ -67,7 +67,7 @@ protected function doSendApi(SentMessage $sentMessage, Email $email, Envelope $e } if (200 !== $statusCode) { - throw new HttpTransportException('Unable to send an email: '.$result['Message'].sprintf(' (code %d).', $result['ErrorCode']), $response); + throw new HttpTransportException('Unable to send an email: '.$response->getContent(false), $response); } $sentMessage->setMessageId($result['id']); From 5bb48270a9e0876ead2b76876f164e5115f6a31c Mon Sep 17 00:00:00 2001 From: Fabien Potencier Date: Thu, 9 Jun 2022 19:37:04 +0200 Subject: [PATCH 03/44] Bump Symfony version to 6.1.2 --- 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 ab882201ee929..da3a3fff0c5e1 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 array $freshCache = []; - public const VERSION = '6.1.1'; - public const VERSION_ID = 60101; + public const VERSION = '6.1.2-DEV'; + public const VERSION_ID = 60102; public const MAJOR_VERSION = 6; public const MINOR_VERSION = 1; - public const RELEASE_VERSION = 1; - public const EXTRA_VERSION = ''; + public const RELEASE_VERSION = 2; + public const EXTRA_VERSION = 'DEV'; public const END_OF_MAINTENANCE = '01/2023'; public const END_OF_LIFE = '01/2023'; From 1605b57c071638c687a5eb7704a55a984b45427e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gabriel=20Ostroluck=C3=BD?= Date: Thu, 2 Jun 2022 00:18:04 +0200 Subject: [PATCH 04/44] [PropertyInfo] Add failing test case for multi phpdoc covered promoted properties This demonstrates that https://github.com/symfony/symfony/pull/46056 causes a regression and incorrectly detects types in case there are multiple phpdoc covered promoted properties. --- .../{PhpStanExtractorTestDoc.php => PhpStanExtractorTest.php} | 1 + .../Component/PropertyInfo/Tests/Fixtures/Php80Dummy.php | 3 ++- 2 files changed, 3 insertions(+), 1 deletion(-) rename src/Symfony/Component/PropertyInfo/Tests/Extractor/{PhpStanExtractorTestDoc.php => PhpStanExtractorTest.php} (99%) diff --git a/src/Symfony/Component/PropertyInfo/Tests/Extractor/PhpStanExtractorTestDoc.php b/src/Symfony/Component/PropertyInfo/Tests/Extractor/PhpStanExtractorTest.php similarity index 99% rename from src/Symfony/Component/PropertyInfo/Tests/Extractor/PhpStanExtractorTestDoc.php rename to src/Symfony/Component/PropertyInfo/Tests/Extractor/PhpStanExtractorTest.php index 7565994ee0c8c..9b49e70e202a7 100644 --- a/src/Symfony/Component/PropertyInfo/Tests/Extractor/PhpStanExtractorTestDoc.php +++ b/src/Symfony/Component/PropertyInfo/Tests/Extractor/PhpStanExtractorTest.php @@ -467,6 +467,7 @@ public function php80TypesProvider() return [ [Php80Dummy::class, 'promotedAndMutated', [new Type(Type::BUILTIN_TYPE_STRING)]], [Php80Dummy::class, 'promoted', null], + [Php80Dummy::class, 'collection', [new Type(Type::BUILTIN_TYPE_ARRAY, collection: true, collectionValueType: new Type(Type::BUILTIN_TYPE_STRING))]], [Php80PromotedDummy::class, 'promoted', null], ]; } diff --git a/src/Symfony/Component/PropertyInfo/Tests/Fixtures/Php80Dummy.php b/src/Symfony/Component/PropertyInfo/Tests/Fixtures/Php80Dummy.php index e7ae2fc83bfec..dc985fea0b212 100644 --- a/src/Symfony/Component/PropertyInfo/Tests/Fixtures/Php80Dummy.php +++ b/src/Symfony/Component/PropertyInfo/Tests/Fixtures/Php80Dummy.php @@ -17,8 +17,9 @@ class Php80Dummy /** * @param string $promotedAndMutated + * @param array $collection */ - public function __construct(private mixed $promoted, private mixed $promotedAndMutated) + public function __construct(private mixed $promoted, private mixed $promotedAndMutated, private array $collection) { } From f503e37d29e99de2f52203dff4cf4ea4ebb5201c Mon Sep 17 00:00:00 2001 From: Simon Podlipsky Date: Tue, 7 Jun 2022 11:36:55 +0300 Subject: [PATCH 05/44] [PropertyInfo] Fix multi phpdoc covered promoted properties --- .../PropertyInfo/Extractor/PhpStanExtractor.php | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/src/Symfony/Component/PropertyInfo/Extractor/PhpStanExtractor.php b/src/Symfony/Component/PropertyInfo/Extractor/PhpStanExtractor.php index 52a4a78f2537f..429f43202543d 100644 --- a/src/Symfony/Component/PropertyInfo/Extractor/PhpStanExtractor.php +++ b/src/Symfony/Component/PropertyInfo/Extractor/PhpStanExtractor.php @@ -99,6 +99,14 @@ public function getTypes(string $class, string $property, array $context = []): continue; } + if ( + $tagDocNode->value instanceof ParamTagValueNode + && null === $prefix + && $tagDocNode->value->parameterName !== '$'.$property + ) { + continue; + } + foreach ($this->phpStanTypeHelper->getTypes($tagDocNode->value, $nameScope) as $type) { switch ($type->getClassName()) { case 'self': @@ -239,10 +247,6 @@ private function getDocBlockFromProperty(string $class, string $property): ?arra $phpDocNode = $this->phpDocParser->parse($tokens); $tokens->consumeTokenType(Lexer::TOKEN_END); - if (self::MUTATOR === $source && !$this->filterDocBlockParams($phpDocNode, $property)) { - return null; - } - return [$phpDocNode, $source, $reflectionProperty->class]; } From 16cf4fc4d0617df32cdeb334d2f791f711539a09 Mon Sep 17 00:00:00 2001 From: Thomas Talbot Date: Sat, 11 Jun 2022 15:17:48 +0200 Subject: [PATCH 06/44] [Messenger] move resetting services at worker stopped into ResetServicesListener --- .../EventListener/ResetServicesListener.php | 8 ++++ .../Command/ConsumeMessagesCommandTest.php | 19 ++++----- .../ResetServicesListenerTest.php | 12 ++++++ .../Component/Messenger/Tests/WorkerTest.php | 39 ++++++++++++++++++- src/Symfony/Component/Messenger/Worker.php | 10 ----- 5 files changed, 66 insertions(+), 22 deletions(-) diff --git a/src/Symfony/Component/Messenger/EventListener/ResetServicesListener.php b/src/Symfony/Component/Messenger/EventListener/ResetServicesListener.php index b57ee728981b6..dd170e0e433a1 100644 --- a/src/Symfony/Component/Messenger/EventListener/ResetServicesListener.php +++ b/src/Symfony/Component/Messenger/EventListener/ResetServicesListener.php @@ -14,6 +14,8 @@ use Symfony\Component\EventDispatcher\EventSubscriberInterface; use Symfony\Component\HttpKernel\DependencyInjection\ServicesResetter; use Symfony\Component\Messenger\Event\WorkerRunningEvent; +use Symfony\Component\Messenger\Event\WorkerStoppedEvent; +use Symfony\Contracts\Service\ResetInterface; /** * @author Grégoire Pineau @@ -34,10 +36,16 @@ public function resetServices(WorkerRunningEvent $event): void } } + public function resetServicesAtStop(WorkerStoppedEvent $event): void + { + $this->servicesResetter->reset(); + } + public static function getSubscribedEvents(): array { return [ WorkerRunningEvent::class => ['resetServices', -1024], + WorkerStoppedEvent::class => ['resetServicesAtStop', -1024], ]; } } diff --git a/src/Symfony/Component/Messenger/Tests/Command/ConsumeMessagesCommandTest.php b/src/Symfony/Component/Messenger/Tests/Command/ConsumeMessagesCommandTest.php index 8a6f5a7d608cf..1bcfeb04a987a 100644 --- a/src/Symfony/Component/Messenger/Tests/Command/ConsumeMessagesCommandTest.php +++ b/src/Symfony/Component/Messenger/Tests/Command/ConsumeMessagesCommandTest.php @@ -26,6 +26,7 @@ use Symfony\Component\Messenger\MessageBusInterface; use Symfony\Component\Messenger\RoutableMessageBus; use Symfony\Component\Messenger\Stamp\BusNameStamp; +use Symfony\Component\Messenger\Tests\ResettableDummyReceiver; use Symfony\Component\Messenger\Transport\Receiver\ReceiverInterface; class ConsumeMessagesCommandTest extends TestCase @@ -116,15 +117,11 @@ public function testRunWithResetServicesOption(bool $shouldReset) { $envelope = new Envelope(new \stdClass()); - $receiver = $this->createMock(ReceiverInterface::class); - $receiver - ->expects($this->exactly(3)) - ->method('get') - ->willReturnOnConsecutiveCalls( - [$envelope], - [/* idle */], - [$envelope, $envelope] - ); + $receiver = new ResettableDummyReceiver([ + [$envelope], + [/* idle */], + [$envelope, $envelope], + ]); $msgCount = 3; $receiverLocator = $this->createMock(ContainerInterface::class); @@ -134,8 +131,7 @@ public function testRunWithResetServicesOption(bool $shouldReset) $bus = $this->createMock(RoutableMessageBus::class); $bus->expects($this->exactly($msgCount))->method('dispatch'); - $servicesResetter = $this->createMock(ServicesResetter::class); - $servicesResetter->expects($this->exactly($shouldReset ? $msgCount : 0))->method('reset'); + $servicesResetter = new ServicesResetter(new \ArrayIterator([$receiver]), ['reset']); $command = new ConsumeMessagesCommand($bus, $receiverLocator, new EventDispatcher(), null, [], new ResetServicesListener($servicesResetter)); @@ -148,6 +144,7 @@ public function testRunWithResetServicesOption(bool $shouldReset) '--limit' => $msgCount, ], $shouldReset ? [] : ['--no-reset' => null])); + $this->assertEquals($shouldReset, $receiver->hasBeenReset(), '$receiver->reset() should have been called'); $tester->assertCommandIsSuccessful(); $this->assertStringContainsString('[OK] Consuming messages from transports "dummy-receiver"', $tester->getDisplay()); } diff --git a/src/Symfony/Component/Messenger/Tests/EventListener/ResetServicesListenerTest.php b/src/Symfony/Component/Messenger/Tests/EventListener/ResetServicesListenerTest.php index ce8f771a0952f..12f86ec6c83cb 100644 --- a/src/Symfony/Component/Messenger/Tests/EventListener/ResetServicesListenerTest.php +++ b/src/Symfony/Component/Messenger/Tests/EventListener/ResetServicesListenerTest.php @@ -14,6 +14,7 @@ use PHPUnit\Framework\TestCase; use Symfony\Component\HttpKernel\DependencyInjection\ServicesResetter; use Symfony\Component\Messenger\Event\WorkerRunningEvent; +use Symfony\Component\Messenger\Event\WorkerStoppedEvent; use Symfony\Component\Messenger\EventListener\ResetServicesListener; use Symfony\Component\Messenger\Worker; @@ -38,4 +39,15 @@ public function testResetServices(bool $shouldReset) $resetListener = new ResetServicesListener($servicesResetter); $resetListener->resetServices($event); } + + public function testResetServicesAtStop() + { + $servicesResetter = $this->createMock(ServicesResetter::class); + $servicesResetter->expects($this->once())->method('reset'); + + $event = new WorkerStoppedEvent($this->createMock(Worker::class)); + + $resetListener = new ResetServicesListener($servicesResetter); + $resetListener->resetServicesAtStop($event); + } } diff --git a/src/Symfony/Component/Messenger/Tests/WorkerTest.php b/src/Symfony/Component/Messenger/Tests/WorkerTest.php index f09d2648798bf..4d0f79b10e41a 100644 --- a/src/Symfony/Component/Messenger/Tests/WorkerTest.php +++ b/src/Symfony/Component/Messenger/Tests/WorkerTest.php @@ -14,6 +14,7 @@ use PHPUnit\Framework\TestCase; use Psr\Log\LoggerInterface; use Symfony\Component\EventDispatcher\EventDispatcher; +use Symfony\Component\HttpKernel\DependencyInjection\ServicesResetter; use Symfony\Component\Messenger\Envelope; use Symfony\Component\Messenger\Event\WorkerMessageFailedEvent; use Symfony\Component\Messenger\Event\WorkerMessageHandledEvent; @@ -21,6 +22,7 @@ use Symfony\Component\Messenger\Event\WorkerRunningEvent; use Symfony\Component\Messenger\Event\WorkerStartedEvent; use Symfony\Component\Messenger\Event\WorkerStoppedEvent; +use Symfony\Component\Messenger\EventListener\ResetServicesListener; use Symfony\Component\Messenger\EventListener\StopWorkerOnMessageLimitListener; use Symfony\Component\Messenger\Exception\RuntimeException; use Symfony\Component\Messenger\Handler\Acknowledger; @@ -103,15 +105,50 @@ public function testWorkerResetsConnectionIfReceiverIsResettable() { $resettableReceiver = new ResettableDummyReceiver([]); - $bus = $this->createMock(MessageBusInterface::class); $dispatcher = new EventDispatcher(); + $dispatcher->addSubscriber(new ResetServicesListener(new ServicesResetter(new \ArrayIterator([$resettableReceiver]), ['reset']))); + $bus = $this->createMock(MessageBusInterface::class); $worker = new Worker([$resettableReceiver], $bus, $dispatcher); $worker->stop(); $worker->run(); $this->assertTrue($resettableReceiver->hasBeenReset()); } + public function testWorkerResetsTransportsIfResetServicesListenerIsCalled() + { + $envelope = new Envelope(new DummyMessage('Hello')); + $resettableReceiver = new ResettableDummyReceiver([[$envelope]]); + + $dispatcher = new EventDispatcher(); + $dispatcher->addSubscriber(new ResetServicesListener(new ServicesResetter(new \ArrayIterator([$resettableReceiver]), ['reset']))); + $dispatcher->addListener(WorkerRunningEvent::class, function (WorkerRunningEvent $event) { + $event->getWorker()->stop(); + }); + + $bus = $this->createMock(MessageBusInterface::class); + $worker = new Worker([$resettableReceiver], $bus, $dispatcher); + $worker->run(); + $this->assertTrue($resettableReceiver->hasBeenReset()); + } + + public function testWorkerDoesNotResetTransportsIfResetServicesListenerIsNotCalled() + { + $envelope = new Envelope(new DummyMessage('Hello')); + $resettableReceiver = new ResettableDummyReceiver([[$envelope]]); + + $bus = $this->createMock(MessageBusInterface::class); + + $dispatcher = new EventDispatcher(); + $dispatcher->addListener(WorkerRunningEvent::class, function (WorkerRunningEvent $event) { + $event->getWorker()->stop(); + }); + + $worker = new Worker([$resettableReceiver], $bus, $dispatcher); + $worker->run(); + $this->assertFalse($resettableReceiver->hasBeenReset()); + } + public function testWorkerDoesNotSendNullMessagesToTheBus() { $receiver = new DummyReceiver([ diff --git a/src/Symfony/Component/Messenger/Worker.php b/src/Symfony/Component/Messenger/Worker.php index f670b564f8fcc..34473bac32267 100644 --- a/src/Symfony/Component/Messenger/Worker.php +++ b/src/Symfony/Component/Messenger/Worker.php @@ -136,7 +136,6 @@ public function run(array $options = []): void $this->flush(true); $this->dispatchEvent(new WorkerStoppedEvent($this)); - $this->resetReceiverConnections(); } private function handleMessage(Envelope $envelope, string $transportName): void @@ -260,15 +259,6 @@ public function getMetadata(): WorkerMetadata return $this->metadata; } - private function resetReceiverConnections(): void - { - foreach ($this->receivers as $receiver) { - if ($receiver instanceof ResetInterface) { - $receiver->reset(); - } - } - } - private function dispatchEvent(object $event): void { if (null === $this->eventDispatcher) { From 133b1655725d44d8a9d79c0b5125740d426db212 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gabriel=20Ostroluck=C3=BD?= Date: Sun, 12 Jun 2022 11:53:37 +0200 Subject: [PATCH 07/44] [WebProfilerBundle] Bump http-kernel requirement to ^6.1 --- src/Symfony/Bundle/WebProfilerBundle/composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Symfony/Bundle/WebProfilerBundle/composer.json b/src/Symfony/Bundle/WebProfilerBundle/composer.json index 9b425459b21ba..a5aefe35b9baa 100644 --- a/src/Symfony/Bundle/WebProfilerBundle/composer.json +++ b/src/Symfony/Bundle/WebProfilerBundle/composer.json @@ -19,7 +19,7 @@ "php": ">=8.1", "symfony/config": "^5.4|^6.0", "symfony/framework-bundle": "^5.4|^6.0", - "symfony/http-kernel": "^5.4|^6.0", + "symfony/http-kernel": "^6.1", "symfony/routing": "^5.4|^6.0", "symfony/twig-bundle": "^5.4|^6.0", "twig/twig": "^2.13|^3.0.4" From 3fcfc205006c8503700c1452747deb6a612b14ab Mon Sep 17 00:00:00 2001 From: Albert Prat Date: Tue, 14 Jun 2022 14:07:47 +0200 Subject: [PATCH 08/44] [FrameworkBundle] Lower JsonSerializableNormalizer priority --- .../Bundle/FrameworkBundle/Resources/config/serializer.xml | 2 +- .../Tests/DependencyInjection/FrameworkExtensionTest.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Symfony/Bundle/FrameworkBundle/Resources/config/serializer.xml b/src/Symfony/Bundle/FrameworkBundle/Resources/config/serializer.xml index c3eea28b8c2b9..19defd885259c 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Resources/config/serializer.xml +++ b/src/Symfony/Bundle/FrameworkBundle/Resources/config/serializer.xml @@ -60,7 +60,7 @@ - + diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/FrameworkExtensionTest.php b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/FrameworkExtensionTest.php index c2c7bc6b851cc..e86e22a201d53 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/FrameworkExtensionTest.php +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/FrameworkExtensionTest.php @@ -1297,7 +1297,7 @@ public function testJsonSerializableNormalizerRegistered() $tag = $definition->getTag('serializer.normalizer'); $this->assertEquals(JsonSerializableNormalizer::class, $definition->getClass()); - $this->assertEquals(-900, $tag[0]['priority']); + $this->assertEquals(-950, $tag[0]['priority']); } public function testObjectNormalizerRegistered() From a9b0f43366ca0b8752df02eff65e1d1b5d7e443a Mon Sep 17 00:00:00 2001 From: Gigino Chianese Date: Wed, 15 Jun 2022 08:50:33 +0200 Subject: [PATCH 09/44] [DoctrineBridge] Extend type guessing on enum fields Doctrine supports enumType on array values. In those cases the guessed type should be of type array with collection information. --- .../PropertyInfo/DoctrineExtractor.php | 24 ++++++++++++++----- .../PropertyInfo/DoctrineExtractorTest.php | 3 +++ .../PropertyInfo/Fixtures/DoctrineEnum.php | 15 ++++++++++++ 3 files changed, 36 insertions(+), 6 deletions(-) diff --git a/src/Symfony/Bridge/Doctrine/PropertyInfo/DoctrineExtractor.php b/src/Symfony/Bridge/Doctrine/PropertyInfo/DoctrineExtractor.php index 9add7946fbea5..8ebd5fbe00b34 100644 --- a/src/Symfony/Bridge/Doctrine/PropertyInfo/DoctrineExtractor.php +++ b/src/Symfony/Bridge/Doctrine/PropertyInfo/DoctrineExtractor.php @@ -152,17 +152,18 @@ public function getTypes($class, $property, array $context = []) } if ($metadata->hasField($property)) { - $nullable = $metadata instanceof ClassMetadataInfo && $metadata->isNullable($property); - if (null !== $enumClass = $metadata->getFieldMapping($property)['enumType'] ?? null) { - return [new Type(Type::BUILTIN_TYPE_OBJECT, $nullable, $enumClass)]; - } - $typeOfField = $metadata->getTypeOfField($property); if (!$builtinType = $this->getPhpType($typeOfField)) { return null; } + $nullable = $metadata instanceof ClassMetadataInfo && $metadata->isNullable($property); + $enumType = null; + if (null !== $enumClass = $metadata->getFieldMapping($property)['enumType'] ?? null) { + $enumType = new Type(Type::BUILTIN_TYPE_OBJECT, $nullable, $enumClass); + } + switch ($builtinType) { case Type::BUILTIN_TYPE_OBJECT: switch ($typeOfField) { @@ -192,11 +193,22 @@ public function getTypes($class, $property, array $context = []) case self::$useDeprecatedConstants ? DBALType::TARRAY : Types::ARRAY: // no break case 'json_array': + // return null if $enumType is set, because we can't determine if collectionKeyType is string or int + if ($enumType) { + return null; + } + return [new Type(Type::BUILTIN_TYPE_ARRAY, $nullable, null, true)]; case self::$useDeprecatedConstants ? DBALType::SIMPLE_ARRAY : Types::SIMPLE_ARRAY: - return [new Type(Type::BUILTIN_TYPE_ARRAY, $nullable, null, true, new Type(Type::BUILTIN_TYPE_INT), new Type(Type::BUILTIN_TYPE_STRING))]; + return [new Type(Type::BUILTIN_TYPE_ARRAY, $nullable, null, true, new Type(Type::BUILTIN_TYPE_INT), $enumType ?? new Type(Type::BUILTIN_TYPE_STRING))]; + } + case Type::BUILTIN_TYPE_INT: + case Type::BUILTIN_TYPE_STRING: + if ($enumType !== null) { + return [$enumType]; } + // no break } return [new Type($builtinType, $nullable)]; diff --git a/src/Symfony/Bridge/Doctrine/Tests/PropertyInfo/DoctrineExtractorTest.php b/src/Symfony/Bridge/Doctrine/Tests/PropertyInfo/DoctrineExtractorTest.php index b1e327968242a..32caea8bd3093 100644 --- a/src/Symfony/Bridge/Doctrine/Tests/PropertyInfo/DoctrineExtractorTest.php +++ b/src/Symfony/Bridge/Doctrine/Tests/PropertyInfo/DoctrineExtractorTest.php @@ -185,6 +185,9 @@ public function testExtractEnum() } $this->assertEquals([new Type(Type::BUILTIN_TYPE_OBJECT, false, EnumString::class)], $this->createExtractor()->getTypes(DoctrineEnum::class, 'enumString', [])); $this->assertEquals([new Type(Type::BUILTIN_TYPE_OBJECT, false, EnumInt::class)], $this->createExtractor()->getTypes(DoctrineEnum::class, 'enumInt', [])); + $this->assertEquals(null, $this->createExtractor()->getTypes(DoctrineEnum::class, 'enumStringArray', [])); + $this->assertEquals([new Type(Type::BUILTIN_TYPE_ARRAY, false, null, true, new Type(Type::BUILTIN_TYPE_INT), new Type(Type::BUILTIN_TYPE_OBJECT, false, EnumInt::class))], $this->createExtractor()->getTypes(DoctrineEnum::class, 'enumIntArray', [])); + $this->assertEquals(null, $this->createExtractor()->getTypes(DoctrineEnum::class, 'enumCustom', [])); } public function typesProvider() diff --git a/src/Symfony/Bridge/Doctrine/Tests/PropertyInfo/Fixtures/DoctrineEnum.php b/src/Symfony/Bridge/Doctrine/Tests/PropertyInfo/Fixtures/DoctrineEnum.php index 467522cbd3914..fd5271fc47730 100644 --- a/src/Symfony/Bridge/Doctrine/Tests/PropertyInfo/Fixtures/DoctrineEnum.php +++ b/src/Symfony/Bridge/Doctrine/Tests/PropertyInfo/Fixtures/DoctrineEnum.php @@ -35,4 +35,19 @@ class DoctrineEnum * @Column(type="integer", enumType="Symfony\Bridge\Doctrine\Tests\PropertyInfo\Fixtures\EnumInt") */ protected $enumInt; + + /** + * @Column(type="array", enumType="Symfony\Bridge\Doctrine\Tests\PropertyInfo\Fixtures\EnumString") + */ + protected $enumStringArray; + + /** + * @Column(type="simple_array", enumType="Symfony\Bridge\Doctrine\Tests\PropertyInfo\Fixtures\EnumInt") + */ + protected $enumIntArray; + + /** + * @Column(type="custom_foo", enumType="Symfony\Bridge\Doctrine\Tests\PropertyInfo\Fixtures\EnumInt") + */ + protected $enumCustom; } From bb0ddf1984cdde3e71f6a35e64e54c13a0fd1cbf Mon Sep 17 00:00:00 2001 From: Mathieu Santostefano Date: Tue, 14 Jun 2022 17:30:05 +0200 Subject: [PATCH 10/44] Fix HttpClientTrait::jsonEncode flags usage --- .../DataCollector/HttpClientDataCollector.php | 2 +- .../DataCollector/HttpClientDataCollectorTest.php | 10 ++++------ 2 files changed, 5 insertions(+), 7 deletions(-) diff --git a/src/Symfony/Component/HttpClient/DataCollector/HttpClientDataCollector.php b/src/Symfony/Component/HttpClient/DataCollector/HttpClientDataCollector.php index dc4b6762b87a7..e026b42d41476 100644 --- a/src/Symfony/Component/HttpClient/DataCollector/HttpClientDataCollector.php +++ b/src/Symfony/Component/HttpClient/DataCollector/HttpClientDataCollector.php @@ -194,7 +194,7 @@ private function getCurlCommand(array $trace): ?string $dataArg = []; if ($json = $trace['options']['json'] ?? null) { - $dataArg[] = '--data '.escapeshellarg(json_encode($json, \JSON_PRETTY_PRINT)); + $dataArg[] = '--data '.escapeshellarg(self::jsonEncode($json)); } elseif ($body = $trace['options']['body'] ?? null) { if (\is_string($body)) { try { diff --git a/src/Symfony/Component/HttpClient/Tests/DataCollector/HttpClientDataCollectorTest.php b/src/Symfony/Component/HttpClient/Tests/DataCollector/HttpClientDataCollectorTest.php index 863c91d3d68db..1eee2fdce1263 100755 --- a/src/Symfony/Component/HttpClient/Tests/DataCollector/HttpClientDataCollectorTest.php +++ b/src/Symfony/Component/HttpClient/Tests/DataCollector/HttpClientDataCollectorTest.php @@ -307,6 +307,8 @@ public function __toString(): string 'json' => [ 'foo' => [ 'bar' => 'baz', + 'qux' => [1.10, 1.0], + 'fred' => ['',"'bar'",'"baz"','&blong&'], ], ], ], @@ -317,14 +319,10 @@ public function __toString(): string --url %1$shttp://localhost:8057/json%1$s \\ --header %1$sContent-Type: application/json%1$s \\ --header %1$sAccept: */*%1$s \\ - --header %1$sContent-Length: 21%1$s \\ + --header %1$sContent-Length: 120%1$s \\ --header %1$sAccept-Encoding: gzip%1$s \\ --header %1$sUser-Agent: Symfony HttpClient/Native%1$s \\ - --data %1$s{ - "foo": { - "bar": "baz" - } -}%1$s', + --data %1$s{"foo":{"bar":"baz","qux":[1.1,1.0],"fred":["\u003Cfoo\u003E","\u0027bar\u0027","\u0022baz\u0022","\u0026blong\u0026"]}}%1$s', ]; } } From e14cea92be7544f9fe429b0350052b6644782618 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gr=C3=A9goire=20Pineau?= Date: Wed, 15 Jun 2022 18:57:10 +0200 Subject: [PATCH 11/44] [MonologBridge] Fixed support of elasticsearch 7.+ in ElasticsearchLogstashHandler --- .../Handler/ElasticsearchLogstashHandler.php | 26 ++++++++--- .../ElasticsearchLogstashHandlerTest.php | 43 +++++++++++++++++++ 2 files changed, 62 insertions(+), 7 deletions(-) diff --git a/src/Symfony/Bridge/Monolog/Handler/ElasticsearchLogstashHandler.php b/src/Symfony/Bridge/Monolog/Handler/ElasticsearchLogstashHandler.php index a59825f6ab1f4..9826bb525773c 100644 --- a/src/Symfony/Bridge/Monolog/Handler/ElasticsearchLogstashHandler.php +++ b/src/Symfony/Bridge/Monolog/Handler/ElasticsearchLogstashHandler.php @@ -48,11 +48,12 @@ class ElasticsearchLogstashHandler extends AbstractHandler private $index; private $client; private $responses; + private $elasticsearchVersion; /** * @param string|int $level The minimum logging level at which this handler will be triggered */ - public function __construct(string $endpoint = 'http://127.0.0.1:9200', string $index = 'monolog', HttpClientInterface $client = null, $level = Logger::DEBUG, bool $bubble = true) + public function __construct(string $endpoint = 'http://127.0.0.1:9200', string $index = 'monolog', HttpClientInterface $client = null, $level = Logger::DEBUG, bool $bubble = true, string $elasticsearchVersion = '1.0.0') { if (!interface_exists(HttpClientInterface::class)) { throw new \LogicException(sprintf('The "%s" handler needs an HTTP client. Try running "composer require symfony/http-client".', __CLASS__)); @@ -63,6 +64,7 @@ public function __construct(string $endpoint = 'http://127.0.0.1:9200', string $ $this->index = $index; $this->client = $client ?: HttpClient::create(['timeout' => 1]); $this->responses = new \SplObjectStorage(); + $this->elasticsearchVersion = $elasticsearchVersion; } public function handle(array $record): bool @@ -100,18 +102,28 @@ private function sendToElasticsearch(array $records) { $formatter = $this->getFormatter(); + if (version_compare($this->elasticsearchVersion, '7', '>=')) { + $headers = json_encode([ + 'index' => [ + '_index' => $this->index, + ], + ]); + } else { + $headers = json_encode([ + 'index' => [ + '_index' => $this->index, + '_type' => '_doc', + ], + ]); + } + $body = ''; foreach ($records as $record) { foreach ($this->processors as $processor) { $record = $processor($record); } - $body .= json_encode([ - 'index' => [ - '_index' => $this->index, - '_type' => '_doc', - ], - ]); + $body .= $headers; $body .= "\n"; $body .= $formatter->format($record); $body .= "\n"; diff --git a/src/Symfony/Bridge/Monolog/Tests/Handler/ElasticsearchLogstashHandlerTest.php b/src/Symfony/Bridge/Monolog/Tests/Handler/ElasticsearchLogstashHandlerTest.php index 2940f0440ff8f..0a30fb3c63bc6 100644 --- a/src/Symfony/Bridge/Monolog/Tests/Handler/ElasticsearchLogstashHandlerTest.php +++ b/src/Symfony/Bridge/Monolog/Tests/Handler/ElasticsearchLogstashHandlerTest.php @@ -64,6 +64,49 @@ public function testHandle() $this->assertSame(1, $callCount); } + public function testHandleWithElasticsearch8() + { + $callCount = 0; + $responseFactory = function ($method, $url, $options) use (&$callCount) { + $body = <<assertSame('POST', $method); + $this->assertSame('http://es:9200/_bulk', $url); + $this->assertSame($body, $options['body']); + $this->assertSame('Content-Type: application/json', $options['normalized_headers']['content-type'][0]); + ++$callCount; + + return new MockResponse(); + }; + + $handler = new ElasticsearchLogstashHandlerWithHardCodedHostname('http://es:9200', 'log', new MockHttpClient($responseFactory), Logger::DEBUG, true, '8.0.0'); + + $record = [ + 'message' => 'My info message', + 'context' => [], + 'level' => Logger::INFO, + 'level_name' => Logger::getLevelName(Logger::INFO), + 'channel' => 'app', + 'datetime' => new \DateTime('2020-01-01T00:00:00+01:00'), + 'extra' => [], + ]; + + $handler->handle($record); + + $this->assertSame(1, $callCount); + } + public function testBandleBatch() { $callCount = 0; From 2ad3f305868b5f7c7988a1e46bd42d83e56c4601 Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Thu, 16 Jun 2022 16:31:53 +0200 Subject: [PATCH 12/44] [HttpKernel] Disable session tracking while collecting profiler data --- .../EventListener/ProfilerListener.php | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/src/Symfony/Component/HttpKernel/EventListener/ProfilerListener.php b/src/Symfony/Component/HttpKernel/EventListener/ProfilerListener.php index b8464f1627353..32e809229a9ed 100644 --- a/src/Symfony/Component/HttpKernel/EventListener/ProfilerListener.php +++ b/src/Symfony/Component/HttpKernel/EventListener/ProfilerListener.php @@ -12,8 +12,10 @@ namespace Symfony\Component\HttpKernel\EventListener; use Symfony\Component\EventDispatcher\EventSubscriberInterface; +use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\RequestMatcherInterface; use Symfony\Component\HttpFoundation\RequestStack; +use Symfony\Component\HttpFoundation\Session\Session; use Symfony\Component\HttpKernel\Event\FilterResponseEvent; use Symfony\Component\HttpKernel\Event\GetResponseForExceptionEvent; use Symfony\Component\HttpKernel\Event\PostResponseEvent; @@ -87,8 +89,21 @@ public function onKernelResponse(FilterResponseEvent $event) return; } - if (!$profile = $this->profiler->collect($request, $event->getResponse(), $exception)) { - return; + $session = method_exists(Request::class, 'getPreferredFormat') && $request->hasPreviousSession() && $request->hasSession() ? $request->getSession() : null; + + if ($session instanceof Session) { + $usageIndexValue = $usageIndexReference = &$session->getUsageIndex(); + $usageIndexReference = \PHP_INT_MIN; + } + + try { + if (!$profile = $this->profiler->collect($request, $event->getResponse(), $exception)) { + return; + } + } finally { + if ($session instanceof Session) { + $usageIndexReference = $usageIndexValue; + } } $this->profiles[$request] = $profile; From 5e8de1e21122eaf2a4e27fb202102d0d4b6a1f56 Mon Sep 17 00:00:00 2001 From: Jonathan Johnson Date: Fri, 17 Jun 2022 01:00:30 -0700 Subject: [PATCH 13/44] [Cache] Respect $save option in ArrayAdapter When $save is passed as the second option to the callback it should be respected, even in the ephemeral array adapter. --- .../Component/Cache/Adapter/ArrayAdapter.php | 5 +++- .../Cache/Tests/Adapter/AdapterTestCase.php | 25 +++++++++++++++++++ .../Tests/Adapter/PhpArrayAdapterTest.php | 1 + 3 files changed, 30 insertions(+), 1 deletion(-) diff --git a/src/Symfony/Component/Cache/Adapter/ArrayAdapter.php b/src/Symfony/Component/Cache/Adapter/ArrayAdapter.php index 157043abef188..20043dec18c5e 100644 --- a/src/Symfony/Component/Cache/Adapter/ArrayAdapter.php +++ b/src/Symfony/Component/Cache/Adapter/ArrayAdapter.php @@ -60,7 +60,10 @@ public function get(string $key, callable $callback, float $beta = null, array & // ArrayAdapter works in memory, we don't care about stampede protection if (\INF === $beta || !$item->isHit()) { $save = true; - $this->save($item->set($callback($item, $save))); + $item->set($callback($item, $save)); + if ($save) { + $this->save($item); + } } return $item->get(); diff --git a/src/Symfony/Component/Cache/Tests/Adapter/AdapterTestCase.php b/src/Symfony/Component/Cache/Tests/Adapter/AdapterTestCase.php index 123cda89b8728..da55270348224 100644 --- a/src/Symfony/Component/Cache/Tests/Adapter/AdapterTestCase.php +++ b/src/Symfony/Component/Cache/Tests/Adapter/AdapterTestCase.php @@ -98,6 +98,31 @@ public function testRecursiveGet() $this->assertSame(1, $cache->get('k2', function () { return 2; })); } + public function testDontSaveWhenAskedNotTo() + { + if (isset($this->skippedTests[__FUNCTION__])) { + $this->markTestSkipped($this->skippedTests[__FUNCTION__]); + } + + $cache = $this->createCachePool(0, __FUNCTION__); + + $v1 = $cache->get('some-key', function($item, &$save){ + $save = false; + return 1; + }); + $this->assertSame($v1, 1); + + $v2 = $cache->get('some-key', function(){ + return 2; + }); + $this->assertSame($v2, 2, 'First value was cached and should not have been'); + + $v3 = $cache->get('some-key', function(){ + $this->fail('Value should have come from cache'); + }); + $this->assertSame($v3, 2); + } + public function testGetMetadata() { if (isset($this->skippedTests[__FUNCTION__])) { diff --git a/src/Symfony/Component/Cache/Tests/Adapter/PhpArrayAdapterTest.php b/src/Symfony/Component/Cache/Tests/Adapter/PhpArrayAdapterTest.php index 58318f6a25294..b7ced48abf7c9 100644 --- a/src/Symfony/Component/Cache/Tests/Adapter/PhpArrayAdapterTest.php +++ b/src/Symfony/Component/Cache/Tests/Adapter/PhpArrayAdapterTest.php @@ -24,6 +24,7 @@ class PhpArrayAdapterTest extends AdapterTestCase { protected $skippedTests = [ 'testGet' => 'PhpArrayAdapter is read-only.', + 'testDontSaveWhenAskedNotTo' => 'PhpArrayAdapter is read-only.', 'testRecursiveGet' => 'PhpArrayAdapter is read-only.', 'testBasicUsage' => 'PhpArrayAdapter is read-only.', 'testBasicUsageWithLongKey' => 'PhpArrayAdapter is read-only.', From 0186ecb30e954603894cf2eb66c9ce9f33213d22 Mon Sep 17 00:00:00 2001 From: Thomas Lallement Date: Fri, 17 Jun 2022 17:20:52 +0200 Subject: [PATCH 14/44] Allow passing null in twig_is_selected_choice In the cached file of my application I can see the following code fragment that have been generated by Symfony: ```php if (( !((array_key_exists("render_preferred_choices", $context)) ? (_twig_default_filter((isset($context["render_preferred_choices"]) || array_key_exists("render_preferred_choices", $context) ? $context["render_preferred_choices"] : (function () { throw new RuntimeError('Variable "render_preferred_choices" does not exist.', 88, $this->source); })()), false)) : (false)) && Symfony\Bridge\Twig\Extension\twig_is_selected_choice($context["choice"], (isset($context["value"]) || array_key_exists("value", $context) ? $context["value"] : (function () { throw new RuntimeError('Variable "value" does not exist.', 88, $this->source); })())))) { echo " selected=\"selected\""; } ``` The 2nd Arg passed when calling ``twig_is_selected_choice`` if the result of ``(isset($context["value"]) || array_key_exists("value", $context) ? $context["value"]``. In that condition, if ``$context['value'] = null, we pass the null Currently I got the following error: ``` Symfony\Bridge\Twig\Extension\twig_is_selected_choice(): Argument #2 ($selectedValue) must be of type array|string, null given, called in X:\workspace-novento\novento-vip-lounge\var\cache\admin_dev\twig\01\01615438ee40292438687b29025d08a9.php on line 534 ``` --- src/Symfony/Bridge/Twig/Extension/FormExtension.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Symfony/Bridge/Twig/Extension/FormExtension.php b/src/Symfony/Bridge/Twig/Extension/FormExtension.php index f7d82e042138d..c726b0584d140 100644 --- a/src/Symfony/Bridge/Twig/Extension/FormExtension.php +++ b/src/Symfony/Bridge/Twig/Extension/FormExtension.php @@ -188,7 +188,7 @@ private function createFieldTranslation(?string $value, array $parameters, strin * * @see ChoiceView::isSelected() */ -function twig_is_selected_choice(ChoiceView $choice, string|array $selectedValue): bool +function twig_is_selected_choice(ChoiceView $choice, string|array|null $selectedValue): bool { if (\is_array($selectedValue)) { return \in_array($choice->value, $selectedValue, true); From 57a46e012a9e5214029dae140af04ce56f0141ab Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Sun, 19 Jun 2022 11:24:30 +0200 Subject: [PATCH 15/44] [ExpressionLanguage] fix tests --- .../ExpressionLanguage/Tests/Node/BinaryNodeTest.php | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Symfony/Component/ExpressionLanguage/Tests/Node/BinaryNodeTest.php b/src/Symfony/Component/ExpressionLanguage/Tests/Node/BinaryNodeTest.php index 2be8b4aecc076..ec17e4ce34cf0 100644 --- a/src/Symfony/Component/ExpressionLanguage/Tests/Node/BinaryNodeTest.php +++ b/src/Symfony/Component/ExpressionLanguage/Tests/Node/BinaryNodeTest.php @@ -173,7 +173,7 @@ public function testEvaluateMatchesWithInvalidRegexp() { $node = new BinaryNode('matches', new ConstantNode('abc'), new ConstantNode('this is not a regexp')); - $this->expectExceptionObject(new SyntaxError('Regexp "this is not a regexp" passed to "matches" is not valid: Delimiter must not be alphanumeric or backslash')); + $this->expectExceptionObject(new SyntaxError('Regexp "this is not a regexp" passed to "matches" is not valid: Delimiter must not be alphanumeric')); $node->evaluate([], []); } @@ -181,7 +181,7 @@ public function testEvaluateMatchesWithInvalidRegexpAsExpression() { $node = new BinaryNode('matches', new ConstantNode('abc'), new NameNode('regexp')); - $this->expectExceptionObject(new SyntaxError('Regexp "this is not a regexp" passed to "matches" is not valid: Delimiter must not be alphanumeric or backslash')); + $this->expectExceptionObject(new SyntaxError('Regexp "this is not a regexp" passed to "matches" is not valid: Delimiter must not be alphanumeric')); $node->evaluate([], ['regexp' => 'this is not a regexp']); } @@ -189,7 +189,7 @@ public function testCompileMatchesWithInvalidRegexp() { $node = new BinaryNode('matches', new ConstantNode('abc'), new ConstantNode('this is not a regexp')); - $this->expectExceptionObject(new SyntaxError('Regexp "this is not a regexp" passed to "matches" is not valid: Delimiter must not be alphanumeric or backslash')); + $this->expectExceptionObject(new SyntaxError('Regexp "this is not a regexp" passed to "matches" is not valid: Delimiter must not be alphanumeric')); $compiler = new Compiler([]); $node->compile($compiler); } @@ -198,7 +198,7 @@ public function testCompileMatchesWithInvalidRegexpAsExpression() { $node = new BinaryNode('matches', new ConstantNode('abc'), new NameNode('regexp')); - $this->expectExceptionObject(new SyntaxError('Regexp "this is not a regexp" passed to "matches" is not valid: Delimiter must not be alphanumeric or backslash')); + $this->expectExceptionObject(new SyntaxError('Regexp "this is not a regexp" passed to "matches" is not valid: Delimiter must not be alphanumeric')); $compiler = new Compiler([]); $node->compile($compiler); eval('$regexp = "this is not a regexp"; '.$compiler->getSource().';'); From e28d378a4fdcc6e4385f08799d6a5f77e1c795ea Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Sun, 19 Jun 2022 11:33:27 +0200 Subject: [PATCH 16/44] [ExpressionLanguage] fix tests (bis) --- .../ExpressionLanguage/Tests/Node/BinaryNodeTest.php | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/src/Symfony/Component/ExpressionLanguage/Tests/Node/BinaryNodeTest.php b/src/Symfony/Component/ExpressionLanguage/Tests/Node/BinaryNodeTest.php index ec17e4ce34cf0..fe3115a225df9 100644 --- a/src/Symfony/Component/ExpressionLanguage/Tests/Node/BinaryNodeTest.php +++ b/src/Symfony/Component/ExpressionLanguage/Tests/Node/BinaryNodeTest.php @@ -173,7 +173,8 @@ public function testEvaluateMatchesWithInvalidRegexp() { $node = new BinaryNode('matches', new ConstantNode('abc'), new ConstantNode('this is not a regexp')); - $this->expectExceptionObject(new SyntaxError('Regexp "this is not a regexp" passed to "matches" is not valid: Delimiter must not be alphanumeric')); + $this->expectException(SyntaxError::class); + $this->expectExceptionMessage('Regexp "this is not a regexp" passed to "matches" is not valid: Delimiter must not be alphanumeric'); $node->evaluate([], []); } @@ -181,7 +182,8 @@ public function testEvaluateMatchesWithInvalidRegexpAsExpression() { $node = new BinaryNode('matches', new ConstantNode('abc'), new NameNode('regexp')); - $this->expectExceptionObject(new SyntaxError('Regexp "this is not a regexp" passed to "matches" is not valid: Delimiter must not be alphanumeric')); + $this->expectException(SyntaxError::class); + $this->expectExceptionMessage('Regexp "this is not a regexp" passed to "matches" is not valid: Delimiter must not be alphanumeric'); $node->evaluate([], ['regexp' => 'this is not a regexp']); } @@ -189,7 +191,8 @@ public function testCompileMatchesWithInvalidRegexp() { $node = new BinaryNode('matches', new ConstantNode('abc'), new ConstantNode('this is not a regexp')); - $this->expectExceptionObject(new SyntaxError('Regexp "this is not a regexp" passed to "matches" is not valid: Delimiter must not be alphanumeric')); + $this->expectException(SyntaxError::class); + $this->expectExceptionMessage('Regexp "this is not a regexp" passed to "matches" is not valid: Delimiter must not be alphanumeric'); $compiler = new Compiler([]); $node->compile($compiler); } @@ -198,7 +201,8 @@ public function testCompileMatchesWithInvalidRegexpAsExpression() { $node = new BinaryNode('matches', new ConstantNode('abc'), new NameNode('regexp')); - $this->expectExceptionObject(new SyntaxError('Regexp "this is not a regexp" passed to "matches" is not valid: Delimiter must not be alphanumeric')); + $this->expectException(SyntaxError::class); + $this->expectExceptionMessage('Regexp "this is not a regexp" passed to "matches" is not valid: Delimiter must not be alphanumeric'); $compiler = new Compiler([]); $node->compile($compiler); eval('$regexp = "this is not a regexp"; '.$compiler->getSource().';'); From b14aa77e4debf903507899bb85ec6015a7382cad Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Sun, 19 Jun 2022 13:27:12 +0200 Subject: [PATCH 17/44] [Cache] Respect $save option in ChainAdapter --- src/Symfony/Component/Cache/Adapter/ChainAdapter.php | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/src/Symfony/Component/Cache/Adapter/ChainAdapter.php b/src/Symfony/Component/Cache/Adapter/ChainAdapter.php index 39d9afd0e057d..257b0734095d5 100644 --- a/src/Symfony/Component/Cache/Adapter/ChainAdapter.php +++ b/src/Symfony/Component/Cache/Adapter/ChainAdapter.php @@ -91,9 +91,17 @@ static function ($sourceItem, $item, $sourceMetadata = null) use ($defaultLifeti */ public function get(string $key, callable $callback, float $beta = null, array &$metadata = null) { + $doSave = true; + $callback = static function (CacheItem $item, bool &$save) use ($callback, &$doSave) { + $value = $callback($item, $save); + $doSave = $save; + + return $value; + }; + $lastItem = null; $i = 0; - $wrap = function (CacheItem $item = null) use ($key, $callback, $beta, &$wrap, &$i, &$lastItem, &$metadata) { + $wrap = function (CacheItem $item = null, bool &$save = true) use ($key, $callback, $beta, &$wrap, &$i, &$doSave, &$lastItem, &$metadata) { $adapter = $this->adapters[$i]; if (isset($this->adapters[++$i])) { $callback = $wrap; @@ -107,6 +115,7 @@ public function get(string $key, callable $callback, float $beta = null, array & if (null !== $item) { ($this->syncItem)($lastItem = $lastItem ?? $item, $item, $metadata); } + $save = $doSave; return $value; }; From 79239feaab194c32b39680da3f9adcd1e949ea21 Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Sun, 19 Jun 2022 13:38:50 +0200 Subject: [PATCH 18/44] CS fix --- .../Doctrine/Form/DoctrineOrmTypeGuesser.php | 5 ----- .../PropertyInfo/DoctrineExtractor.php | 19 +------------------ .../Form/Extension/Core/Type/FileType.php | 3 --- .../Component/Form/Util/ServerParams.php | 3 --- .../HttpFoundation/File/UploadedFile.php | 3 --- .../DataCollector/MemoryDataCollector.php | 3 --- .../Command/ConsumeMessagesCommand.php | 3 --- 7 files changed, 1 insertion(+), 38 deletions(-) diff --git a/src/Symfony/Bridge/Doctrine/Form/DoctrineOrmTypeGuesser.php b/src/Symfony/Bridge/Doctrine/Form/DoctrineOrmTypeGuesser.php index 944c305ab70a7..c5ff1aa3674f1 100644 --- a/src/Symfony/Bridge/Doctrine/Form/DoctrineOrmTypeGuesser.php +++ b/src/Symfony/Bridge/Doctrine/Form/DoctrineOrmTypeGuesser.php @@ -60,15 +60,12 @@ public function guessType($class, $property) switch ($metadata->getTypeOfField($property)) { case self::$useDeprecatedConstants ? Type::TARRAY : Types::ARRAY: - // no break case self::$useDeprecatedConstants ? Type::SIMPLE_ARRAY : Types::SIMPLE_ARRAY: return new TypeGuess('Symfony\Component\Form\Extension\Core\Type\CollectionType', [], Guess::MEDIUM_CONFIDENCE); case self::$useDeprecatedConstants ? Type::BOOLEAN : Types::BOOLEAN: return new TypeGuess('Symfony\Component\Form\Extension\Core\Type\CheckboxType', [], Guess::HIGH_CONFIDENCE); case self::$useDeprecatedConstants ? Type::DATETIME : Types::DATETIME_MUTABLE: - // no break case self::$useDeprecatedConstants ? Type::DATETIMETZ : Types::DATETIMETZ_MUTABLE: - // no break case 'vardatetime': return new TypeGuess('Symfony\Component\Form\Extension\Core\Type\DateTimeType', [], Guess::HIGH_CONFIDENCE); case 'datetime_immutable': @@ -89,9 +86,7 @@ public function guessType($class, $property) case self::$useDeprecatedConstants ? Type::FLOAT : Types::FLOAT: return new TypeGuess('Symfony\Component\Form\Extension\Core\Type\NumberType', [], Guess::MEDIUM_CONFIDENCE); case self::$useDeprecatedConstants ? Type::INTEGER : Types::INTEGER: - // no break case self::$useDeprecatedConstants ? Type::BIGINT : Types::BIGINT: - // no break case self::$useDeprecatedConstants ? Type::SMALLINT : Types::SMALLINT: return new TypeGuess('Symfony\Component\Form\Extension\Core\Type\IntegerType', [], Guess::MEDIUM_CONFIDENCE); case self::$useDeprecatedConstants ? Type::STRING : Types::STRING: diff --git a/src/Symfony/Bridge/Doctrine/PropertyInfo/DoctrineExtractor.php b/src/Symfony/Bridge/Doctrine/PropertyInfo/DoctrineExtractor.php index 8ebd5fbe00b34..c0528defcd9e7 100644 --- a/src/Symfony/Bridge/Doctrine/PropertyInfo/DoctrineExtractor.php +++ b/src/Symfony/Bridge/Doctrine/PropertyInfo/DoctrineExtractor.php @@ -168,11 +168,8 @@ public function getTypes($class, $property, array $context = []) case Type::BUILTIN_TYPE_OBJECT: switch ($typeOfField) { case self::$useDeprecatedConstants ? DBALType::DATE : Types::DATE_MUTABLE: - // no break case self::$useDeprecatedConstants ? DBALType::DATETIME : Types::DATETIME_MUTABLE: - // no break case self::$useDeprecatedConstants ? DBALType::DATETIMETZ : Types::DATETIMETZ_MUTABLE: - // no break case 'vardatetime': case self::$useDeprecatedConstants ? DBALType::TIME : Types::TIME_MUTABLE: return [new Type(Type::BUILTIN_TYPE_OBJECT, $nullable, 'DateTime')]; @@ -191,7 +188,6 @@ public function getTypes($class, $property, array $context = []) case Type::BUILTIN_TYPE_ARRAY: switch ($typeOfField) { case self::$useDeprecatedConstants ? DBALType::TARRAY : Types::ARRAY: - // no break case 'json_array': // return null if $enumType is set, because we can't determine if collectionKeyType is string or int if ($enumType) { @@ -208,7 +204,7 @@ public function getTypes($class, $property, array $context = []) if ($enumType !== null) { return [$enumType]; } - // no break + break; } return [new Type($builtinType, $nullable)]; @@ -282,7 +278,6 @@ private function getPhpType(string $doctrineType): ?string { switch ($doctrineType) { case self::$useDeprecatedConstants ? DBALType::SMALLINT : Types::SMALLINT: - // no break case self::$useDeprecatedConstants ? DBALType::INTEGER : Types::INTEGER: return Type::BUILTIN_TYPE_INT; @@ -290,13 +285,9 @@ private function getPhpType(string $doctrineType): ?string return Type::BUILTIN_TYPE_FLOAT; case self::$useDeprecatedConstants ? DBALType::BIGINT : Types::BIGINT: - // no break case self::$useDeprecatedConstants ? DBALType::STRING : Types::STRING: - // no break case self::$useDeprecatedConstants ? DBALType::TEXT : Types::TEXT: - // no break case self::$useDeprecatedConstants ? DBALType::GUID : Types::GUID: - // no break case self::$useDeprecatedConstants ? DBALType::DECIMAL : Types::DECIMAL: return Type::BUILTIN_TYPE_STRING; @@ -304,21 +295,15 @@ private function getPhpType(string $doctrineType): ?string return Type::BUILTIN_TYPE_BOOL; case self::$useDeprecatedConstants ? DBALType::BLOB : Types::BLOB: - // no break case 'binary': return Type::BUILTIN_TYPE_RESOURCE; case self::$useDeprecatedConstants ? DBALType::OBJECT : Types::OBJECT: - // no break case self::$useDeprecatedConstants ? DBALType::DATE : Types::DATE_MUTABLE: - // no break case self::$useDeprecatedConstants ? DBALType::DATETIME : Types::DATETIME_MUTABLE: - // no break case self::$useDeprecatedConstants ? DBALType::DATETIMETZ : Types::DATETIMETZ_MUTABLE: - // no break case 'vardatetime': case self::$useDeprecatedConstants ? DBALType::TIME : Types::TIME_MUTABLE: - // no break case 'date_immutable': case 'datetime_immutable': case 'datetimetz_immutable': @@ -327,9 +312,7 @@ private function getPhpType(string $doctrineType): ?string return Type::BUILTIN_TYPE_OBJECT; case self::$useDeprecatedConstants ? DBALType::TARRAY : Types::ARRAY: - // no break case self::$useDeprecatedConstants ? DBALType::SIMPLE_ARRAY : Types::SIMPLE_ARRAY: - // no break case 'json_array': return Type::BUILTIN_TYPE_ARRAY; } diff --git a/src/Symfony/Component/Form/Extension/Core/Type/FileType.php b/src/Symfony/Component/Form/Extension/Core/Type/FileType.php index 343fc76d475e0..b610d4c65edc3 100644 --- a/src/Symfony/Component/Form/Extension/Core/Type/FileType.php +++ b/src/Symfony/Component/Form/Extension/Core/Type/FileType.php @@ -200,11 +200,8 @@ private static function getMaxFilesize() switch (substr($iniMax, -1)) { case 't': $max *= 1024; - // no break case 'g': $max *= 1024; - // no break case 'm': $max *= 1024; - // no break case 'k': $max *= 1024; } diff --git a/src/Symfony/Component/Form/Util/ServerParams.php b/src/Symfony/Component/Form/Util/ServerParams.php index b6ce9d1065617..446e9cfed3707 100644 --- a/src/Symfony/Component/Form/Util/ServerParams.php +++ b/src/Symfony/Component/Form/Util/ServerParams.php @@ -62,11 +62,8 @@ public function getPostMaxSize() switch (substr($iniMax, -1)) { case 't': $max *= 1024; - // no break case 'g': $max *= 1024; - // no break case 'm': $max *= 1024; - // no break case 'k': $max *= 1024; } diff --git a/src/Symfony/Component/HttpFoundation/File/UploadedFile.php b/src/Symfony/Component/HttpFoundation/File/UploadedFile.php index 6e035a55cdcb0..3e482b8a830fa 100644 --- a/src/Symfony/Component/HttpFoundation/File/UploadedFile.php +++ b/src/Symfony/Component/HttpFoundation/File/UploadedFile.php @@ -273,11 +273,8 @@ private static function parseFilesize(string $size) switch (substr($size, -1)) { case 't': $max *= 1024; - // no break case 'g': $max *= 1024; - // no break case 'm': $max *= 1024; - // no break case 'k': $max *= 1024; } diff --git a/src/Symfony/Component/HttpKernel/DataCollector/MemoryDataCollector.php b/src/Symfony/Component/HttpKernel/DataCollector/MemoryDataCollector.php index ff0ccd9fa9eb3..7119bf31ada8a 100644 --- a/src/Symfony/Component/HttpKernel/DataCollector/MemoryDataCollector.php +++ b/src/Symfony/Component/HttpKernel/DataCollector/MemoryDataCollector.php @@ -114,11 +114,8 @@ private function convertToBytes(string $memoryLimit) switch (substr($memoryLimit, -1)) { case 't': $max *= 1024; - // no break case 'g': $max *= 1024; - // no break case 'm': $max *= 1024; - // no break case 'k': $max *= 1024; } diff --git a/src/Symfony/Component/Messenger/Command/ConsumeMessagesCommand.php b/src/Symfony/Component/Messenger/Command/ConsumeMessagesCommand.php index defa1a4385b64..8873f43cd44e8 100644 --- a/src/Symfony/Component/Messenger/Command/ConsumeMessagesCommand.php +++ b/src/Symfony/Component/Messenger/Command/ConsumeMessagesCommand.php @@ -219,11 +219,8 @@ private function convertToBytes(string $memoryLimit): int switch (substr(rtrim($memoryLimit, 'b'), -1)) { case 't': $max *= 1024; - // no break case 'g': $max *= 1024; - // no break case 'm': $max *= 1024; - // no break case 'k': $max *= 1024; } From bd623b9466aa0e4e18fecfeb930c9e0ea0ecd4f0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tam=C3=A1s=20Nagy=20=28T-bond=29?= Date: Sun, 27 Mar 2022 01:51:41 +0100 Subject: [PATCH 19/44] [Serializer] Try all possible denormalization route with union types when ALLOW_EXTRA_ATTRIBUTES=false --- .../Normalizer/AbstractObjectNormalizer.php | 15 ++++- .../Serializer/Tests/SerializerTest.php | 55 +++++++++++++++++++ 2 files changed, 69 insertions(+), 1 deletion(-) diff --git a/src/Symfony/Component/Serializer/Normalizer/AbstractObjectNormalizer.php b/src/Symfony/Component/Serializer/Normalizer/AbstractObjectNormalizer.php index 5977d994987c4..36198fcb5468f 100644 --- a/src/Symfony/Component/Serializer/Normalizer/AbstractObjectNormalizer.php +++ b/src/Symfony/Component/Serializer/Normalizer/AbstractObjectNormalizer.php @@ -370,7 +370,7 @@ public function denormalize($data, $type, $format = null, array $context = []) } } - if (!empty($extraAttributes)) { + if ($extraAttributes) { throw new ExtraAttributesException($extraAttributes); } @@ -405,6 +405,7 @@ private function validateAndDenormalize(string $currentClass, string $attribute, $expectedTypes = []; $isUnionType = \count($types) > 1; + $extraAttributesException = null; foreach ($types as $type) { if (null === $data && $type->isNullable()) { return null; @@ -494,9 +495,21 @@ private function validateAndDenormalize(string $currentClass, string $attribute, if (!$isUnionType) { throw $e; } + } catch (ExtraAttributesException $e) { + if (!$isUnionType) { + throw $e; + } + + if (!$extraAttributesException) { + $extraAttributesException = $e; + } } } + if ($extraAttributesException) { + throw $extraAttributesException; + } + if ($context[self::DISABLE_TYPE_ENFORCEMENT] ?? $this->defaultContext[self::DISABLE_TYPE_ENFORCEMENT] ?? false) { return $data; } diff --git a/src/Symfony/Component/Serializer/Tests/SerializerTest.php b/src/Symfony/Component/Serializer/Tests/SerializerTest.php index 06eda94f53609..b5a0f19390f07 100644 --- a/src/Symfony/Component/Serializer/Tests/SerializerTest.php +++ b/src/Symfony/Component/Serializer/Tests/SerializerTest.php @@ -19,6 +19,7 @@ use Symfony\Component\Serializer\Encoder\DecoderInterface; use Symfony\Component\Serializer\Encoder\EncoderInterface; use Symfony\Component\Serializer\Encoder\JsonEncoder; +use Symfony\Component\Serializer\Exception\ExtraAttributesException; use Symfony\Component\Serializer\Exception\InvalidArgumentException; use Symfony\Component\Serializer\Exception\LogicException; use Symfony\Component\Serializer\Exception\NotNormalizableValueException; @@ -31,6 +32,7 @@ use Symfony\Component\Serializer\Mapping\Factory\ClassMetadataFactory; use Symfony\Component\Serializer\Mapping\Factory\ClassMetadataFactoryInterface; use Symfony\Component\Serializer\Mapping\Loader\AnnotationLoader; +use Symfony\Component\Serializer\Normalizer\AbstractNormalizer; use Symfony\Component\Serializer\Normalizer\AbstractObjectNormalizer; use Symfony\Component\Serializer\Normalizer\ArrayDenormalizer; use Symfony\Component\Serializer\Normalizer\CustomNormalizer; @@ -573,6 +575,35 @@ public function testUnionTypeDeserializable() $this->assertEquals(new DummyUnionType(), $actual, 'Union type denormalization third case failed.'); } + public function testUnionTypeDeserializableWithoutAllowedExtraAttributes() + { + $classMetadataFactory = new ClassMetadataFactory(new AnnotationLoader(new AnnotationReader())); + $extractor = new PropertyInfoExtractor([], [new PhpDocExtractor(), new ReflectionExtractor()]); + $serializer = new Serializer( + [ + new ObjectNormalizer($classMetadataFactory, null, null, $extractor, new ClassDiscriminatorFromClassMetadata($classMetadataFactory)), + ], + ['json' => new JsonEncoder()] + ); + + $actual = $serializer->deserialize('{ "v": { "a": 0 }}', DummyUnionWithAAndB::class, 'json', [ + AbstractNormalizer::ALLOW_EXTRA_ATTRIBUTES => false, + ]); + + $this->assertEquals(new DummyUnionWithAAndB(new DummyATypeForUnion()), $actual); + + $actual = $serializer->deserialize('{ "v": { "b": 1 }}', DummyUnionWithAAndB::class, 'json', [ + AbstractNormalizer::ALLOW_EXTRA_ATTRIBUTES => false, + ]); + + $this->assertEquals(new DummyUnionWithAAndB(new DummyBTypeForUnion()), $actual); + + $this->expectException(ExtraAttributesException::class); + $serializer->deserialize('{ "v": { "b": 1, "c": "i am not allowed" }}', DummyUnionWithAAndB::class, 'json', [ + AbstractNormalizer::ALLOW_EXTRA_ATTRIBUTES => false, + ]); + } + /** * @requires PHP 8.2 */ @@ -678,6 +709,30 @@ public function setChanged($changed): self } } +class DummyATypeForUnion +{ + public $a = 0; +} + +class DummyBTypeForUnion +{ + public $b = 1; +} + +class DummyUnionWithAAndB +{ + /** @var DummyATypeForUnion|DummyBTypeForUnion */ + public $v; + + /** + * @param DummyATypeForUnion|DummyBTypeForUnion $v + */ + public function __construct($v) + { + $this->v = $v; + } +} + interface NormalizerAwareNormalizer extends NormalizerInterface, NormalizerAwareInterface { } From 7fc7acb1e4448762f438af03cadb2ce54e3918e0 Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Sun, 19 Jun 2022 13:59:55 +0200 Subject: [PATCH 20/44] [PropertyInfo] CS fix --- src/Symfony/Bridge/Doctrine/PropertyInfo/DoctrineExtractor.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Symfony/Bridge/Doctrine/PropertyInfo/DoctrineExtractor.php b/src/Symfony/Bridge/Doctrine/PropertyInfo/DoctrineExtractor.php index c0528defcd9e7..681aa24e327a9 100644 --- a/src/Symfony/Bridge/Doctrine/PropertyInfo/DoctrineExtractor.php +++ b/src/Symfony/Bridge/Doctrine/PropertyInfo/DoctrineExtractor.php @@ -201,7 +201,7 @@ public function getTypes($class, $property, array $context = []) } case Type::BUILTIN_TYPE_INT: case Type::BUILTIN_TYPE_STRING: - if ($enumType !== null) { + if ($enumType) { return [$enumType]; } break; From 445b78a9b97fe4f551448c7c01313b8e6a4c346b Mon Sep 17 00:00:00 2001 From: Gigino Chianese Date: Sun, 19 Jun 2022 14:09:58 +0200 Subject: [PATCH 21/44] [DoctrineBridge] Add missing break --- src/Symfony/Bridge/Doctrine/PropertyInfo/DoctrineExtractor.php | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Symfony/Bridge/Doctrine/PropertyInfo/DoctrineExtractor.php b/src/Symfony/Bridge/Doctrine/PropertyInfo/DoctrineExtractor.php index 681aa24e327a9..0c7c48d1c0968 100644 --- a/src/Symfony/Bridge/Doctrine/PropertyInfo/DoctrineExtractor.php +++ b/src/Symfony/Bridge/Doctrine/PropertyInfo/DoctrineExtractor.php @@ -199,6 +199,7 @@ public function getTypes($class, $property, array $context = []) case self::$useDeprecatedConstants ? DBALType::SIMPLE_ARRAY : Types::SIMPLE_ARRAY: return [new Type(Type::BUILTIN_TYPE_ARRAY, $nullable, null, true, new Type(Type::BUILTIN_TYPE_INT), $enumType ?? new Type(Type::BUILTIN_TYPE_STRING))]; } + break; case Type::BUILTIN_TYPE_INT: case Type::BUILTIN_TYPE_STRING: if ($enumType) { From 12e40a02b11f32ede046eda8c8769634f5044ca6 Mon Sep 17 00:00:00 2001 From: HypeMC Date: Sun, 19 Jun 2022 00:46:53 +0200 Subject: [PATCH 22/44] [HttpClient] Fix Copy as curl with base uri --- .../Component/HttpClient/CurlHttpClient.php | 2 +- .../DataCollector/HttpClientDataCollector.php | 7 +++---- .../HttpClient/Response/AmpResponse.php | 1 + .../HttpClient/Response/CurlResponse.php | 3 ++- .../HttpClient/Response/MockResponse.php | 1 + .../HttpClient/Response/NativeResponse.php | 1 + .../HttpClientDataCollectorTest.php | 16 ++++++++++++++++ 7 files changed, 25 insertions(+), 6 deletions(-) diff --git a/src/Symfony/Component/HttpClient/CurlHttpClient.php b/src/Symfony/Component/HttpClient/CurlHttpClient.php index 9aff84dbca73b..96c37a5cf6923 100644 --- a/src/Symfony/Component/HttpClient/CurlHttpClient.php +++ b/src/Symfony/Component/HttpClient/CurlHttpClient.php @@ -301,7 +301,7 @@ public function request(string $method, string $url, array $options = []): Respo } } - return $pushedResponse ?? new CurlResponse($this->multi, $ch, $options, $this->logger, $method, self::createRedirectResolver($options, $host, $port), CurlClientState::$curlVersion['version_number']); + return $pushedResponse ?? new CurlResponse($this->multi, $ch, $options, $this->logger, $method, self::createRedirectResolver($options, $host, $port), CurlClientState::$curlVersion['version_number'], $url); } /** diff --git a/src/Symfony/Component/HttpClient/DataCollector/HttpClientDataCollector.php b/src/Symfony/Component/HttpClient/DataCollector/HttpClientDataCollector.php index dc4b6762b87a7..3c8443eb0986e 100644 --- a/src/Symfony/Component/HttpClient/DataCollector/HttpClientDataCollector.php +++ b/src/Symfony/Component/HttpClient/DataCollector/HttpClientDataCollector.php @@ -178,8 +178,7 @@ private function getCurlCommand(array $trace): ?string return null; } - $debug = explode("\n", $trace['info']['debug']); - $url = self::mergeQueryString($trace['url'], $trace['options']['query'] ?? [], true); + $url = $trace['info']['original_url'] ?? $trace['info']['url'] ?? $trace['url']; $command = ['curl', '--compressed']; if (isset($trace['options']['resolve'])) { @@ -199,7 +198,7 @@ private function getCurlCommand(array $trace): ?string if (\is_string($body)) { try { $dataArg[] = '--data '.escapeshellarg($body); - } catch (\ValueError $e) { + } catch (\ValueError) { return null; } } elseif (\is_array($body)) { @@ -214,7 +213,7 @@ private function getCurlCommand(array $trace): ?string $dataArg = empty($dataArg) ? null : implode(' ', $dataArg); - foreach ($debug as $line) { + foreach (explode("\n", $trace['info']['debug']) as $line) { $line = substr($line, 0, -1); if (str_starts_with('< ', $line)) { diff --git a/src/Symfony/Component/HttpClient/Response/AmpResponse.php b/src/Symfony/Component/HttpClient/Response/AmpResponse.php index f5d0095ec97c6..f107ccfa6cf65 100644 --- a/src/Symfony/Component/HttpClient/Response/AmpResponse.php +++ b/src/Symfony/Component/HttpClient/Response/AmpResponse.php @@ -80,6 +80,7 @@ public function __construct(AmpClientState $multi, Request $request, array $opti $info['http_method'] = $request->getMethod(); $info['start_time'] = null; $info['redirect_url'] = null; + $info['original_url'] = $info['url']; $info['redirect_time'] = 0.0; $info['redirect_count'] = 0; $info['size_upload'] = 0.0; diff --git a/src/Symfony/Component/HttpClient/Response/CurlResponse.php b/src/Symfony/Component/HttpClient/Response/CurlResponse.php index 9a8abca522025..233198f3d78fd 100644 --- a/src/Symfony/Component/HttpClient/Response/CurlResponse.php +++ b/src/Symfony/Component/HttpClient/Response/CurlResponse.php @@ -43,7 +43,7 @@ final class CurlResponse implements ResponseInterface, StreamableInterface /** * @internal */ - public function __construct(CurlClientState $multi, \CurlHandle|string $ch, array $options = null, LoggerInterface $logger = null, string $method = 'GET', callable $resolveRedirect = null, int $curlVersion = null) + public function __construct(CurlClientState $multi, \CurlHandle|string $ch, array $options = null, LoggerInterface $logger = null, string $method = 'GET', callable $resolveRedirect = null, int $curlVersion = null, string $originalUrl = null) { $this->multi = $multi; @@ -69,6 +69,7 @@ public function __construct(CurlClientState $multi, \CurlHandle|string $ch, arra $this->info['user_data'] = $options['user_data'] ?? null; $this->info['max_duration'] = $options['max_duration'] ?? null; $this->info['start_time'] = $this->info['start_time'] ?? microtime(true); + $this->info['original_url'] = $originalUrl ?? $this->info['url'] ?? curl_getinfo($ch, \CURLINFO_EFFECTIVE_URL); $info = &$this->info; $headers = &$this->headers; $debugBuffer = $this->debugBuffer; diff --git a/src/Symfony/Component/HttpClient/Response/MockResponse.php b/src/Symfony/Component/HttpClient/Response/MockResponse.php index fe89cd18edbb5..044734a3b8d87 100644 --- a/src/Symfony/Component/HttpClient/Response/MockResponse.php +++ b/src/Symfony/Component/HttpClient/Response/MockResponse.php @@ -142,6 +142,7 @@ public static function fromRequest(string $method, string $url, array $options, $response->info['user_data'] = $options['user_data'] ?? null; $response->info['max_duration'] = $options['max_duration'] ?? null; $response->info['url'] = $url; + $response->info['original_url'] = $url; if ($mock instanceof self) { $mock->requestOptions = $response->requestOptions; diff --git a/src/Symfony/Component/HttpClient/Response/NativeResponse.php b/src/Symfony/Component/HttpClient/Response/NativeResponse.php index 077d8f9a8ddcc..ab0cf095908f7 100644 --- a/src/Symfony/Component/HttpClient/Response/NativeResponse.php +++ b/src/Symfony/Component/HttpClient/Response/NativeResponse.php @@ -66,6 +66,7 @@ public function __construct(NativeClientState $multi, $context, string $url, arr // Temporary resource to dechunk the response stream $this->buffer = fopen('php://temp', 'w+'); + $info['original_url'] = implode('', $info['url']); $info['user_data'] = $options['user_data']; $info['max_duration'] = $options['max_duration']; ++$multi->responseCount; diff --git a/src/Symfony/Component/HttpClient/Tests/DataCollector/HttpClientDataCollectorTest.php b/src/Symfony/Component/HttpClient/Tests/DataCollector/HttpClientDataCollectorTest.php index 863c91d3d68db..3a0dc64fbd97b 100755 --- a/src/Symfony/Component/HttpClient/Tests/DataCollector/HttpClientDataCollectorTest.php +++ b/src/Symfony/Component/HttpClient/Tests/DataCollector/HttpClientDataCollectorTest.php @@ -194,6 +194,22 @@ public function provideCurlRequests(): iterable --url %1$shttp://localhost:8057/json%1$s \\ --header %1$sAccept: */*%1$s \\ --header %1$sAccept-Encoding: gzip%1$s \\ + --header %1$sUser-Agent: Symfony HttpClient/Native%1$s', + ]; + yield 'GET with base uri' => [ + [ + 'method' => 'GET', + 'url' => '1', + 'options' => [ + 'base_uri' => 'http://localhost:8057/json/', + ], + ], + 'curl \\ + --compressed \\ + --request GET \\ + --url %1$shttp://localhost:8057/json/1%1$s \\ + --header %1$sAccept: */*%1$s \\ + --header %1$sAccept-Encoding: gzip%1$s \\ --header %1$sUser-Agent: Symfony HttpClient/Native%1$s', ]; yield 'GET with resolve' => [ From 12460fa0819c4b71c63148dd6a62466b1387c799 Mon Sep 17 00:00:00 2001 From: Alex Pott Date: Wed, 15 Jun 2022 09:12:29 +0100 Subject: [PATCH 23/44] [HttpFoundation] Update "[Session] Overwrite invalid session id" to only validate when files session storage is used --- .../Session/Storage/NativeSessionStorage.php | 2 +- .../Storage/NativeSessionStorageTest.php | 23 +++++++++++++++++-- 2 files changed, 22 insertions(+), 3 deletions(-) diff --git a/src/Symfony/Component/HttpFoundation/Session/Storage/NativeSessionStorage.php b/src/Symfony/Component/HttpFoundation/Session/Storage/NativeSessionStorage.php index 76ebfa08a482d..4caba27dbc2df 100644 --- a/src/Symfony/Component/HttpFoundation/Session/Storage/NativeSessionStorage.php +++ b/src/Symfony/Component/HttpFoundation/Session/Storage/NativeSessionStorage.php @@ -153,7 +153,7 @@ public function start() } $sessionId = $_COOKIE[session_name()] ?? null; - if ($sessionId && !preg_match('/^[a-zA-Z0-9,-]{22,}$/', $sessionId)) { + if ($sessionId && $this->saveHandler instanceof AbstractProxy && 'files' === $this->saveHandler->getSaveHandlerName() && !preg_match('/^[a-zA-Z0-9,-]{22,}$/', $sessionId)) { // the session ID in the header is invalid, create a new one session_id(session_create_id()); } diff --git a/src/Symfony/Component/HttpFoundation/Tests/Session/Storage/NativeSessionStorageTest.php b/src/Symfony/Component/HttpFoundation/Tests/Session/Storage/NativeSessionStorageTest.php index 776da2adc27f1..86b4dd505567b 100644 --- a/src/Symfony/Component/HttpFoundation/Tests/Session/Storage/NativeSessionStorageTest.php +++ b/src/Symfony/Component/HttpFoundation/Tests/Session/Storage/NativeSessionStorageTest.php @@ -294,12 +294,31 @@ public function testGetBagsOnceSessionStartedIsIgnored() $this->assertEquals($storage->getBag('flashes'), $bag); } - public function testRegenerateInvalidSessionId() + public function testRegenerateInvalidSessionIdForNativeFileSessionHandler() { $_COOKIE[session_name()] = '&~['; - $started = (new NativeSessionStorage())->start(); + session_id('&~['); + $storage = new NativeSessionStorage([], new NativeFileSessionHandler()); + $started = $storage->start(); $this->assertTrue($started); $this->assertMatchesRegularExpression('/^[a-zA-Z0-9,-]{22,}$/', session_id()); + $storage->save(); + + $_COOKIE[session_name()] = '&~['; + session_id('&~['); + $storage = new NativeSessionStorage([], new SessionHandlerProxy(new NativeFileSessionHandler())); + $started = $storage->start(); + + $this->assertTrue($started); + $this->assertMatchesRegularExpression('/^[a-zA-Z0-9,-]{22,}$/', session_id()); + $storage->save(); + + $_COOKIE[session_name()] = '&~['; + session_id('&~['); + $storage = new NativeSessionStorage([], new NullSessionHandler()); + $started = $storage->start(); + $this->assertTrue($started); + $this->assertSame('&~[', session_id()); } } From 4f96afe3ab077fb557d2fdd5e1e7fad8ec265ab2 Mon Sep 17 00:00:00 2001 From: mondrake Date: Sat, 18 Jun 2022 21:42:44 +0200 Subject: [PATCH 24/44] Exclude from baseline generation deprecations triggered in legacy test --- .../Bridge/PhpUnit/DeprecationErrorHandler/Configuration.php | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/Symfony/Bridge/PhpUnit/DeprecationErrorHandler/Configuration.php b/src/Symfony/Bridge/PhpUnit/DeprecationErrorHandler/Configuration.php index 4420ef3d0e46c..bc46e4f447912 100644 --- a/src/Symfony/Bridge/PhpUnit/DeprecationErrorHandler/Configuration.php +++ b/src/Symfony/Bridge/PhpUnit/DeprecationErrorHandler/Configuration.php @@ -170,6 +170,10 @@ public function tolerates(array $deprecationGroups) */ public function isBaselineDeprecation(Deprecation $deprecation) { + if ($deprecation->isLegacy()) { + return false; + } + if ($deprecation->originatesFromAnObject()) { $location = $deprecation->originatingClass().'::'.$deprecation->originatingMethod(); } else { From 07ec2de641a7acd10159c2a8a3b32e17c57d1579 Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Sun, 19 Jun 2022 15:24:10 +0200 Subject: [PATCH 25/44] [Messenger] CS fix --- .../Component/Messenger/EventListener/ResetServicesListener.php | 1 - src/Symfony/Component/Messenger/Worker.php | 1 - 2 files changed, 2 deletions(-) diff --git a/src/Symfony/Component/Messenger/EventListener/ResetServicesListener.php b/src/Symfony/Component/Messenger/EventListener/ResetServicesListener.php index dd170e0e433a1..d5266f3669f5e 100644 --- a/src/Symfony/Component/Messenger/EventListener/ResetServicesListener.php +++ b/src/Symfony/Component/Messenger/EventListener/ResetServicesListener.php @@ -15,7 +15,6 @@ use Symfony\Component\HttpKernel\DependencyInjection\ServicesResetter; use Symfony\Component\Messenger\Event\WorkerRunningEvent; use Symfony\Component\Messenger\Event\WorkerStoppedEvent; -use Symfony\Contracts\Service\ResetInterface; /** * @author Grégoire Pineau diff --git a/src/Symfony/Component/Messenger/Worker.php b/src/Symfony/Component/Messenger/Worker.php index 34473bac32267..754d1c1b1e75a 100644 --- a/src/Symfony/Component/Messenger/Worker.php +++ b/src/Symfony/Component/Messenger/Worker.php @@ -31,7 +31,6 @@ use Symfony\Component\Messenger\Transport\Receiver\QueueReceiverInterface; use Symfony\Component\Messenger\Transport\Receiver\ReceiverInterface; use Symfony\Contracts\EventDispatcher\EventDispatcherInterface; -use Symfony\Contracts\Service\ResetInterface; /** * @author Samuel Roze From caddb276441fc5c7c1b668b6c3383cdb5f5ce670 Mon Sep 17 00:00:00 2001 From: Christian Flothmann Date: Mon, 20 Jun 2022 10:12:38 +0200 Subject: [PATCH 26/44] [PhpUnitBridge] fix tests --- .../Bridge/PhpUnit/Tests/DeprecationErrorHandler/baseline.phpt | 1 + .../Bridge/PhpUnit/Tests/DeprecationErrorHandler/baseline2.phpt | 2 ++ .../Bridge/PhpUnit/Tests/DeprecationErrorHandler/baseline3.phpt | 2 +- .../Tests/DeprecationErrorHandler/generate_baseline.phpt | 1 + 4 files changed, 5 insertions(+), 1 deletion(-) diff --git a/src/Symfony/Bridge/PhpUnit/Tests/DeprecationErrorHandler/baseline.phpt b/src/Symfony/Bridge/PhpUnit/Tests/DeprecationErrorHandler/baseline.phpt index 533912c106cbd..83d448ea8ca7b 100644 --- a/src/Symfony/Bridge/PhpUnit/Tests/DeprecationErrorHandler/baseline.phpt +++ b/src/Symfony/Bridge/PhpUnit/Tests/DeprecationErrorHandler/baseline.phpt @@ -78,3 +78,4 @@ print "Cannot test baselineFile contents because it is generated in a shutdown f ?> --EXPECT-- Cannot test baselineFile contents because it is generated in a shutdown function registered by another shutdown function. +Legacy deprecation notices (1) diff --git a/src/Symfony/Bridge/PhpUnit/Tests/DeprecationErrorHandler/baseline2.phpt b/src/Symfony/Bridge/PhpUnit/Tests/DeprecationErrorHandler/baseline2.phpt index f520912694a1e..925d5c2384901 100644 --- a/src/Symfony/Bridge/PhpUnit/Tests/DeprecationErrorHandler/baseline2.phpt +++ b/src/Symfony/Bridge/PhpUnit/Tests/DeprecationErrorHandler/baseline2.phpt @@ -66,6 +66,8 @@ $foo->testLegacyFoo(); $foo->testNonLegacyBar(); ?> --EXPECTF-- +Legacy deprecation notices (1) + Other deprecation notices (2) 1x: root deprecation diff --git a/src/Symfony/Bridge/PhpUnit/Tests/DeprecationErrorHandler/baseline3.phpt b/src/Symfony/Bridge/PhpUnit/Tests/DeprecationErrorHandler/baseline3.phpt index 28d1a74ffd427..d814c02b555b3 100644 --- a/src/Symfony/Bridge/PhpUnit/Tests/DeprecationErrorHandler/baseline3.phpt +++ b/src/Symfony/Bridge/PhpUnit/Tests/DeprecationErrorHandler/baseline3.phpt @@ -69,7 +69,7 @@ $foo->testLegacyFoo(); $foo->testNonLegacyBar(); ?> --EXPECTF-- -Legacy deprecation notices (1) +Legacy deprecation notices (2) Other deprecation notices (2) diff --git a/src/Symfony/Bridge/PhpUnit/Tests/DeprecationErrorHandler/generate_baseline.phpt b/src/Symfony/Bridge/PhpUnit/Tests/DeprecationErrorHandler/generate_baseline.phpt index 112a02b4c41a0..5b80791a15112 100644 --- a/src/Symfony/Bridge/PhpUnit/Tests/DeprecationErrorHandler/generate_baseline.phpt +++ b/src/Symfony/Bridge/PhpUnit/Tests/DeprecationErrorHandler/generate_baseline.phpt @@ -62,3 +62,4 @@ print "Cannot test baselineFile contents because it is generated in a shutdown f ?> --EXPECT-- Cannot test baselineFile contents because it is generated in a shutdown function registered by another shutdown function. +Legacy deprecation notices (1) From c5834becf38f3d0743f4038ef82b9ffe744ee712 Mon Sep 17 00:00:00 2001 From: Andreas Hennings Date: Mon, 20 Jun 2022 05:03:35 +0200 Subject: [PATCH 27/44] [Yaml] Enhance coverage in yaml DumperTest. --- .../Component/Yaml/Tests/DumperTest.php | 47 ++++++++++++------- 1 file changed, 30 insertions(+), 17 deletions(-) diff --git a/src/Symfony/Component/Yaml/Tests/DumperTest.php b/src/Symfony/Component/Yaml/Tests/DumperTest.php index 6329aec86ccff..2ebbbd047313c 100644 --- a/src/Symfony/Component/Yaml/Tests/DumperTest.php +++ b/src/Symfony/Component/Yaml/Tests/DumperTest.php @@ -28,7 +28,7 @@ class DumperTest extends TestCase '' => 'bar', 'foo' => '#bar', 'foo\'bar' => [], - 'bar' => [1, 'foo'], + 'bar' => [1, 'foo', ['a' => 'A']], 'foobar' => [ 'foo' => 'bar', 'bar' => [1, 'foo'], @@ -64,6 +64,8 @@ public function testIndentationInConstructor() bar: - 1 - foo + - + a: A foobar: foo: bar bar: @@ -107,7 +109,7 @@ public function testSpecifications() public function testInlineLevel() { $expected = <<<'EOF' -{ '': bar, foo: '#bar', 'foo''bar': { }, bar: [1, foo], foobar: { foo: bar, bar: [1, foo], foobar: { foo: bar, bar: [1, foo] } } } +{ '': bar, foo: '#bar', 'foo''bar': { }, bar: [1, foo, { a: A }], foobar: { foo: bar, bar: [1, foo], foobar: { foo: bar, bar: [1, foo] } } } EOF; $this->assertEquals($expected, $this->dumper->dump($this->array, -10), '->dump() takes an inline level argument'); $this->assertEquals($expected, $this->dumper->dump($this->array, 0), '->dump() takes an inline level argument'); @@ -116,7 +118,7 @@ public function testInlineLevel() '': bar foo: '#bar' 'foo''bar': { } -bar: [1, foo] +bar: [1, foo, { a: A }] foobar: { foo: bar, bar: [1, foo], foobar: { foo: bar, bar: [1, foo] } } EOF; @@ -129,6 +131,7 @@ public function testInlineLevel() bar: - 1 - foo + - { a: A } foobar: foo: bar bar: [1, foo] @@ -144,6 +147,8 @@ public function testInlineLevel() bar: - 1 - foo + - + a: A foobar: foo: bar bar: @@ -163,6 +168,8 @@ public function testInlineLevel() bar: - 1 - foo + - + a: A foobar: foo: bar bar: @@ -379,8 +386,9 @@ public function testDumpingTaggedValueSequenceRespectsInlineLevel() new TaggedValue('user', [ 'username' => 'jane', ]), - new TaggedValue('user', [ - 'username' => 'john', + new TaggedValue('names', [ + 'john', + 'claire', ]), ]; @@ -389,8 +397,9 @@ public function testDumpingTaggedValueSequenceRespectsInlineLevel() $expected = <<assertSame($expected, $yaml); @@ -402,8 +411,9 @@ public function testDumpingTaggedValueSequenceWithInlinedTagValues() new TaggedValue('user', [ 'username' => 'jane', ]), - new TaggedValue('user', [ - 'username' => 'john', + new TaggedValue('names', [ + 'john', + 'claire', ]), ]; @@ -411,7 +421,7 @@ public function testDumpingTaggedValueSequenceWithInlinedTagValues() $expected = <<assertSame($expected, $yaml); @@ -423,8 +433,9 @@ public function testDumpingTaggedValueMapRespectsInlineLevel() 'user1' => new TaggedValue('user', [ 'username' => 'jane', ]), - 'user2' => new TaggedValue('user', [ - 'username' => 'john', + 'names1' => new TaggedValue('names', [ + 'john', + 'claire', ]), ]; @@ -433,8 +444,9 @@ public function testDumpingTaggedValueMapRespectsInlineLevel() $expected = <<assertSame($expected, $yaml); @@ -446,8 +458,9 @@ public function testDumpingTaggedValueMapWithInlinedTagValues() 'user1' => new TaggedValue('user', [ 'username' => 'jane', ]), - 'user2' => new TaggedValue('user', [ - 'username' => 'john', + 'names1' => new TaggedValue('names', [ + 'john', + 'claire', ]), ]; @@ -455,7 +468,7 @@ public function testDumpingTaggedValueMapWithInlinedTagValues() $expected = <<assertSame($expected, $yaml); From 953c09c91998f7c6eb475ec19279d60eca11d622 Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Mon, 20 Jun 2022 13:50:03 +0200 Subject: [PATCH 28/44] Stick to PHPUnit 8.5.26 --- phpunit | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/phpunit b/phpunit index 7ca6ceeccbee8..e26fecd73cc9d 100755 --- a/phpunit +++ b/phpunit @@ -13,7 +13,7 @@ if (!getenv('SYMFONY_PHPUNIT_VERSION')) { if (\PHP_VERSION_ID < 70200) { putenv('SYMFONY_PHPUNIT_VERSION=7.5'); } elseif (\PHP_VERSION_ID < 70300) { - putenv('SYMFONY_PHPUNIT_VERSION=8.5'); + putenv('SYMFONY_PHPUNIT_VERSION=8.5.26'); } else { putenv('SYMFONY_PHPUNIT_VERSION=9.5'); } From 1041cb0777a8fcf33bbfc2db39e5fa571a69de2f Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Mon, 20 Jun 2022 16:16:33 +0200 Subject: [PATCH 29/44] [MonologBridge] fix tests --- .../Monolog/Tests/Handler/ElasticsearchLogstashHandlerTest.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/Symfony/Bridge/Monolog/Tests/Handler/ElasticsearchLogstashHandlerTest.php b/src/Symfony/Bridge/Monolog/Tests/Handler/ElasticsearchLogstashHandlerTest.php index 32a724c0a87d0..e3ef0f0bbb35c 100644 --- a/src/Symfony/Bridge/Monolog/Tests/Handler/ElasticsearchLogstashHandlerTest.php +++ b/src/Symfony/Bridge/Monolog/Tests/Handler/ElasticsearchLogstashHandlerTest.php @@ -84,7 +84,8 @@ public function testHandleWithElasticsearch8() return new MockResponse(); }; - $handler = new ElasticsearchLogstashHandlerWithHardCodedHostname('http://es:9200', 'log', new MockHttpClient($responseFactory), Logger::DEBUG, true, '8.0.0'); + $handler = new ElasticsearchLogstashHandler('http://es:9200', 'log', new MockHttpClient($responseFactory), Logger::DEBUG, true, '8.0.0'); + $handler->setFormatter($this->getDefaultFormatter()); $record = [ 'message' => 'My info message', From 637599095196f3eb3e0881ef64f35b0fe7ff5b7a Mon Sep 17 00:00:00 2001 From: Gigino Chianese Date: Mon, 20 Jun 2022 20:33:41 +0200 Subject: [PATCH 30/44] [DoctrineBridge] Fix value type for simple_array --- src/Symfony/Bridge/Doctrine/PropertyInfo/DoctrineExtractor.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Symfony/Bridge/Doctrine/PropertyInfo/DoctrineExtractor.php b/src/Symfony/Bridge/Doctrine/PropertyInfo/DoctrineExtractor.php index 79951e427d4b8..e01554cea6eca 100644 --- a/src/Symfony/Bridge/Doctrine/PropertyInfo/DoctrineExtractor.php +++ b/src/Symfony/Bridge/Doctrine/PropertyInfo/DoctrineExtractor.php @@ -180,7 +180,7 @@ public function getTypes(string $class, string $property, array $context = []) return [new Type(Type::BUILTIN_TYPE_ARRAY, $nullable, null, true)]; case Types::SIMPLE_ARRAY: - return [new Type(Type::BUILTIN_TYPE_ARRAY, $nullable, null, true, new Type(Type::BUILTIN_TYPE_INT), new Type(Type::BUILTIN_TYPE_STRING))]; + return [new Type(Type::BUILTIN_TYPE_ARRAY, $nullable, null, true, new Type(Type::BUILTIN_TYPE_INT), $enumType ?? new Type(Type::BUILTIN_TYPE_STRING))]; } break; case Type::BUILTIN_TYPE_INT: From 5149f0d1d850f3d569a2afca8ce6f21b77b867a0 Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Tue, 21 Jun 2022 10:28:57 +0200 Subject: [PATCH 31/44] [MonologBridge] fix tests --- .../Tests/Handler/ElasticsearchLogstashHandlerTest.php | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/src/Symfony/Bridge/Monolog/Tests/Handler/ElasticsearchLogstashHandlerTest.php b/src/Symfony/Bridge/Monolog/Tests/Handler/ElasticsearchLogstashHandlerTest.php index e3ef0f0bbb35c..3e8dde6d4bbda 100644 --- a/src/Symfony/Bridge/Monolog/Tests/Handler/ElasticsearchLogstashHandlerTest.php +++ b/src/Symfony/Bridge/Monolog/Tests/Handler/ElasticsearchLogstashHandlerTest.php @@ -87,15 +87,7 @@ public function testHandleWithElasticsearch8() $handler = new ElasticsearchLogstashHandler('http://es:9200', 'log', new MockHttpClient($responseFactory), Logger::DEBUG, true, '8.0.0'); $handler->setFormatter($this->getDefaultFormatter()); - $record = [ - 'message' => 'My info message', - 'context' => [], - 'level' => Logger::INFO, - 'level_name' => Logger::getLevelName(Logger::INFO), - 'channel' => 'app', - 'datetime' => new \DateTime('2020-01-01T00:00:00+01:00'), - 'extra' => [], - ]; + $record = RecordFactory::create(Logger::INFO, 'My info message', 'app', datetime: new \DateTimeImmutable('2020-01-01T00:00:00+01:00')); $handler->handle($record); From 22cd9cbc86b20985bd65a6f6e4fc2f020b0b0947 Mon Sep 17 00:00:00 2001 From: Damien ALEXANDRE Date: Tue, 21 Jun 2022 14:42:24 +0200 Subject: [PATCH 32/44] [Intl] Fix the IntlDateFormatter::formatObject signature --- src/Symfony/Component/Intl/DateFormatter/IntlDateFormatter.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Symfony/Component/Intl/DateFormatter/IntlDateFormatter.php b/src/Symfony/Component/Intl/DateFormatter/IntlDateFormatter.php index 4da012f52073c..9e31312517638 100644 --- a/src/Symfony/Component/Intl/DateFormatter/IntlDateFormatter.php +++ b/src/Symfony/Component/Intl/DateFormatter/IntlDateFormatter.php @@ -243,7 +243,7 @@ public function format($timestamp) * * @throws MethodNotImplementedException */ - public function formatObject($object, $format = null, $locale = null) + public static function formatObject($object, $format = null, $locale = null) { throw new MethodNotImplementedException(__METHOD__); } From f1604e60367438bffbddc26a559134ae27edfcfd Mon Sep 17 00:00:00 2001 From: Alexandre Jardin Date: Wed, 22 Jun 2022 09:18:33 +0200 Subject: [PATCH 33/44] [Messenger] Do not log the message object itself In order to avoid the leak of sensitive data (e.g. credentials) or the overflow of third-party services. --- .../EventListener/SendFailedMessageForRetryListener.php | 1 - .../Component/Messenger/Middleware/HandleMessageMiddleware.php | 1 - .../Component/Messenger/Middleware/SendMessageMiddleware.php | 1 - src/Symfony/Component/Messenger/Worker.php | 1 - 4 files changed, 4 deletions(-) diff --git a/src/Symfony/Component/Messenger/EventListener/SendFailedMessageForRetryListener.php b/src/Symfony/Component/Messenger/EventListener/SendFailedMessageForRetryListener.php index b355df8b7fcbf..dab74b203f795 100644 --- a/src/Symfony/Component/Messenger/EventListener/SendFailedMessageForRetryListener.php +++ b/src/Symfony/Component/Messenger/EventListener/SendFailedMessageForRetryListener.php @@ -56,7 +56,6 @@ public function onMessageFailed(WorkerMessageFailedEvent $event) $message = $envelope->getMessage(); $context = [ - 'message' => $message, 'class' => \get_class($message), ]; diff --git a/src/Symfony/Component/Messenger/Middleware/HandleMessageMiddleware.php b/src/Symfony/Component/Messenger/Middleware/HandleMessageMiddleware.php index 3daa659f7e86f..149f304467057 100644 --- a/src/Symfony/Component/Messenger/Middleware/HandleMessageMiddleware.php +++ b/src/Symfony/Component/Messenger/Middleware/HandleMessageMiddleware.php @@ -53,7 +53,6 @@ public function handle(Envelope $envelope, StackInterface $stack): Envelope $message = $envelope->getMessage(); $context = [ - 'message' => $message, 'class' => \get_class($message), ]; diff --git a/src/Symfony/Component/Messenger/Middleware/SendMessageMiddleware.php b/src/Symfony/Component/Messenger/Middleware/SendMessageMiddleware.php index 792eaa95f1063..669fe7652f86a 100644 --- a/src/Symfony/Component/Messenger/Middleware/SendMessageMiddleware.php +++ b/src/Symfony/Component/Messenger/Middleware/SendMessageMiddleware.php @@ -46,7 +46,6 @@ public function __construct(SendersLocatorInterface $sendersLocator, EventDispat public function handle(Envelope $envelope, StackInterface $stack): Envelope { $context = [ - 'message' => $envelope->getMessage(), 'class' => \get_class($envelope->getMessage()), ]; diff --git a/src/Symfony/Component/Messenger/Worker.php b/src/Symfony/Component/Messenger/Worker.php index 754d1c1b1e75a..33358d3d61b4d 100644 --- a/src/Symfony/Component/Messenger/Worker.php +++ b/src/Symfony/Component/Messenger/Worker.php @@ -208,7 +208,6 @@ private function ack(): bool if (null !== $this->logger) { $message = $envelope->getMessage(); $context = [ - 'message' => $message, 'class' => \get_class($message), ]; $this->logger->info('{class} was handled successfully (acknowledging to transport).', $context); From d2aaf51404dac043d8425a29d9c67045e8949947 Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Wed, 22 Jun 2022 17:01:38 +0200 Subject: [PATCH 34/44] =?UTF-8?q?=C2=B5cs=20fix?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../DependencyInjection/Tests/Dumper/PhpDumperTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Symfony/Component/DependencyInjection/Tests/Dumper/PhpDumperTest.php b/src/Symfony/Component/DependencyInjection/Tests/Dumper/PhpDumperTest.php index d5b0056efae54..059e83a71085b 100644 --- a/src/Symfony/Component/DependencyInjection/Tests/Dumper/PhpDumperTest.php +++ b/src/Symfony/Component/DependencyInjection/Tests/Dumper/PhpDumperTest.php @@ -805,7 +805,7 @@ public function testLazyArgumentProvideGenerator() switch (++$i) { case 0: $this->assertEquals('k1', $k); - $this->assertInstanceOf(\stdCLass::class, $v); + $this->assertInstanceOf(\stdClass::class, $v); break; case 1: $this->assertEquals('k2', $k); From f4c81f13caffb66d7ef383a7b1dc0b8f2cba1655 Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Thu, 23 Jun 2022 12:21:08 +0200 Subject: [PATCH 35/44] Fix global state pollution between tests run with ApplicationTester --- .../Console/Tester/ApplicationTester.php | 38 ++++++++++++++----- 1 file changed, 29 insertions(+), 9 deletions(-) diff --git a/src/Symfony/Component/Console/Tester/ApplicationTester.php b/src/Symfony/Component/Console/Tester/ApplicationTester.php index 4f99da18d5f8b..ce4e5c18dcaf6 100644 --- a/src/Symfony/Component/Console/Tester/ApplicationTester.php +++ b/src/Symfony/Component/Console/Tester/ApplicationTester.php @@ -54,17 +54,37 @@ public function __construct(Application $application) */ public function run(array $input, $options = []) { - $this->input = new ArrayInput($input); - if (isset($options['interactive'])) { - $this->input->setInteractive($options['interactive']); - } + $prevShellVerbosity = getenv('SHELL_VERBOSITY'); - if ($this->inputs) { - $this->input->setStream(self::createStream($this->inputs)); - } + try { + $this->input = new ArrayInput($input); + if (isset($options['interactive'])) { + $this->input->setInteractive($options['interactive']); + } - $this->initOutput($options); + if ($this->inputs) { + $this->input->setStream(self::createStream($this->inputs)); + } - return $this->statusCode = $this->application->run($this->input, $this->output); + $this->initOutput($options); + + return $this->statusCode = $this->application->run($this->input, $this->output); + } finally { + // SHELL_VERBOSITY is set by Application::configureIO so we need to unset/reset it + // to its previous value to avoid one test's verbosity to spread to the following tests + if (false === $prevShellVerbosity) { + if (\function_exists('putenv')) { + @putenv('SHELL_VERBOSITY'); + } + unset($_ENV['SHELL_VERBOSITY']); + unset($_SERVER['SHELL_VERBOSITY']); + } else { + if (\function_exists('putenv')) { + @putenv('SHELL_VERBOSITY='.$prevShellVerbosity); + } + $_ENV['SHELL_VERBOSITY'] = $prevShellVerbosity; + $_SERVER['SHELL_VERBOSITY'] = $prevShellVerbosity; + } + } } } From 4d44563a13dd57e55a926045e82e2ffda7b70f4c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?K=C3=A9vin=20Dunglas?= Date: Thu, 23 Jun 2022 13:46:06 +0200 Subject: [PATCH 36/44] [Security] Fix legacy impersonation system When using the legacy authentication system with a user class not implementing `EquatableInterface` (for instance, the default when using Sylius) a bug prevents the impersonation system to work properly. The switch is done correctly, but then the user is disconnected on the next request because `SecurityContext::hasUserChanged()` compares the roles of the token in session with the roles of the temporary token, and they aren't equal. `ROLE_PREVIOUS_ADMIN` is added in `SwitchUserListener::attemptSwitchUser()`, but then removed if the legacy system is still enabled in `UserAuthenticationProvider`. It looks like this bug has been introduced while deprecating support for role classes: https://github.com/symfony/symfony/commit/d64372df8c8d63e124d14de5c08fcbbb4674a12e#diff-914ec544d4f7b26fda540aea3d7bc57cc5057d76bfb9ad72047d77739e3bb5a3L115 This patch fixes the issue (tested on a real Sylius project). --- .../Authentication/Provider/UserAuthenticationProvider.php | 5 ++++- .../Provider/UserAuthenticationProviderTest.php | 1 + 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/src/Symfony/Component/Security/Core/Authentication/Provider/UserAuthenticationProvider.php b/src/Symfony/Component/Security/Core/Authentication/Provider/UserAuthenticationProvider.php index c038c769a553c..81731e8dd0b67 100644 --- a/src/Symfony/Component/Security/Core/Authentication/Provider/UserAuthenticationProvider.php +++ b/src/Symfony/Component/Security/Core/Authentication/Provider/UserAuthenticationProvider.php @@ -94,7 +94,10 @@ public function authenticate(TokenInterface $token) } if ($token instanceof SwitchUserToken) { - $authenticatedToken = new SwitchUserToken($user, $token->getCredentials(), $this->providerKey, $user->getRoles(), $token->getOriginalToken()); + $roles = $user->getRoles(); + $roles[] = 'ROLE_PREVIOUS_ADMIN'; + + $authenticatedToken = new SwitchUserToken($user, $token->getCredentials(), $this->providerKey, $roles, $token->getOriginalToken()); } else { $authenticatedToken = new UsernamePasswordToken($user, $token->getCredentials(), $this->providerKey, $user->getRoles()); } diff --git a/src/Symfony/Component/Security/Core/Tests/Authentication/Provider/UserAuthenticationProviderTest.php b/src/Symfony/Component/Security/Core/Tests/Authentication/Provider/UserAuthenticationProviderTest.php index c4bcd8f580100..446a04061d091 100644 --- a/src/Symfony/Component/Security/Core/Tests/Authentication/Provider/UserAuthenticationProviderTest.php +++ b/src/Symfony/Component/Security/Core/Tests/Authentication/Provider/UserAuthenticationProviderTest.php @@ -225,6 +225,7 @@ public function testAuthenticatePreservesOriginalToken() $this->assertSame($originalToken, $authToken->getOriginalToken()); $this->assertSame($user, $authToken->getUser()); $this->assertContains('ROLE_FOO', $authToken->getRoleNames()); + $this->assertContains('ROLE_PREVIOUS_ADMIN', $authToken->getRoleNames()); $this->assertEquals('foo', $authToken->getCredentials()); $this->assertEquals(['foo' => 'bar'], $authToken->getAttributes(), '->authenticate() copies token attributes'); } From 33fb1533c191739511f630418a787ea0ab95d414 Mon Sep 17 00:00:00 2001 From: Thibault Buathier Date: Fri, 24 Jun 2022 12:01:15 +0200 Subject: [PATCH 37/44] [Serializer] Fix denormalization union types with constructor --- .../Normalizer/AbstractObjectNormalizer.php | 16 ++++++++++ .../Serializer/Tests/SerializerTest.php | 32 ++++++++++++++----- 2 files changed, 40 insertions(+), 8 deletions(-) diff --git a/src/Symfony/Component/Serializer/Normalizer/AbstractObjectNormalizer.php b/src/Symfony/Component/Serializer/Normalizer/AbstractObjectNormalizer.php index 36198fcb5468f..fbe5d25d479a9 100644 --- a/src/Symfony/Component/Serializer/Normalizer/AbstractObjectNormalizer.php +++ b/src/Symfony/Component/Serializer/Normalizer/AbstractObjectNormalizer.php @@ -20,6 +20,7 @@ use Symfony\Component\Serializer\Encoder\XmlEncoder; use Symfony\Component\Serializer\Exception\ExtraAttributesException; use Symfony\Component\Serializer\Exception\LogicException; +use Symfony\Component\Serializer\Exception\MissingConstructorArgumentsException; use Symfony\Component\Serializer\Exception\NotNormalizableValueException; use Symfony\Component\Serializer\Exception\RuntimeException; use Symfony\Component\Serializer\Mapping\AttributeMetadataInterface; @@ -395,6 +396,8 @@ abstract protected function setAttributeValue($object, $attribute, $value, $form * @return mixed * * @throws NotNormalizableValueException + * @throws ExtraAttributesException + * @throws MissingConstructorArgumentsException * @throws LogicException */ private function validateAndDenormalize(string $currentClass, string $attribute, $data, ?string $format, array $context) @@ -406,6 +409,7 @@ private function validateAndDenormalize(string $currentClass, string $attribute, $expectedTypes = []; $isUnionType = \count($types) > 1; $extraAttributesException = null; + $missingConstructorArgumentException = null; foreach ($types as $type) { if (null === $data && $type->isNullable()) { return null; @@ -503,6 +507,14 @@ private function validateAndDenormalize(string $currentClass, string $attribute, if (!$extraAttributesException) { $extraAttributesException = $e; } + } catch (MissingConstructorArgumentsException $e) { + if (!$isUnionType) { + throw $e; + } + + if (!$missingConstructorArgumentException) { + $missingConstructorArgumentException = $e; + } } } @@ -510,6 +522,10 @@ private function validateAndDenormalize(string $currentClass, string $attribute, throw $extraAttributesException; } + if ($missingConstructorArgumentException) { + throw $missingConstructorArgumentException; + } + if ($context[self::DISABLE_TYPE_ENFORCEMENT] ?? $this->defaultContext[self::DISABLE_TYPE_ENFORCEMENT] ?? false) { return $data; } diff --git a/src/Symfony/Component/Serializer/Tests/SerializerTest.php b/src/Symfony/Component/Serializer/Tests/SerializerTest.php index b5a0f19390f07..df8732d29e342 100644 --- a/src/Symfony/Component/Serializer/Tests/SerializerTest.php +++ b/src/Symfony/Component/Serializer/Tests/SerializerTest.php @@ -586,20 +586,26 @@ public function testUnionTypeDeserializableWithoutAllowedExtraAttributes() ['json' => new JsonEncoder()] ); - $actual = $serializer->deserialize('{ "v": { "a": 0 }}', DummyUnionWithAAndB::class, 'json', [ + $actual = $serializer->deserialize('{ "v": { "a": 0 }}', DummyUnionWithAAndCAndB::class, 'json', [ AbstractNormalizer::ALLOW_EXTRA_ATTRIBUTES => false, ]); - $this->assertEquals(new DummyUnionWithAAndB(new DummyATypeForUnion()), $actual); + $this->assertEquals(new DummyUnionWithAAndCAndB(new DummyATypeForUnion()), $actual); - $actual = $serializer->deserialize('{ "v": { "b": 1 }}', DummyUnionWithAAndB::class, 'json', [ + $actual = $serializer->deserialize('{ "v": { "b": 1 }}', DummyUnionWithAAndCAndB::class, 'json', [ AbstractNormalizer::ALLOW_EXTRA_ATTRIBUTES => false, ]); - $this->assertEquals(new DummyUnionWithAAndB(new DummyBTypeForUnion()), $actual); + $this->assertEquals(new DummyUnionWithAAndCAndB(new DummyBTypeForUnion()), $actual); + + $actual = $serializer->deserialize('{ "v": { "c": 3 }}', DummyUnionWithAAndCAndB::class, 'json', [ + AbstractNormalizer::ALLOW_EXTRA_ATTRIBUTES => false, + ]); + + $this->assertEquals(new DummyUnionWithAAndCAndB(new DummyCTypeForUnion(3)), $actual); $this->expectException(ExtraAttributesException::class); - $serializer->deserialize('{ "v": { "b": 1, "c": "i am not allowed" }}', DummyUnionWithAAndB::class, 'json', [ + $serializer->deserialize('{ "v": { "b": 1, "d": "i am not allowed" }}', DummyUnionWithAAndCAndB::class, 'json', [ AbstractNormalizer::ALLOW_EXTRA_ATTRIBUTES => false, ]); } @@ -719,13 +725,23 @@ class DummyBTypeForUnion public $b = 1; } -class DummyUnionWithAAndB +class DummyCTypeForUnion +{ + public $c = 2; + + public function __construct($c) + { + $this->c = $c; + } +} + +class DummyUnionWithAAndCAndB { - /** @var DummyATypeForUnion|DummyBTypeForUnion */ + /** @var DummyATypeForUnion|DummyCTypeForUnion|DummyBTypeForUnion */ public $v; /** - * @param DummyATypeForUnion|DummyBTypeForUnion $v + * @param DummyATypeForUnion|DummyCTypeForUnion|DummyBTypeForUnion $v */ public function __construct($v) { From 71cafbc54c914217a9ff3d140d0cd8dda3ac751e Mon Sep 17 00:00:00 2001 From: Mark Ogilvie Date: Fri, 24 Jun 2022 12:57:32 +0100 Subject: [PATCH 38/44] Initially set user null. getUser is ?UserInterface return, but throws unset user exception. Typed property Symfony\Component\Security\Core\Exception\AccountStatusException::$user must not be accessed before initialization --- .../Security/Core/Exception/AccountStatusException.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Symfony/Component/Security/Core/Exception/AccountStatusException.php b/src/Symfony/Component/Security/Core/Exception/AccountStatusException.php index b3263cbca5fc3..76878f9ff2916 100644 --- a/src/Symfony/Component/Security/Core/Exception/AccountStatusException.php +++ b/src/Symfony/Component/Security/Core/Exception/AccountStatusException.php @@ -22,7 +22,7 @@ */ abstract class AccountStatusException extends AuthenticationException { - private UserInterface $user; + private ?UserInterface $user = null; /** * Get the user. From 640af5c7f046f327d2b71dd780cd6826b82565ce Mon Sep 17 00:00:00 2001 From: plfort Date: Thu, 23 Jun 2022 22:03:41 +0200 Subject: [PATCH 39/44] [HtmlSanitizer] Fix default configuration --- .../Resources/config/html_sanitizer.php | 2 +- .../Fixtures/php/html_sanitizer.php | 2 +- .../php/html_sanitizer_default_config.php | 5 +++ .../Fixtures/xml/html_sanitizer.xml | 2 +- .../xml/html_sanitizer_default_config.xml | 11 ++++++ .../Fixtures/yml/html_sanitizer.yml | 2 +- .../yml/html_sanitizer_default_config.yml | 3 ++ .../FrameworkExtensionTest.php | 38 +++++++++++++++---- 8 files changed, 53 insertions(+), 12 deletions(-) create mode 100644 src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/html_sanitizer_default_config.php create mode 100644 src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/html_sanitizer_default_config.xml create mode 100644 src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/html_sanitizer_default_config.yml diff --git a/src/Symfony/Bundle/FrameworkBundle/Resources/config/html_sanitizer.php b/src/Symfony/Bundle/FrameworkBundle/Resources/config/html_sanitizer.php index 9afb6326179fd..175dc2e23d0da 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Resources/config/html_sanitizer.php +++ b/src/Symfony/Bundle/FrameworkBundle/Resources/config/html_sanitizer.php @@ -18,7 +18,7 @@ return static function (ContainerConfigurator $container) { $container->services() ->set('html_sanitizer.config.default', HtmlSanitizerConfig::class) - ->call('allowSafeElements') + ->call('allowSafeElements', [], true) ->set('html_sanitizer.sanitizer.default', HtmlSanitizer::class) ->args([service('html_sanitizer.config.default')]) diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/html_sanitizer.php b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/html_sanitizer.php index 2c8e2eb165071..2d117e8380a45 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/html_sanitizer.php +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/html_sanitizer.php @@ -4,7 +4,7 @@ 'http_method_override' => false, 'html_sanitizer' => [ 'sanitizers' => [ - 'default' => [ + 'custom' => [ 'allow_safe_elements' => true, 'allow_static_elements' => true, 'allow_elements' => [ diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/html_sanitizer_default_config.php b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/html_sanitizer_default_config.php new file mode 100644 index 0000000000000..ae973a2db6b5c --- /dev/null +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/html_sanitizer_default_config.php @@ -0,0 +1,5 @@ +loadFromExtension('framework', [ + 'http_method_override' => false, + 'html_sanitizer' => null]); diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/html_sanitizer.xml b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/html_sanitizer.xml index a974ec6cab418..771652c8d1a28 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/html_sanitizer.xml +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/html_sanitizer.xml @@ -7,7 +7,7 @@ - + + + + + + + diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/html_sanitizer.yml b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/html_sanitizer.yml index 414fcfffcf5f1..007f4875b6f79 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/html_sanitizer.yml +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/html_sanitizer.yml @@ -2,7 +2,7 @@ framework: http_method_override: false html_sanitizer: sanitizers: - default: + custom: allow_safe_elements: true allow_static_elements: true allow_elements: diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/html_sanitizer_default_config.yml b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/html_sanitizer_default_config.yml new file mode 100644 index 0000000000000..94fff31d66886 --- /dev/null +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/html_sanitizer_default_config.yml @@ -0,0 +1,3 @@ +framework: + http_method_override: false + html_sanitizer: ~ diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/FrameworkExtensionTest.php b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/FrameworkExtensionTest.php index 1ee7b36229e0d..3347a16877b88 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/FrameworkExtensionTest.php +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/FrameworkExtensionTest.php @@ -2050,16 +2050,14 @@ public function testHtmlSanitizer() $container = $this->createContainerFromFile('html_sanitizer'); // html_sanitizer service - $this->assertTrue($container->hasAlias('html_sanitizer'), '->registerHtmlSanitizerConfiguration() loads html_sanitizer.php'); - $this->assertSame('html_sanitizer.sanitizer.default', (string) $container->getAlias('html_sanitizer')); - $this->assertSame(HtmlSanitizer::class, $container->getDefinition('html_sanitizer.sanitizer.default')->getClass()); - $this->assertCount(1, $args = $container->getDefinition('html_sanitizer.sanitizer.default')->getArguments()); - $this->assertSame('html_sanitizer.config.default', (string) $args[0]); + $this->assertSame(HtmlSanitizer::class, $container->getDefinition('html_sanitizer.sanitizer.custom')->getClass()); + $this->assertCount(1, $args = $container->getDefinition('html_sanitizer.sanitizer.custom')->getArguments()); + $this->assertSame('html_sanitizer.config.custom', (string) $args[0]); // config - $this->assertTrue($container->hasDefinition('html_sanitizer.config.default'), '->registerHtmlSanitizerConfiguration() loads custom sanitizer'); - $this->assertSame(HtmlSanitizerConfig::class, $container->getDefinition('html_sanitizer.config.default')->getClass()); - $this->assertCount(23, $calls = $container->getDefinition('html_sanitizer.config.default')->getMethodCalls()); + $this->assertTrue($container->hasDefinition('html_sanitizer.config.custom'), '->registerHtmlSanitizerConfiguration() loads custom sanitizer'); + $this->assertSame(HtmlSanitizerConfig::class, $container->getDefinition('html_sanitizer.config.custom')->getClass()); + $this->assertCount(23, $calls = $container->getDefinition('html_sanitizer.config.custom')->getMethodCalls()); $this->assertSame( [ ['allowSafeElements', [], true], @@ -2103,6 +2101,30 @@ static function ($call) { // Named alias $this->assertSame('html_sanitizer.sanitizer.all.sanitizer', (string) $container->getAlias(HtmlSanitizerInterface::class.' $allSanitizer')); $this->assertFalse($container->hasAlias(HtmlSanitizerInterface::class.' $default')); + } + + public function testHtmlSanitizerDefaultConfig() + { + $container = $this->createContainerFromFile('html_sanitizer_default_config'); + + // html_sanitizer service + $this->assertTrue($container->hasAlias('html_sanitizer'), '->registerHtmlSanitizerConfiguration() loads default_config'); + $this->assertSame('html_sanitizer.sanitizer.default', (string) $container->getAlias('html_sanitizer')); + $this->assertSame(HtmlSanitizer::class, $container->getDefinition('html_sanitizer.sanitizer.default')->getClass()); + $this->assertCount(1, $args = $container->getDefinition('html_sanitizer.sanitizer.default')->getArguments()); + $this->assertSame('html_sanitizer.config.default', (string) $args[0]); + + // config + $this->assertTrue($container->hasDefinition('html_sanitizer.config.default'), '->registerHtmlSanitizerConfiguration() loads custom sanitizer'); + $this->assertSame(HtmlSanitizerConfig::class, $container->getDefinition('html_sanitizer.config.default')->getClass()); + $this->assertCount(1, $calls = $container->getDefinition('html_sanitizer.config.default')->getMethodCalls()); + $this->assertSame( + ['allowSafeElements', [], true], + $calls[0] + ); + + // Named alias + $this->assertFalse($container->hasAlias(HtmlSanitizerInterface::class.' $default')); // Default alias $this->assertSame('html_sanitizer', (string) $container->getAlias(HtmlSanitizerInterface::class)); From 4dff49ff34d0e3037ba1957a5a5d2e34847a6055 Mon Sep 17 00:00:00 2001 From: Andreas Heigl Date: Fri, 24 Jun 2022 09:03:23 +0200 Subject: [PATCH 40/44] Fix double authentication via RememberMe resulting in wrong RememberMe cookie being set in client --- .../PersistentRememberMeHandler.php | 1 + .../PersistentRememberMeHandlerTest.php | 37 +++++++++++++++++++ 2 files changed, 38 insertions(+) diff --git a/src/Symfony/Component/Security/Http/RememberMe/PersistentRememberMeHandler.php b/src/Symfony/Component/Security/Http/RememberMe/PersistentRememberMeHandler.php index 191d2ede852b8..8a5db07e5e8ab 100644 --- a/src/Symfony/Component/Security/Http/RememberMe/PersistentRememberMeHandler.php +++ b/src/Symfony/Component/Security/Http/RememberMe/PersistentRememberMeHandler.php @@ -75,6 +75,7 @@ public function processRememberMe(RememberMeDetails $rememberMeDetails, UserInte if ($this->tokenVerifier) { $isTokenValid = $this->tokenVerifier->verifyToken($persistentToken, $tokenValue); + $tokenValue = $persistentToken->getTokenValue(); } else { $isTokenValid = hash_equals($persistentToken->getTokenValue(), $tokenValue); } diff --git a/src/Symfony/Component/Security/Http/Tests/RememberMe/PersistentRememberMeHandlerTest.php b/src/Symfony/Component/Security/Http/Tests/RememberMe/PersistentRememberMeHandlerTest.php index 7448520497eaf..770a1c634abe6 100644 --- a/src/Symfony/Component/Security/Http/Tests/RememberMe/PersistentRememberMeHandlerTest.php +++ b/src/Symfony/Component/Security/Http/Tests/RememberMe/PersistentRememberMeHandlerTest.php @@ -17,6 +17,7 @@ use Symfony\Component\HttpFoundation\RequestStack; use Symfony\Component\Security\Core\Authentication\RememberMe\PersistentToken; use Symfony\Component\Security\Core\Authentication\RememberMe\TokenProviderInterface; +use Symfony\Component\Security\Core\Authentication\RememberMe\TokenVerifierInterface; use Symfony\Component\Security\Core\Exception\AuthenticationException; use Symfony\Component\Security\Core\Exception\CookieTheftException; use Symfony\Component\Security\Core\User\InMemoryUser; @@ -102,6 +103,42 @@ public function testConsumeRememberMeCookieValid() $this->assertSame(explode(':', $rememberParts[3])[0], explode(':', $cookieParts[3])[0]); // series } + public function testConsumeRememberMeCookieValidByValidatorWithoutUpdate() + { + $verifier = $this->createMock(TokenVerifierInterface::class); + $handler = new PersistentRememberMeHandler($this->tokenProvider, 'secret', $this->userProvider, $this->requestStack, [], null, $verifier); + + $persistentToken = new PersistentToken(InMemoryUser::class, 'wouter', 'series1', 'tokenvalue', new \DateTime('30 seconds')); + + $this->tokenProvider->expects($this->any()) + ->method('loadTokenBySeries') + ->with('series1') + ->willReturn($persistentToken) + ; + + $verifier->expects($this->any()) + ->method('verifyToken') + ->with($persistentToken, 'oldTokenValue') + ->willReturn(true) + ; + + $rememberMeDetails = new RememberMeDetails(InMemoryUser::class, 'wouter', 360, 'series1:oldTokenValue'); + $handler->consumeRememberMeCookie($rememberMeDetails); + + // assert that the cookie has been updated with a new base64 encoded token value + $this->assertTrue($this->request->attributes->has(ResponseListener::COOKIE_ATTR_NAME)); + + /** @var Cookie $cookie */ + $cookie = $this->request->attributes->get(ResponseListener::COOKIE_ATTR_NAME); + + $cookieParts = explode(':', base64_decode($cookie->getValue()), 4); + + $this->assertSame(InMemoryUser::class, $cookieParts[0]); // class + $this->assertSame(base64_encode('wouter'), $cookieParts[1]); // identifier + $this->assertSame('360', $cookieParts[2]); // expire + $this->assertSame('series1:tokenvalue', $cookieParts[3]); // value + } + public function testConsumeRememberMeCookieInvalidToken() { $this->expectException(CookieTheftException::class); From 9ed79ce0f69a7071066344fa37ae2c6cc4635352 Mon Sep 17 00:00:00 2001 From: Francois Martin Date: Sun, 26 Jun 2022 17:57:47 +0200 Subject: [PATCH 41/44] Add an invariable word in french --- src/Symfony/Component/String/Inflector/FrenchInflector.php | 2 +- .../Component/String/Tests/Inflector/FrenchInflectorTest.php | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/Symfony/Component/String/Inflector/FrenchInflector.php b/src/Symfony/Component/String/Inflector/FrenchInflector.php index 42f6125aae663..f58f7c0c0e234 100644 --- a/src/Symfony/Component/String/Inflector/FrenchInflector.php +++ b/src/Symfony/Component/String/Inflector/FrenchInflector.php @@ -108,7 +108,7 @@ final class FrenchInflector implements InflectorInterface * A list of words which should not be inflected. * This list is only used by singularize. */ - private const UNINFLECTED = '/^(abcès|accès|abus|albatros|anchois|anglais|autobus|bois|brebis|carquois|cas|chas|colis|concours|corps|cours|cyprès|décès|devis|discours|dos|embarras|engrais|entrelacs|excès|fils|fois|gâchis|gars|glas|héros|intrus|jars|jus|kermès|lacis|legs|lilas|marais|mars|matelas|mépris|mets|mois|mors|obus|os|palais|paradis|parcours|pardessus|pays|plusieurs|poids|pois|pouls|printemps|processus|progrès|puits|pus|rabais|radis|recors|recours|refus|relais|remords|remous|rictus|rhinocéros|repas|rubis|sas|secours|sens|souris|succès|talus|tapis|tas|taudis|temps|tiers|univers|velours|verglas|vernis|virus)$/i'; + private const UNINFLECTED = '/^(abcès|accès|abus|albatros|anchois|anglais|autobus|bois|brebis|carquois|cas|chas|colis|concours|corps|cours|cyprès|décès|devis|discours|dos|embarras|engrais|entrelacs|excès|fils|fois|gâchis|gars|glas|héros|intrus|jars|jus|kermès|lacis|legs|lilas|marais|mars|matelas|mépris|mets|mois|mors|obus|os|palais|paradis|parcours|pardessus|pays|plusieurs|poids|pois|pouls|printemps|processus|progrès|puits|pus|rabais|radis|recors|recours|refus|relais|remords|remous|rictus|rhinocéros|repas|rubis|sans|sas|secours|sens|souris|succès|talus|tapis|tas|taudis|temps|tiers|univers|velours|verglas|vernis|virus)$/i'; /** * {@inheritdoc} diff --git a/src/Symfony/Component/String/Tests/Inflector/FrenchInflectorTest.php b/src/Symfony/Component/String/Tests/Inflector/FrenchInflectorTest.php index ff4deb4eac9aa..9122281c27c84 100644 --- a/src/Symfony/Component/String/Tests/Inflector/FrenchInflectorTest.php +++ b/src/Symfony/Component/String/Tests/Inflector/FrenchInflectorTest.php @@ -31,6 +31,7 @@ public function pluralizeProvider() ['héros', 'héros'], ['nez', 'nez'], ['rictus', 'rictus'], + ['sans', 'sans'], ['souris', 'souris'], ['tas', 'tas'], ['toux', 'toux'], From d0955c2c6a5290037cd31a9b19222f7baeb39e6c Mon Sep 17 00:00:00 2001 From: Matthias Pigulla Date: Fri, 24 Jun 2022 15:11:10 +0200 Subject: [PATCH 42/44] [HttpKernel] Fix a PHP 8.1 deprecation notice in HttpCache --- src/Symfony/Component/HttpKernel/HttpCache/HttpCache.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Symfony/Component/HttpKernel/HttpCache/HttpCache.php b/src/Symfony/Component/HttpKernel/HttpCache/HttpCache.php index 7deda42fc7186..84b77c518a3f4 100644 --- a/src/Symfony/Component/HttpKernel/HttpCache/HttpCache.php +++ b/src/Symfony/Component/HttpKernel/HttpCache/HttpCache.php @@ -718,7 +718,7 @@ private function mayServeStaleWhileRevalidate(Response $entry): bool $timeout = $this->options['stale_while_revalidate']; } - return abs($entry->getTtl()) < $timeout; + return abs($entry->getTtl() ?? 0) < $timeout; } /** From de42e9e8c2e3960a9fa07e39ff4a30d7aa81e3d2 Mon Sep 17 00:00:00 2001 From: Fabien Potencier Date: Sun, 26 Jun 2022 19:06:08 +0200 Subject: [PATCH 43/44] Update CHANGELOG for 6.1.2 --- CHANGELOG-6.1.md | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/CHANGELOG-6.1.md b/CHANGELOG-6.1.md index ecfb505d25ca3..933e6b1d88dae 100644 --- a/CHANGELOG-6.1.md +++ b/CHANGELOG-6.1.md @@ -7,6 +7,34 @@ in 6.1 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.1.0...v6.1.1 +* 6.1.2 (2022-06-26) + + * bug #46779 [String] Add an invariable word in french (lemonlab) + * bug #46765 [Serializer] Fix denormalization union types with constructor (Gwemox) + * bug #46769 [HttpKernel] Fix a PHP 8.1 deprecation notice in HttpCache (mpdude) + * bug #46760 Fix double authentication via RememberMe resulting in wrong RememberMe cookie being set in client (heiglandreas) + * bug #46766 Initially set user null. (mogilvie) + * bug #46735 [Messenger] Do not log the message object itself (ajardin) + * bug #46748 [Security] Fix legacy impersonation system (dunglas) + * bug #46747 Fix global state pollution between tests run with ApplicationTester (Seldaek) + * bug #46730 [Intl] Fix the IntlDateFormatter::formatObject signature (damienalexandre) + * bug #46668 [FrameworkBundle] Lower JsonSerializableNormalizer priority (aprat84) + * bug #46711 [PhpUnitBridge] Exclude from baseline generation deprecations triggered in legacy test (mondrake) + * bug #46678 [HttpFoundation] Update "[Session] Overwrite invalid session id" to only validate when files session storage is used (alexpott) + * bug #46665 [HttpClient] Fix Copy as curl with base uri (HypeMC) + * bug #46670 [HttpClient] Fix json encode flags usage in copy-as-curl generation (welcoMattic) + * bug #45861 [Serializer] Try all possible denormalization route with union types when ALLOW_EXTRA_ATTRIBUTES=false (T-bond) + * bug #46676 [DoctrineBridge] Extend type guessing on enum fields (Gigino Chianese) + * bug #46699 [Cache] Respect $save option in all adapters (jrjohnson) + * bug #46697 [HttpKernel] Disable session tracking while collecting profiler data (nicolas-grekas) + * bug #46704 Allow passing null in twig_is_selected_choice (raziel057) + * bug #46684 [MonologBridge] Fixed support of elasticsearch 7.+ in ElasticsearchLogstashHandler (lyrixx) + * bug #46650 [WebProfilerBundle] Bump http-kernel requirement to ^6.1 (ostrolucky) + * bug #46646 [Messenger] move resetting services at worker stopped into listener (Thomas Talbot) + * bug #46611 [PropertyInfo] Fix multi phpdoc covered promoted properties (ostrolucky, simPod) + * bug #46368 [Mailer] Fix for missing sender name in case with usage of the EnvelopeListener (bobahvas) + * bug #46603 [Mailer] Fix Error Handling for OhMySMTP Bridge (paul-oms) + * 6.1.1 (2022-06-09) * bug #46570 [HttpClient][WebProfilerBundle] Catch errors when encoding body for c… (Phillip Look) From 6108bf747e69c738f6cd6a70156dc59404e3af5d Mon Sep 17 00:00:00 2001 From: Fabien Potencier Date: Sun, 26 Jun 2022 19:06:14 +0200 Subject: [PATCH 44/44] Update VERSION for 6.1.2 --- src/Symfony/Component/HttpKernel/Kernel.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Symfony/Component/HttpKernel/Kernel.php b/src/Symfony/Component/HttpKernel/Kernel.php index da3a3fff0c5e1..44beb5ca270ae 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 array $freshCache = []; - public const VERSION = '6.1.2-DEV'; + public const VERSION = '6.1.2'; public const VERSION_ID = 60102; public const MAJOR_VERSION = 6; public const MINOR_VERSION = 1; public const RELEASE_VERSION = 2; - public const EXTRA_VERSION = 'DEV'; + public const EXTRA_VERSION = ''; public const END_OF_MAINTENANCE = '01/2023'; public const END_OF_LIFE = '01/2023';