Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit 7d3129a

Browse filesBrowse 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 symfony/symfony#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 symfony/symfony#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 ------- f5ef421474 [Messenger] Middleware factories support in config
2 parents 1fbdbbb + a7fc38b commit 7d3129a
Copy full SHA for 7d3129a

File tree

Expand file treeCollapse file tree

2 files changed

+72
-12
lines changed
Filter options
Expand file treeCollapse file tree

2 files changed

+72
-12
lines changed

‎DependencyInjection/MessengerPass.php

Copy file name to clipboardExpand all lines: DependencyInjection/MessengerPass.php
+22-9Lines changed: 22 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -248,24 +248,37 @@ private function registerBusToCollector(ContainerBuilder $container, string $bus
248248
$container->getDefinition('messenger.data_collector')->addMethodCall('registerBus', array($busId, new Reference($tracedBusId)));
249249
}
250250

251-
private function registerBusMiddleware(ContainerBuilder $container, string $busId, array $middleware)
251+
private function registerBusMiddleware(ContainerBuilder $container, string $busId, array $middlewareCollection)
252252
{
253-
$container->getDefinition($busId)->replaceArgument(0, array_map(function (string $name) use ($container, $busId) {
254-
if (!$container->has($messengerMiddlewareId = 'messenger.middleware.'.$name)) {
255-
$messengerMiddlewareId = $name;
253+
$middlewareReferences = array();
254+
foreach ($middlewareCollection as $middlewareItem) {
255+
$id = $middlewareItem['id'];
256+
$arguments = $middlewareItem['arguments'] ?? array();
257+
if (!$container->has($messengerMiddlewareId = 'messenger.middleware.'.$id)) {
258+
$messengerMiddlewareId = $id;
256259
}
257260

258261
if (!$container->has($messengerMiddlewareId)) {
259-
throw new RuntimeException(sprintf('Invalid middleware "%s": define such service to be able to use it.', $name));
262+
throw new RuntimeException(sprintf('Invalid middleware "%s": define such service to be able to use it.', $id));
260263
}
261264

262-
if ($container->getDefinition($messengerMiddlewareId)->isAbstract()) {
265+
if (($definition = $container->findDefinition($messengerMiddlewareId))->isAbstract()) {
263266
$childDefinition = new ChildDefinition($messengerMiddlewareId);
267+
$count = \count($definition->getArguments());
268+
foreach (array_values($arguments ?? array()) as $key => $argument) {
269+
// Parent definition can provide default arguments.
270+
// Replace each explicitly or add if not set:
271+
$key < $count ? $childDefinition->replaceArgument($key, $argument) : $childDefinition->addArgument($argument);
272+
}
264273

265-
$container->setDefinition($messengerMiddlewareId = $busId.'.middleware.'.$name, $childDefinition);
274+
$container->setDefinition($messengerMiddlewareId = $busId.'.middleware.'.$id, $childDefinition);
275+
} elseif ($arguments) {
276+
throw new RuntimeException(sprintf('Invalid middleware factory "%s": a middleware factory must be an abstract definition.', $id));
266277
}
267278

268-
return new Reference($messengerMiddlewareId);
269-
}, $middleware));
279+
$middlewareReferences[] = new Reference($messengerMiddlewareId);
280+
}
281+
282+
$container->getDefinition($busId)->replaceArgument(0, $middlewareReferences);
270283
}
271284
}

‎Tests/DependencyInjection/MessengerPassTest.php

Copy file name to clipboardExpand all lines: Tests/DependencyInjection/MessengerPassTest.php
+50-3Lines changed: 50 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313

1414
use PHPUnit\Framework\TestCase;
1515
use Symfony\Component\DependencyInjection\Argument\ServiceClosureArgument;
16+
use Symfony\Component\DependencyInjection\Compiler\ResolveChildDefinitionsPass;
1617
use Symfony\Component\DependencyInjection\ContainerBuilder;
1718
use Symfony\Component\DependencyInjection\Reference;
1819
use Symfony\Component\DependencyInjection\ServiceLocator;
@@ -359,14 +360,42 @@ public function testRegistersMiddlewareFromServices()
359360
$container = $this->getContainerBuilder();
360361
$container->register($fooBusId = 'messenger.bus.foo', MessageBusInterface::class)->setArgument(0, array())->addTag('messenger.bus');
361362
$container->register('messenger.middleware.allow_no_handler', AllowNoHandlerMiddleware::class)->setAbstract(true);
363+
$container->register('middleware_with_factory', UselessMiddleware::class)->addArgument('some_default')->setAbstract(true);
364+
$container->register('middleware_with_factory_using_default', UselessMiddleware::class)->addArgument('some_default')->setAbstract(true);
362365
$container->register(UselessMiddleware::class, UselessMiddleware::class);
363366

364-
$container->setParameter($middlewareParameter = $fooBusId.'.middleware', array(UselessMiddleware::class, 'allow_no_handler'));
367+
$container->setParameter($middlewareParameter = $fooBusId.'.middleware', array(
368+
array('id' => UselessMiddleware::class),
369+
array('id' => 'middleware_with_factory', 'arguments' => array('foo', 'bar')),
370+
array('id' => 'middleware_with_factory_using_default'),
371+
array('id' => 'allow_no_handler'),
372+
));
365373

366374
(new MessengerPass())->process($container);
375+
(new ResolveChildDefinitionsPass())->process($container);
367376

368377
$this->assertTrue($container->hasDefinition($childMiddlewareId = $fooBusId.'.middleware.allow_no_handler'));
369-
$this->assertEquals(array(new Reference(UselessMiddleware::class), new Reference($childMiddlewareId)), $container->getDefinition($fooBusId)->getArgument(0));
378+
379+
$this->assertTrue($container->hasDefinition($factoryChildMiddlewareId = $fooBusId.'.middleware.middleware_with_factory'));
380+
$this->assertEquals(
381+
array('foo', 'bar'),
382+
$container->getDefinition($factoryChildMiddlewareId)->getArguments(),
383+
'parent default argument is overridden, and next ones appended'
384+
);
385+
386+
$this->assertTrue($container->hasDefinition($factoryWithDefaultChildMiddlewareId = $fooBusId.'.middleware.middleware_with_factory_using_default'));
387+
$this->assertEquals(
388+
array('some_default'),
389+
$container->getDefinition($factoryWithDefaultChildMiddlewareId)->getArguments(),
390+
'parent default argument is used'
391+
);
392+
393+
$this->assertEquals(array(
394+
new Reference(UselessMiddleware::class),
395+
new Reference($factoryChildMiddlewareId),
396+
new Reference($factoryWithDefaultChildMiddlewareId),
397+
new Reference($childMiddlewareId),
398+
), $container->getDefinition($fooBusId)->getArgument(0));
370399
$this->assertFalse($container->hasParameter($middlewareParameter));
371400
}
372401

