Completed
Pull Request — master (#951)
by David
02:26
created

EntityListenerPass::attachToListener()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 22

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
c 0
b 0
f 0
dl 0
loc 22
rs 9.568
cc 3
nc 3
nop 4
1
<?php
2
3
namespace Doctrine\Bundle\DoctrineBundle\DependencyInjection\Compiler;
4
5
use Doctrine\Bundle\DoctrineBundle\Mapping\EntityListenerServiceResolver;
6
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
7
use Symfony\Component\DependencyInjection\Compiler\ServiceLocatorTagPass;
8
use Symfony\Component\DependencyInjection\ContainerBuilder;
9
use Symfony\Component\DependencyInjection\Exception\InvalidArgumentException;
10
use Symfony\Component\DependencyInjection\Reference;
11
12
/**
13
 * Class for Symfony bundles to register entity listeners
14
 */
15
class EntityListenerPass implements CompilerPassInterface
16
{
17
    /**
18
     * {@inheritDoc}
19
     */
20
    public function process(ContainerBuilder $container)
21
    {
22
        $resolvers = $container->findTaggedServiceIds('doctrine.orm.entity_listener');
23
24
        $lazyServiceReferencesByResolver = [];
25
26
        foreach ($resolvers as $id => $tagAttributes) {
27
            foreach ($tagAttributes as $attributes) {
28
                $name          = isset($attributes['entity_manager']) ? $attributes['entity_manager'] : $container->getParameter('doctrine.default_entity_manager');
29
                $entityManager = sprintf('doctrine.orm.%s_entity_manager', $name);
30
31
                if (! $container->hasDefinition($entityManager)) {
32
                    continue;
33
                }
34
35
                $resolverId = sprintf('doctrine.orm.%s_entity_listener_resolver', $name);
36
37
                if (! $container->has($resolverId)) {
38
                    continue;
39
                }
40
41
                $resolver = $container->findDefinition($resolverId);
42
                $resolver->setPublic(true);
43
44
                if (isset($attributes['entity']) && isset($attributes['event'])) {
45
                    $this->attachToListener($container, $name, $id, $attributes);
46
                }
47
48
                $class = $resolver->getClass();
49
50
                if (substr($class, 0, 1) === '%') {
51
                    // resolve container parameter first
52
                    $class = $container->getParameterBag()->resolveValue($resolver->getClass());
53
                }
54
                $resolverSupportsLazyListeners = is_a($class, EntityListenerServiceResolver::class, true);
55
56
                $lazyByAttribute = isset($attributes['lazy']) && $attributes['lazy'];
57
                if ($lazyByAttribute && ! $resolverSupportsLazyListeners) {
58
                    throw new InvalidArgumentException(
59
                        sprintf('Lazy-loaded entity listeners can only be resolved by a resolver implementing %s.', EntityListenerServiceResolver::class)
60
                    );
61
                }
62
63
                if (! isset($attributes['lazy']) && $resolverSupportsLazyListeners || $lazyByAttribute) {
64
                    $listener = $container->findDefinition($id);
65
66
                    if ($listener->isAbstract()) {
67
                        throw new InvalidArgumentException(sprintf('The service "%s" must not be abstract as this entity listener is lazy-loaded.', $id));
68
                    }
69
70
                    $resolver->addMethodCall('registerService', [$listener->getClass(), $id]);
71
72
                    if (! isset($lazyServiceReferencesByResolver[$resolverId])) {
73
                        $lazyServiceReferencesByResolver[$resolverId] = [];
74
                    }
75
                    $lazyServiceReferencesByResolver[$resolverId][$id] = new Reference($id);
76
                } else {
77
                    $resolver->addMethodCall('register', [new Reference($id)]);
78
                }
79
            }
80
        }
81
82
        foreach ($lazyServiceReferencesByResolver as $resolverId => $listenerReferences) {
83
            $container->findDefinition($resolverId)->replaceArgument(0, ServiceLocatorTagPass::register($container, $listenerReferences));
84
        }
85
    }
86
87
    private function attachToListener(ContainerBuilder $container, $name, $id, array $attributes)
88
    {
89
        $listenerId = sprintf('doctrine.orm.%s_listeners.attach_entity_listeners', $name);
90
91
        if (! $container->has($listenerId)) {
92
            return;
93
        }
94
95
        $serviceDef = $container->getDefinition($id);
96
97
        $args = [
98
            $attributes['entity'],
99
            $serviceDef->getClass(),
100
            $attributes['event'],
101
        ];
102
103
        if (isset($attributes['method'])) {
104
            $args[] = $attributes['method'];
105
        }
106
107
        $container->findDefinition($listenerId)->addMethodCall('addEntityListener', $args);
108
    }
109
}
110