Completed
Push — master ( c5c117...8f19bf )
by Yann
10s
created

__construct()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 9
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 7
CRAP Score 1

Importance

Changes 0
Metric Value
dl 0
loc 9
ccs 7
cts 7
cp 1
rs 9.6666
c 0
b 0
f 0
cc 1
eloc 6
nc 1
nop 2
crap 1
1
<?php
2
3
namespace Yokai\EnumBundle\DependencyInjection\CompilerPass;
4
5
use ReflectionClass;
6
use RuntimeException;
7
use Symfony\Component\DependencyInjection\ChildDefinition;
8
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
9
use Symfony\Component\DependencyInjection\Container;
10
use Symfony\Component\DependencyInjection\ContainerBuilder;
11
use Symfony\Component\DependencyInjection\Definition;
12
use Symfony\Component\DependencyInjection\DefinitionDecorator;
13
use Symfony\Component\Finder\Finder;
14
use Symfony\Component\Finder\SplFileInfo;
15
use Yokai\EnumBundle\Enum\AbstractTranslatedEnum;
16
use Yokai\EnumBundle\Enum\EnumInterface;
17
18
/**
19
 * @author Yann Eugoné <[email protected]>
20
 */
21
class DeclarativeEnumCollectorCompilerPass implements CompilerPassInterface
22
{
23
    /**
24
     * @var string
25
     */
26
    private $bundleDir;
27
28
    /**
29
     * @var string
30
     */
31
    private $bundleNamespace;
32
33
    /**
34
     * @var string
35
     */
36
    private $bundleName;
37
38
    /**
39
     * @var string
40
     */
41
    private $transDomain;
42
43
    /**
44
     * @param string      $bundle
45
     * @param string|null $transDomain
46
     */
47 3
    public function __construct($bundle, $transDomain = null)
48
    {
49 3
        $reflection = new ReflectionClass($bundle);
50 3
        $this->bundleDir = dirname($reflection->getFileName());
51 3
        $this->bundleNamespace = $reflection->getNamespaceName();
52 3
        $this->bundleName = $reflection->getShortName();
53
54 3
        $this->transDomain = $transDomain;
55 3
    }
56
57
    /**
58
     * @inheritdoc
59
     */
60 3
    public function process(ContainerBuilder $container)
61
    {
62 3
        if (!class_exists('Symfony\Component\Finder\Finder')) {
63
            throw new RuntimeException('You need the symfony/finder component to register enums.');
64
        }
65
66 3
        $enumDir = $this->bundleDir . '/Enum';
67
68 3
        if (!is_dir($enumDir)) {
69
            return;
70
        }
71
72 3
        $finder = new Finder();
73 3
        $finder->files()->name('*Enum.php')->in($enumDir);
74
75 3
        foreach ($finder as $file) {
76
            /** @var SplFileInfo $file */
77 3
            $enumNamespace = $this->bundleNamespace . '\\Enum';
78 3
            if ($relativePath = $file->getRelativePath()) {
79 3
                $enumNamespace .= '\\' . strtr($relativePath, '/', '\\');
80 3
            }
81
82 3
            $enumClass = $enumNamespace . '\\' . $file->getBasename('.php');
83 3
            $enumReflection = new ReflectionClass($enumClass);
84
85 3
            if (!$enumReflection->isSubclassOf(EnumInterface::class) || $enumReflection->isAbstract()) {
86
                continue; //Not an enum or abstract enum
87
            }
88
89 3
            $definition = null;
90 3
            $requiredParameters = 0;
91 3
            if ($enumReflection->getConstructor()) {
92 3
                $requiredParameters = $enumReflection->getConstructor()->getNumberOfRequiredParameters();
93 3
            }
94
95 3
            if ($requiredParameters === 0) {
96 3
                $definition = new Definition($enumClass);
97 3
            } elseif ($requiredParameters === 2 && $enumReflection->isSubclassOf(AbstractTranslatedEnum::class)) {
98 3
                if (class_exists('Symfony\Component\DependencyInjection\ChildDefinition')) {
99
                    // ChildDefinition was introduced as Symfony 3.3
100
                    $definition = new ChildDefinition('enum.abstract_translated');
101
                } else {
102
                    // DefinitionDecorator was deprecated as Symfony 3.3
103 3
                    $definition = new DefinitionDecorator('enum.abstract_translated');
104
                }
105 3
                $definition->setClass($enumClass);
106 3
                $definition->addArgument(
107 3
                    $this->getTransPattern($enumClass)
108 3
                );
109
110 3
                if ($this->transDomain) {
111
                    $definition->addMethodCall(
112
                        'setTransDomain',
113
                        [
114
                            $this->transDomain
115
                        ]
116
                    );
117
                }
118 3
            }
119
120 3
            if (!$definition) {
121
                continue; //Could not determine how to create definition for the enum
122
            }
123
124 3
            $definition->addTag('enum');
125
126 3
            $container->setDefinition(
127 3
                $this->getServiceId($enumClass),
128
                $definition
129 3
            );
130 3
        }
131 3
    }
132
133
    /**
134
     * @param string $enumClass
135
     *
136
     * @return string
137
     */
138 3
    private function getServiceId($enumClass)
139
    {
140 3
        $enumNamespace = $this->bundleNamespace.'\\Enum\\';
141
142 3
        return sprintf('%s.enum.%s',
143 3
            Container::underscore(
144 3
                substr($this->bundleName, 0, -6)
145 3
            ),
146 3
            Container::underscore(
147 3
                str_replace(
148 3
                    '\\',
149 3
                    '',
150 3
                    str_replace(
151 3
                        $enumNamespace,
152 3
                        '',
153 3
                        substr($enumClass, 0, -4)
154 3
                    )
155 3
                )
156 3
            )
157 3
        );
158
    }
159
160
    /**
161
     * @param string $enumClass
162
     *
163
     * @return string
164
     */
165 3
    private function getTransPattern($enumClass)
166
    {
167 3
        $parts = array_filter(
168 3
            array_map(
169 3
                [$this, 'underscore'],
170 3
                explode(
171 3
                    '\\',
172 3
                    str_replace(
173 3
                        $this->bundleNamespace . '\\',
174 3
                        '',
175
                        $enumClass
176 3
                    )
177 3
                )
178 3
            )
179 3
        );
180
181 3
        $enum = array_pop($parts);
182
183 3
        return implode('_', $parts) . '.' . $enum . '.label_%s';
184
    }
185
186
    /**
187
     * @param string $input
188
     *
189
     * @return string
190
     */
191 3
    private function underscore($input)
192
    {
193 3
        return strtolower(
194 3
            preg_replace(
195 3
                '~(?<=\\w)([A-Z])~', '_$1',
196 3
                preg_replace(
197 3
                    '~(Enum|Bundle)~',
198 3
                    '',
199
                    $input
200 3
                )
201 3
            )
202 3
        );
203
    }
204
}
205