Completed
Push — master ( 2e2167...affc35 )
by Alex
01:44
created

Configuration::addArrayNode()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 17
Code Lines 12

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 11
CRAP Score 1.0005

Importance

Changes 0
Metric Value
dl 0
loc 17
ccs 11
cts 12
cp 0.9167
rs 9.4285
c 0
b 0
f 0
cc 1
eloc 12
nc 1
nop 1
crap 1.0005
1
<?php
2
declare(strict_types=1);
3
4
namespace AlexMasterov\PsyshBundle\DependencyInjection;
5
6
use Symfony\Component\Config\Definition\{
7
    Builder\ArrayNodeDefinition,
8
    Builder\TreeBuilder,
9
    ConfigurationInterface,
10
    Exception\InvalidConfigurationException
11
};
12
13
class Configuration implements ConfigurationInterface
14
{
15
    /**
16
     * @inheritDoc
17
     */
18 3
    public function getConfigTreeBuilder()
19
    {
20 3
        $treeBuilder = new TreeBuilder();
21 3
        $rootNode = $treeBuilder->root('psysh');
22
23
        $rootNode
24 3
            ->children()
25 3
                ->append($this->addVariablesNode())
26 3
                ->append($this->addArrayNode('commands'))
27 3
                ->append($this->addErrorLoggingLevelNode())
28 3
                ->scalarNode('config_dir')->end()
29 3
                ->scalarNode('data_dir')->end()
30 3
                ->scalarNode('runtime_dir')
31 3
                    ->info('Set the shell\'s temporary directory location')
32 3
                ->end()
33 3
                ->integerNode('history_size')
34 3
                    ->info('If set to zero (0), the history size is unlimited')
35 3
                ->end()
36 3
                ->scalarNode('history_file')->end()
37 3
                ->scalarNode('manual_db_file')->end()
38 3
                ->booleanNode('tab_completion')->end()
39 3
                ->append($this->addArrayNode('tab_completion_matchers'))
40 3
                ->scalarNode('startup_message')->end()
41 3
                ->booleanNode('require_semicolons')->end()
42 3
                ->booleanNode('erase_duplicates')->end()
43 3
                ->booleanNode('pcntl')->end()
44 3
                ->booleanNode('readline')->end()
45 3
                ->booleanNode('unicode')->end()
46 3
                ->enumNode('color_mode')
47 3
                    ->values(['auto', 'forced', 'disabled'])
48 3
                ->end()
49 3
                ->scalarNode('pager')->treatNullLike('less')->end()
50 3
                ->enumNode('update_check')->defaultValue('never')
51 3
                    ->values(['never', 'always', 'daily', 'weekly', 'monthly'])
52 3
                ->end()
53 3
            ->end()
54
        ;
55
56 3
        $this->normalizeRootNode($rootNode);
57
58 3
        return $treeBuilder;
59
    }
60
61 3
    private function normalizeRootNode(ArrayNodeDefinition $rootNode): void
62
    {
63
        $normalizer = static function (array $config): array {
64 2
            static $keys = [
65
                'pcntl'    => 'usePcntl',
66
                'readline' => 'useReadline',
67
                'unicode'  => 'useUnicode',
68
            ];
69
70
            // config_dir -> configDir
71
            $camelize = static function (string $value): string {
72 2
                return \str_replace('_', '', \lcfirst(\ucwords(\strtolower($value), '_')));
73 2
            };
74
75 2
            $normalized = [];
76 2
            foreach ($config as $key => $value) {
77 2
                if (empty($value)) {
78 1
                    continue;
79
                }
80 2
                $key = $keys[$key] ?? $camelize($key);
81 2
                $normalized[$key] = $value;
82
            }
83
84 2
            return $normalized;
85 3
        };
86
87 3
        $rootNode->validate()->always()->then($normalizer)->end();
88 3
    }
89
90 3
    private function addVariablesNode(): ArrayNodeDefinition
91
    {
92 3
        $node = new ArrayNodeDefinition('variables');
93
        $node
94 3
            ->normalizeKeys(false)
95 3
            ->useAttributeAsKey('name')
96 3
            ->prototype('variable')->end()
97 3
            ->validate()
98 3
                ->always()
99
                ->then(static function ($variables) {
100 2
                    return \array_filter($variables, 'is_string');
101 3
                })
102 3
            ->end()
103
        ;
104
105 3
        return $node;
106
    }
107
108 3
    private function addErrorLoggingLevelNode(): ArrayNodeDefinition
109
    {
110 3
        $node = new ArrayNodeDefinition('error_logging_level');
111
        $node
112 3
            ->beforeNormalization()
113 3
                ->ifString()
114
                ->then(static function ($v) {
115 2
                    return \preg_split('/\s*,\s*/', $v, -1, \PREG_SPLIT_NO_EMPTY);
116 3
                })
117 3
            ->end()
118 3
            ->prototype('scalar')->end()
119 3
            ->validate()
120 3
                ->always()
121
                ->then(static function ($methods) {
122
                    $invalidMethods = \array_filter($methods, static function ($method) {
123 2
                        return false === \defined("E_{$method}");
124 2
                    });
125
126 2
                    if (empty($invalidMethods)) {
127
                        return \array_reduce($methods, static function ($level, $method) {
128 1
                            return $level |= \constant("E_{$method}");
129 1
                        });
130
                    }
131
132 1
                    throw new InvalidConfigurationException(\sprintf(
133 1
                        'The errors are not supported: "%s".',
134 1
                        \implode('", "', $invalidMethods)
135
                    ));
136 3
                })
137 3
            ->end()
138
        ;
139
140 3
        return $node;
141
    }
142
143 3
    private function addArrayNode(string $name): ArrayNodeDefinition
144
    {
145 3
        $node = new ArrayNodeDefinition($name);
146
        $node
147 3
            ->normalizeKeys(false)
148 3
            ->useAttributeAsKey('name')
149 3
            ->beforeNormalization()
150 3
                ->ifString()
151 3
                ->then(static function ($v) {
152
                    return \preg_split('/\s*,\s*/', $v, -1, \PREG_SPLIT_NO_EMPTY);
153 3
                })
154 3
            ->end()
155 3
            ->prototype('scalar')->end()
156
        ;
157
158 3
        return $node;
159
    }
160
}
161