-
-
Notifications
You must be signed in to change notification settings - Fork 9.6k
[Messenger] Middleware factories support in config #27128
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
Conversation
I don't see the point of the |
Same as for keeping the simple |
To me, using these arguments is the "advanced" way of configuring the middleware: using the object syntax with the - - doctrine_transaction_middleware: ['entity_manager_name']
+ - {id: 'doctrine_transaction_middleware', arguments: ['entity_manager_name']} Or do I miss something? |
@sroze or drop the |
@sroze : Obviously you didn't miss anything. I just like this syntax :) (and I expected end-users to have a preference for it too but that's just my guess).
My own preference is 1. Perhaps 4. |
Looking at it this way, 4 looks nicer but the “one only” limitation is too many assumptions IMHO. 3 is verbose and 4 not really coherent. Let’s keep 1 then, good point 😃 |
foreach (array_values($arguments ?? array()) as $key => $argument) { | ||
// Parent definition can provide default arguments. | ||
// Replace each explicitly or add if not set: | ||
$key < $count ? $childDefinition->replaceArgument($key, $argument) : $childDefinition->addArgument($argument); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why not just using setArgument
here?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Due to the way child definitions arguments work, using replaceArgument
saves an extra hard coded index_
prefix for the key here.
symfony/src/Symfony/Component/DependencyInjection/ChildDefinition.php
Lines 98 to 99 in d264fce
if (is_int($index)) { | |
$this->arguments['index_'.$index] = $value; |
@@ -202,22 +202,35 @@ private function registerBusToCollector(ContainerBuilder $container, string $bus | |||
|
|||
private function registerBusMiddleware(ContainerBuilder $container, string $busId, array $middleware) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could you rename to $middlewareCollection
to make it more explicit?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sure, good idea 👍 (uncountable nouns are hell in programmation)
$container->setDefinition($messengerMiddlewareId = $busId.'.middleware.'.$name, $childDefinition); | ||
$container->setDefinition($messengerMiddlewareId = $busId.'.middleware.'.$id, $childDefinition); | ||
} elseif ($arguments) { | ||
throw new RuntimeException(sprintf('Invalid middleware factory "%s": a middleware factory must be an abstract definition.', $id)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could we put that first as a simple if
so we don't have this extra indentation?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think so, it'll still need the abstract check and won't save any indent, right?
$container->register(UselessMiddleware::class, UselessMiddleware::class); | ||
|
||
$container->setParameter($middlewareParameter = $fooBusId.'.middleware', array(UselessMiddleware::class, 'allow_no_handler')); | ||
$container->setParameter($middlewareParameter = $fooBusId.'.middleware', array( | ||
array('id' => UselessMiddleware::class, 'arguments' => array()), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As you deal with the fact that arguments
might not be present, shouldn't we remove it here?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The config adds the default [] value, but not the default middleware in https://github.com/ogizanagi/symfony/blob/a36dad010b7634bbe3c35f74490ced841d0fc2a1/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php#L1472-L1474
Should I update the extension and enforce in the pass? Or the config so it removes it if empty? Not really worth it IMHO.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
NVM, understood. I thought this was the FrameworkExtensionTest
class 😅
$arguments = reset($middleware); | ||
|
||
return array( | ||
'id' => key($middleware), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we should throw an exception is we have multiple keys in here
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The issue is that beforeNormalization
isn't really designed for throwing. It's the validate
responsibility which would also prepend the path. But at this point we would have already ignored the extra keys.
So we could add manually something like:
if (\count($middleware) > 1) {
throw new \InvalidArgumentException(sprintf('At path "framework.messenger.buses.middleware": expected a single entry for a middleware item array, with factory id as key and arguments as value. Got "%s".', json_encode($middleware)));
}
Do you think it is worth it?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I’d say, it’s easy to end up with something like that:
middleware:
- foo: 1
bar: { baz: ~ }
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Alright, added
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Great. Needs to be in 4.1 because it changes the XML syntax for middlewares for the good 👍
Failure on |
I've just created the PR on doctrine/DoctrineBundle#817 to wire the services when the component is enabled. |
Thank you @ogizanagi. |
…izanagi) This PR was squashed before being merged into the 4.1 branch (closes #27128). Discussion ---------- [Messenger] Middleware factories support in config | 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 | N/A <!-- #-prefixed issue number(s), if any --> | License | MIT | Doc PR | todo Following #26864, this would allow to configure easily the middlewares by using an abstract factory definition to which are provided simple arguments (just scalars, no services references). For instance, here is how the DoctrineBundle would benefit from such a feature (also solving the wiring of the `DoctrineTransactionMiddleware` reverted in #26684): ```yaml framework: messenger: buses: default: middleware: - logger - doctrine_transaction_middleware: ['entity_manager_name'] ``` where `doctrine_transaction_middleware` would be an abstract factory definition provided by the doctrine bundle: ```yml services: doctrine.orm.messenger.middleware_factory.transaction: class: Symfony\Bridge\Doctrine\Messenger\DoctrineTransactionMiddlewareFactory arguments: ['@doctrine'] doctrine_transaction_middleware: class: Symfony\Bridge\Doctrine\Messenger\DoctrineTransactionMiddleware factory: ['@doctrine.orm.messenger.middleware_factory.transaction', 'createMiddleware'] abstract: true # the default arguments to use when none provided from config. # i.e: # middlewares: # - doctrine_transaction_middleware: ~ arguments: ['default'] ``` and is interpreted as: ```yml buses: default: middleware: - id: logger arguments: { } - id: doctrine_transaction_middleware arguments: - entity_manager_name default_middleware: true ``` --- <details> <summary>Here is the whole config reference with these changes: </summary> ```yaml # Messenger configuration messenger: enabled: true routing: # Prototype message_class: senders: [] serializer: enabled: true format: json context: # Prototype name: ~ encoder: messenger.transport.serializer decoder: messenger.transport.serializer adapters: # Prototype name: dsn: ~ options: [] default_bus: null buses: # Prototype name: default_middleware: true middleware: # Prototype - id: ~ # Required arguments: [] ``` </details> Commits ------- f5ef421 [Messenger] Middleware factories support in config
…iereguiluz) This PR was merged into the 4.1 branch. Discussion ---------- [Messenger] Document middleware factories <!-- If your pull request fixes a BUG, use the oldest maintained branch that contains the bug (see https://symfony.com/roadmap for the list of maintained branches). If your pull request documents a NEW FEATURE, use the same Symfony branch where the feature was introduced (and `master` for features of unreleased versions). --> Refs: - Symfony PR: symfony/symfony#27128 - DoctrineBundle PR: doctrine/DoctrineBundle#817 Commits ------- c5ef7c8 Reowrd to restore the original meaning a87f21b Minor rewords 2880027 [Messenger] Document middleware factories
Following #26864, this would allow to configure easily the middlewares by using an abstract factory definition to which are provided simple arguments (just scalars, no services references).
For instance, here is how the DoctrineBundle would benefit from such a feature (also solving the wiring of the
DoctrineTransactionMiddleware
reverted in #26684):where
doctrine_transaction_middleware
would be an abstract factory definition provided by the doctrine bundle:and is interpreted as:
Here is the whole config reference with these changes: