8000 Merge branch '6.3' into 6.4 · symfony/symfony@fa24f92 · GitHub
[go: up one dir, main page]

Skip to content

Commit fa24f92

Browse files
Merge branch '6.3' into 6.4
* 6.3: Add missing return type [HttpClient] Fix pausing responses before they start when using curl separate child and parent context in NotificationEmail on writes [Mailer] [Mailgun] Fix sender header encoding do 8000 not overwrite the cache key when it is false [Mailer] Throw TransportException when unable to read from socket [Serializer] Rewrite `AbstractObjectNormalizer::createChildContext()` to use the provided `cache_key` from original context when creating child contexts [HttpClient] Fix error chunk creation in passthru Adjusting and removing the 'review' attribute from the pt_br translation XML. [Serializer] Take unnamed variadic parameters into account when denormalizing Fix context data and display extra data
2 parents 30810dd + d493c39 commit fa24f92

File tree

15 files changed

+310
-15
lines changed

15 files changed

+310
-15
lines changed

src/Symfony/Bridge/Monolog/Command/ServerLogCommand.php

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -164,7 +164,8 @@ private function displayLog(OutputInterface $output, int $clientId, array $recor
164164
$record['channel'],
165165
Level::fromValue($record['level']),
166166
$record['message'],
167-
$record['context']->getContext(),
167+
$record['context']->getValue(true),
168+
$record['extra']->getValue(true),
168169
);
169170
}
170171

src/Symfony/Bridge/Twig/Mime/NotificationEmail.php

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -174,6 +174,26 @@ public function getHtmlTemplate(): ?string
174174
return '@email/'.$this->theme.'/notification/body.html.twig';
175175
}
176176

177+
/**
178+
* @return $this
179+
*/
180+
public function context(array $context): static
181+
{
182+
$parentContext = [];
183+
184+
foreach ($context as $key => $value) {
185+
if (\array_key_exists($key, $this->context)) {
186+
$this->context[$key] = $value;
187+
} else {
188+
$parentContext[$key] = $value;
189+
}
190+
}
191+
192+
parent::context($parentContext);
193+
194+
return $this;
195+
}
196+
177197
public function getContext(): array
178198
{
179199
return array_merge($this->context, parent::getContext());

src/Symfony/Bridge/Twig/Tests/Mime/NotificationEmailTest.php

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -128,4 +128,54 @@ public function testPublicMailSubject()
128128
$headers = $email->getPreparedHeaders();
129129
$this->assertSame('Foo', $headers->get('Subject')->getValue());
130130
}
131+
132+
public function testContext()
133+
{
134+
$email = new NotificationEmail();
135+
$email->context(['some' => 'context']);
136+
137+
$this->assertSame([
138+
'importance' => NotificationEmail::IMPORTANCE_LOW,
139+
'content' => '',
140+
'exception' => false,
141+
'action_text' => null,
142+
'action_url' => null,
143+
'markdown' => false,
144+
'raw' => false,
145+
'footer_text' => 'Notification e-mail sent by Symfony',
146+
'some' => 'context',
147+
], $email->getContext());
148+
149+
$context = $email->getContext();
150+
$context['foo'] = 'bar';
151+
$email->context($context);
152+
153+
$this->assertSame([
154+
'importance' => NotificationEmail::IMPORTANCE_LOW,
155+
'content' => '',
156+
'exception' => false,
157+
'action_text' => null,
158+
'action_url' => null,
159+
'markdown' => false,
160+
'raw' => false,
161+
'footer_text' => 'Notification e-mail sent by Symfony',
162+
'some' => 'context',
163+
'foo' => 'bar',
164+
], $email->getContext());
165+
166+
$email->action('Action Text', 'Action URL');
167+
168+
$this->assertSame([
169+
'importance' => NotificationEmail::IMPORTANCE_LOW,
170+
'content' => '',
171+
'exception' => false,
172+
'action_text' => 'Action Text',
173+
'action_url' => 'Action URL',
174+
'markdown' => false,
175+
'raw' => false,
176+
'footer_text' => 'Notification e-mail sent by Symfony',
177+
'some' => 'context',
178+
'foo' => 'bar',
179+
], $email->getContext());
180+
}
131181
}

