feature #31429 [Messenger] add support for abstract handlers (timiTao)

This PR was submitted for the 4.4 branch but it was merged into the 5.1-dev branch instead.

Discussion
----------

[Messenger] add support for abstract handlers

| Q             | A
| ------------- | ---
| Branch?       | master <!-- see below -->
| Bug fix?      | no
| New feature?  | yes <!-- 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 | #31417    <!-- #-prefixed issue number(s), if any -->
| License       | MIT
| Doc PR        | symfony/symfony-docs#... <!-- required for new features -->

Added handling abstract handler.

Commits
-------

22e59f31be [Messenger] fix support for abstract handlers
This commit is contained in:
Nicolas Grekas 2020-02-04 14:57:55 +01:00
commit 2aca43f908
2 changed files with 46 additions and 2 deletions

View File

@ -78,7 +78,7 @@ class MessengerPass implements CompilerPassInterface
throw new RuntimeException(sprintf('Invalid handler service "%s": bus "%s" specified on the tag "%s" does not exist (known ones are: %s).', $serviceId, $tag['bus'], $this->handlerTag, implode(', ', $busIds)));
}
$className = $container->getDefinition($serviceId)->getClass();
$className = $this->getServiceClass($container, $serviceId);
$r = $container->getReflectionClass($className);
if (null === $r) {
@ -240,7 +240,7 @@ class MessengerPass implements CompilerPassInterface
$receiverMapping = [];
foreach ($container->findTaggedServiceIds($this->receiverTag) as $id => $tags) {
$receiverClass = $container->findDefinition($id)->getClass();
$receiverClass = $this->getServiceClass($container, $id);
if (!is_subclass_of($receiverClass, ReceiverInterface::class)) {
throw new RuntimeException(sprintf('Invalid receiver "%s": class "%s" must implement interface "%s".', $id, $receiverClass, ReceiverInterface::class));
}
@ -336,4 +336,19 @@ class MessengerPass implements CompilerPassInterface
$container->getDefinition($busId)->replaceArgument(0, new IteratorArgument($middlewareReferences));
}
private function getServiceClass(ContainerBuilder $container, string $serviceId): string
{
while (true) {
$definition = $container->findDefinition($serviceId);
if (!$definition->getClass() && $definition instanceof ChildDefinition) {
$serviceId = $definition->getParent();
continue;
}
return $definition->getClass();
}
}
}

View File

@ -12,6 +12,7 @@
namespace Symfony\Component\Messenger\Tests\DependencyInjection;
use PHPUnit\Framework\TestCase;
use Symfony\Component\DependencyInjection\ChildDefinition;
use Symfony\Component\DependencyInjection\Compiler\ResolveChildDefinitionsPass;
use Symfony\Component\DependencyInjection\Compiler\ResolveClassPass;
use Symfony\Component\DependencyInjection\ContainerBuilder;
@ -225,6 +226,34 @@ class MessengerPassTest extends TestCase
$this->assertSame(PrioritizedHandler::class, $secondHandlerDefinition->getClass());
}
public function testRegisterAbstractHandler()
{
$container = $this->getContainerBuilder($messageBusId = 'message_bus');
$container->register($messageBusId, MessageBusInterface::class)->addTag('messenger.bus')->setArgument(0, []);
$container
->register(DummyHandler::class, DummyHandler::class)
->setAbstract(true);
$container
->setDefinition($abstractDirectChildId = 'direct_child', new ChildDefinition(DummyHandler::class))
->setAbstract(true);
$container
->setDefinition($abstractHandlerId = 'child', new ChildDefinition($abstractDirectChildId))
->addTag('messenger.message_handler');
(new MessengerPass())->process($container);
$messageHandlerMapping = $container->getDefinition($messageBusId.'.messenger.handlers_locator')->getArgument(0);
$this->assertHandlerDescriptor(
$container,
$messageHandlerMapping,
DummyMessage::class,
[$abstractHandlerId]
);
}
public function testThrowsExceptionIfTheHandlerClassDoesNotExist()
{
$this->expectException('Symfony\Component\DependencyInjection\Exception\RuntimeException');