Completed
Pull Request — master (#3)
by Jacob
02:17
created

Configuration::validateMetadataCache()   B

Complexity

Conditions 5
Paths 3

Size

Total Lines 12
Code Lines 7

Duplication

Lines 0
Ratio 0 %

Importance

Changes 2
Bugs 0 Features 0
Metric Value
c 2
b 0
f 0
dl 0
loc 12
rs 8.8571
cc 5
eloc 7
nc 3
nop 1
1
<?php
2
3
namespace As3\Bundle\ModlrBundle\DependencyInjection;
4
5
use Symfony\Component\Config\Definition\Builder\TreeBuilder;
6
use Symfony\Component\Config\Definition\ConfigurationInterface;
7
use Symfony\Component\Config\Definition\Exception\InvalidConfigurationException;
8
9
/**
10
 * Validates and merges configuration for Modlr.
11
 *
12
 * @author  Jacob Bare <[email protected]>
13
 */
14
class Configuration implements ConfigurationInterface
15
{
16
    /**
17
     * {@inheritDoc}
18
     */
19
    public function getConfigTreeBuilder()
20
    {
21
        $treeBuilder = new TreeBuilder();
22
        $treeBuilder->root('as3_modlr')
23
            ->children()
24
                ->append($this->getAdapterNode())
25
                ->append($this->getMetadataNode())
26
                ->append($this->getPersistersNode())
27
                ->append($this->getRestNode())
28
                ->append($this->getSearchClientsNode())
29
            ->end()
30
        ;
31
        return $treeBuilder;
32
    }
33
34
    /**
35
     * Formats the root REST endpoint.
36
     *
37
     * @param   string  $endpoint
38
     * @return  string
39
     */
40
    private function formatRestEndpoint($endpoint)
41
    {
42
        return sprintf('%s', trim($endpoint, '/'));
43
    }
44
45
    /**
46
     * Gets the api adapter configuration node.
47
     *
48
     * @return  \Symfony\Component\Config\Definition\Builder\ArrayNodeDefinition
49
     */
50
    private function getAdapterNode()
51
    {
52
        $treeBuilder = new TreeBuilder();
53
        $node = $treeBuilder->root('adapter');
54
        return $node
55
            ->isRequired()
56
            ->addDefaultsIfNotSet()
57
            ->children()
58
                ->scalarNode('type')->end()
59
                ->scalarNode('service')->end()
60
            ->end()
61
            ->validate()
62
                ->always(function($v) {
63
                    $this->validateAdapter($v);
64
                    return $v;
65
                })
66
            ->end()
67
        ;
68
    }
69
70
    /**
71
     * Gets the metadata configuration node.
72
     *
73
     * @return  \Symfony\Component\Config\Definition\Builder\ArrayNodeDefinition
74
     */
75
    private function getMetadataNode()
76
    {
77
        $treeBuilder = new TreeBuilder();
78
        $node = $treeBuilder->root('metadata');
79
        return $node
80
            ->addDefaultsIfNotSet()
81
            ->children()
82
                ->arrayNode('drivers')
83
                    ->defaultValue(['default' => ['type' => 'yml']])
84
                    ->useAttributeAsKey('name')
85
                    ->prototype('array')
86
                        ->performNoDeepMerging()
87
                        ->children()
88
89
                            ->enumNode('type')->defaultValue('file')
90
                            ->values(['yml', null])
91
                            ->end()
92
                            ->scalarNode('service')->cannotBeEmpty()->end()
93
94
                            ->arrayNode('parameters')
95
                                ->prototype('variable')->end()
96
                            ->end()
97
98
                        ->end()
99
                    ->end()
100
                    ->validate()
101
                        ->always(function($v) {
102
                            $this->validateMetadataDrivers($v);
103
                            return $v;
104
                        })
105
                    ->end()
106
                ->end()
107
108
                ->arrayNode('cache')
109
                    ->canBeDisabled()
110
                    ->children()
111
112
                        ->enumNode('type')->defaultValue('file')
113
                            ->values(['file', 'binary_file', 'redis', null])
114
                        ->end()
115
                        ->scalarNode('service')->cannotBeEmpty()->end()
116
117
                        ->arrayNode('parameters')
118
                            ->prototype('variable')->end()
119
                        ->end()
120
121
                    ->end()
122
123
                    ->validate()
124
                        ->always(function($v) {
125
                            $this->validateMetadataCache($v);
126
                            return $v;
127
                        })
128
                    ->end()
129
                ->end()
130
            ->end()
131
        ;
132
    }
133
134
    /**
135
     * Gets the persisters configuration node.
136
     *
137
     * @return  \Symfony\Component\Config\Definition\Builder\ArrayNodeDefinition
138
     */
139 View Code Duplication
    private function getPersistersNode()
1 ignored issue
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
140
    {
141
        $treeBuilder = new TreeBuilder();
142
        $node = $treeBuilder->root('persisters');
143
        return $node
144
            ->isRequired()
145
            ->useAttributeAsKey('name')
146
            ->prototype('array')
147
                ->children()
148
149
                    ->scalarNode('type')->cannotBeEmpty()->end()
150
                    ->scalarNode('service')->cannotBeEmpty()->end()
151
152
                    ->arrayNode('parameters')
153
                        ->prototype('variable')->end()
154
                    ->end()
155
                ->end()
156
            ->end()
157
            ->validate()
158
                ->always(function($v) {
159
                    $this->validatePersisters($v);
160
                    return $v;
161
                })
162
            ->end()
163
        ;
164
    }
165
166
    /**
167
     * Gets the rest configuration node.
168
     *
169
     * @return  \Symfony\Component\Config\Definition\Builder\ArrayNodeDefinition
170
     */
171
    private function getRestNode()
172
    {
173
        $treeBuilder = new TreeBuilder();
174
        $node = $treeBuilder->root('rest');
175
        return $node
176
            ->addDefaultsIfNotSet()
177
            ->children()
178
                ->scalarNode('root_endpoint')->isRequired()->cannotBeEmpty()->defaultValue('modlr/api')
179
                    ->validate()
180
                        ->always(function($v) {
181
                            $v = $this->formatRestEndpoint($v);
182
                            return $v;
183
                        })
184
                    ->end()
185
                ->end()
186
            ->end()
187
188
        ;
189
    }
190
191
    /**
192
     * Gets the search clients configuration node.
193
     *
194
     * @return  \Symfony\Component\Config\Definition\Builder\ArrayNodeDefinition
195
     */
196 View Code Duplication
    private function getSearchClientsNode()
1 ignored issue
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
197
    {
198
        $treeBuilder = new TreeBuilder();
199
        $node = $treeBuilder->root('search_clients');
200
        return $node
201
            ->isRequired()
202
            ->useAttributeAsKey('name')
203
            ->prototype('array')
204
                ->children()
205
206
                    ->scalarNode('type')->cannotBeEmpty()->end()
207
                    ->scalarNode('service')->cannotBeEmpty()->end()
208
209
                    ->arrayNode('parameters')
210
                        ->prototype('variable')->end()
211
                    ->end()
212
                ->end()
213
            ->end()
214
            ->validate()
215
                ->always(function($v) {
216
                    $this->validateSearchClients($v);
217
                    return $v;
218
                })
219
            ->end()
220
        ;
221
    }
222
223
    /**
224
     * Validates the api adapter config.
225
     *
226
     * @param   array   $adapter
227
     * @return  self
228
     * @throws  InvalidConfigurationException
229
     */
230
    private function validateAdapter(array $adapter)
231
    {
232
        $this->validateTypeAndService($adapter, 'as3_modlr.adapter');
233
234
        if (isset($adapter['type'])) {
235
            if ('jsonapiorg' === $adapter['type']) {
236
                if (false === class_exists('As3\Modlr\Api\JsonApiOrg\Adapter')) {
237
                    throw new InvalidConfigurationException('The jsonapi.org adapter class was not found for "as3_modlr.adapter.type" - was the library installed?');
238
                }
239
            } else {
240
                throw new InvalidConfigurationException('An unrecognized adapter type was set for "as3_modlr.adapter.type"');
241
            }
242
        }
243
        return $this;
244
    }
245
246
    /**
247
     * Validates the metadata cache config.
248
     *
249
     * @param   array   $config
250
     * @return  self
251
     * @throws  InvalidConfigurationException
252
     */
253
    private function validateMetadataCache(array $config)
254
    {
255
        if (false === $config['enabled']) {
256
            return $this;
257
        }
258
259
        $this->validateTypeAndService($config, 'as3_modlr.metadata.cache');
260
        if (isset($config['type']) && 'redis' === $config['type'] && !isset($config['parameters']['handler'])) {
261
            throw new InvalidConfigurationException('A Redis handler service name must be defined for "as3_modlr.metadata.cache.parameters.handler"');
262
        }
263
        return $this;
264
    }
265
266
    /**
267
     * Validates the metadata drivers config.
268
     *
269
     * @param   array   $drivers
270
     * @return  self
271
     * @throws  InvalidConfigurationException
272
     */
273
    private function validateMetadataDrivers(array $drivers)
274
    {
275
        foreach ($drivers as $name => $config) {
276
            $this->validateTypeAndService($config, sprintf('as3_modlr.metadata.drivers.%s', $name));
277
        }
278
        return $this;
279
    }
280
281
    /**
282
     * Validates the persisters config.
283
     *
284
     * @param   array   $persisters
285
     * @return  self
286
     * @throws  InvalidConfigurationException
287
     */
288
    private function validatePersisters(array $persisters)
289
    {
290
        foreach ($persisters as $name => $config) {
291
            $this->validateTypeAndService($config, sprintf('as3_modlr.persisters.%s', $name));
292
            if (isset($config['type'])) {
293
                if ('mongodb' === $config['type']) {
294 View Code Duplication
                    if (false === class_exists(Utility::getLibraryClass('Persister\MongoDb\Persister'))) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
295
                        throw new InvalidConfigurationException(sprintf('The MongoDB persister library class was not found for "as3_modlr.persisters.%s.type" - was the library installed?', $name));
296
                    }
297
                    if (!isset($config['parameters']['host'])) {
298
                        throw new InvalidConfigurationException(sprintf('The MongoDB persister requires a value for "as3_modlr.persisters.%s.parameters.host"', $name));
299
                    }
300
                } else {
301
                    throw new InvalidConfigurationException(sprintf('An unrecognized persister type was set for "as3_modlr.persisters.%s.type"', $name));
302
                }
303
            }
304
        }
305
    }
306
307
    /**
308
     * Validates the search clients config.
309
     *
310
     * @param   array   $clients
311
     * @return  self
312
     * @throws  InvalidConfigurationException
313
     */
314
    private function validateSearchClients(array $clients)
315
    {
316
        foreach ($clients as $name => $config) {
317
            $this->validateTypeAndService($config, sprintf('as3_modlr.search_clients.%s', $name));
318
            if (isset($config['type'])) {
319
                if ('elastic' === $config['type']) {
320 View Code Duplication
                    if (false === class_exists(Utility::getLibraryClass('Search\Elastic\Client'))) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
321
                        throw new InvalidConfigurationException(sprintf('The Elastic persister library class was not found for "as3_modlr.search_clients.%s.type" - was the library installed?', $name));
322
                    }
323
                } else {
324
                    throw new InvalidConfigurationException(sprintf('An unrecognized search type was set for "as3_modlr.search_clients.%s.type"', $name));
325
                }
326
            }
327
        }
328
    }
329
330
    private function validateTypeAndService(array $config, $path)
331
    {
332 View Code Duplication
        if (!isset($config['type']) && !isset($config['service'])) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
333
            throw new InvalidConfigurationException(sprintf('You must set one of "type" or "service" for "%s"', $path));
334
        }
335 View Code Duplication
        if (isset($config['type']) && isset($config['service'])) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
336
            throw new InvalidConfigurationException(sprintf('You cannot set both "type" and "service" for "%s" - please choose one.', $path));
337
        }
338
    }
339
}
340