Skip to content

Commit 160c97e

Browse files
committed
feature #27230 [Messenger] Select alternatives on missing receiver arg or typo (yceruto)
This PR was merged into the 4.1 branch. Discussion ---------- [Messenger] Select alternatives on missing receiver arg or typo | Q | A | ------------- | --- | Branch? | 4.1 | Bug fix? | no | New feature? | yes | BC breaks? | no | Deprecations? | no | Tests pass? | yes | Fixed tickets | - | License | MIT | Doc PR | - If there is more than one receiver available - `bin/console messenger:consume-messages`: ![messenger_consume_missing](https://user-images.githubusercontent.com/2028198/39895594-d4f652c6-5478-11e8-87cf-a1e08e681320.png) If typo and there is similarities - `bin/console messenger:consume-messages amq`: ![messenger_consume_typo](https://user-images.githubusercontent.com/2028198/39895599-d9f0705e-5478-11e8-9d6b-59d62930d4cb.png) requires #27224 Commits ------- 54c2541 Select alternatives on missing receiver arg or typo
2 parents f1967aa + 54c2541 commit 160c97e

File tree

4 files changed

+57
-30
lines changed

4 files changed

+57
-30
lines changed

src/Symfony/Component/Messenger/Command/ConsumeMessagesCommand.php

+45-4
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
use Symfony\Component\Console\Input\InputInterface;
2020
use Symfony\Component\Console\Input\InputOption;
2121
use Symfony\Component\Console\Output\OutputInterface;
22+
use Symfony\Component\Console\Style\SymfonyStyle;
2223
use Symfony\Component\Messenger\MessageBusInterface;
2324
use Symfony\Component\Messenger\Transport\Enhancers\StopWhenMemoryUsageIsExceededReceiver;
2425
use Symfony\Component\Messenger\Transport\Enhancers\StopWhenMessageCountIsExceededReceiver;
@@ -37,14 +38,14 @@ class ConsumeMessagesCommand extends Command
3738
private $bus;
3839
private $receiverLocator;
3940
private $logger;
40-
private $defaultReceiverName;
41+
private $receiverNames;
4142

42-
public function __construct(MessageBusInterface $bus, ContainerInterface $receiverLocator, LoggerInterface $logger = null, string $defaultReceiverName = null)
43+
public function __construct(MessageBusInterface $bus, ContainerInterface $receiverLocator, LoggerInterface $logger = null, array $receiverNames = array())
4344
{
4445
$this->bus = $bus;
4546
$this->receiverLocator = $receiverLocator;
4647
$this->logger = $logger;
47-
$this->defaultReceiverName = $defaultReceiverName;
48+
$this->receiverNames = $receiverNames;
4849

4950
parent::__construct();
5051
}
@@ -54,9 +55,11 @@ public function __construct(MessageBusInterface $bus, ContainerInterface $receiv
5455
*/
5556
protected function configure(): void
5657
{
58+
$defaultReceiverName = 1 === \count($this->receiverNames) ? current($this->receiverNames) : null;
59+
5760
$this
5861
->setDefinition(array(
59-
new InputArgument('receiver', $this->defaultReceiverName ? InputArgument::OPTIONAL : InputArgument::REQUIRED, 'Name of the receiver', $this->defaultReceiverName),
62+
new InputArgument('receiver', $defaultReceiverName ? InputArgument::OPTIONAL : InputArgument::REQUIRED, 'Name of the receiver', $defaultReceiverName),
6063
new InputOption('limit', 'l', InputOption::VALUE_REQUIRED, 'Limit the number of received messages'),
6164
new InputOption('memory-limit', 'm', InputOption::VALUE_REQUIRED, 'The memory limit the worker can consume'),
6265
new InputOption('time-limit', 't', InputOption::VALUE_REQUIRED, 'The time limit in seconds the worker can run'),
@@ -83,6 +86,27 @@ protected function configure(): void
8386
;
8487
}
8588

89+
/**
90+
* {@inheritdoc}
91+
*/
92+
protected function interact(InputInterface $input, OutputInterface $output)
93+
{
94+
if (!$this->receiverNames || $this->receiverLocator->has($receiverName = $input->getArgument('receiver'))) {
95+
return;
96+
}
97+
98+
$style = new SymfonyStyle($input, $output);
99+
if (null === $receiverName) {
100+
$style->block('Missing receiver argument.', null, 'error', ' ', true);
101+
$input->setArgument('receiver', $style->choice('Select one of the available receivers', $this->receiverNames));
102+
} elseif ($alternatives = $this->findAlternatives($receiverName, $this->receiverNames)) {
103+
$style->block(sprintf('Receiver "%s" is not defined.', $receiverName), null, 'error', ' ', true);
104+
if ($style->confirm(sprintf('Do you want to receive from "%s" instead? ', $alternatives[0]), false)) {
105+
$input->setArgument('receiver', $alternatives[0]);
106+
}
107+
}
108+
}
109+
86110
/**
87111
* {@inheritdoc}
88112
*/
@@ -134,4 +158,21 @@ private function convertToBytes(string $memoryLimit): int
134158

135159
return $max;
136160
}
161+
162+
private function findAlternatives($name, array $collection)
163+
{
164+
$alternatives = array();
165+
foreach ($collection as $item) {
166+
$lev = levenshtein($name, $item);
167+
if ($lev <= \strlen($name) / 3 || false !== strpos($item, $name)) {
168+
$alternatives[$item] = isset($alternatives[$item]) ? $alternatives[$item] - $lev : $lev;
169+
}
170+
}
171+
172+
$threshold = 1e3;
173+
$alternatives = array_filter($alternatives, function ($lev) use ($threshold) { return $lev < 2 * $threshold; });
174+
ksort($alternatives, SORT_NATURAL | SORT_FLAG_CASE);
175+
176+
return array_keys($alternatives);
177+
}
137178
}

src/Symfony/Component/Messenger/DependencyInjection/MessengerPass.php

+7-4
Original file line numberDiff line numberDiff line change
@@ -193,9 +193,8 @@ private function guessHandledClasses(\ReflectionClass $handlerClass, string $ser
193193
private function registerReceivers(ContainerBuilder $container)
194194
{
195195
$receiverMapping = array();
196-
$taggedReceivers = $container->findTaggedServiceIds($this->receiverTag);
197196

198-
foreach ($taggedReceivers as $id => $tags) {
197+
foreach ($container->findTaggedServiceIds($this->receiverTag) as $id => $tags) {
199198
$receiverClass = $container->findDefinition($id)->getClass();
200199
if (!is_subclass_of($receiverClass, ReceiverInterface::class)) {
201200
throw new RuntimeException(sprintf('Invalid receiver "%s": class "%s" must implement interface "%s".', $id, $receiverClass, ReceiverInterface::class));
@@ -210,8 +209,12 @@ private function registerReceivers(ContainerBuilder $container)
210209
}
211210
}
212211

213-
if (1 === \count($taggedReceivers) && $container->hasDefinition('console.command.messenger_consume_messages')) {
214-
$container->getDefinition('console.command.messenger_consume_messages')->replaceArgument(3, (string) current($receiverMapping));
212+
if ($container->hasDefinition('console.command.messenger_consume_messages')) {
213+
$receiverNames = array();
214+
foreach ($receiverMapping as $name => $reference) {
215+
$receiverNames[(string) $reference] = $name;
216+
}
217+
$container->getDefinition('console.command.messenger_consume_messages')->replaceArgument(3, array_values($receiverNames));
215218
}
216219

217220
$container->getDefinition('messenger.receiver_locator')->replaceArgument(0, $receiverMapping);

src/Symfony/Component/Messenger/Tests/Command/ConsumeMessagesCommandTest.php

+3-3
Original file line numberDiff line numberDiff line change
@@ -20,15 +20,15 @@ class ConsumeMessagesCommandTest extends TestCase
2020
{
2121
public function testConfigurationWithDefaultReceiver()
2222
{
23-
$command = new ConsumeMessagesCommand($this->createMock(MessageBus::class), $this->createMock(ServiceLocator::class), null, 'messenger.transport.amqp');
23+
$command = new ConsumeMessagesCommand($this->createMock(MessageBus::class), $this->createMock(ServiceLocator::class), null, array('amqp'));
2424
$inputArgument = $command->getDefinition()->getArgument('receiver');
2525
$this->assertFalse($inputArgument->isRequired());
26-
$this->assertSame('messenger.transport.amqp', $inputArgument->getDefault());
26+
$this->assertSame('amqp', $inputArgument->getDefault());
2727
}
2828

2929
public function testConfigurationWithoutDefaultReceiver()
3030
{
31-
$command = new ConsumeMessagesCommand($this->createMock(MessageBus::class), $this->createMock(ServiceLocator::class));
31+
$command = new ConsumeMessagesCommand($this->createMock(MessageBus::class), $this->createMock(ServiceLocator::class), null, array('amqp', 'dummy'));
3232
$inputArgument = $command->getDefinition()->getArgument('receiver');
3333
$this->assertTrue($inputArgument->isRequired());
3434
$this->assertNull($inputArgument->getDefault());

src/Symfony/Component/Messenger/Tests/DependencyInjection/MessengerPassTest.php

+2-19
Original file line numberDiff line numberDiff line change
@@ -166,24 +166,7 @@ public function testItRegistersReceiversWithoutTagName()
166166
$this->assertEquals(array(AmqpReceiver::class => new Reference(AmqpReceiver::class)), $container->getDefinition('messenger.receiver_locator')->getArgument(0));
167167
}
168168

169-
public function testItRegistersOneReceiverAndSetsTheDefaultOneOnTheCommand()
170-
{
171-
$container = $this->getContainerBuilder();
172-
$container->register('console.command.messenger_consume_messages', ConsumeMessagesCommand::class)->setArguments(array(
173-
new Reference('message_bus'),
174-
new Reference('messenger.receiver_locator'),
175-
null,
176-
null,
177-
));
178-
179-
$container->register(AmqpReceiver::class, AmqpReceiver::class)->addTag('messenger.receiver', array('alias' => 'amqp'));
180-
181-
(new MessengerPass())->process($container);
182-
183-
$this->assertSame(AmqpReceiver::class, $container->getDefinition('console.command.messenger_consume_messages')->getArgument(3));
184-
}
185-
186-
public function testItRegistersMultipleReceiversAndDoesNotSetTheDefaultOneOnTheCommand()
169+
public function testItRegistersMultipleReceiversAndSetsTheReceiverNamesOnTheCommand()
187170
{
188171
$container = $this->getContainerBuilder();
189172
$container->register('console.command.messenger_consume_messages', ConsumeMessagesCommand::class)->setArguments(array(
@@ -198,7 +181,7 @@ public function testItRegistersMultipleReceiversAndDoesNotSetTheDefaultOneOnTheC
198181

199182
(new MessengerPass())->process($container);
200183

201-
$this->assertNull($container->getDefinition('console.command.messenger_consume_messages')->getArgument(3));
184+
$this->assertSame(array('amqp', 'dummy'), $container->getDefinition('console.command.messenger_consume_messages')->getArgument(3));
202185
}
203186

204187
public function testItRegistersSenders()

0 commit comments

Comments
 (0)