8000 Merge branch '4.3' into 4.4 · symfony/symfony@3cd20c9 · GitHub
[go: up one dir, main page]

Skip to content

Commit 3cd20c9

Browse files
Merge branch '4.3' into 4.4
* 4.3: [Routing] Add a param annotation for $annot. [DI] fix docblock [Console] fix docblock Add missing translations for Armenian locale [Process] Added missing return type. [Process] Doc block backport. Added doc block for Registry::supports(). [Cache] Fix predis test Don't duplicate addresses in Sendgrid Transport Remove unnecessary statement Fix some docblocks. [Messenger] make delay exchange and queues durable like the normal ones by default Cancel delayed message if handler fails Added tests for #32370
2 parents 7bdeff0 + 3aa4537 commit 3cd20c9

File tree

16 files changed

+250
-30
lines changed

16 files changed

+250
-30
lines changed

src/Symfony/Bundle/FrameworkBundle/Command/AbstractConfigCommand.php

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
use Symfony\Component\Config\Definition\ConfigurationInterface;
1515
use Symfony\Component\Console\Exception\LogicException;
1616
use Symfony\Component\Console\Helper\Table;
17+
use Symfony\Component\Console\Output\OutputInterface;
1718
use Symfony\Component\Console\Style\StyleInterface;
1819
use Symfony\Component\DependencyInjection\Extension\ExtensionInterface;
1920

