Skip to content

[Messenger] Allow to typehint multiple buses #27054

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 3 commits into from

Conversation

sroze
Copy link
Contributor

@sroze sroze commented Apr 25, 2018

Q A
Branch? master
Bug fix? no
New feature? no
BC breaks? no
Deprecations? no
Tests pass? yes
Fixed tickets ø
License MIT
Doc PR ø

When defining multiple buses, it becomes impossible to type-hint the MessageBusInterface. This PR adds the ability to wrap the bus within a decorator that you will be able to typehint.

As a developer, you will create your classes:

namespace App\Bus;

use Symfony\Component\Messenger\DecoratedMessageBus;

final class CommandBus extends DecoratedMessageBus
{
}

Configure your bus to use it:

framework:
    messenger:
        buses:
            commands:
                decorator_class: 'App\Bus\CommandBus'

You can now typehint your CommandBus 🥁 💃 ⭐️

@sroze sroze added this to the 4.1 milestone Apr 25, 2018
Copy link
Member

@chalasr chalasr left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

mainly wording suggestions

*
* @author Samuel Roze <samuel.roze@gmail.com>
*/
abstract class DecoratedMessageBus implements MessageBusInterface
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If concrete children are decorators then this is a base decorator, isn't it? Also core abstract classes are prefixed by Abstract so, AbstractMessageBusDecorator?

