Skip to content

Commit f59ce97

Browse files
committed
feature #27128 [Messenger] Middleware factories support in config (ogizanagi)
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
2 parents 5f0e2d6 + f5ef421 commit f59ce97

File tree

13 files changed

+222
-24
lines changed

13 files changed

+222
-24
lines changed
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <fabien@symfony.com>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespace Symfony\Bridge\Doctrine\Messenger;
13+
14+
use Symfony\Bridge\Doctrine\ManagerRegistry;
15+
16+
/**
17+
* Create a Doctrine ORM transaction middleware to be used in a message bus from an entity manager name.
18+
*
19+
* @author Maxime Steinhausser <maxime.steinhausser@gmail.com>
20+
*
21+
* @experimental in 4.1
22+
* @final
23+
*/
24+
class DoctrineTransactionMiddlewareFactory
25+
{
26+
private $managerRegistry;
27+
28+
public function __construct(ManagerRegistry $managerRegistry)
29+
{
30+
$this->managerRegistry = $managerRegistry;
31+
}
32+
33+
public function createMiddleware(string $managerName): DoctrineTransactionMiddleware
34+
{
35+
return new DoctrineTransactionMiddleware($this->managerRegistry, $managerName);
36+
}
37+
}

src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Configuration.php

Lines changed: 30 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1061,7 +1061,36 @@ function ($a) {
10611061
})
10621062
->end()
10631063
->defaultValue(array())
1064-
->prototype('scalar')->end()
1064+
->prototype('array')
1065+
->beforeNormalization()
1066+
->always()
1067+
->then(function ($middleware): array {
1068+
if (!\is_array($middleware)) {
1069+
return array('id' => $middleware);
1070+
}
1071+
if (isset($middleware['id'])) {
1072+
return $middleware;
1073+
}
1074+
if (\count($middleware) > 1) {
1075+
throw new \InvalidArgumentException(sprintf('There is an error at path "framework.messenger" in one of the buses middleware definitions: expected a single entry for a middleware item config, with factory id as key and arguments as value. Got "%s".', json_encode($middleware)));
1076+
}
1077+
1078+
return array(
1079+
'id' => key($middleware),
1080+
'arguments' => current($middleware),
1081+
);
1082+
})
1083+
->end()
1084+
->fixXmlConfig('argument')
1085+
->children()
1086+
->scalarNode('id')->isRequired()->cannotBeEmpty()->end()
1087+
->arrayNode('arguments')
1088+
->normalizeKeys(false)
1089+
->defaultValue(array())
1090+
->prototype('variable')
1091+
->end()
1092+
->end()
1093+
->end()
10651094
->end()
10661095
->end()
10671096
->end()

src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1468,12 +1468,17 @@ private function registerMessengerConfiguration(array $config, ContainerBuilder
14681468
$config['default_bus'] = key($config['buses']);
14691469
}
14701470