@@ -26,6 +27,9 @@
2627
*/
2728
abstract class AbstractConfigCommand extends ContainerDebugCommand
2829
{
30+
/**
31+
* @param OutputInterface|StyleInterface $output
32+
*/
2933
protected function listBundles($output)
3034
{
3135
$title = 'Available registered bundles with their extension alias if available';

src/Symfony/Component/BrowserKit/CookieJar.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -111,8 +111,8 @@ public function clear()
111111
/**
112112
* Updates the cookie jar from a response Set-Cookie headers.
113113
*
114-
* @param array $setCookies Set-Cookie headers from an HTTP response
115-
* @param string $uri The base URL
114+
* @param string[] $setCookies Set-Cookie headers from an HTTP response
115+
* @param string $uri The base URL
116116
*/
117117
public function updateFromSetCookie(array $setCookies, $uri = null)
118118
{

src/Symfony/Component/Cache/Tests/Adapter/PredisAdapterTest.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ public function testCreateConnection()
3434

3535
$params = [
3636
'scheme' => 'tcp',
37-
'host' => 'localhost',
37+
'host' => $redisHost,
3838
'port' => 6379,
3939
'persistent' => 0,
4040
'timeout' => 3,

src/Symfony/Component/Console/Tester/TesterTrait.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -110,7 +110,7 @@ public function getStatusCode()
110110
* @param array $inputs An array of strings representing each input
111111
* passed to the command input stream
112112
*
113-
* @return self
113+
* @return $this
114114
*/
115115
public function setInputs(array $inputs)
116116
{

src/Symfony/Component/DependencyInjection/ChildDefinition.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,7 @@ public function getArgument($index)
8989
* @param int|string $index
9090
* @param mixed $value
9191
*
92-
* @return self the current instance
92+
* @return $this
9393
*
9494
* @throws InvalidArgumentException when $index isn't an integer
9595
*/

src/Symfony/Component/DependencyInjection/Dumper/PhpDumper.php

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1208,7 +1208,6 @@ private function addMethodMap(): string
12081208
if (!$id->isDeprecated()) {
12091209
continue;
12101210
}
1211-
$id = (string) $id;
12121211
$code .= ' '.$this->doExport($alias).' => '.$this->doExport($this->generateMethodName($alias)).",\n";
12131212
}
12141213

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
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\Mailer\Bridge\Sendgrid\Tests\Http\Api;
13+
14+
use PHPUnit\Framework\TestCase;
15+
use Symfony\Component\Mailer\Bridge\Sendgrid\Http\Api\SendgridTransport;
16+
use Symfony\Component\Mime\Email;
17+
use Symfony\Contracts\HttpClient\HttpClientInterface;
18+
use Symfony\Contracts\HttpClient\ResponseInterface;
19+
20+
class SendgridTransportTest extends TestCase
21+
{
22+
public function testSend()
23+
{
24+
$email = new Email();
25+
$email->from('foo@example.com')
26+
->to('bar@example.com')
27+
->bcc('baz@example.com');
28+
29+
$response = $this->createMock(ResponseInterface::class);
30+
31+
$response
32+
->expects($this->once())
33+
->method('getStatusCode')
34+
->willReturn(202);
35+
36+
$httpClient = $this->createMock(HttpClientInterface::class);
37+
38+
$httpClient
39+
->expects($this->once())
40+
->method('request')
41+
->with('POST', 'https://api.sendgrid.com/v3/mail/send', [
42+
'json' => [
43+
'personalizations' => [
44+
[
45+
'to' => [['email' => 'bar@example.com']],
46+
'subject' => null,
47+
'bcc' => [['email' => 'baz@example.com']],
48+
],
49+
],
50+
'from' => ['email' => 'foo@example.com'],
51+
'content' => [],
52+
],
53+
'auth_bearer' => 'foo',
54+
])
55+
->willReturn($response);
56+
57+
$mailer = new SendgridTransport('foo', $httpClient);
58+
59+
$mailer->send($email);
60+
}
61+
}

src/Symfony/Component/Mailer/Bridge/Sendgrid/Transport/SendgridApiTransport.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,7 @@ private function getPayload(Email $email, SmtpEnvelope $envelope): array
7373
}
7474

7575
$personalization = [
76-
'to' => array_map($addressStringifier, $this->getRecipients($email, $envelope)),
76+
'to' => array_map($addressStringifier, $email->getTo()),
7777
'subject' => $email->getSubject(),
7878
];
7979
if ($emails = array_map($addressStringifier, $email->getCc())) {

src/Symfony/Component/Messenger/Middleware/DispatchAfterCurrentBusMiddleware.php

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,12 +81,16 @@ public function handle(Envelope $envelope, StackInterface $stack): Envelope
8181
// "Root dispatch" call is finished, dispatch stored messages.
8282
$exceptions = [];
8383
while (null !== $queueItem = array_shift($this->queue)) {
84+
// Save how many messages are left in queue before handling the message
85+
$queueLengthBefore = \count($this->queue);
8486
try {
8587
// Execute the stored messages
8688
$queueItem->getStack()->next()->handle($queueItem->getEnvelope(), $queueItem->getStack());
8789
} catch (\Exception $exception) {
8890
// Gather all exceptions
8991
$exceptions[] = $exception;
92+
// Restore queue to previous state
93+
$this->queue = \array_slice($this->queue, 0, $queueLengthBefore);
9094
}
9195
}
9296

src/Symfony/Component/Messenger/Tests/Middleware/DispatchAfterCurrentBusMiddlewareTest.php

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,86 @@ public function testThrowingEventsHandlingWontStopExecution()
9999
$messageBus->dispatch($message);
100100
}
101101

102+
public function testLongChainWithExceptions()
103+
{
104+
$command = new DummyMessage('Level 0');
105+
106+
$eventL1a = new DummyEvent('Event level 1A');
107+
$eventL1b = new DummyEvent('Event level 1B'); // will dispatch 2 more events
108+
$eventL1c = new DummyEvent('Event level 1C');
109+
110+
$eventL2a = new DummyEvent('Event level 2A'); // Will dispatch 1 event and throw exception
111+
$eventL2b = new DummyEvent('Event level 2B'); // Will dispatch 1 event
112+
113+
$eventL3a = new DummyEvent('Event level 3A'); // This should never get handled.
114+
$eventL3b = new DummyEvent('Event level 3B');
115+
116+
$middleware = new DispatchAfterCurrentBusMiddleware();
117+
$handlingMiddleware = $this->createMock(MiddlewareInterface::class);
118+
119+
$eventBus = new MessageBus([
120+
$middleware,
121+
$handlingMiddleware,
122+
]);
123+
124+
// The command bus will dispatch 3 events.
125+
$commandBus = new MessageBus([
126+
$middleware,
127+
new DispatchingMiddleware($eventBus, [
128+
new Envelope($eventL1a, [new DispatchAfterCurrentBusStamp()]),
129+
new Envelope($eventL1b, [new DispatchAfterCurrentBusStamp()]),
130+
new Envelope($eventL1c, [new DispatchAfterCurrentBusStamp()]),
131+
]),
132+
$handlingMiddleware,
133+
]);
134+
135+
// Expect main dispatched message to be handled first:
136+
$this->expectHandledMessage($handlingMiddleware, 0, $command);
137+
138+
$this->expectHandledMessage($handlingMiddleware, 1, $eventL1a);
139+
140+
// Handling $eventL1b will dispatch 2 more events
141+
$handlingMiddleware->expects($this->at(2))->method('handle')->with($this->callback(function (Envelope $envelope) use ($eventL1b) {
142+
return $envelope->getMessage() === $eventL1b;
143+
}))->willReturnCallback(function ($envelope, StackInterface $stack) use ($eventBus, $eventL2a, $eventL2b) {
144+
$envelope1 = new Envelope($eventL2a, [new DispatchAfterCurrentBusStamp()]);
145+
$eventBus->dispatch($envelope1);
146+
$eventBus->dispatch(new Envelope($eventL2b, [new DispatchAfterCurrentBusStamp()]));
147+
148+
return $stack->next()->handle($envelope, $stack);
149+
});
150+
151+
$this->expectHandledMessage($handlingMiddleware, 3, $eventL1c);
152+
153+
// Handle $eventL2a will dispatch event and throw exception
154+
$handlingMiddleware->expects($this->at(4))->method('handle')->with($this->callback(function (Envelope $envelope) use ($eventL2a) {
155+
return $envelope->getMessage() === $eventL2a;
156+
}))->willReturnCallback(function ($envelope, StackInterface $stack) use ($eventBus, $eventL3a) {
157+
$eventBus->dispatch(new Envelope($eventL3a, [new DispatchAfterCurrentBusStamp()]));
158+
159+
throw new \RuntimeException('Some exception while handling Event level 2a');
160+
});
161+
162+
// Make sure $eventL2b is handled, since it was dispatched from $eventL1b
163+
$handlingMiddleware->expects($this->at(5))->method('handle')->with($this->callback(function (Envelope $envelope) use ($eventL2b) {
164+
return $envelope->getMessage() === $eventL2b;
165+
}))->willReturnCallback(function ($envelope, StackInterface $stack) use ($eventBus, $eventL3b) {
166+
$eventBus->dispatch(new Envelope($eventL3b, [new DispatchAfterCurrentBusStamp()]));
167+
168+
return $stack->next()->handle($envelope, $stack);
169+
});
170+
171+
// We dont handle exception L3a since L2a threw an exception.
172+
$this->expectHandledMessage($handlingMiddleware, 6, $eventL3b);
173+
174+
// Note: $eventL3a should not be handled.
175+
176+
$this->expectException(DelayedMessageHandlingException::class);
177+
$this->expectExceptionMessage('RuntimeException: Some exception while handling Event level 2a');
178+
179+
$commandBus->dispatch($command);
180+
}
181+
102182
public function testHandleDelayedEventFromQueue()
103183
{
104184
$message = new DummyMessage('Hello');

src/Symfony/Component/Messenger/Tests/Transport/AmqpExt/ConnectionTest.php

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -364,7 +364,7 @@ public function testAutoSetupWithDelayDeclaresExchangeQueuesAndDelay()
364364
$amqpQueue->expects($this->once())->method('setName')->with(self::DEFAULT_EXCHANGE_NAME);
365365
$amqpQueue->expects($this->once())->m 10000 ethod('declareQueue');
366366

367-
$delayExchange->expects($this->once())->method('setName')->with('delay');
367+
$delayExchange->expects($this->once())->method('setName')->with('delays');
368368
$delayExchange->expects($this->once())->method('declareExchange');
369369
$delayExchange->expects($this->once())->method('publish');
370370

@@ -398,7 +398,7 @@ public function testItDelaysTheMessage()
398398
]);
399399

400400
$delayQueue->expects($this->once())->method('declareQueue');
401-
$delayQueue->expects($this->once())->method('bind')->with('delay', 'delay_messages__5000');
401+
$delayQueue->expects($this->once())->method('bind')->with('delays', 'delay_messages__5000');
402402

403403
$delayExchange->expects($this->once())->method('publish')->with('{}', 'delay_messages__5000', AMQP_NOPARAM, ['headers' => ['x-some-headers' => 'foo']]);
404404

@@ -440,7 +440,7 @@ public function testItDelaysTheMessageWithADifferentRoutingKeyAndTTLs()
440440
]);
441441

