Completed
Pull Request — master (#44)
by Tobias
09:06
created

Configuration   A

Complexity

Total Complexity 16

Size/Duplication

Total Lines 287
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 5

Test Coverage

Coverage 100%

Importance

Changes 7
Bugs 0 Features 3
Metric Value
wmc 16
c 7
b 0
f 3
lcom 1
cbo 5
dl 0
loc 287
ccs 186
cts 186
cp 1
rs 10

5 Methods

Rating   Name   Duplication   Size   Complexity  
B getConfigTreeBuilder() 0 67 7
A configureClients() 0 20 1
B configurePlugins() 0 111 1
B addAuthenticationPluiginNode() 0 44 5
A validateAuthenticationType() 0 18 2
1
<?php
2
3
namespace Http\HttplugBundle\DependencyInjection;
4
5
use Symfony\Component\Config\Definition\ArrayNode;
6
use Symfony\Component\Config\Definition\Builder\ArrayNodeDefinition;
7
use Symfony\Component\Config\Definition\Builder\TreeBuilder;
8
use Symfony\Component\Config\Definition\ConfigurationInterface;
9
use Symfony\Component\Config\Definition\Exception\InvalidConfigurationException;
10
11
/**
12
 * This class contains the configuration information for the bundle.
13
 *
14
 * This information is solely responsible for how the different configuration
15
 * sections are normalized, and merged.
16
 *
17
 * @author David Buchmann <[email protected]>
18
 * @author Tobias Nyholm <[email protected]>
19
 */
20
class Configuration implements ConfigurationInterface
21
{
22
    /**
23
     * {@inheritdoc}
24
     */
25 6
    public function getConfigTreeBuilder()
26
    {
27 6
        $treeBuilder = new TreeBuilder();
28 6
        $rootNode = $treeBuilder->root('httplug');
29
30 6
        $this->configureClients($rootNode);
31 6
        $this->configurePlugins($rootNode);
32
33
        $rootNode
34 6
            ->validate()
35
                ->ifTrue(function ($v) {
36 6
                    return !empty($v['classes']['client'])
37 6
                        || !empty($v['classes']['message_factory'])
38 3
                        || !empty($v['classes']['uri_factory'])
39 6
                        || !empty($v['classes']['stream_factory']);
40 6
                })
41 6
                ->then(function ($v) {
42 3
                    foreach ($v['classes'] as $key => $class) {
43 3
                        if (null !== $class && !class_exists($class)) {
44 1
                            throw new InvalidConfigurationException(sprintf(
45 1
                                'Class %s specified for httplug.classes.%s does not exist.',
46 1
                                $class,
47
                                $key
48 1
                            ));
49
                        }
50 2
                    }
51
52 2
                    return $v;
53 6
                })
54 6
            ->end()
55 6
            ->children()
56 6
                ->arrayNode('main_alias')
57 6
                    ->addDefaultsIfNotSet()
58 6
                    ->info('Configure which service the main alias point to.')
59 6
                    ->children()
60 6
                        ->scalarNode('client')->defaultValue('httplug.client.default')->end()
61 6
                        ->scalarNode('message_factory')->defaultValue('httplug.message_factory.default')->end()
62 6
                        ->scalarNode('uri_factory')->defaultValue('httplug.uri_factory.default')->end()
63 6
                        ->scalarNode('stream_factory')->defaultValue('httplug.stream_factory.default')->end()
64 6
                    ->end()
65 6
                ->end()
66 6
                ->arrayNode('classes')
67 6
                    ->addDefaultsIfNotSet()
68 6
                    ->info('Overwrite a service class instead of using the discovery mechanism.')
69 6
                    ->children()
70 6
                        ->scalarNode('client')->defaultNull()->end()
71 6
                        ->scalarNode('message_factory')->defaultNull()->end()
72 6
                        ->scalarNode('uri_factory')->defaultNull()->end()
73 6
                        ->scalarNode('stream_factory')->defaultNull()->end()
74 6
                    ->end()
75 6
                ->end()
76 6
                ->arrayNode('toolbar')
77 6
                    ->addDefaultsIfNotSet()
78 6
                    ->info('Extend the debug profiler with inforation about requests.')
79 6
                    ->children()
80 6
                        ->enumNode('enabled')
81 6
                            ->info('If "auto" (default), the toolbar is activated when kernel.debug is true. You can force the toolbar on and off by changing this option.')
82 6
                            ->values([true, false, 'auto'])
83 6
                            ->defaultValue('auto')
84 6
                        ->end()
85 6
                        ->scalarNode('formatter')->defaultNull()->end()
86 6
                    ->end()
87 6
                ->end()
88 6
            ->end();
89
90 6
        return $treeBuilder;
91
    }
92
93 6
    protected function configureClients(ArrayNodeDefinition $root)
94
    {
95 6
        $root->children()
96 6
            ->arrayNode('clients')
97 6
                ->useAttributeAsKey('name')
98 6
                ->prototype('array')
99 6
                ->children()
100 6
                    ->scalarNode('factory')
101 6
                        ->isRequired()
102 6
                        ->cannotBeEmpty()
103 6
                        ->info('The service id of a factory to use when creating the adapter.')
104 6
                    ->end()
105 6
                    ->arrayNode('plugins')
106 6
                        ->info('A list of service ids of plugins. The order is important.')
107 6
                        ->prototype('scalar')->end()
108 6
                    ->end()
109 6
                    ->variableNode('config')->defaultValue([])->end()
110 6
                ->end()
111 6
            ->end();
112 6
    }
113
114
    /**
115
     * @param ArrayNodeDefinition $root
116
     */
117 6
    protected function configurePlugins(ArrayNodeDefinition $root)
118
    {
119 6
        $root->children()
120 6
            ->arrayNode('plugins')
121 6
                ->addDefaultsIfNotSet()
122 6
                ->children()
123
                    ->append($this->addAuthenticationPluiginNode())
124 6
125 6
                    ->arrayNode('cache')
126 6
                    ->canBeEnabled()
127 6
                    ->addDefaultsIfNotSet()
128 6
                        ->children()
129 6
                            ->scalarNode('cache_pool')
130 6
                                ->info('This must be a service id to a service implementing Psr\Cache\CacheItemPoolInterface')
131 6
                                ->isRequired()
132 6
                                ->cannotBeEmpty()
133 6
                            ->end()
134
                            ->scalarNode('stream_factory')
135 6
                                ->info('This must be a service id to a service implementing Http\Message\StreamFactory')
136 6
                                ->defaultValue('httplug.stream_factory')
137 6
                                ->cannotBeEmpty()
138 6
                            ->end()
139 6
                            ->arrayNode('config')
140 6
                                ->addDefaultsIfNotSet()
141 6
                                ->children()
142 6
                                    ->scalarNode('default_ttl')->defaultNull()->end()
143 6
                                    ->scalarNode('respect_cache_headers')->defaultTrue()->end()
144 6
                                ->end()
145 6
                            ->end()
146 6
                        ->end()
147 6
                    ->end() // End cache plugin
148 6
149 6
                    ->arrayNode('cookie')
150 6
                    ->canBeEnabled()
151 6
                        ->children()
152 6
                            ->scalarNode('cookie_jar')
153 6
                                ->info('This must be a service id to a service implementing Http\Message\CookieJar')
154 6
                                ->isRequired()
155 6
                                ->cannotBeEmpty()
156 6
                            ->end()
157 6
                        ->end()
158
                    ->end() // End cookie plugin
159 6
160 6
                    ->arrayNode('decoder')
161 6
                    ->canBeDisabled()
162 6
                    ->addDefaultsIfNotSet()
163 6
                        ->children()
164 6
                            ->scalarNode('use_content_encoding')->defaultTrue()->end()
165 6
                        ->end()
166 6
                    ->end() // End decoder plugin
167 6
168 6
                    ->arrayNode('history')
169
                    ->canBeEnabled()
170 6
                        ->children()
171 6
                            ->scalarNode('journal')
172 6
                                ->info('This must be a service id to a service implementing Http\Client\Plugin\Journal')
173 6
                                ->isRequired()
174 6
                                ->cannotBeEmpty()
175 6
                            ->end()
176 6
                        ->end()
177
                    ->end() // End history plugin
178 6
179 6
                    ->arrayNode('logger')
180 6
                    ->canBeDisabled()
181 6
                    ->addDefaultsIfNotSet()
182 6
                        ->children()
183 6
                            ->scalarNode('logger')
184 6
                                ->info('This must be a service id to a service implementing Psr\Log\LoggerInterface')
185 6
                                ->defaultValue('logger')
186 6
                                ->cannotBeEmpty()
187 6
                            ->end()
188
                            ->scalarNode('formatter')
189 6
                                ->info('This must be a service id to a service implementing Http\Message\Formatter')
190 6
                                ->defaultNull()
191 6
                            ->end()
192 6
                        ->end()
193 6
                    ->end() // End logger plugin
194 6
195 6
                    ->arrayNode('redirect')
196 6
                    ->canBeDisabled()
197 6
                    ->addDefaultsIfNotSet()
198 6
                        ->children()
199 6
                            ->scalarNode('preserve_header')->defaultTrue()->end()
200 6
                            ->scalarNode('use_default_for_multiple')->defaultTrue()->end()
201 6
                        ->end()
202 6
                    ->end() // End redirect plugin
203 6
204
                    ->arrayNode('retry')
205 6
                    ->canBeDisabled()
206 6
                    ->addDefaultsIfNotSet()
207 6
                        ->children()
208 6
                            ->scalarNode('retry')->defaultValue(1)->end()
209 6
                        ->end()
210 6
                    ->end() // End retry plugin
211 6
212 6
                    ->arrayNode('stopwatch')
213
                    ->canBeDisabled()
214 6
                    ->addDefaultsIfNotSet()
215 6
                        ->children()
216 6
                            ->scalarNode('stopwatch')
217 6
                                ->info('This must be a service id to a service extending Symfony\Component\Stopwatch\Stopwatch')
218 6
                                ->defaultValue('debug.stopwatch')
219 6
                                ->cannotBeEmpty()
220 6
                            ->end()
221
                        ->end()
222 6
                    ->end() // End stopwatch plugin
223 6
224 6
                ->end()
225 6
            ->end()
226 6
        ->end();
227 6
    }
228 6
229 6
    /**
230 6
     * Add configuration for authentication plugin.
231 6
     *
232 6
     * @return ArrayNodeDefinition|\Symfony\Component\Config\Definition\Builder\NodeDefinition
233
     */
234 6
    private function addAuthenticationPluiginNode()
235 6
    {
236 6
        $builder = new TreeBuilder();
237 6
        $node = $builder->root('authentication');
238
        $node
239
            ->useAttributeAsKey('name')
240
            ->prototype('array')
241
                ->validate()
242
                    ->always()
243
                    ->then(function ($config) {
244
                        switch ($config['type']) {
245
                            case 'basic':
246
                                $this->validateAuthenticationType(['username', 'password'], $config, 'basic');
247
                                break;
248
                            case 'bearer':
249
                                $this->validateAuthenticationType(['token'], $config, 'bearer');
250
                                break;
251
                            case 'service':
252
                                $this->validateAuthenticationType(['service'], $config, 'service');
253
                                break;
254
                            case 'wsse':
255
                                $this->validateAuthenticationType(['username', 'password'], $config, 'wsse');
256
                                break;
257
                        }
258
259
                        return $config;
260
                    })
261
                ->end()
262
                ->children()
263
                    ->enumNode('type')
264
                        ->values(['basic', 'bearer', 'wsse', 'service'])
265
                        ->isRequired()
266
                        ->cannotBeEmpty()
267
                    ->end()
268
                    ->scalarNode('username')->end()
269
                    ->scalarNode('password')->end()
270
                    ->scalarNode('token')->end()
271
                    ->scalarNode('service')->end()
272
                    ->end()
273
                ->end()
274
            ->end(); // End authentication plugin
275
276
        return $node;
277
    }
278
279
    /**
280
     * Validate that the configuration fragment has the specified keys and none other.
281
     *
282
     * @param array  $expected Fields that must exist
283
     * @param array  $actual   Actual configuration hashmap
284
     * @param string $authName Name of authentication method for error messages
285
     *
286
     * @throws InvalidConfigurationException If $actual does not have exactly the keys specified in $expected (plus 'type')
287
     */
288
    private function validateAuthenticationType(array $expected, array $actual, $authName)
289
    {
290
        unset($actual['type']);
291
        $actual = array_keys($actual);
292
        sort($actual);
293
        sort($expected);
294
295
        if ($expected === $actual) {
296
            return;
297
        }
298
299
        throw new InvalidConfigurationException(sprintf(
300
            'Authentication "%s" requires %s but got %s',
301
            $authName,
302
            implode(', ', $expected),
303
            implode(', ', $actual)
304
        ));
305
    }
306
}
307