Completed
Push — master ( 48eaef...45b9c9 )
by Nikola
03:05
created

CompilerPass::filterExcludedDefinitions()   D

Complexity

Conditions 9
Paths 48

Size

Total Lines 33
Code Lines 16

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 18
CRAP Score 9

Importance

Changes 2
Bugs 1 Features 0
Metric Value
c 2
b 1
f 0
dl 0
loc 33
ccs 18
cts 18
cp 1
rs 4.909
cc 9
eloc 16
nc 48
nop 2
crap 9
1
<?php
2
/*
3
 * This file is part of the  TraitorBundle, an RunOpenCode project.
4
 *
5
 * (c) 2016 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 14
    public function process(ContainerBuilder $container)
24
    {
25 14
        if (!$container->hasParameter('roc.traitor.injection_map') || count($container->getParameter('roc.traitor.injection_map')) === 0) {
26 2
            return;
27
        }
28
29 12
        if ($container->hasParameter('roc.traitor.filter.tags') || $container->hasParameter('roc.traitor.filter.namespaces')) {
30
31 4
            $definitions = array_merge(
32 4
                $container->hasParameter('roc.traitor.filter.tags') ? $this->getDefinitionsFromTags($container, $container->getParameter('roc.traitor.filter.tags')) : array(),
33 4
                $container->hasParameter('roc.traitor.filter.namespaces') ? $this->getDefinitionsFromClassNamespaces($container, $container->getParameter('roc.traitor.filter.namespaces')) : array()
34 4
            );
35
36 4
        } else {
37
38 8
            $definitions = $this->getDefinitionsFromClassNamespaces($container, array());
39
        }
40
41 12
        $definitions = $this->filterExcludedDefinitions($container, $definitions);
42
43 12
        $this->processInjection($definitions, $container->getParameter('roc.traitor.injection_map'));
44 12
    }
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 10
    protected function getDefinitionsFromClassNamespaces(ContainerBuilder $container, array $filters)
54
    {
55 10
        $result = array();
56
57
        /**
58
         * @var Definition $definition
59
         */
60 10
        foreach ($container->getDefinitions() as $id => $definition) {
61
62 10
            $class = $definition->getClass();
63
64 10
            if (count($filters) > 0) {
65
66 2
                $found = false;
67
68 2
                foreach ($filters as $namespace) {
69
70 2
                    if (ClassUtils::isWithinNamespace($class, $namespace)) {
71 2
                        $found = true;
72 2
                        break;
73
                    }
74 2
                }
75
76 2
                if (!$found) {
77 2
                    continue; // Go to next definition
78
                }
79 2
            }
80
81 10
            $result[$id] = $definition;
82 10
        }
83
84 10
        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 2
    protected function getDefinitionsFromTags(ContainerBuilder $container, array $tags)
95
    {
96 2
        $result = array();
97
98 2
        if (count($tags) > 0) {
99
100 2
            foreach ($tags as $tag) {
101
102 2
                foreach (array_keys($container->findTaggedServiceIds($tag)) as $id) {
103
104 2
                    $result[$id] = $container->getDefinition($id);
105 2
                }
106 2
            }
107 2
        }
108
109 2
        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 12
    protected function processInjection(array $definitions, array $injectionMap)
119
    {
120 12
        if (count($injectionMap) > 0 && count($definitions) > 0) {
121
122
            /**
123
             * @var Definition $definition
124
             */
125 12
            foreach ($definitions as $definition) {
126
127 12
                $class = $definition->getClass();
128
129 12
                foreach ($injectionMap as $trait => $injectionDefinition) {
130
131 12
                    if (class_exists($class) && ClassUtils::usesTrait($class, $trait)) {
132
133 12
                        $arguments = array();
134
135 12
                        foreach ($injectionDefinition[1] as $argument) {
136
137 12
                            if ('@' === $argument[0]) {
138 12
                                $arguments[] = new Reference(ltrim($argument, '@'));
139 12
                            } else {
140
                                $arguments[] = $argument;
141
                            }
142 12
                        }
143
144 12
                        $definition->addMethodCall($injectionDefinition['0'], $arguments);
145 12
                    }
146 12
                }
147 12
            }
148 12
        }
149 12
    }
150
151
    /**
152
     * Remove excluded definitions from definitions collection.
153
     *
154
     * @param ContainerBuilder $container
155
     * @param Definition[] $definitions
156
     * @return Definition[]
157
     */
158 12
    protected function filterExcludedDefinitions(ContainerBuilder $container, array $definitions)
159
    {
160 12
        $excludedServices = $container->hasParameter('roc.traitor.exclude.services') ? $container->getParameter('roc.traitor.exclude.services') : array();
161 12
        $excludedClasses = $container->hasParameter('roc.traitor.exclude.classes') ? $container->getParameter('roc.traitor.exclude.classes') : array();
162 12
        $excludedNamespaces = $container->hasParameter('roc.traitor.exclude.namespaces') ? $container->getParameter('roc.traitor.exclude.namespaces') : array();
163
164
165 12
        $result = array();
166
167 12
        foreach ($definitions as $serviceId => $definition) {
168
169 12
            if (in_array($serviceId, $excludedServices, true)) {
170 2
                continue;
171
            }
172
173 12
            $serviceFqcn = ltrim($definition->getClass(), '\\');
174
175 12
            if (in_array($serviceFqcn, $excludedClasses, true)) {
176 2
                continue;
177
            }
178
179 12
            foreach ($excludedNamespaces as $excludedNamespace) {
180
181 2
                if (strpos($serviceFqcn, $excludedNamespace) === 0) {
182 2
                    continue 2;
183
                }
184 12
            }
185
186 12
            $result[$serviceId] = $definition;
187 12
        }
188
189 12
        return $result;
190
    }
191
}
192