src/Symfony/Component/HttpClient/Response/AsyncResponse.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@ public function __construct(HttpClientInterface $client, string $method, string
6666
while (true) {
6767
foreach (self::stream([$response], $timeout) as $chunk) {
6868
if ($chunk->isTimeout() && $response->passthru) {
69-
foreach (self::passthru($response->client, $response, new ErrorChunk($response->offset, new TransportException($chunk->getError()))) as $chunk) {
69+
foreach (self::passthru($response->client, $response, new ErrorChunk($response->offset, $chunk->getError())) as $chunk) {
7070
if ($chunk->isFirst()) {
7171
return false;
7272
}

src/Symfony/Component/HttpClient/Response/CurlResponse.php

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -98,7 +98,6 @@ public function __construct(CurlClientState $multi, \CurlHandle|string $ch, ?arr
9898
$this->info['pause_handler'] = static function (float $duration) use ($ch, $multi, $execCounter) {
9999
if (0 < $duration) {
100100
if ($execCounter === $multi->execCounter) {
101-
$multi->execCounter = !\is_float($execCounter) ? 1 + $execCounter : \PHP_INT_MIN;
102101
curl_multi_remove_handle($multi->handle, $ch);
103102
}
104103

src/Symfony/Component/HttpClient/Tests/RetryableHttpClientTest.php

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313

1414
use PHPUnit\Framework\TestCase;
1515
use Symfony\Component\HttpClient\Exception\ServerException;
16+
use Symfony\Component\HttpClient\Exception\TimeoutException;
1617
use Symfony\Component\HttpClient\HttpClient;
1718
use Symfony\Component\HttpClient\MockHttpClient;
1819
use Symfony\Component\HttpClient\NativeHttpClient;
@@ -21,6 +22,7 @@
2122
use Symfony\Component\HttpClient\Retry\GenericRetryStrategy;
2223
use Symfony\Component\HttpClient\RetryableHttpClient;
2324
use Symfony\Contracts\HttpClient\Exception\TransportExceptionInterface;
25+
use Symfony\Contracts\HttpClient\Test\TestHttpServer;
2426

2527
class RetryableHttpClientTest extends TestCase
2628
{
@@ -245,6 +247,35 @@ public function testRetryOnErrorAssertContent()
245247
self::assertSame('Test out content', $response->getContent(), 'Content should be buffered');
246248
}
247249

250+
/**
251+
* @testWith ["GET"]
252+
* ["POST"]
253+
* ["PUT"]
254+
* ["PATCH"]
255+
* ["DELETE"]
256+
*/
257+
public function testRetryOnHeaderTimeout(string $method)
258+
{
259+
$client = HttpClient::create();
260+
261+
if ($client instanceof NativeHttpClient) {
262+
$this->markTestSkipped('NativeHttpClient cannot timeout before receiving headers');
263+
}
264+
265+
TestHttpServer::start();
266+
267+
$client = new RetryableHttpClient($client);
268+
$response = $client->request($method, 'http://localhost:8057/timeout-header', ['timeout' => 0.1]);
269+
270+
try {
271+
$response->getStatusCode();
272+
$this->fail(TimeoutException::class.' expected');
273+
} catch (TimeoutException $e) {
274+
}
275+
276+
$this->assertSame('Idle timeout reached for "http://localhost:8057/timeout-header".', $response->getInfo('error'));
277+
}
278+
248279
public function testRetryWithMultipleBaseUris()
249280
{
250281
$client = new RetryableHttpClient(

src/Symfony/Component/Mailer/Bridge/Mailgun/Tests/Transport/MailgunApiTransportTest.php

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -268,4 +268,17 @@ public function testTagAndMetadataHeaders()
268268
$this->assertArrayHasKey('v:Client-ID', $payload);
269269
$this->assertSame('12345', $payload['v:Client-ID']);
270270
}
271+
272+
public function testEnvelopeSenderHeaderIsCorrectlyEncoded()
273+
{
274+
$email = new Email();
275+
$envelope = new Envelope(new Address('alice@system.com', 'Žluťoučký Kůň'), [new Address('bob@system.com')]);
276+
277+
$transport = new MailgunApiTransport('ACCESS_KEY', 'DOMAIN');
278+
$method = new \ReflectionMethod(MailgunApiTransport::class, 'getPayload');
279+
$payload = $method->invoke($transport, $email, $envelope);
280+
281+
$this->assertArrayHasKey('h:Sender', $payload);
282+
$this->assertSame('=?utf-8?Q?=C5=BDlu=C5=A5ou=C4=8Dk=C3=BD_K=C5=AF=C5=88?= <alice@system.com>', $payload['h:Sender']);
283+
}
271284
}

src/Symfony/Component/Mailer/Bridge/Mailgun/Transport/MailgunApiTransport.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,7 @@ protected function doSendApi(SentMessage $sentMessage, Email $email, Envelope $e
8787
private function getPayload(Email $email, Envelope $envelope): array
8888
{
8989
$headers = $email->getHeaders();
90-
$headers->addHeader('h:Sender', $envelope->getSender()->toString());
90+
$headers->addMailboxHeader('h:Sender', $envelope->getSender());
9191
$html = $email->getHtmlBody();
9292
if (null !== $html && \is_resource($html)) {
9393
if (stream_get_meta_data($html)['seekable'] ?? false) {

src/Symfony/Component/Mailer/Transport/Smtp/Stream/AbstractStream.php

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,7 @@ public function readLine(): string
7777
return '';
7878
}
7979

80-
$line = fgets($this->out);
80+
$line = @fgets($this->out);
8181
if ('' === $line || false === $line) {
8282
$metas = stream_get_meta_data($this->out);
8383
if ($metas['timed_out']) {
@@ -86,6 +86,9 @@ public function readLine(): string
8686
if ($metas['eof']) {
8787
throw new TransportException(sprintf('Connection to "%s" has been closed unexpectedly.', $this->getReadConnectionDescription()));
8888
}
89+
if (false === $line) {
90+
throw new TransportException(sprintf('Unable to read from connection to "%s": ', $this->getReadConnectionDescription()).error_get_last()['message']);
91+
}
8992
}
9093

9194
$this->debug .= sprintf('< %s', $line);

src/Symfony/Component/Serializer/Normalizer/AbstractNormalizer.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -361,7 +361,7 @@ protected function instantiateObject(array &$data, string $class, array &$contex
361361
$variadicParameters[$parameterKey] = $this->denormalizeParameter($reflectionClass, $constructorParameter, $paramName, $parameterData, $attributeContext, $format);
362362
}
363363

364-
$params = array_merge($params, $variadicParameters);
364+
$params = array_merge(array_values($params), $variadicParameters);
365365
$unsetKeys[] = $key;
366366
}
367367
} elseif ($allowed && !$ignored && (isset($data[$key]) || \array_key_exists($key, $data))) {

src/Symfony/Component/Serializer/Normalizer/AbstractObjectNormalizer.php

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -734,7 +734,11 @@ private function isMaxDepthReached(array $attributesMetadata, string $class, str
734734
protected function createChildContext(array $parentContext, string $attribute, ?string $format): array
735735
{
736736
$context = parent::createChildContext($parentContext, $attribute, $format);
737-
$context['cache_key'] = $this->getCacheKey($format, $context);
737+
if ($context['cache_key'] ?? false) {
738+
$context['cache_key'] .= '-'.$attribute;
739+
} elseif (false !== ($context['cache_key'] ?? null)) {
740+
$context['cache_key'] = $this->getCacheKey($format, $context);
741+
}
738742

739743
return $context;
740744
}
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <fabien@symfony.com>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespace Symfony\Component\Serializer\Tests\Fixtures;
13+
14+
class DummyWithWithVariadicParameterConstructor
15+
{
16+
private $foo;
17+
18+
private $bar;
19+
20+
private $baz;
21+
22+
public function __construct(string $foo, int $bar = 1, Dummy ...$baz)
23+
{
24+
$this->foo = $foo;
25+
$this->bar = $bar;
26+
$this->baz = $baz;
27+
}
28+
29+
public function getFoo(): string
30+
{
31+
return $this->foo;
32+
}
33+
34+
public function getBar(): int
35+
{
36+
return $this->bar;
37+
}
38+
39+
/** @return Dummy[] */
40+
public function getBaz(): array
41+
{
42+
return $this->baz;
43+
}
44+
}

src/Symfony/Component/Serializer/Tests/Normalizer/AbstractNormalizerTest.php

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030
use Symfony\Component\Serializer\Tests\Fixtures\AbstractNormalizerDummy;
3131
use Symfony\Component\Serializer\Tests\Fixtures\Attributes\IgnoreDummy;
3232
use Symfony\Component\Serializer\Tests\Fixtures\Dummy;
33+
use Symfony\Component\Serializer\Tests\Fixtures\DummyWithWithVariadicParameterConstructor;
3334
use Symfony\Component\Serializer\Tests\Fixtures\NullableConstructorArgumentDummy;
3435
use Symfony\Component\Serializer\Tests\Fixtures\NullableOptionalConstructorArgumentDummy;
3536
use Symfony\Component\Serializer\Tests\Fixtures\StaticConstructorDummy;
@@ -248,6 +249,25 @@ public static function getNormalizer()
248249
yield [new ObjectNormalizer(null, null, null, $extractor)];
249250
}
250251

252+
public function testVariadicConstructorDenormalization()
253+
{
254+
$data = [
255+
'foo' => 'woo',
256+
'baz' => [
257+
['foo' => null, 'bar' => null, 'baz' => null, 'qux' => null],
258+
['foo' => null, 'bar' => null, 'baz' => null, 'qux' => null],
259+
],
260+
];
261+
262+
$normalizer = new ObjectNormalizer();
263+
$normalizer->setSerializer(new Serializer([$normalizer]));
264+
265+
$expected = new DummyWithWithVariadicParameterConstructor('woo', 1, new Dummy(), new Dummy());
266+
$actual = $normalizer->denormalize($data, DummyWithWithVariadicParameterConstructor::class);
267+
268+
$this->assertEquals($expected, $actual);
269+
}
270+
251271
public static function getNormalizerWithCustomNameConverter()
252272
{
253273
$extractor = new PhpDocExtractor();

0 commit comments

Comments
 (0)
0