Skip to content

Commit 0b8321a

Browse files
committed
bug #26816 [Messenger][FrameworkBundle] Move collector, command into the component & minor tweaks (ogizanagi)
This PR was squashed before being merged into the 4.1-dev branch (closes #26816). Discussion ---------- [Messenger][FrameworkBundle] Move collector, command into the component & minor tweaks | Q | A | ------------- | --- | Branch? | master <!-- see below --> | Bug fix? | no | New feature? | no <!-- don't forget to update src/**/CHANGELOG.md files --> | BC breaks? | no <!-- see https://symfony.com/bc --> | Deprecations? | no <!-- don't forget to update UPGRADE-*.md and src/**/CHANGELOG.md files --> | Tests pass? | yes <!-- please add some, will be required by reviewers --> | Fixed tickets | N/A <!-- #-prefixed issue number(s), if any --> | License | MIT | Doc PR | N/A Some suggestions more aligned with most of the core practices, mainly: - Move the command & collector to the component itself. They are not dependent of the Fwb in any way and are useful out of the fwb usage. - Add an exception in FrameworkExtension if the `framework.messenger` key is enabled, but the component isn't installed. Commits ------- 6aec62bad3 [FrameworkBundle] Minor messenger component tweaks f9c9ca0514 [Messenger] Move data collector & command into the component
2 parents a350831 + 25761a8 commit 0b8321a

File tree

4 files changed

+324
-1
lines changed

4 files changed

+324
-1
lines changed

Command/ConsumeMessagesCommand.php

Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <[email protected]>
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\Messenger\Command;
13+
14+
use Psr\Container\ContainerInterface;
15+
use Symfony\Component\Console\Command\Command;
16+
use Symfony\Component\Console\Input\InputArgument;
17+
use Symfony\Component\Console\Input\InputInterface;
18+
use Symfony\Component\Console\Input\InputOption;
19+
use Symfony\Component\Console\Output\OutputInterface;
20+
use Symfony\Component\Messenger\MessageBusInterface;
21+
use Symfony\Component\Messenger\Transport\Enhancers\MaximumCountReceiver;
22+
use Symfony\Component\Messenger\Transport\ReceiverInterface;
23+
use Symfony\Component\Messenger\Worker;
24+
25+
/**
26+
* @author Samuel Roze <[email protected]>
27+
*
28+
* @experimental in 4.1
29+
*/
30+
class ConsumeMessagesCommand extends Command
31+
{
32+
protected static $defaultName = 'messenger:consume-messages';
33+
34+
private $bus;
35+
private $receiverLocator;
36+
37+
public function __construct(MessageBusInterface $bus, ContainerInterface $receiverLocator)
38+
{
39+
parent::__construct();
40+
41+
$this->bus = $bus;
42+
$this->receiverLocator = $receiverLocator;
43+
}
44+
45+
/**
46+
* {@inheritdoc}
47+
*/
48+
protected function configure()
49+
{
50+
$this
51+
->setDefinition(array(
52+
new InputArgument('receiver', InputArgument::REQUIRED, 'Name of the receiver'),
53+
new InputOption('limit', 'l', InputOption::VALUE_REQUIRED, 'Limit the number of received messages'),
54+
))
55+
->setDescription('Consumes messages')
56+
->setHelp(<<<'EOF'
57+
The <info>%command.name%</info> command consumes messages and dispatches them to the message bus.
58+
59+
<info>php %command.full_name% <receiver-name></info>
60+
61+
Use the --limit option to limit the number of messages received:
62+
63+
<info>php %command.full_name% <receiver-name> --limit=10</info>
64+
EOF
65+
)
66+
;
67+
}
68+
69+
/**
70+
* {@inheritdoc}
71+
*/
72+
protected function execute(InputInterface $input, OutputInterface $output)
73+
{
74+
if (!$this->receiverLocator->has($receiverName = $input->getArgument('receiver'))) {
75+
throw new \RuntimeException(sprintf('Receiver "%s" does not exist.', $receiverName));
76+
}
77+
78+
if (!($receiver = $this->receiverLocator->get($receiverName)) instanceof ReceiverInterface) {
79+
throw new \RuntimeException(sprintf('Receiver "%s" is not a valid message consumer. It must implement the "%s" interface.', $receiverName, ReceiverInterface::class));
80+
}
81+
82+
if ($limit = $input->getOption('limit')) {
83+
$receiver = new MaximumCountReceiver($receiver, $limit);
84+
}
85+
86+
$worker = new Worker($receiver, $this->bus);
87+
$worker->run();
88+
}
89+
}
Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <[email protected]>
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\Messenger\DataCollector;
13+
14+
use Symfony\Component\HttpFoundation\Request;
15+
use Symfony\Component\HttpFoundation\Response;
16+
use Symfony\Component\HttpKernel\DataCollector\DataCollector;
17+
use Symfony\Component\Messenger\MiddlewareInterface;
18+
19+
/**
20+
* @author Samuel Roze <[email protected]>
21+
*
22+
* @experimental in 4.1
23+
*/
24+
class MessengerDataCollector extends DataCollector implements MiddlewareInterface
25+
{
26+
/**
27+
* {@inheritdoc}
28+
*/
29+
public function collect(Request $request, Response $response, \Exception $exception = null)
30+
{
31+
// noop
32+
}
33+
34+
/**
35+
* {@inheritdoc}
36+
*/
37+
public function getName()
38+
{
39+
return 'messenger';
40+
}
41+
42+
/**
43+
* {@inheritdoc}
44+
*/
45+
public function reset()
46+
{
47+
$this->data = array();
48+
}
49+
50+
/**
51+
* {@inheritdoc}
52+
*/
53+
public function handle($message, callable $next)
54+
{
55+
$debugRepresentation = array(
56+
'message' => array(
57+
'type' => get_class($message),
58+
'object' => $this->cloneVar($message),
59+
),
60+
);
61+
62+
$exception = null;
63+
try {
64+
$result = $next($message);
65+
66+
if (\is_object($result)) {
67+
$debugRepresentation['result'] = array(
68+
'type' => \get_class($result),
69+
'object' => $this->cloneVar($result),
70+
);
71+
} elseif (\is_array($result)) {
72+
$debugRepresentation['result'] = array(
73+
'type' => 'array',
74+
'object' => $this->cloneVar($result),
75+
);
76+
} else {
77+
$debugRepresentation['result'] = array(
78+
'type' => \gettype($result),
79+
'value' => $result,
80+
);
81+
}
82+
} catch (\Throwable $exception) {
83+
$debugRepresentation['exception'] = array(
84+
'type' => \get_class($exception),
85+
'message' => $exception->getMessage(),
86+
);
87+
}
88+
89+
$this->data['messages'][] = $debugRepresentation;
90+
91+
if (null !== $exception) {
92+
throw $exception;
93+
}
94+
95+
return $result;
96+
}
97+
98+
public function getMessages(): array
99+
{
100+
return $this->data['messages'] ?? array();
101+
}
102+
}
Lines changed: 130 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,130 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <[email protected]>
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\Messenger\Tests\DataCollector;
13+
14+
use PHPUnit\Framework\TestCase;
15+
use Symfony\Component\Messenger\DataCollector\MessengerDataCollector;
16+
use Symfony\Component\Messenger\Tests\Fixtures\DummyMessage;
17+
use Symfony\Component\VarDumper\Test\VarDumperTestTrait;
18+
19+
/**
20+
* @author Maxime Steinhausser <[email protected]>
21+
*/
22+
class MessengerDataCollectorTest extends TestCase
23+
{
24+
use VarDumperTestTrait;
25+
26+
/**
27+
* @dataProvider getHandleTestData
28+
*/
29+
public function testHandle($returnedValue, $expected)
30+
{
31+
$collector = new MessengerDataCollector();
32+
$message = new DummyMessage('dummy message');
33+
34+
$next = $this->createPartialMock(\stdClass::class, array('__invoke'));
35+
$next->expects($this->once())->method('__invoke')->with($message)->willReturn($returnedValue);
36+
37+
$this->assertSame($returnedValue, $collector->handle($message, $next));
38+
39+
$messages = $collector->getMessages();
40+
$this->assertCount(1, $messages);
41+
42+
$this->assertDumpMatchesFormat($expected, $messages[0]);
43+
}
44+
45+
public function getHandleTestData()
46+
{
47+
$messageDump = <<<DUMP
48+
"message" => array:2 [
49+
"type" => "Symfony\Component\Messenger\Tests\Fixtures\DummyMessage"
50+
"object" => Symfony\Component\VarDumper\Cloner\Data {%A
51+
%A+class: "Symfony\Component\Messenger\Tests\Fixtures\DummyMessage"%A
52+
}
53+
]
54+
DUMP;
55+
56+
yield 'no returned value' => array(
57+
null,
58+
<<<DUMP
59+
array:2 [
60+
$messageDump
61+
"result" => array:2 [
62+
"type" => "NULL"
63+
"value" => null
64+
]
65+
]
66+
DUMP
67+
);
68+
69+
yield 'scalar returned value' => array(
70+
'returned value',
71+
<<<DUMP
72+
array:2 [
73+
$messageDump
74+
"result" => array:2 [
75+
"type" => "string"
76+
"value" => "returned value"
77+
]
78+
]
79+
DUMP
80+
);
81+
82+
yield 'array returned value' => array(
83+
array('returned value'),
84+
<<<DUMP
85+
array:2 [
86+
$messageDump
87+
"result" => array:2 [
88+
"type" => "array"
89+
"object" => Symfony\Component\VarDumper\Cloner\Data {%A
90+
]
91+
]
92+
DUMP
93+
);
94+
}
95+
96+
public function testHandleWithException()
97+
{
98+
$collector = new MessengerDataCollector();
99+
$message = new DummyMessage('dummy message');
100+
101+
$expectedException = new \RuntimeException('foo');
102+
$next = $this->createPartialMock(\stdClass::class, array('__invoke'));
103+
$next->expects($this->once())->method('__invoke')->with($message)->willThrowException($expectedException);
104+
105+
try {
106+
$collector->handle($message, $next);
107+
} catch (\Throwable $actualException) {
108+
$this->assertSame($expectedException, $actualException);
109+
}
110+
111+
$messages = $collector->getMessages();
112+
$this->assertCount(1, $messages);
113+
114+
$this->assertDumpMatchesFormat(<<<DUMP
115+
array:2 [
116+
"message" => array:2 [
117+
"type" => "Symfony\Component\Messenger\Tests\Fixtures\DummyMessage"
118+
"object" => Symfony\Component\VarDumper\Cloner\Data {%A
119+
%A+class: "Symfony\Component\Messenger\Tests\Fixtures\DummyMessage"%A
120+
}
121+
]
122+
"exception" => array:2 [
123+
"type" => "RuntimeException"
124+
"message" => "foo"
125+
]
126+
]
127+
DUMP
128+
, $messages[0]);
129+
}
130+
}

composer.json

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,9 @@
2121
"require-dev": {
2222
"symfony/serializer": "~3.4|~4.0",
2323
"symfony/dependency-injection": "~3.4.6|~4.0",
24-
"symfony/property-access": "~3.4|~4.0"
24+
"symfony/http-kernel": "~3.4|~4.0",
25+
"symfony/property-access": "~3.4|~4.0",
26+
"symfony/var-dumper": "~3.4|~4.0"
2527
},
2628
"suggest": {
2729
"sroze/enqueue-bridge": "For using the php-enqueue library as an adapter."

0 commit comments

Comments
 (0)