Completed
Push — master ( 1f38f3...62a406 )
by Yann
13:37 queued 12:18
created

getServiceId()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 21
Code Lines 13

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 13
CRAP Score 1

Importance

Changes 0
Metric Value
dl 0
loc 21
ccs 13
cts 13
cp 1
rs 9.3142
c 0
b 0
f 0
cc 1
eloc 13
nc 1
nop 1
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
            }
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
            }
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 3
                    $definition = new ChildDefinition('enum.abstract_translated');
101
                } else {
102
                    // DefinitionDecorator was deprecated as Symfony 3.3
103
                    $definition = new DefinitionDecorator('enum.abstract_translated');
0 ignored issues
show
Deprecated Code introduced by
The class Symfony\Component\Depend...ion\DefinitionDecorator has been deprecated with message: The DefinitionDecorator class is deprecated since version 3.3 and will be removed in 4.0. Use the Symfony\Component\DependencyInjection\ChildDefinition class instead.

This class, trait or interface has been deprecated. The supplier of the file has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the type will be removed from the class and what other constant to use instead.

Loading history...
104
                }
105 3
                $definition->setClass($enumClass);
106 3
                $definition->addArgument(
107 3
                    $this->getTransPattern($enumClass)
108
                );
109
110 3
                if ($this->transDomain) {
111
                    $definition->addMethodCall(
112
                        'setTransDomain',
113
                        [
114
                            $this->transDomain
115
                        ]
116
                    );
117
                }
118
            }
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 3
                $definition
129
            );
130
        }
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
            ),
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
                    )
155
                )
156
            )
157
        );
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 3
                        $enumClass
176
                    )
177
                )
178
            )
179
        );
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 3
                    $input
200
                )
201
            )
202
        );
203
    }
204
}
205