1471-
$defaultMiddleware = array('before' => array('logging'), 'after' => array('route_messages', 'call_message_handler'));
1471+
$defaultMiddleware = array(
1472+
'before' => array(array('id' => 'logging')),
1473+
'after' => array(array('id' => 'route_messages'), array('id' => 'call_message_handler')),
1474+
);
14721475
foreach ($config['buses'] as $busId => $bus) {
14731476
$middleware = $bus['default_middleware'] ? array_merge($defaultMiddleware['before'], $bus['middleware'], $defaultMiddleware['after']) : $bus['middleware'];
14741477

1475-
if (!$validationConfig['enabled'] && \in_array('messenger.middleware.validation', $middleware, true)) {
1476-
throw new LogicException('The Validation middleware is only available when the Validator component is installed and enabled. Try running "composer require symfony/validator".');
1478+
foreach ($middleware as $middlewareItem) {
1479+
if (!$validationConfig['enabled'] && 'messenger.middleware.validation' === $middlewareItem['id']) {
1480+
throw new LogicException('The Validation middleware is only available when the Validator component is installed and enabled. Try running "composer require symfony/validator".');
1481+
}
14771482
}
14781483

14791484
$container->setParameter($busId.'.middleware', $middleware);

src/Symfony/Bundle/FrameworkBundle/Resources/config/schema/symfony-1.0.xsd

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -391,9 +391,16 @@
391391

392392
<xsd:complexType name="messenger_bus">
393393
<xsd:sequence>
394-
<xsd:element name="middleware" type="xsd:string" minOccurs="0" maxOccurs="unbounded" />
394+
<xsd:element name="middleware" type="messenger_middleware" minOccurs="0" maxOccurs="unbounded" />
395395
</xsd:sequence>
396396
<xsd:attribute name="name" type="xsd:string" use="required"/>
397397
<xsd:attribute name="default-middleware" type="xsd:boolean"/>
398398
</xsd:complexType>
399+
400+
<xsd:complexType name="messenger_middleware">
401+
<xsd:sequence>
402+
<xsd:element name="argument" type="xsd:anyType" minOccurs="0" maxOccurs="unbounded" />
403+
</xsd:sequence>
404+
<xsd:attribute name="id" type="xsd:string" use="required"/>
405+
</xsd:complexType>
399406
</xsd:schema>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
<?php
2+
3+
$container->loadFromExtension('framework', array(
4+
'messenger' => array(
5+
'buses' => array(
6+
'command_bus' => array(
7+
'middleware' => array(
8+
array(
9+
'foo' => array('qux'),
10+
'bar' => array('baz'),
11+
),
12+
),
13+
),
14+
),
15+
),
16+
));

src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/messenger_multiple_buses.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
'messenger.bus.commands' => null,
88
'messenger.bus.events' => array(
99
'middleware' => array(
10+
array('with_factory' => array('foo', true, array('bar' => 'baz'))),
1011
'allow_no_handler',
1112
),
1213
),

src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/messenger_multiple_buses.xml

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,12 +9,19 @@
99
<framework:messenger default-bus="messenger.bus.commands">
1010
<framework:bus name="messenger.bus.commands" />
1111
<framework:bus name="messenger.bus.events">
12-
<framework:middleware>allow_no_handler</framework:middleware>
12+
<framework:middleware id="with_factory">
13+
<framework:argument>foo</framework:argument>
14+
<framework:argument>true</framework:argument>
15+
<framework:argument>
16+
<framework:bar>baz</framework:bar>
17+
</framework:argument>
18+
</framework:middleware>
19+
<framework:middleware id="allow_no_handler" />
1320
</framework:bus>
1421
<framework:bus name="messenger.bus.queries" default-middleware="false">
15-
<framework:middleware>route_messages</framework:middleware>
16-
<framework:middleware>allow_no_handler</framework:middleware>
17-
<framework:middleware>call_message_handler</framework:middleware>
22+
<framework:middleware id="route_messages" />
23+
<framework:middleware id="allow_no_handler" />
24+
<framework:middleware id="call_message_handler" />
1825
</framework:bus>
1926
</framework:messenger>
2027
</framework:config>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
framework:
2+
messenger:
3+
buses:
4+
command_bus:
5+
middleware:
6+
- foo: ['qux']
7+
bar: ['baz']

src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/messenger_multiple_buses.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ framework:
55
messenger.bus.commands: ~
66
messenger.bus.events:
77
middleware:
8+
- with_factory: [foo, true, { bar: baz }]
89
- "allow_no_handler"
910
messenger.bus.queries:
1011
default_middleware: false

src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/FrameworkExtensionTest.php

Lines changed: 26 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -604,18 +604,41 @@ public function testMessengerWithMultipleBuses()
604604

605605
$this->assertTrue($container->has('messenger.bus.commands'));
606606
$this->assertSame(array(), $container->getDefinition('messenger.bus.commands')->getArgument(0));
607-
$this->assertEquals(array('logging', 'route_messages', 'call_message_handler'), $container->getParameter('messenger.bus.commands.middleware'));
607+
$this->assertEquals(array(
608+
array('id' => 'logging'),
609+
array('id' => 'route_messages'),
610+
array('id' => 'call_message_handler'),
611+
), $container->getParameter('messenger.bus.commands.middleware'));
608612
$this->assertTrue($container->has('messenger.bus.events'));
609613
$this->assertSame(array(), $container->getDefinition('messenger.bus.events')->getArgument(0));
610-
$this->assertEquals(array('logging', 'allow_no_handler', 'route_messages', 'call_message_handler'), $container->getParameter('messenger.bus.events.middleware'));
614+
$this->assertEquals(array(
615+
array('id' => 'logging'),
616+
array('id' => 'with_factory', 'arguments' => array('foo', true, array('bar' => 'baz'))),
617+
array('id' => 'allow_no_handler', 'arguments' => array()),
618+
array('id' => 'route_messages'),
619+
array('id' => 'call_message_handler'),
620+
), $container->getParameter('messenger.bus.events.middleware'));
611621
$this->assertTrue($container->has('messenger.bus.queries'));
612622
$this->assertSame(array(), $container->getDefinition('messenger.bus.queries')->getArgument(0));
613-
$this->assertEquals(array('route_messages', 'allow_no_handler', 'call_message_handler'), $container->getParameter('messenger.bus.queries.middleware'));
623+
$this->assertEquals(array(
624+
array('id' => 'route_messages', 'arguments' => array()),
625+
array('id' => 'allow_no_handler', 'arguments' => array()),
626+
array('id' => 'call_message_handler', 'arguments' => array()),
627+
), $container->getParameter('messenger.bus.queries.middleware'));
614628

615629
$this->assertTrue($container->hasAlias('message_bus'));
616630
$this->assertSame('messenger.bus.commands', (string) $container->getAlias('message_bus'));
617631
}
618632

633+
/**
634+
* @expectedException \InvalidArgumentException
635+
* @expectedExceptionMessage There is an error at path "framework.messenger" in one of the buses middleware definitions: expected a single entry for a middleware item config, with factory id as key and arguments as value. Got "{"foo":["qux"],"bar":["baz"]}"
636+
*/
637+
public function testMessengerMiddlewareFactoryErroneousFormat()
638+
{
639+
$this->createContainerFromFile('messenger_middleware_factory_erroneous_format');
640+
}
641+
619642
public function testTranslator()
620643
{
621644
$container = $this->createContainerFromFile('full');

0 commit comments

Comments
 (0)