Completed
Push — master ( 89600f...8b2509 )
by Maxime
01:55 queued 11s
created

Configuration::addDoctrineSection()   B

Complexity

Conditions 6
Paths 1

Size

Total Lines 73

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 73
rs 7.9668
c 0
b 0
f 0
cc 6
nc 1
nop 1

How to fix   Long Method   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
3
/*
4
 * This file is part of the "elao/enum" package.
5
 *
6
 * Copyright (C) Elao
7
 *
8
 * @author Elao <[email protected]>
9
 */
10
11
namespace Elao\Enum\Bridge\Symfony\Bundle\DependencyInjection;
12
13
use Elao\Enum\EnumInterface;
14
use Symfony\Component\Config\Definition\Builder\ArrayNodeDefinition;
15
use Symfony\Component\Config\Definition\Builder\TreeBuilder;
16
use Symfony\Component\Config\Definition\ConfigurationInterface;
17
use Symfony\Component\Serializer\SerializerInterface;
18
19
class Configuration implements ConfigurationInterface
20
{
21
    public function getConfigTreeBuilder()
22
    {
23
        $treeBuilder = new TreeBuilder('elao_enum');
24
        $rootNode = method_exists(TreeBuilder::class, 'getRootNode') ? $treeBuilder->getRootNode() : $treeBuilder->root('elao_enum');
0 ignored issues
show
Bug introduced by
The method root() does not seem to exist on object<Symfony\Component...on\Builder\TreeBuilder>.

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
25
26
        $rootNode->children()
27
            ->arrayNode('argument_value_resolver')->canBeDisabled()->end()
28
            ->arrayNode('serializer')
29
                ->{interface_exists(SerializerInterface::class) ? 'canBeDisabled' : 'canBeEnabled'}()
30
            ->end()
31
        ->end();
32
33
        $this->addDoctrineSection($rootNode);
34
        $this->addTranslationExtractorSection($rootNode);
35
        $this->addJsEnumsSection($rootNode);
36
37
        return $treeBuilder;
38
    }
39
40
    private function addDoctrineSection(ArrayNodeDefinition $rootNode)
41
    {
42
        $rootNode->children()
43
            ->arrayNode('doctrine')
44
            ->addDefaultsIfNotSet()
45
            ->fixXmlConfig('type')
46
            ->children()
47
                ->booleanNode('enum_sql_declaration')
48
                    ->defaultValue(false)
49
                    ->info('If true, by default for string enumerations, generate DBAL types with an ENUM SQL declaration with enum values instead of a VARCHAR (Your platform must support it)')
50
                ->end()
51
                ->arrayNode('types')
52
                    ->beforeNormalization()
53
                        ->always(function ($values) {
54
                            $legacyFormat = false;
55
                            foreach ($values as $name => $config) {
56
                                if (class_exists($name)) {
57
                                    $legacyFormat = true;
58
                                    @trigger_error('Using enum FQCN as keys at path "elao_enum.doctrine.types" is deprecated. Provide the name as keys and add the "class" option for each entry instead.', E_USER_DEPRECATED);
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition here. This can introduce security issues, and is generally not recommended.

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
59
                                    break;
60
                                }
61
                            }
62
                            $newValues = [];
63
64
                            if ($legacyFormat) {
65
                                foreach ($values as $name => $value) {
66
                                    if (\is_string($value)) {
67
                                        $newValues[$value] = $name;
68
                                    } else {
69
                                        $newValues[$value['name']] = $value + ['class' => $name];
70
                                    }
71
                                }
72
                            } else {
73
                                $newValues = $values;
74
                            }
75
76
                            return $newValues;
77
                        })
78
                    ->end()
79
                    ->useAttributeAsKey('name')
80
                    ->arrayPrototype()
81
                    ->beforeNormalization()
82
                        ->ifString()->then(static function (string $v): array { return ['class' => $v]; })
83
                    ->end()
84
                    ->children()
85
                        ->scalarNode('class')
86
                            ->cannotBeEmpty()
87
                            ->validate()
88
                                ->ifTrue(static function (string $class): bool {return !is_a($class, EnumInterface::class, true); })
89
                                ->thenInvalid(sprintf('Invalid class. Expected instance of "%s"', EnumInterface::class))
90
                            ->end()
91
                        ->end()
92
                        ->enumNode('type')
93
                            ->values(['enum', 'string', 'int', 'collection'])
94
                            ->info(<<<TXT
95
Which column definition to use and the way the enumeration values are stored in the database:
96
- string: VARCHAR
97
- enum: ENUM(...values) (Your platform must support it)
98
- int: INT
99
- collection: JSON
100
101
Default is either "string" or "enum", controlled by the `elao_enum.doctrine.enum_sql_declaration` option.
102
Default for flagged enums is "int".
103
TXT
104
                            )
105
                            ->cannotBeEmpty()
106
                            ->defaultValue(null)
107
                        ->end()
108
                    ->end()
109
                ->end()
110
            ->end()
111
        ->end();
112
    }
113
114
    private function addTranslationExtractorSection(ArrayNodeDefinition $rootNode)
115
    {
116
        $rootNode->children()
117
            ->arrayNode('translation_extractor')
118
            ->canBeEnabled()
119
            ->fixXmlConfig('path')
120
            ->children()
121
                ->arrayNode('paths')
122
                    ->example(['App\Enum' => '%kernel.project_dir%/src/Enum'])
123
                    ->useAttributeAsKey('namespace')
124
                    ->scalarPrototype()
125
                    ->end()
126
                ->end()
127
                ->scalarNode('domain')
128
                    ->defaultValue('messages')
129
                    ->cannotBeEmpty()
130
                ->end()
131
                ->scalarNode('filename_pattern')
132
                    ->example('*Enum.php')
133
                    ->defaultValue('*.php')
134
                    ->cannotBeEmpty()
135
                ->end()
136
                ->arrayNode('ignore')
137
                    ->example(['%kernel.project_dir%/src/Enum/Other/*'])
138
                    ->scalarPrototype()->cannotBeEmpty()->end()
139
                ->end()
140
            ->end()
141
        ->end();
142
    }
143
144
    private function addJsEnumsSection(ArrayNodeDefinition $rootNode)
145
    {
146
        $rootNode->children()
147
            ->arrayNode('js')
148
                ->addDefaultsIfNotSet()
149
                ->fixXmlConfig('path')
150
                ->children()
151
                    ->scalarNode('base_dir')
152
                        ->info('A prefixed dir used for relative paths supplied for each of the generated enums and library path')
153
                        ->example('%kernel.project_dir%/assets/js/modules')
154
                        ->defaultNull()
155
                    ->end()
156
                    ->scalarNode('lib_path')
157
                        ->info('The path of the file were to place the javascript library sources used by the dumped enums.')
158
                        ->example('%kernel.project_dir%/assets/js/lib/enum.js')
159
                        ->defaultNull()
160
                    ->end()
161
                    ->arrayNode('paths')
162
                        ->defaultValue([])
163
                        ->info('Path where to generate the javascript enums per enum class')
164
                        ->example(['App\Enum\SimpleEnum' => '"common/SimpleEnum.js"'])
165
                        ->useAttributeAsKey('class')
166
                        ->validate()
167
                            ->ifTrue(static function (array $v): bool {return self::hasNonEnumKeys($v); })
168
                            ->then(static function (array $v) { self::throwsNonEnumKeysException($v); })
169
                        ->end()
170
                        ->scalarPrototype()->end()
171
                    ->end()
172
                ->end()
173
            ->end()
174
        ->end();
175
    }
176
177
    private static function hasNonEnumKeys(array $values): bool
178
    {
179
        $classes = array_column($values, 'class');
180
        foreach ($classes as $class) {
181
            if (!is_a($class, EnumInterface::class, true)) {
182
                return true;
183
            }
184
        }
185
186
        return false;
187
    }
188
189
    private static function throwsNonEnumKeysException(array $values)
190
    {
191
        $classes = array_column($values, 'class');
192
        $invalids = [];
193
        foreach ($classes as $class) {
194
            if (!is_a($class, EnumInterface::class, true)) {
195
                $invalids[] = $class;
196
            }
197
        }
198
199
        throw new \InvalidArgumentException(sprintf(
200
            'Invalid classes %s. Expected instances of "%s"',
201
            json_encode($invalids),
202
            EnumInterface::class
203
        ));
204
    }
205
}
206