Completed
Push — master ( 4b7d76...9c0fcf )
by Tobias
12:59 queued 09:16
created

CompilerPasses::removeCommandHandlerDuplicates()   C

Complexity

Conditions 7
Paths 11

Size

Total Lines 31
Code Lines 16

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 8
CRAP Score 14.2702

Importance

Changes 0
Metric Value
dl 0
loc 31
ccs 8
cts 17
cp 0.4706
rs 6.7272
c 0
b 0
f 0
cc 7
eloc 16
nc 11
nop 1
crap 14.2702
1
<?php
2
3
namespace Happyr\SimpleBusBundle\DependencyInjection\CompilerPass;
4
5
use Happyr\SimpleBusBundle\Message\Publisher\RabbitMQPublisher;
6
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
7
use Symfony\Component\DependencyInjection\ContainerBuilder;
8
use Symfony\Component\DependencyInjection\ContainerInterface;
9
use Symfony\Component\DependencyInjection\Reference;
10
11
/**
12
 * @author Tobias Nyholm
13
 */
14
class CompilerPasses implements CompilerPassInterface
15
{
16 1
    public function process(ContainerBuilder $container)
17
    {
18 1
        $this->removeCommandHandlerDuplicates($container);
19 1
        $this->handleEventSubscriberDuplicates($container);
20 1
        $this->processMessageHandlers($container);
21 1
        $this->replaceSimpleBusPublisher($container);
22 1
    }
23
24
    /**
25
     * If we find to command handler services that are registered on the same command, make sure we remove the one with '.auto' on the end.
26
     *
27
     * @param ContainerBuilder $container
28
     */
29 1
    private function removeCommandHandlerDuplicates(ContainerBuilder $container)
30
    {
31 1
        $taggedServices = array_merge($container->findTaggedServiceIds('command_handler'), $container->findTaggedServiceIds('asynchronous_command_handler'));
32
33 1
        $commands = [];
34
35 1
        foreach ($taggedServices as $id => $tags) {
36 1
            foreach ($tags as $tag) {
37 1
                if (isset($commands[$tag['handles']])) {
38
                    // Find the one that ends with '.auto'
39
                    $removeServiceId = null;
40
41
                    if (substr($id, -5) === '.auto') {
42
                        $removeServiceId = $id;
43
                    }
44
45
                    if (substr($commands[$tag['handles']], -5) === '.auto') {
46
                        $removeServiceId = $commands[$tag['handles']];
47
                        $commands[$tag['handles']] = $id;
48
                    }
49
50
                    if ($removeServiceId !== null) {
51
                        // Remove the definition
52
                        $container->removeDefinition($removeServiceId);
53
                        continue;
54
                    }
55
                }
56 1
                $commands[$tag['handles']] = $id;
57
            }
58
        }
59 1
    }
60
61
    /**
62
     * @param ContainerBuilder $container
63
     */
64 1
    private function handleEventSubscriberDuplicates(ContainerBuilder $container)
65
    {
66 1
        $taggedServices = array_merge($container->findTaggedServiceIds('event_subscriber'), $container->findTaggedServiceIds('asynchronous_event_subscriber'));
67
68
        // Keys are event class names
69 1
        $events = [];
70
71 1
        foreach ($taggedServices as $id => $tags) {
72 1
            foreach ($tags as $tag) {
73 1
                if (isset($tag['subscribes_to'])) {
74 1
                    $events[$tag['subscribes_to']][] = $id;
75
                }
76
            }
77
        }
78
79 1
        foreach ($events as $eventClass => $subscribersIds) {
80 1
            if (count($subscribersIds) <= 1) {
81 1
                continue;
82
            }
83
84
            // Get services
85
            $subscriberClassNames = [];
86
            foreach ($subscribersIds as $subscribersId) {
87
                $service = $container->getDefinition($subscribersId);
88
                $subscriberClassNames[$service->getClass()][] = $subscribersId;
89
            }
90
91
            foreach ($subscriberClassNames as $className => $services) {
92
                if (count($services) <= 1) {
93
                    continue;
94
                }
95
96
                // IF we have multiple services registed to the same event subscriber, remove the auto added ones.
97
                foreach ($services as $serviceId) {
98
                    if (substr($serviceId, -5) === '.auto') {
99
                        $container->removeDefinition($serviceId);
100
                    }
101
                }
102
            }
103
        }
104 1
    }
105
106
    /**
107
     * @param ContainerBuilder $container
108
     */
109 1
    private function processMessageHandlers(ContainerBuilder $container)
110
    {
111 1
        $taggedServices = array_merge(
112 1
            $container->findTaggedServiceIds('command_handler'),
113 1
            $container->findTaggedServiceIds('event_subscriber'),
114 1
            $container->findTaggedServiceIds('asynchronous_command_handler'),
115 1
            $container->findTaggedServiceIds('asynchronous_event_subscriber')
116
        );
117 1
        $doctrine = $this->hasDoctrine($container);
118
119 1
        foreach ($taggedServices as $id => $tags) {
120 1
            $def = $container->findDefinition($id);
121 1
            $class = $def->getClass();
122
123 1
            if (method_exists($class, 'setEventRecorder')) {
124
                $def->addMethodCall('setEventRecorder', [new Reference('event_recorder')]);
125
            }
126
127 1
            if (method_exists($class, 'setCommandBus')) {
128
                $def->addMethodCall('setCommandBus', [new Reference('command_bus')]);
129
            }
130
131 1
            if (method_exists($class, 'setEventBus')) {
132
                $def->addMethodCall('setEventBus', [new Reference('event_bus')]);
133
            }
134
135 1
            if ($doctrine && method_exists($class, 'setEntityManager')) {
136
                $def->addMethodCall('setEntityManager', [new Reference('doctrine.orm.entity_manager')]);
137
            }
138
139 1
            if (in_array('Psr\Log\LoggerAwareInterface', class_implements($class))) {
140 1
                $def->addMethodCall('setLogger', [new Reference('logger', ContainerInterface::NULL_ON_INVALID_REFERENCE)]);
141
            }
142
        }
143 1
    }
144
145
    /**
146
     * @param ContainerBuilder $container
147
     */
148 1
    private function replaceSimpleBusPublisher(ContainerBuilder $container)
149
    {
150 1
        if ($container->has('simple_bus.rabbit_mq_bundle_bridge.event_publisher')) {
151 1
            $container->getDefinition('simple_bus.rabbit_mq_bundle_bridge.event_publisher')
152 1
                ->setClass(RabbitMQPublisher::class)
153 1
                ->setLazy(true);
154 1
            $container->getDefinition('simple_bus.rabbit_mq_bundle_bridge.command_publisher')
155 1
                ->setClass(RabbitMQPublisher::class)
156 1
                ->setLazy(true);
157
        }
158 1
    }
159
160
    /**
161
     * @param ContainerBuilder $container
162
     *
163
     * @return bool
164
     */
165 1
    private function hasDoctrine(ContainerBuilder $container)
166
    {
167 1
        return $container->hasDefinition('doctrine.orm.entity_manager') ||
168 1
            $container->hasAlias('doctrine.orm.entity_manager');
169
    }
170
}
171