442442
$delayQueue->expects($this->once())->method('declareQueue');
443-
$delayQueue->expects($this->once())->method('bind')->with('delay', 'delay_messages__120000');
443+
$delayQueue->expects($this->once())->method('bind')->with('delays', 'delay_messages__120000');
444444

445445
$delayExchange->expects($this->once())->method('publish')->with('{}', 'delay_messages__120000', AMQP_NOPARAM, ['headers' => []]);
446446
$connection->publish('{}', [], 120000);
@@ -544,7 +544,7 @@ public function testItDelaysTheMessageWithTheInitialSuppliedRoutingKeyAsArgument
544544
]);
545545

546546
$delayQueue->expects($this->once())->method('declareQueue');
547-
$delayQueue->expects($this->once())->method('bind')->with('delay', 'delay_messages_routing_key_120000');
547+
$delayQueue->expects($this->once())->method('bind')->with('delays', 'delay_messages_routing_key_120000');
548548

549549
$delayExchange->expects($this->once())->method('publish')->with('{}', 'delay_messages_routing_key_120000', AMQP_NOPARAM, ['headers' => []]);
550550
$connection->publish('{}', [], 120000, new AmqpStamp('routing_key'));

src/Symfony/Component/Messenger/Transport/AmqpExt/Connection.php

