Passed
Push — master ( 4e035c...639836 )
by Roni
02:57
created

Configuration::getRootNode()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 7
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 3
dl 0
loc 7
rs 10
c 0
b 0
f 0
cc 2
nc 2
nop 1
1
<?php
2
3
/*
4
 * This file is part of the XiideaEasyAuditBundle package.
5
 *
6
 * (c) Xiidea <http://www.xiidea.net>
7
 *
8
 * This source file is subject to the MIT license that is bundled
9
 * with this source code in the file LICENSE.
10
 */
11
12
namespace Xiidea\EasyAuditBundle\DependencyInjection;
13
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\Config\Definition\Exception\InvalidConfigurationException;
18
19
/**
20
 * This is the class that validates and merges configuration from your app/config files.
21
 *
22
 * To learn more see {@link http://symfony.com/doc/current/cookbook/bundles/extension.html#cookbook-bundles-extension-config-class}
23
 */
24
class Configuration implements ConfigurationInterface
25
{
26
    const ROOT_NODE_NAME = 'xiidea_easy_audit';
27
28
    /**
29
     * {@inheritdoc}
30
     */
31
    public function getConfigTreeBuilder()
32
    {
33
        $treeBuilder = new TreeBuilder(self::ROOT_NODE_NAME);
34
35
        $rootNode = $treeBuilder->getRootNode();
36
37
        $this->addRequiredConfigs($rootNode);
38
        $this->addDefaultServices($rootNode);
39
        $this->addOptionalConfigs($rootNode);
40
        $this->addChannelHandlers($rootNode);
41
42
        return $treeBuilder;
43
    }
44
45
    /**
46
     * @param ArrayNodeDefinition $rootNode
47
     */
48
    private function addRequiredConfigs(ArrayNodeDefinition $rootNode)
49
    {
50
        $rootNode
51
            ->children()
52
                ->scalarNode('user_property')->isRequired()->end()
53
                ->scalarNode('audit_log_class')->cannotBeOverwritten()->isRequired()->cannotBeEmpty()->end()
0 ignored issues
show
Bug introduced by
The method scalarNode() does not exist on Symfony\Component\Config...der\NodeParentInterface. It seems like you code against a sub-type of Symfony\Component\Config...der\NodeParentInterface such as Symfony\Component\Config...ion\Builder\NodeBuilder. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

53
                ->/** @scrutinizer ignore-call */ scalarNode('audit_log_class')->cannotBeOverwritten()->isRequired()->cannotBeEmpty()->end()
Loading history...
54
            ->end();
55
    }
56
57
    /**
58
     * @param ArrayNodeDefinition $rootNode
59
     */
60
    private function addDefaultServices(ArrayNodeDefinition $rootNode)
61
    {
62
        $rootNode
63
            ->children()
64
                ->scalarNode('resolver')->defaultValue('xiidea.easy_audit.default_event_resolver')->end()
65
                ->scalarNode('doctrine_event_resolver')
66
                    ->defaultValue(null)
67
                ->end()
68
                ->booleanNode('default_logger')->defaultValue(true)->end()
69
            ->end();
70
    }
71
72
    /**
73
     * @param ArrayNodeDefinition $rootNode
74
     */
75
    private function addOptionalConfigs(ArrayNodeDefinition $rootNode)
76
    {
77
        $rootNode
78
            ->children()
79
                ->variableNode('doctrine_objects')
80
                    ->defaultValue(array())
81
                ->end()
82
                ->variableNode('events')->defaultValue(array())->end()
0 ignored issues
show
Bug introduced by
The method variableNode() does not exist on Symfony\Component\Config...der\NodeParentInterface. It seems like you code against a sub-type of Symfony\Component\Config...der\NodeParentInterface such as Symfony\Component\Config...ion\Builder\NodeBuilder. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

82
                ->/** @scrutinizer ignore-call */ variableNode('events')->defaultValue(array())->end()
Loading history...
83
                ->variableNode('custom_resolvers')->defaultValue(array())->end()
84
            ->end();
85
    }
86
87
    /**
88
     * @param ArrayNodeDefinition $rootNode
89
     */
90
    private function addChannelHandlers(ArrayNodeDefinition $rootNode)
91
    {
92
        $rootNode
93
            ->fixXmlConfig('loggerChannel')
94
            ->children()
95
                ->arrayNode('logger_channel')
96
                    ->canBeUnset()
97
                    ->useAttributeAsKey('name')
98
                    ->prototype('array')
99
                    ->fixXmlConfig('channel', 'elements')
0 ignored issues
show
Bug introduced by
The method fixXmlConfig() does not exist on Symfony\Component\Config...\Builder\NodeDefinition. It seems like you code against a sub-type of Symfony\Component\Config...\Builder\NodeDefinition such as Symfony\Component\Config...der\ArrayNodeDefinition. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

99
                    ->/** @scrutinizer ignore-call */ fixXmlConfig('channel', 'elements')
Loading history...
100
                        ->canBeUnset()
101
                        ->beforeNormalization()->ifString()->then($this->changeToArrayFromString())->end()
102
                        ->beforeNormalization()->ifTrue($this->isIndexedArray())->then($this->changeToAssoc())->end()
103
                        ->validate()->ifTrue($this->isEmpty())->thenUnset()->end()
104
                        ->validate()->always($this->getChannelTypeValidator())->end()
105
                        ->children()
106
                            ->scalarNode('type')->validate()
107
                                ->ifNotInArray(array('inclusive', 'exclusive'))
108
                                ->thenInvalid('The type of channels has to be inclusive or exclusive')->end()->end()
109
                            ->arrayNode('elements')->prototype('scalar')->end()->end()->end()
110
                        ->end()
111
                    ->end()
112
                ->end()
113
            ->end();
114
    }
115
116
    /**
117
     * @return \Closure
118
     */
119
    private function getChannelTypeValidator()
120
    {
121
        return function ($v) {
122
            $isExclusiveList = isset($v['type']) ? 'exclusive' === $v['type'] : null;
123
            $elements = array();
124
125
            foreach ($v['elements'] as $element) {
126
                Configuration::appendChannelTypes($element, $isExclusiveList, $elements);
127
            }
128
129
            return array('type' => $isExclusiveList ? 'exclusive' : 'inclusive', 'elements' => $elements);
130
        };
131
    }
132
133
    /**
134
     * @param bool $invalid
135
     *
136
     * @throws InvalidConfigurationException
137
     */
138
    public static function throwExceptionOnInvalid($invalid)
139
    {
140
        if (!$invalid) {
141
            return;
142
        }
143
144
        throw new InvalidConfigurationException(
145
            'Cannot combine exclusive/inclusive definitions in channels list'
146
        );
147
    }
148
149
    public static function appendChannelTypes($element, &$isExclusiveList, &$elements = array())
150
    {
151
        $isExclusiveItem = 0 === strpos($element, '!');
152
153
        self::throwExceptionOnInvalid(!$isExclusiveItem === $isExclusiveList);
154
155
        $elements[] = $isExclusiveItem ? substr($element, 1) : $element;
156
        $isExclusiveList = $isExclusiveItem;
157
    }
158
159
    /**
160
     * @return \Closure
161
     */
162
    private function isIndexedArray()
163
    {
164
        return function ($v) {
165
            return is_array($v) && is_numeric(key($v));
166
        };
167
    }
168
169
    /**
170
     * @return \Closure
171
     */
172
    private function changeToAssoc()
173
    {
174
        return function ($v) {
175
            return array('elements' => $v);
176
        };
177
    }
178
179
    /**
180
     * @return \Closure
181
     */
182
    private function changeToArrayFromString()
183
    {
184
        return function ($v) {
185
            return array('elements' => array($v));
186
        };
187
    }
188
189
    /**
190
     * @return \Closure
191
     */
192
    private function isEmpty()
193
    {
194
        return function ($v) {
195
            return empty($v);
196
        };
197
    }
198
}
199