Configuration::addVariablesNode()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 14

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 8
CRAP Score 1

Importance

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