Completed
Push — master ( 5fb808...2585b9 )
by Nikola
19:32 queued 18s
created

CompilerPass::processInjection()   D

Complexity

Conditions 9
Paths 7

Size

Total Lines 32
Code Lines 13

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 13
CRAP Score 9

Importance

Changes 0
Metric Value
dl 0
loc 32
ccs 13
cts 13
cp 1
rs 4.909
c 0
b 0
f 0
cc 9
eloc 13
nc 7
nop 2
crap 9
1
<?php
2
/*
3
 * This file is part of the  TraitorBundle, an RunOpenCode project.
4
 *
5
 * (c) 2017 RunOpenCode
6
 *
7
 * For the full copyright and license information, please view the LICENSE
8
 * file that was distributed with this source code.
9
 */
10
namespace RunOpenCode\Bundle\Traitor\DependencyInjection;
11
12
use RunOpenCode\Bundle\Traitor\Utils\ClassUtils;
13
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
14
use Symfony\Component\DependencyInjection\ContainerBuilder;
15
use Symfony\Component\DependencyInjection\Definition;
16
use Symfony\Component\DependencyInjection\Reference;
17
18
class CompilerPass implements CompilerPassInterface
19
{
20
    /**
21
     * {@inheritdoc}
22
     */
23 7
    public function process(ContainerBuilder $container)
24
    {
25 7
        if (!$container->hasParameter('runopencode.traitor.injection_map') || count($container->getParameter('runopencode.traitor.injection_map')) === 0) {
26 1
            return;
27
        }
28
29 6
        if ($container->hasParameter('runopencode.traitor.filter.tags') || $container->hasParameter('runopencode.traitor.filter.namespaces')) {
30
31 2
            $definitions = array_merge(
32 2
                $container->hasParameter('runopencode.traitor.filter.tags') ? $this->getDefinitionsFromTags($container, $container->getParameter('runopencode.traitor.filter.tags')) : array(),
33 2
                $container->hasParameter('runopencode.traitor.filter.namespaces') ? $this->getDefinitionsFromClassNamespaces($container, $container->getParameter('runopencode.traitor.filter.namespaces')) : array()
34
            );
35
36
        } else {
37
38 4
            $definitions = $this->getDefinitionsFromClassNamespaces($container, array());
39
        }
40
41 6
        $definitions = $this->filterExcludedDefinitions($container, $definitions);
42
43 6
        $this->processInjection($definitions, $container->getParameter('runopencode.traitor.injection_map'));
44 6
    }
45
46
    /**
47
     * Get definitions from container based on namespace filter
48
     *
49
     * @param ContainerBuilder $container
50
     * @param array $filters Namespace prefixes
51
     * @return Definition[] Definitions indexed by service ID
52
     */
53 5
    protected function getDefinitionsFromClassNamespaces(ContainerBuilder $container, array $filters)
54
    {
55 5
        $result = array();
56
57
        /**
58
         * @var Definition $definition
59
         */
60 5
        foreach ($container->getDefinitions() as $id => $definition) {
61
62 5
            $class = $definition->getClass();
63
64 5
            if (count($filters) > 0) {
65
66 1
                $found = false;
67
68 1
                foreach ($filters as $namespace) {
69
70 1
                    if (ClassUtils::isWithinNamespace($class, $namespace)) {
71 1
                        $found = true;
72 1
                        break;
73
                    }
74
                }
75
76 1
                if (!$found) {
77 1
                    continue; // Go to next definition
78
                }
79
            }
80
81 5
            $result[$id] = $definition;
82
        }
83
84 5
        return $result;
85
    }
86
87
    /**
88
     * Get definitions from container based on service tag filter
89
     *
90
     * @param ContainerBuilder $container
91
     * @param array $tags Tag names
92
     * @return Definition[] Definitions indexed by service ID
93
     */
94 1
    protected function getDefinitionsFromTags(ContainerBuilder $container, array $tags)
95
    {
96 1
        $result = array();
97
98 1
        if (count($tags) > 0) {
99
100 1
            foreach ($tags as $tag) {
101
102 1
                foreach (array_keys($container->findTaggedServiceIds($tag)) as $id) {
103
104 1
                    $result[$id] = $container->getDefinition($id);
105
                }
106
            }
107
        }
108
109 1
        return $result;
110
    }
111
112
    /**
113
     * Process injection of services via traits for given definitions.
114
     *
115
     * @param Definition[] $definitions Definitions to process.
116
     * @param array $injectionMap Injection map.
117
     */
118 6
    protected function processInjection(array $definitions, array $injectionMap)
119
    {
120 6
        if (count($injectionMap) > 0 && count($definitions) > 0) {
121
122
            /**
123
             * @var Definition $definition
124
             */
125 6
            foreach ($definitions as $definition) {
126
127 6
                $class = $definition->getClass();
128
129 6
                foreach ($injectionMap as $trait => $injectionDefinition) {
130
131 6
                    if (class_exists($class) && ClassUtils::usesTrait($class, $trait)) {
132
133 6
                        $arguments = array();
134
135 6
                        foreach ($injectionDefinition[1] as $argument) {
136
137 6
                            if ('@' === $argument[0]) {
138 6
                                $arguments[] = new Reference(ltrim($argument, '@'));
139
                            } else {
140 6
                                $arguments[] = $argument;
141
                            }
142
                        }
143
144 6
                        $definition->addMethodCall($injectionDefinition['0'], $arguments);
145
                    }
146
                }
147
            }
148
        }
149 6
    }
150
151
    /**
152
     * Remove excluded definitions from definitions collection.
153
     *
154
     * @param ContainerBuilder $container
155
     * @param Definition[] $definitions
156
     * @return Definition[]
157
     */
158 6
    protected function filterExcludedDefinitions(ContainerBuilder $container, array $definitions)
159
    {
160 6
        $excludedServices = $container->hasParameter('runopencode.traitor.exclude.services') ? $container->getParameter('runopencode.traitor.exclude.services') : array();
161 6
        $excludedClasses = $container->hasParameter('runopencode.traitor.exclude.classes') ? $container->getParameter('runopencode.traitor.exclude.classes') : array();
162 6
        $excludedNamespaces = $container->hasParameter('runopencode.traitor.exclude.namespaces') ? $container->getParameter('runopencode.traitor.exclude.namespaces') : array();
163
164
165 6
        $result = array();
166
167 6
        foreach ($definitions as $serviceId => $definition) {
168
169 6
            if (in_array($serviceId, $excludedServices, true)) {
170 1
                continue;
171
            }
172
173 6
            $serviceFqcn = ltrim($definition->getClass(), '\\');
174
175 6
            if (in_array($serviceFqcn, $excludedClasses, true)) {
176 1
                continue;
177
            }
178
179 6
            foreach ($excludedNamespaces as $excludedNamespace) {
180
181 1
                if (strpos($serviceFqcn, $excludedNamespace) === 0) {
182 1
                    continue 2;
183
                }
184
            }
185
186 6
            $result[$serviceId] = $definition;
187
        }
188
189 6
        return $result;
190
    }
191
}
192