Lines changed: 19 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ public function __construct(array $connectionOptions, array $exchangeOptions, ar
6060
{
6161
$this->connectionOptions = array_replace_recursive([
6262
'delay' => [
63-
'exchange_name' => 'delay',
63+
'exchange_name' => 'delays',
6464
'queue_name_pattern' => 'delay_%exchange_name%_%routing_key%_%delay%',
6565
],
6666
], $connectionOptions);
@@ -92,7 +92,7 @@ public function __construct(array $connectionOptions, array $exchangeOptions, ar
9292
* * arguments: Extra arguments
9393
* * delay:
9494
* * queue_name_pattern: Pattern to use to create the queues (Default: "delay_%exchange_name%_%routing_key%_%delay%")
95-
* * exchange_name: Name of the exchange to be used for the delayed/retried messages (Default: "delay")
95+
* * exchange_name: Name of the exchange to be used for the delayed/retried messages (Default: "delays")
9696
* * auto_setup: Enable or not the auto-setup of queues and exchanges (Default: true)
9797
* * prefetch_count: set channel prefetch count
9898
*/
@@ -251,6 +251,11 @@ private function getDelayExchange(): \AMQPExchange
251251
$this->amqpDelayExchange = $this->amqpFactory->createExchange($this->channel());
252252
$this->amqpDelayExchange->setName($this->connectionOptions['delay']['exchange_name']);
253253
$this->amqpDelayExchange->setType(AMQP_EX_TYPE_DIRECT);
254+
if ('delays' === $this->connectionOptions['delay']['exchange_name']) {
255+
// only add the new flag when the name was not provided explicitly so we're using the new default name to prevent a redeclaration error
256+
// the condition will be removed in 4.4
257+
$this->amqpDelayExchange->setFlags(AMQP_DURABLE);
258+
}
254259
}
255260

256261
return $this->amqpDelayExchange;
@@ -273,16 +278,24 @@ private function createDelayQueue(int $delay, ?string $routingKey)
273278
[$delay, $this->exchangeOptions['name'], $routingKey ?? ''],
274279
$this->connectionOptions['delay']['queue_name_pattern']
275280
));
281+
if ('delay_%exchange_name%_%routing_key%_%delay%' === $this->connectionOptions['delay']['queue_name_pattern']) {
282+
// the condition will be removed in 4.4
283+
$queue->setFlags(AMQP_DURABLE);
284+
$extraArguments = [
285+
// delete the delay queue 10 seconds after the message expires
286+
// publishing another message redeclares the queue which renews the lease
287+
'x-expires' => $delay + 10000,
288+
];
289+
} else {
290+
$extraArguments = [];
291+
}
276292
$queue->setArguments([
277293
'x-message-ttl' => $delay,
278-
// delete the delay queue 10 seconds after the message expires
279-
// publishing another message redeclares the queue which renews the lease
280-
'x-expires' => $delay + 10000,
281294
'x-dead-letter-exchange' => $this->exchangeOptions['name'],
282295
// after being released from to DLX, make sure the original routing key will be used
283296
// we must use an empty string instead of null for the argument to be picked up
284297
'x-dead-letter-routing-key' => $routingKey ?? '',
285-
]);
298+
] + $extraArguments);
286299

287300
return $queue;
288301
}

0 commit comments

Comments
 (0)
0