Completed
Pull Request — master (#692)
by Renan
04:40
created

DoctrineDBALLoggerPass::isChainLogger()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 12
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 12
rs 9.4285
c 0
b 0
f 0
cc 3
eloc 6
nc 3
nop 1
1
<?php
2
3
namespace Doctrine\Bundle\DoctrineBundle\DependencyInjection\Compiler;
4
5
use Doctrine\DBAL\Logging\SQLLogger;
6
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
7
use Symfony\Component\DependencyInjection\ContainerBuilder;
8
use Symfony\Component\DependencyInjection\Definition;
9
use Symfony\Component\DependencyInjection\Exception\InvalidArgumentException;
10
use Symfony\Component\DependencyInjection\Reference;
11
12
final class DoctrineDBALLoggerPass implements CompilerPassInterface
13
{
14
    private const TAG_NAME = 'doctrine.dbal.logger';
15
    private const BASE_CHAIN_NAME = 'doctrine.dbal.logger.chain';
16
17
    public function process(ContainerBuilder $container)
18
    {
19
        $serviceList = $container->findTaggedServiceIds(self::TAG_NAME, true);
20
        $serviceList = array_keys($serviceList);
21
22
        if (empty($serviceList)) {
23
            return;
24
        }
25
26
        foreach ($serviceList as $serviceId) {
27
            $this->ensureIsValidServiceDefinition($container, $serviceId);
28
        }
29
30
        $connectionList = $container->getParameter('doctrine.connections');
31
32
        foreach ($connectionList as $connectionName => $connectionId) {
33
            $configurationDefinition = $container->getDefinition($connectionId . '.configuration');
34
            $chainDefinition = $this->createChainDefinitionAttachedToConnection($container, $connectionName, $configurationDefinition);
35
36
            foreach ($serviceList as $serviceId) {
37
                $serviceReference = new Reference($serviceId);
38
                $chainDefinition->addMethodCall('addLogger', [$serviceReference]);
39
            }
40
        }
41
    }
42
43
    private function ensureIsValidServiceDefinition(ContainerBuilder $container, string $serviceId): void
44
    {
45
        $serviceDefinition = $container->getDefinition($serviceId);
46
47
        $serviceClass = $container->getParameterBag()->resolveValue(
48
            $serviceDefinition->getClass()
49
        );
50
        $reflectionClass = $container->getReflectionClass($serviceClass);
51
52
        if (!$reflectionClass) {
53
            throw new InvalidArgumentException(sprintf(
54
                'Class "%s" used for service "%s" cannot be found.',
55
                $serviceClass,
56
                $serviceId
57
            ));
58
        }
59
60
        if (!$reflectionClass->implementsInterface(SQLLogger::class)) {
61
            throw new InvalidArgumentException(sprintf(
62
                'The service "%s" tagged "%s" must implement "%s".',
63
                $serviceId,
64
                self::TAG_NAME,
65
                SQLLogger::class
66
            ));
67
        }
68
69
        if ($reflectionClass->isAbstract()) {
70
            throw new InvalidArgumentException(sprintf(
71
                'The service "%s" tagged "%s" cannot be abstract.',
72
                $serviceId,
73
                self::TAG_NAME
74
            ));
75
        }
76
    }
77
78
    private function createChainDefinitionAttachedToConnection(
79
        ContainerBuilder $container,
80
        string $connectionName,
81
        $configurationDefinition
82
    ): Definition {
83
        $configuredLoggerReference = $this->getSQLLoggerFromConnection($configurationDefinition);
84
85
        if ($configuredLoggerReference === null) {
86
            return $this->createChainAndAttachToConnection($container, $connectionName, $configurationDefinition);
87
        }
88
89
        $configuredLoggerDefinition = $container->getDefinition((string)$configuredLoggerReference);
90
91
        if ($this->isChainLogger($configuredLoggerDefinition)) {
92
            return $configuredLoggerDefinition;
93
        }
94
95
        $chainDefinition = $this->createChainAndAttachToConnection($container, $connectionName, $configurationDefinition);
96
        $chainDefinition->addMethodCall('addLogger', [$configuredLoggerReference]);
97
98
        return $chainDefinition;
99
    }
100
101
    private function getSQLLoggerFromConnection(Definition $configurationDefinition): ?Reference
0 ignored issues
show
Documentation introduced by
The return type could not be reliably inferred; please add a @return annotation.

Our type inference engine in quite powerful, but sometimes the code does not provide enough clues to go by. In these cases we request you to add a @return annotation as described here.

Loading history...
102
    {
103
        $methodCallList = $configurationDefinition->getMethodCalls();
104
105
        foreach ($methodCallList as $methodCall) {
106
            if ($methodCall[0] !== 'setSQLLogger') {
107
                continue;
108
            }
109
110
            return $methodCall[1][0];
111
        }
112
113
        return null;
114
    }
115
116
    private function isChainLogger(Definition $serviceDefinition): bool
117
    {
118
        $methodCallList = $serviceDefinition->getMethodCalls();
119
120
        foreach ($methodCallList as $methodCall) {
121
            if ($methodCall[0] === 'addLogger') {
122
                return true;
123
            }
124
        }
125
126
        return false;
127
    }
128
129
    private function createChainAndAttachToConnection(
130
        ContainerBuilder $container,
131
        string $connectionName,
132
        Definition $configurationDefinition
133
    ): Definition {
134
        $chainId = self::BASE_CHAIN_NAME . '.' . $connectionName;
135
136
        $chainReference = new Reference($chainId);
137
        $chainDefinition = new Definition(self::BASE_CHAIN_NAME);
138
139
        $container->setDefinition($chainId, $chainDefinition);
140
141
        $configurationDefinition->removeMethodCall('setSQLLogger');
142
        $configurationDefinition->addMethodCall('setSQLLogger', [$chainReference]);
143
144
        return $chainDefinition;
145
    }
146
}
147