Completed
Push — sensio-insight-fixes ( 787c3e )
by Yann
07:09
created

getTransPattern()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 20
Code Lines 12

Duplication

Lines 0
Ratio 0 %

Importance

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