/**
* A decorated message bus.
*
* Use this abstract class to created your message bus decorator to specialise your
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

typo to create

* A decorated message bus.
*
* Use this abstract class to created your message bus decorator to specialise your
* bus instances and type-hint them.
Copy link
Member

@chalasr chalasr Apr 26, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I suggest type-hint against them, dependents type-hint one of their dependencies against the type they need

@@ -1481,8 +1481,13 @@ private function registerMessengerConfiguration(array $config, ContainerBuilder
throw new LogicException('The Validation middleware is only available when the Validator component is installed and enabled. Try running "composer require symfony/validator".');
}

$tagAttributes = array('name' => $name);
if (isset($bus['decorator_class'])) {
$tagAttributes['decorator_class'] = $bus['decorator_class'];
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should it fail if the class does not implement MessageBusInterface at least? Perhaps give a complete hint about what is needed for using this option

@@ -413,3 +425,7 @@ public function handle($message, callable $next)
return $next($message);
}
}

final class MyTypeHintedBus extends DecoratedMessageBus
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

TypeHinted is misleading here :) a class is a type, method arguments are type-hinted

@ro0NL
Copy link
Contributor

ro0NL commented Apr 26, 2018

it becomes impossible to type-hint the MessageBusInterface

you'll get the default bus AFAIK...

You can now typehint your CommandBus

What if the same decorated class is used multiple times across buses?

isn't this just like saying My\CommandBus: '@messenger.bus.command', using regular DI wiring. Put different; do we really want/need this feature?

@sroze
Copy link
Contributor Author

sroze commented Apr 27, 2018

What if the same decorated class is used multiple times across buses?

Well, you know what is going to happen: the auto-wiring won't be happy :)

isn't this just like saying My\CommandBus: '@messenger.bus.command', using regular DI wiring. Put different; do we really want/need this feature?

Ish. It still means you'd have to create the My\CommandBus class, but it's a good point. Should we go with just the class and no FWB configuration?

@ro0NL
Copy link
Contributor

ro0NL commented Apr 27, 2018

Or just a trait maybe =/ i would indeed avoid the FWB config.

@sroze
Copy link
Contributor Author

sroze commented Apr 27, 2018

It works well with the following configuration 👍

services:
    'App\Bus\CommandBus':
        decorates: "messenger.bus.commands"

@sroze sroze force-pushed the uses-custom-class branch 2 times, most recently from 99669ba to 2b601ad Compare April 27, 2018 09:10
@sroze
Copy link
Contributor Author

sroze commented Apr 27, 2018

To be completed by a lovely documentation :)

@kbond
Copy link
Member

kbond commented Apr 27, 2018

In development, with the following configuration:

services:
    'App\Bus\CommandBus':
        decorates: "messenger.bus.commands"

The decorated bus is an instance of Symfony\Component\Messenger\MessageBus not Symfony\Component\Messenger\TraceableMessageBus

@sroze
Copy link
Contributor Author

sroze commented Apr 27, 2018

@kbond you need to typehint ither MessageBusInterface or your own App\Bus\CommandBus not Symfony\Component\Messenger\MessageBus 😉

@kbond
Copy link
Member

kbond commented Apr 27, 2018

@sroze I type-hinted my own bus which extends from AbstractMessageBusDecorator. The $decoratedBus property is not and instance of Symfony\Component\Messenger\TraceableMessageBus

It is the correct bus it just doesn't show any activity in the profiler.

@sroze
Copy link
Contributor Author

sroze commented Apr 27, 2018

I'm sorry but I don't understand the problem... "it works well on my machine" 😅 Can you give me the exact error you face and the classes & configuration you have? :)

@kbond
Copy link
Member

kbond commented Apr 27, 2018

There is no error.

messenger config:

framework:
    messenger:
        default_bus: event
        buses:
            command:
                default_middlewares: false
                middlewares:
                    - logging
                    - Symfony\Bridge\Doctrine\Messenger\DoctrineTransactionMiddleware
                    - call_message_handler
            query:
                default_middlewares: false
                middlewares:
                    - logging
                    - call_message_handler
            event:
                middleware:
                    - tolerate_no_handler

service config:

services:
    App\Messenger\CommandBus:
        decorates: messenger.bus.command

my command bus class:

namespace App\Messenger;

use Symfony\Component\Messenger\AbstractMessageBusDecorator;

final class CommandBus extends AbstractMessageBusDecorator
{
}

controller injecting command bus:

public function myAction(CommandBus $commandBus)
{
    dump($commandBus);

    // ...
}

Screenshot of dumped $commandBus:

symfony profiler

Notice the decorated bus is just MessageBus not TraceableMessageBus.

@kbond
Copy link
Member

kbond commented Apr 27, 2018

Note, if I change my service config to:

services:
    App\Messenger\CommandBus: ['@messenger.bus.command']

symfony profiler 1

The TraceableMessageBus is the decoratedBus.

@sroze
Copy link
Contributor Author

sroze commented Apr 27, 2018

Oh, excellent. Thank you for checking that. That's what will be in the documentation then :)

@sroze
Copy link
Contributor Author

sroze commented Apr 28, 2018

Status: Ready

Copy link
Contributor

@ro0NL ro0NL left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

not sure core needs it.. (i'd write this out anyway :)) but 👍 for the intend allthough i'd use a trait to avoid inheritance and own the private decorated bus in my own class.

Copy link
Member

@weaverryan weaverryan left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm, it seems like a pretty small feature in its final form. So, I think it's ok. @sroze can you open a Docs PR before this gets merged with a quick dump of the final "docs" needed to make this work? I'm not 100% clear which service configuration was finally the correct one from the comments.

@sroze
Copy link
Contributor Author

sroze commented May 3, 2018

@nicolas-grekas
Copy link
Member

nicolas-grekas commented May 4, 2018

I'm very skeptical about this PR and the related § in symfony/symfony-docs#9727.
This encourages type-hinting against a concrete implementation and totally breaks SOLID, isn't it?
I acknowledge there is a DX issue and that this proposal tries to solve it. Coincidentally, I was talking about the exact same issue with @weaverryan today, telling him about a solution we might want to push forward in 4.2 (it's too early to elaborate here for now).

@sroze
Copy link
Contributor Author

sroze commented May 4, 2018 via email

@nicolas-grekas
Copy link
Member

nicolas-grekas commented May 4, 2018

No need for any dedicated interfaces, using bindings solves the issue:
$commandBus: @messenger.bus.command

@sroze
Copy link
Contributor Author

sroze commented May 4, 2018

Outch. Not sure how I feel about that one. I'll give a try.

@nicolas-grekas
Copy link
Member

nicolas-grekas commented May 5, 2018

As explained, I'm:-1: as this would put users in a dead end. We should tell about using bindings instead, and seek for a better experience in 4.2 that doesn't break SOLID.

@sroze
Copy link
Contributor Author

sroze commented May 6, 2018

Closing, as I'll update the documentation to recommend the binding, that makes sense actually.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

7 participants