Completed
Push — cq ( ade73a...a41f67 )
by Roni
02:53
created

Configuration::changeToAssoc()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 6
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 0
loc 6
rs 9.4285
cc 1
eloc 3
nc 1
nop 0
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
    /**
27
     * {@inheritDoc}
28
     */
29
    public function getConfigTreeBuilder()
30
    {
31
        $treeBuilder = new TreeBuilder();
32
33
        $rootNode = $treeBuilder->root('xiidea_easy_audit');
34
35
        $this->addRequiredConfigs($rootNode);
36
        $this->addDefaultServices($rootNode);
37
        $this->addOptionalConfigs($rootNode);
38
        $this->addChannelHandlers($rootNode);
39
40
        return $treeBuilder;
41
    }
42
43
    /**
44
     * @param ArrayNodeDefinition $rootNode
45
     */
46
    private function addRequiredConfigs(ArrayNodeDefinition $rootNode)
47
    {
48
        $rootNode
49
            ->children()
50
                ->scalarNode('user_property')->isRequired()->defaultValue(null)->end()
51
                ->scalarNode('entity_class')->cannotBeOverwritten()->isRequired()->cannotBeEmpty()->end()
52
            ->end();
53
    }
54
55
    /**
56
     * @param ArrayNodeDefinition $rootNode
57
     */
58
    private function addDefaultServices(ArrayNodeDefinition $rootNode)
59
    {
60
        $rootNode
61
            ->children()
62
                ->scalarNode('resolver')->defaultValue('xiidea.easy_audit.default_event_resolver')->end()
63
                ->scalarNode('entity_event_resolver')
64
                    ->defaultValue('xiidea.easy_audit.default_entity_event_resolver')
65
                ->end()
66
                ->booleanNode('default_logger')->defaultValue(true)->end()
67
            ->end();
68
    }
69
70
    /**
71
     * @param ArrayNodeDefinition $rootNode
72
     */
73
    private function addOptionalConfigs(ArrayNodeDefinition $rootNode)
74
    {
75
        $rootNode
76
            ->children()
77
                ->variableNode('doctrine_entities')->defaultValue(array())->end()
78
                ->variableNode('events')->defaultValue(array())->end()
79
                ->variableNode('custom_resolvers')->defaultValue(array())->end()
80
            ->end();
81
    }
82
83
    /**
84
     * @param ArrayNodeDefinition $rootNode
85
     */
86
    private function addChannelHandlers(ArrayNodeDefinition $rootNode)
87
    {
88
        $rootNode
89
            ->fixXmlConfig('loggerChannel')
90
            ->children()
91
                ->arrayNode('logger_channel')
92
                    ->canBeUnset()
93
                    ->useAttributeAsKey('name')
94
                    ->prototype('array')
95
                    ->fixXmlConfig('channel', 'elements')
96
                        ->canBeUnset()
97
                        ->beforeNormalization()->ifString()->then($this->changeToArrayFromString())->end()
98
                        ->beforeNormalization()->ifTrue($this->isIndexedArray())->then($this->changeToAssoc())->end()
99
                        ->validate()->ifTrue($this->isEmpty())->thenUnset()->end()
100
                        ->validate()->always($this->getChannelTypeValidator())->end()
101
                        ->children()
102
                            ->scalarNode('type')->validate()
103
                                ->ifNotInArray(array('inclusive', 'exclusive'))
104
                                ->thenInvalid('The type of channels has to be inclusive or exclusive')->end()->end()
105
                            ->arrayNode('elements')->prototype('scalar')->end()->end()->end()
106
                        ->end()
107
                    ->end()
108
                ->end()
109
            ->end();
110
    }
111
112
    /**
113
     * @return \Closure
114
     */
115
    private function getChannelTypeValidator()
116
    {
117
        return function ($v) {
118
            $isExclusiveList = isset($v['type']) ? 'exclusive' === $v['type'] : null;
119
            $elements = array();
120
121
            foreach ($v['elements'] as $element) {
122
                Configuration::appendChannelTypes($element, $isExclusiveList, $elements);
123
            }
124
125
            return array('type' => $isExclusiveList ? 'exclusive' : 'inclusive', 'elements' => $elements);
126
        };
127
    }
128
129
    /**
130
     * @param boolean $invalid
131
     * @throws InvalidConfigurationException
132
     */
133
    public static function throwExceptionOnInvalid($invalid)
134
    {
135
        if(!$invalid) {
136
            return;
137
        }
138
139
        throw new InvalidConfigurationException(
140
            'Cannot combine exclusive/inclusive definitions in channels list'
141
        );
142
    }
143
144
    public static function appendChannelTypes($element, &$isExclusiveList, &$elements = array())
145
    {
146
        $isExclusiveItem = 0 === strpos($element, '!');
147
148
        self::throwExceptionOnInvalid(!$isExclusiveItem === $isExclusiveList);
149
150
        $elements[] = $isExclusiveItem ? substr($element, 1) : $element;
151
        $isExclusiveList = $isExclusiveItem;
152
    }
153
154
    /**
155
     * @return \Closure
156
     */
157
    private function isIndexedArray()
158
    {
159
        return function ($v) {
160
            return is_array($v) && is_numeric(key($v));
161
        };
162
    }
163
164
    /**
165
     * @return \Closure
166
     */
167
    private function changeToAssoc()
168
    {
169
        return function ($v) {
170
            return array('elements' => $v);
171
        };
172
    }
173
174
    /**
175
     * @return \Closure
176
     */
177
    private function changeToArrayFromString()
178
    {
179
        return function ($v) {
180
            return array('elements' => array($v));
181
        };
182
    }
183
184
    /**
185
     * @return \Closure
186
     */
187
    private function isEmpty()
188
    {
189
        return function ($v) {
190
            return empty($v);
191
        };
192
    }
193
}
194