From fbb534a8385e42c43c34f36358a65c75f256c200 Mon Sep 17 00:00:00 2001 From: Vincent Touzet Date: Wed, 21 Nov 2018 22:50:37 +0100 Subject: [PATCH] [Messenger] Add a command to setup transports --- .../Bundle/FrameworkBundle/CHANGELOG.md | 1 + .../FrameworkExtension.php | 1 + .../Resources/config/console.xml | 7 ++ src/Symfony/Component/Messenger/CHANGELOG.md | 2 + .../Command/SetupTransportsCommand.php | 80 ++++++++++++++++ .../DependencyInjection/MessengerPass.php | 13 ++- .../Command/SetupTransportsCommandTest.php | 92 +++++++++++++++++++ .../DependencyInjection/MessengerPassTest.php | 17 ++++ .../Transport/AmqpExt/AmqpTransport.php | 11 ++- .../Transport/SetupableTransportInterface.php | 23 +++++ 10 files changed, 242 insertions(+), 5 deletions(-) create mode 100644 src/Symfony/Component/Messenger/Command/SetupTransportsCommand.php create mode 100644 src/Symfony/Component/Messenger/Tests/Command/SetupTransportsCommandTest.php create mode 100644 src/Symfony/Component/Messenger/Transport/SetupableTransportInterface.php diff --git a/src/Symfony/Bundle/FrameworkBundle/CHANGELOG.md b/src/Symfony/Bundle/FrameworkBundle/CHANGELOG.md index 7ecd3acd76d1d..d993fbe2584a2 100644 --- a/src/Symfony/Bundle/FrameworkBundle/CHANGELOG.md +++ b/src/Symfony/Bundle/FrameworkBundle/CHANGELOG.md @@ -19,6 +19,7 @@ CHANGELOG * Added support for Translator paths, Twig paths in translation commands. * Added support for PHP files with translations in translation commands. * Added support for boolean container parameters within routes. + * Added the `messenger:setup-transports` command to setup messenger transports 4.2.0 ----- diff --git a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php index fa505bbb0cf67..4ed9cbb8a20cf 100644 --- a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php +++ b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php @@ -279,6 +279,7 @@ public function load(array $configs, ContainerBuilder $container) } else { $container->removeDefinition('console.command.messenger_consume_messages'); $container->removeDefinition('console.command.messenger_debug'); + $container->removeDefinition('console.command.messenger_setup_transports'); } $this->registerValidationConfiguration($config['validation'], $container, $loader); diff --git a/src/Symfony/Bundle/FrameworkBundle/Resources/config/console.xml b/src/Symfony/Bundle/FrameworkBundle/Resources/config/console.xml index 35d9f813c4223..6ae1cb8cc306d 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Resources/config/console.xml +++ b/src/Symfony/Bundle/FrameworkBundle/Resources/config/console.xml @@ -89,6 +89,13 @@ + + + + + + + diff --git a/src/Symfony/Component/Messenger/CHANGELOG.md b/src/Symfony/Component/Messenger/CHANGELOG.md index 24641be9f2d37..cb0b734f9fe72 100644 --- a/src/Symfony/Component/Messenger/CHANGELOG.md +++ b/src/Symfony/Component/Messenger/CHANGELOG.md @@ -51,6 +51,8 @@ CHANGELOG and queues by default. Previously, this was done when in "debug" mode only. Pass the `auto_setup` connection option to control this. + * Added a `SetupTransportsCommand` command to setup the transports + 4.2.0 ----- diff --git a/src/Symfony/Component/Messenger/Command/SetupTransportsCommand.php b/src/Symfony/Component/Messenger/Command/SetupTransportsCommand.php new file mode 100644 index 0000000000000..1adac92a25419 --- /dev/null +++ b/src/Symfony/Component/Messenger/Command/SetupTransportsCommand.php @@ -0,0 +1,80 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Messenger\Command; + +use Psr\Container\ContainerInterface; +use Symfony\Component\Console\Command\Command; +use Symfony\Component\Console\Input\InputArgument; +use Symfony\Component\Console\Input\InputInterface; +use Symfony\Component\Console\Output\OutputInterface; +use Symfony\Component\Console\Style\SymfonyStyle; +use Symfony\Component\Messenger\Transport\SetupableTransportInterface; + +/** + * @author Vincent Touzet + */ +class SetupTransportsCommand extends Command +{ + protected static $defaultName = 'messenger:setup-transports'; + + private $transportLocator; + private $transportNames; + + public function __construct(ContainerInterface $transportLocator, array $transportNames = []) + { + $this->transportLocator = $transportLocator; + $this->transportNames = $transportNames; + + parent::__construct(); + } + + protected function configure() + { + $this + ->addArgument('transport', InputArgument::OPTIONAL, 'Name of the transport to setup', null) + ->setHelp(<<%command.name% command setups the transports: + + php %command.full_name% + +Or a specific transport only: + + php %command.full_name% +EOF + ) + ; + } + + protected function execute(InputInterface $input, OutputInterface $output) + { + $io = new SymfonyStyle($input, $output); + + $transportNames = $this->transportNames; + // do we want to setup only one transport? + if ($transport = $input->getArgument('transport')) { + if (!$this->transportLocator->has($transport)) { + throw new \RuntimeException(sprintf('The "%s" transport does not exist.', $transport)); + } + $transportNames = [$transport]; + } + + foreach ($transportNames as $id => $transportName) { + $transport = $this->transportLocator->get($transportName); + if ($transport instanceof SetupableTransportInterface) { + $transport->setup(); + $io->success(sprintf('The "%s" transport was setup successfully.', $transportName)); + } else { + $io->note(sprintf('The "%s" transport does not support setup.', $transportName)); + } + } + } +} diff --git a/src/Symfony/Component/Messenger/DependencyInjection/MessengerPass.php b/src/Symfony/Component/Messenger/DependencyInjection/MessengerPass.php index 92ddfc2d4a3ce..fc0252e64b02a 100644 --- a/src/Symfony/Component/Messenger/DependencyInjection/MessengerPass.php +++ b/src/Symfony/Component/Messenger/DependencyInjection/MessengerPass.php @@ -236,11 +236,11 @@ private function registerReceivers(ContainerBuilder $container, array $busIds) } } + $receiverNames = []; + foreach ($receiverMapping as $name => $reference) { + $receiverNames[(string) $reference] = $name; + } if ($container->hasDefinition('console.command.messenger_consume_messages')) { - $receiverNames = []; - foreach ($receiverMapping as $name => $reference) { - $receiverNames[(string) $reference] = $name; - } $buses = []; foreach ($busIds as $busId) { $buses[$busId] = new Reference($busId); @@ -251,6 +251,11 @@ private function registerReceivers(ContainerBuilder $container, array $busIds) ->replaceArgument(3, array_values($receiverNames)); } + if ($container->hasDefinition('console.command.messenger_setup_transports')) { + $container->getDefinition('console.command.messenger_setup_transports') + ->replaceArgument(1, array_values($receiverNames)); + } + $container->getDefinition('messenger.receiver_locator')->replaceArgument(0, $receiverMapping); } diff --git a/src/Symfony/Component/Messenger/Tests/Command/SetupTransportsCommandTest.php b/src/Symfony/Component/Messenger/Tests/Command/SetupTransportsCommandTest.php new file mode 100644 index 0000000000000..48df2782bdb6e --- /dev/null +++ b/src/Symfony/Component/Messenger/Tests/Command/SetupTransportsCommandTest.php @@ -0,0 +1,92 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Messenger\Tests\Command; + +use PHPUnit\Framework\MockObject\MockObject; +use PHPUnit\Framework\TestCase; +use Symfony\Component\Console\Tester\CommandTester; +use Symfony\Component\DependencyInjection\ServiceLocator; +use Symfony\Component\Messenger\Command\SetupTransportsCommand; +use Symfony\Component\Messenger\Transport\SetupableTransportInterface; +use Symfony\Component\Messenger\Transport\TransportInterface; + +class SetupTransportsCommandTest extends TestCase +{ + public function testReceiverNames() + { + // mock a service locator + /** @var MockObject|ServiceLocator $serviceLocator */ + $serviceLocator = $this->createMock(ServiceLocator::class); + // get method must be call twice and will return consecutively a setup-able transport and a non setup-able transport + $serviceLocator->expects($this->exactly(2)) + ->method('get') + ->will($this->onConsecutiveCalls( + $this->createMock(SetupableTransportInterface::class), + $this->createMock(TransportInterface::class) + )); + $serviceLocator + ->method('has') + ->willReturn(true); + + $command = new SetupTransportsCommand($serviceLocator, ['amqp', 'other_transport']); + $tester = new CommandTester($command); + $tester->execute([]); + $display = $tester->getDisplay(); + + $this->assertContains('The "amqp" transport was setup successfully.', $display); + $this->assertContains('The "other_transport" transport does not support setup.', $display); + } + + public function testReceiverNameArgument() + { + // mock a service locator + /** @var MockObject|ServiceLocator $serviceLocator */ + $serviceLocator = $this->createMock(ServiceLocator::class); + // get method must be call twice and will return consecutively a setup-able transport and a non setup-able transport + $serviceLocator->expects($this->exactly(1)) + ->method('get') + ->will($this->onConsecutiveCalls( + $this->createMock(SetupableTransportInterface::class) + )); + $serviceLocator->expects($this->exactly(1)) + ->method('has') + ->willReturn(true); + + $command = new SetupTransportsCommand($serviceLocator, ['amqp', 'other_transport']); + $tester = new CommandTester($command); + $tester->execute(['transport' => 'amqp']); + $display = $tester->getDisplay(); + + $this->assertContains('The "amqp" transport was setup successfully.', $display); + } + + /** + * @expectedException \RuntimeException + * @expectedExceptionMessage The "not_found" transport does not exist. + */ + public function testReceiverNameArgumentNotFound() + { + // mock a service locator + /** @var MockObject|ServiceLocator $serviceLocator */ + $serviceLocator = $this->createMock(ServiceLocator::class); + // get method must be call twice and will return consecutively a setup-able transport and a non setup-able transport + $serviceLocator->expects($this->exactly(0)) + ->method('get'); + $serviceLocator->expects($this->exactly(1)) + ->method('has') + ->willReturn(false); + + $command = new SetupTransportsCommand($serviceLocator, ['amqp', 'other_transport']); + $tester = new CommandTester($command); + $tester->execute(['transport' => 'not_found']); + } +} diff --git a/src/Symfony/Component/Messenger/Tests/DependencyInjection/MessengerPassTest.php b/src/Symfony/Component/Messenger/Tests/DependencyInjection/MessengerPassTest.php index c6ef2c0cecb59..4e32ba9b49aab 100644 --- a/src/Symfony/Component/Messenger/Tests/DependencyInjection/MessengerPassTest.php +++ b/src/Symfony/Component/Messenger/Tests/DependencyInjection/MessengerPassTest.php @@ -20,6 +20,7 @@ use Symfony\Component\DependencyInjection\ServiceLocator; use Symfony\Component\Messenger\Command\ConsumeMessagesCommand; use Symfony\Component\Messenger\Command\DebugCommand; +use Symfony\Component\Messenger\Command\SetupTransportsCommand; use Symfony\Component\Messenger\DataCollector\MessengerDataCollector; use Symfony\Component\Messenger\DependencyInjection\MessengerPass; use Symfony\Component\Messenger\Envelope; @@ -265,6 +266,22 @@ public function testItRegistersMultipleReceiversAndSetsTheReceiverNamesOnTheComm $this->assertSame(['amqp', 'dummy'], $container->getDefinition('console.command.messenger_consume_messages')->getArgument(3)); } + public function testItSetsTheReceiverNamesOnTheSetupTransportsCommand() + { + $container = $this->getContainerBuilder(); + $container->register('console.command.messenger_setup_transports', SetupTransportsCommand::class)->setArguments([ + new Reference('messenger.receiver_locator'), + null, + ]); + + $container->register(AmqpReceiver::class, AmqpReceiver::class)->addTag('messenger.receiver', ['alias' => 'amqp']); + $container->register(DummyReceiver::class, DummyReceiver::class)->addTag('messenger.receiver', ['alias' => 'dummy']); + + (new MessengerPass())->process($container); + + $this->assertSame(['amqp', 'dummy'], $container->getDefinition('console.command.messenger_setup_transports')->getArgument(1)); + } + public function testItShouldNotThrowIfGeneratorIsReturnedInsteadOfArray() { $container = $this->getContainerBuilder($busId = 'message_bus'); diff --git a/src/Symfony/Component/Messenger/Transport/AmqpExt/AmqpTransport.php b/src/Symfony/Component/Messenger/Transport/AmqpExt/AmqpTransport.php index a98c90596634c..2146bd900d29c 100644 --- a/src/Symfony/Component/Messenger/Transport/AmqpExt/AmqpTransport.php +++ b/src/Symfony/Component/Messenger/Transport/AmqpExt/AmqpTransport.php @@ -14,6 +14,7 @@ use Symfony\Component\Messenger\Envelope; use Symfony\Component\Messenger\Transport\Serialization\PhpSerializer; use Symfony\Component\Messenger\Transport\Serialization\SerializerInterface; +use Symfony\Component\Messenger\Transport\SetupableTransportInterface; use Symfony\Component\Messenger\Transport\TransportInterface; /** @@ -21,7 +22,7 @@ * * @experimental in 4.2 */ -class AmqpTransport implements TransportInterface +class AmqpTransport implements TransportInterface, SetupableTransportInterface { private $serializer; private $connection; @@ -74,6 +75,14 @@ public function send(Envelope $envelope): Envelope return ($this->sender ?? $this->getSender())->send($envelope); } + /** + * {@inheritdoc} + */ + public function setup(): void + { + $this->connection->setup(); + } + private function getReceiver() { return $this->receiver = new AmqpReceiver($this->connection, $this->serializer); diff --git a/src/Symfony/Component/Messenger/Transport/SetupableTransportInterface.php b/src/Symfony/Component/Messenger/Transport/SetupableTransportInterface.php new file mode 100644 index 0000000000000..8b6a857f60f52 --- /dev/null +++ b/src/Symfony/Component/Messenger/Transport/SetupableTransportInterface.php @@ -0,0 +1,23 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Messenger\Transport; + +/** + * @author Vincent Touzet + */ +interface SetupableTransportInterface +{ + /** + * Setup the transport. + */ + public function setup(): void; +} pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy