Skip to content

Commit f7038da

Browse files
committed
Add priority field to processor tags
1 parent 6201959 commit f7038da

File tree

3 files changed

+131
-33
lines changed

3 files changed

+131
-33
lines changed

src/DependencyInjection/Compiler/AddProcessorsPass.php

Lines changed: 58 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -11,10 +11,11 @@
1111

1212
namespace Symfony\Bundle\MonologBundle\DependencyInjection\Compiler;
1313

14+
use Symfony\Component\DependencyInjection\Argument\TaggedIteratorArgument;
1415
use Symfony\Component\DependencyInjection\ChildDefinition;
1516
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
17+
use Symfony\Component\DependencyInjection\Compiler\PriorityTaggedServiceTrait;
1618
use Symfony\Component\DependencyInjection\ContainerBuilder;
17-
use Symfony\Component\DependencyInjection\Reference;
1819

1920
/**
2021
* Registers processors in Monolog loggers or handlers.
@@ -25,48 +26,78 @@
2526
*/
2627
class AddProcessorsPass implements CompilerPassInterface
2728
{
29+
use PriorityTaggedServiceTrait;
30+
31+
private $channelPass;
32+
33+
public function __construct(?LoggerChannelPass $channelPass = null)
34+
{
35+
$this->channelPass = $channelPass;
36+
}
37+
2838
public function process(ContainerBuilder $container)
2939
{
3040
if (!$container->hasDefinition('monolog.logger')) {
3141
return;
3242
}
3343

44+
$indexedTags = [];
45+
$i = 1;
46+
3447
foreach ($container->findTaggedServiceIds('monolog.processor') as $id => $tags) {
3548
if (array_any($tags, $closure = function (array $tag) { return (bool) $tag; })) {
3649
$tags = array_filter($tags, $closure);
3750
}
3851

39-
foreach ($tags as $tag) {
40-
if (!empty($tag['channel']) && !empty($tag['handler'])) {
41-
throw new \InvalidArgumentException(\sprintf('you cannot specify both the "handler" and "channel" attributes for the "monolog.processor" tag on service "%s"', $id));
42-
}
52+
foreach ($tags as &$tag) {
53+
$indexedTags[$tag['index'] = $i++] = $tag;
54+
}
55+
unset($tag);
56+
$definition = $container->getDefinition($id);
57+
$definition->setTags(array_merge($definition->getTags(), ['monolog.processor' => $tags]));
58+
}
4359

44-
if (!empty($tag['handler'])) {
45-
$definition = $container->findDefinition(\sprintf('monolog.handler.%s', $tag['handler']));
46-
$parentDef = $definition;
47-
while (!$parentDef->getClass() && $parentDef instanceof ChildDefinition) {
48-
$parentDef = $container->findDefinition($parentDef->getParent());
49-
}
50-
$class = $container->getParameterBag()->resolveValue($parentDef->getClass());
51-
if (!method_exists($class, 'pushProcessor')) {
52-
throw new \InvalidArgumentException(\sprintf('The "%s" handler does not accept processors', $tag['handler']));
53-
}
54-
} elseif (!empty($tag['channel'])) {
55-
if ('app' === $tag['channel']) {
56-
$definition = $container->getDefinition('monolog.logger');
57-
} else {
58-
$definition = $container->getDefinition(\sprintf('monolog.logger.%s', $tag['channel']));
60+
$taggedIteratorArgument = new TaggedIteratorArgument('monolog.processor', 'index', null, true);
61+
// array_reverse is used because ProcessableHandlerTrait::pushProcessor prepends processors to the beginning of the stack
62+
foreach (array_reverse($this->findAndSortTaggedServices($taggedIteratorArgument, $container), true) as $index => $reference) {
63+
$tag = $indexedTags[$index];
64+
65+
if (!empty($tag['channel']) && !empty($tag['handler'])) {
66+
throw new \InvalidArgumentException(\sprintf('you cannot specify both the "handler" and "channel" attributes for the "monolog.processor" tag on service "%s"', $reference));
67+
}
68+
69+
if (!empty($tag['handler'])) {
70+
$parentDef = $container->findDefinition(\sprintf('monolog.handler.%s', $tag['handler']));
71+
$definitions = [$parentDef];
72+
while (!$parentDef->getClass() && $parentDef instanceof ChildDefinition) {
73+
$parentDef = $container->findDefinition($parentDef->getParent());
74+
}
75+
$class = $container->getParameterBag()->resolveValue($parentDef->getClass());
76+
if (!method_exists($class, 'pushProcessor')) {
77+
throw new \InvalidArgumentException(\sprintf('The "%s" handler does not accept processors', $tag['handler']));
78+
}
79+
} elseif (!empty($tag['channel'])) {
80+
$loggerId = 'app' === $tag['channel'] ? 'monolog.logger' : \sprintf('monolog.logger.%s', $tag['channel']);
81+
$definitions = [$container->getDefinition($loggerId)];
82+
} else {
83+
if ($this->channelPass) {
84+
$definitions = [];
85+
foreach ($this->channelPass->getChannels() as $channel) {
86+
$loggerId = 'app' === $channel ? 'monolog.logger' : \sprintf('monolog.logger.%s', $channel);
87+
$definitions[] = $container->getDefinition($loggerId);
5988
}
6089
} else {
61-
$definition = $container->getDefinition('monolog.logger_prototype');
90+
$definitions = [$container->getDefinition('monolog.logger_prototype')];
6291
}
92+
}
6393

64-
if (!empty($tag['method'])) {
65-
$processor = [new Reference($id), $tag['method']];
66-
} else {
67-
// If no method is defined, fallback to use __invoke
68-
$processor = new Reference($id);
69-
}
94+
if (!empty($tag['method'])) {
95+
$processor = [$reference, $tag['method']];
96+
} else {
97+
// If no method is defined, fallback to use __invoke
98+
$processor = $reference;
99+
}
100+
foreach ($definitions as $definition) {
70101
$definition->addMethodCall('pushProcessor', [$processor]);
71102
}
72103
}

src/MonologBundle.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ public function build(ContainerBuilder $container)
3737

3838
$container->addCompilerPass($channelPass = new LoggerChannelPass());
3939
$container->addCompilerPass(new FixEmptyLoggerPass($channelPass));
40-
$container->addCompilerPass(new AddProcessorsPass());
40+
$container->addCompilerPass(new AddProcessorsPass($channelPass));
4141
$container->addCompilerPass(new AddSwiftMailerTransportPass());
4242
}
4343

tests/DependencyInjection/Compiler/AddProcessorsPassTest.php

Lines changed: 72 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
use Symfony\Component\DependencyInjection\Definition;
2525
use Symfony\Component\DependencyInjection\Loader\PhpFileLoader;
2626
use Symfony\Component\DependencyInjection\Reference;
27+
use Symfony\Component\DependencyInjection\TypedReference;
2728

2829
class AddProcessorsPassTest extends TestCase
2930
{
@@ -34,12 +35,40 @@ public function testHandlerProcessors()
3435
$service = $container->getDefinition('monolog.handler.test');
3536
$calls = $service->getMethodCalls();
3637
$this->assertCount(1, $calls);
37-
$this->assertEquals(['pushProcessor', [new Reference('test')]], $calls[0]);
38+
$this->assertEquals(['pushProcessor', [new TypedReference('test', 'TestClass')]], $calls[0]);
3839

3940
$service = $container->getDefinition('handler_test');
4041
$calls = $service->getMethodCalls();
4142
$this->assertCount(1, $calls);
42-
$this->assertEquals(['pushProcessor', [new Reference('test2')]], $calls[0]);
43+
$this->assertEquals(['pushProcessor', [new TypedReference('test2', 'TestClass')]], $calls[0]);
44+
45+
$service = $container->getDefinition('monolog.handler.priority_test');
46+
$calls = $service->getMethodCalls();
47+
$this->assertCount(5, $calls);
48+
$this->assertEquals(['pushProcessor', [new TypedReference('processor-10', 'TestClass')]], $calls[0]);
49+
$this->assertEquals(['pushProcessor', [new TypedReference('processor+10', 'TestClass')]], $calls[1]);
50+
$this->assertEquals(['pushProcessor', [new TypedReference('processor+20', 'TestClass')]], $calls[2]);
51+
$this->assertEquals(['pushProcessor', [new TypedReference('processor+20', 'TestClass')]], $calls[2]);
52+
$this->assertEquals(['pushProcessor', [new TypedReference('processor+25+35', 'TestClass')]], $calls[3]);
53+
$this->assertEquals(['pushProcessor', [new TypedReference('processor+35+25', 'TestClass')]], $calls[4]);
54+
55+
$service = $container->getDefinition('monolog.handler.priority_test_2');
56+
$calls = $service->getMethodCalls();
57+
$this->assertCount(2, $calls);
58+
$this->assertEquals(['pushProcessor', [new TypedReference('processor+35+25', 'TestClass')]], $calls[0]);
59+
$this->assertEquals(['pushProcessor', [new TypedReference('processor+25+35', 'TestClass')]], $calls[1]);
60+
61+
$service = $container->getDefinition('monolog.logger');
62+
$calls = $service->getMethodCalls();
63+
$this->assertCount(2, $calls);
64+
$this->assertEquals(['useMicrosecondTimestamps', ['%monolog.use_microseconds%']], $calls[0]);
65+
$this->assertEquals(['pushProcessor', [new TypedReference('processor_all_channels+0', 'TestClass')]], $calls[1]);
66+
67+
$service = $container->getDefinition('monolog.logger.test');
68+
$calls = $service->getMethodCalls();
69+
$this->assertCount(2, $calls);
70+
$this->assertEquals(['pushProcessor', [new TypedReference('processor_test_channel-25', 'TestClass')]], $calls[0]);
71+
$this->assertEquals(['pushProcessor', [new TypedReference('processor_all_channels+0', 'TestClass')]], $calls[1]);
4372
}
4473

4574
public function testFailureOnHandlerWithoutPushProcessor()
@@ -126,25 +155,63 @@ protected function getContainer()
126155
$loader = new PhpFileLoader($container, new FileLocator(__DIR__.'/../../../config'));
127156
$loader->load('monolog.php');
128157

158+
$container->setParameter('monolog.additional_channels', ['test']);
159+
$container->setParameter('monolog.handlers_to_channels', []);
160+
129161
$definition = $container->getDefinition('monolog.logger_prototype');
130162
$container->setParameter('monolog.handler.console.class', ConsoleHandler::class);
131163
$container->setDefinition('monolog.handler.test', new Definition('%monolog.handler.console.class%', [100, false]));
132164
$container->setDefinition('handler_test', new Definition('%monolog.handler.console.class%', [100, false]));
165+
$container->setDefinition('monolog.handler.priority_test', new Definition('%monolog.handler.console.class%', [100, false]));
166+
$container->setDefinition('monolog.handler.priority_test_2', new Definition('%monolog.handler.console.class%', [100, false]));
133167
$container->setAlias('monolog.handler.test2', 'handler_test');
134168
$definition->addMethodCall('pushHandler', [new Reference('monolog.handler.test')]);
135169
$definition->addMethodCall('pushHandler', [new Reference('monolog.handler.test2')]);
170+
$definition->addMethodCall('pushHandler', [new Reference('monolog.handler.priority_test')]);
171+
$definition->addMethodCall('pushHandler', [new Reference('monolog.handler.priority_test_2')]);
136172

137-
$service = new Definition('TestClass', ['false', new Reference('logger')]);
173+
$service = new Definition('TestClass');
138174
$service->addTag('monolog.processor', ['handler' => 'test']);
139175
$container->setDefinition('test', $service);
140176

141-
$service = new Definition('TestClass', ['false', new Reference('logger')]);
177+
$service = new Definition('TestClass');
142178
$service->addTag('monolog.processor', ['handler' => 'test2']);
143179
$container->setDefinition('test2', $service);
144180

181+
$service = new Definition('TestClass');
182+
$service->addTag('monolog.processor', ['handler' => 'priority_test', 'priority' => 10]);
183+
$container->setDefinition('processor+10', $service);
184+
185+
$service = new Definition('TestClass');
186+
$service->addTag('monolog.processor', ['handler' => 'priority_test', 'priority' => -10]);
187+
$container->setDefinition('processor-10', $service);
188+
189+
$service = new Definition('TestClass');
190+
$service->addTag('monolog.processor', ['handler' => 'priority_test', 'priority' => 20]);
191+
$container->setDefinition('processor+20', $service);
192+
193+
$service = new Definition('TestClass');
194+
$service->addTag('monolog.processor', ['handler' => 'priority_test', 'priority' => 35]);
195+
$service->addTag('monolog.processor', ['handler' => 'priority_test_2', 'priority' => 25]);
196+
$container->setDefinition('processor+35+25', $service);
197+
198+
$service = new Definition('TestClass');
199+
$service->addTag('monolog.processor', ['handler' => 'priority_test', 'priority' => 25]);
200+
$service->addTag('monolog.processor', ['handler' => 'priority_test_2', 'priority' => 35]);
201+
$container->setDefinition('processor+25+35', $service);
202+
203+
$service = new Definition('TestClass');
204+
$service->addTag('monolog.processor', ['priority' => 0]);
205+
$container->setDefinition('processor_all_channels+0', $service);
206+
207+
$service = new Definition('TestClass');
208+
$service->addTag('monolog.processor', ['channel' => 'test', 'priority' => -25]);
209+
$container->setDefinition('processor_test_channel-25', $service);
210+
145211
$container->getCompilerPassConfig()->setOptimizationPasses([]);
146212
$container->getCompilerPassConfig()->setRemovingPasses([]);
147-
$container->addCompilerPass(new AddProcessorsPass());
213+
$container->addCompilerPass($channelPass = new LoggerChannelPass());
214+
$container->addCompilerPass(new AddProcessorsPass($channelPass));
148215
$container->compile();
149216

150217
return $container;

0 commit comments

Comments
 (0)