Completed
Pull Request — master (#98)
by Benjamin
01:32
created

Configuration::addDoctrineSection()   B

Complexity

Conditions 6
Paths 1

Size

Total Lines 72

Duplication

Lines 0
Ratio 0 %

Importance

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