@@ -378,7 +407,25 @@ public function testCannotRegistersAnUndefinedMiddleware()
378407
{
379408
$container = $this->getContainerBuilder();
380409
$container->register($fooBusId = 'messenger.bus.foo', MessageBusInterface::class)->setArgument(0, array())->addTag('messenger.bus');
381-
$container->setParameter($middlewareParameter = $fooBusId.'.middleware', array('not_defined_middleware'));
410+
$container->setParameter($middlewareParameter = $fooBusId.'.middleware', array(
411+
array('id' => 'not_defined_middleware', 'arguments' => array()),
412+
));
413+
414+
(new MessengerPass())->process($container);
415+
}
416+
417+
/**
418+
* @expectedException \Symfony\Component\DependencyInjection\Exception\RuntimeException
419+
* @expectedExceptionMessage Invalid middleware factory "not_an_abstract_definition": a middleware factory must be an abstract definition.
420+
*/
421+
public function testMiddlewareFactoryDefinitionMustBeAbstract()
422+
{
423+
$container = $this->getContainerBuilder();
424+
$container->register('not_an_abstract_definition', UselessMiddleware::class);
425+
$container->register($fooBusId = 'messenger.bus.foo', MessageBusInterface::class)->setArgument(0, array())->addTag('messenger.bus', array('name' => 'foo'));
426+
$container->setParameter($middlewareParameter = $fooBusId.'.middleware', array(
427+
array('id' => 'not_an_abstract_definition', 'arguments' => array('foo')),
428+
));
382429

383430
(new MessengerPass())->process($container);
384431
}

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.