Completed
Push — master ( 506e91...1c7433 )
by Peter
32s queued 11s
created

Configuration::getConfigTreeBuilder()   F

Complexity

Conditions 30
Paths 2

Size

Total Lines 143

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 78
CRAP Score 30.014

Importance

Changes 0
Metric Value
dl 0
loc 143
ccs 78
cts 80
cp 0.975
rs 3.3333
c 0
b 0
f 0
cc 30
nc 2
nop 0
crap 30.014

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
declare(strict_types=1);
3
4
/**
5
 * GpsLab component.
6
 *
7
 * @author    Peter Gribanov <[email protected]>
8
 * @copyright Copyright (c) 2017, Peter Gribanov
9
 * @license   http://opensource.org/licenses/MIT
10
 */
11
12
namespace GpsLab\Bundle\GeoIP2Bundle\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
18
class Configuration implements ConfigurationInterface
19
{
20
    private const URL = 'https://download.maxmind.com/app/geoip_download?edition_id=%s&license_key=%s&suffix=tar.gz';
21
22
    private const PATH = '%s/%s.mmdb';
23
24
    /**
25
     * @var string
26
     */
27
    private $cache_dir;
28
29
    /**
30
     * @param string|null $cache_dir
31
     */
32 41
    public function __construct(?string $cache_dir)
33
    {
34 41
        $this->cache_dir = $cache_dir ?: sys_get_temp_dir();
35 41
    }
36
37
    /**
38
     * @return TreeBuilder
39
     */
40 41
    public function getConfigTreeBuilder(): TreeBuilder
41
    {
42 41
        $tree_builder = new TreeBuilder('gpslab_geoip');
43
44 41
        if (method_exists($tree_builder, 'getRootNode')) {
45
            // Symfony 4.2 +
46 41
            $root_node = $tree_builder->getRootNode();
47
        } else {
48
            // Symfony 4.1 and below
49
            $root_node = $tree_builder->root('gpslab_geoip');
0 ignored issues
show
Bug introduced by
The method root() does not seem to exist on object<Symfony\Component...on\Builder\TreeBuilder>.

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
50
        }
51
52
        // normalize default_database from databases
53
        $root_node
54 41
            ->beforeNormalization()
55
            ->ifTrue(static function ($v): bool {
56
                return
57 39
                    is_array($v) &&
58 39
                    !array_key_exists('default_database', $v) &&
59 39
                    array_key_exists('databases', $v) &&
60 39
                    is_array($v['databases']);
61 41
            })
62
            ->then(static function (array $v): array {
63 14
                $keys = array_keys($v['databases']);
64 14
                $v['default_database'] = reset($keys);
65
66 14
                return $v;
67 41
            });
68
69
        // normalize databases root configuration to default_database
70
        $root_node
71 41
            ->beforeNormalization()
72
            ->ifTrue(static function ($v): bool {
73 39
                return $v && is_array($v) && !array_key_exists('databases', $v) && !array_key_exists('database', $v);
74 41
            })
75
            ->then(static function (array $v): array {
76
                // key that should not be rewritten to the database config
77 10
                $database = [];
78 10
                foreach ($v as $key => $value) {
79 10
                    if ($key !== 'default_database') {
80 10
                        $database[$key] = $v[$key];
81 10
                        unset($v[$key]);
82
                    }
83
                }
84 10
                $v['default_database'] = isset($v['default_database']) ? (string) $v['default_database'] : 'default';
85 10
                $v['databases'] = [$v['default_database'] => $database];
86
87 10
                return $v;
88 41
            });
89
90
        // default_database should be exists in databases
91
        $root_node
92 41
            ->validate()
93
                ->ifTrue(static function ($v): bool {
94
                    return
95 27
                        is_array($v) &&
96 27
                        array_key_exists('default_database', $v) &&
97 27
                        array_key_exists('databases', $v) &&
98 27
                        $v['databases'] &&
99 27
                        !array_key_exists($v['default_database'], $v['databases']);
100 41
                })
101
                ->then(static function (array $v): array {
102 4
                    $databases = implode('", "', array_keys($v['databases']));
103
104 4
                    throw new \InvalidArgumentException(sprintf('Undefined default database "%s". Available "%s" databases.', $v['default_database'], $databases));
105 41
                });
106
107
        // add license to databases config if not exists (allow use a global license for all databases)
108
        $root_node
109 41
            ->beforeNormalization()
110
            ->ifTrue(static function ($v): bool {
111
                return
112 39
                    is_array($v) &&
113 39
                    array_key_exists('license', $v) &&
114 39
                    array_key_exists('databases', $v) &&
115 39
                    is_array($v['databases']);
116 41
            })
117
            ->then(static function (array $v): array {
118 6
                foreach ($v['databases'] as $name => $database) {
119 4
                    if (!array_key_exists('license', $database)) {
120 4
                        $v['databases'][$name]['license'] = $v['license'];
121
                    }
122
                }
123
124 6
                return $v;
125 41
            });
126
127
        // add locales to databases config if not exists (allow use a global locales for all databases)
128
        $root_node
129 41
            ->beforeNormalization()
130
            ->ifTrue(static function ($v): bool {
131
                return
132 39
                    is_array($v) &&
133 39
                    array_key_exists('locales', $v) &&
134 39
                    array_key_exists('databases', $v) &&
135 39
                    is_array($v['databases']);
136 41
            })
137
            ->then(static function (array $v): array {
138 2
                foreach ($v['databases'] as $name => $database) {
139 2
                    if (!array_key_exists('locales', $database)) {
140 2
                        $v['databases'][$name]['locales'] = $v['locales'];
141
                    }
142
                }
143
144 2
                return $v;
145 41
            });
146
147
        // validate database locales
148
        $root_node
149 41
            ->validate()
150
                ->ifTrue(static function ($v): bool {
151
                    return
152 23
                        is_array($v) &&
153 23
                        array_key_exists('databases', $v) &&
154 23
                        is_array($v['databases']);
155 41
                })
156
                ->then(static function (array $v): array {
157 23
                    foreach ($v['databases'] as $name => $database) {
158 17
                        if (!array_key_exists('locales', $database) || empty($database['locales'])) {
159
                            throw new \InvalidArgumentException(sprintf('The list of locales should not be empty in databases "%s".', $name));
160
                        }
161
                    }
162
163 23
                    return $v;
164 41
                });
165
166 41
        $root_node->fixXmlConfig('locale');
167 41
        $locales = $root_node->children()->arrayNode('locales');
168 41
        $locales->prototype('scalar');
169
        $locales
170 41
            ->treatNullLike([])
171 41
            ->defaultValue(['en']);
172
173 41
        $root_node->children()->scalarNode('license');
174
175 41
        $default_database = $root_node->children()->scalarNode('default_database');
176 41
        $default_database->defaultValue('default');
177
178 41
        $root_node->fixXmlConfig('database');
179 41
        $root_node->append($this->getDatabaseNode());
180
181 41
        return $tree_builder;
182
    }
183
184
    /**
185
     * @return ArrayNodeDefinition
186
     */
187 41
    private function getDatabaseNode(): ArrayNodeDefinition
188
    {
189 41
        $tree_builder = new TreeBuilder('databases');
190
191 41
        if (method_exists($tree_builder, 'getRootNode')) {
192
            // Symfony 4.2 +
193 41
            $root_node = $tree_builder->getRootNode();
194
        } else {
195
            // Symfony 4.1 and below
196
            $root_node = $tree_builder->root('databases');
0 ignored issues
show
Bug introduced by
The method root() does not seem to exist on object<Symfony\Component...on\Builder\TreeBuilder>.

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
197
        }
198
199
        /** @var ArrayNodeDefinition $database_node */
200
        $database_node = $root_node
201 41
            ->requiresAtLeastOneElement()
202 41
            ->useAttributeAsKey('name')
203 41
            ->prototype('array');
204
205
        // normalize url from license and edition
206
        $database_node
207 41
            ->beforeNormalization()
208
            ->ifTrue(static function ($v): bool {
209
                return
210 29
                    is_array($v) &&
211 29
                    !array_key_exists('url', $v) &&
212 29
                    array_key_exists('license', $v) &&
213 29
                    array_key_exists('edition', $v);
214 41
            })
215
            ->then(static function (array $v): array {
216 19
                $v['url'] = sprintf(self::URL, urlencode($v['edition']), urlencode($v['license']));
217
218 19
                return $v;
219 41
            });
220
221
        // normalize path from edition
222
        $database_node
223 41
            ->beforeNormalization()
224
            ->ifTrue(static function ($v): bool {
225 29
                return is_array($v) && !array_key_exists('path', $v) && array_key_exists('edition', $v);
226 41
            })
227
            ->then(function (array $v): array {
228 23
                $v['path'] = sprintf(self::PATH, $this->cache_dir, $v['edition']);
229
230 23
                return $v;
231 41
            });
232
233 41
        $url = $database_node->children()->scalarNode('url');
234 41
        $url->isRequired();
235
        // url must be a valid URL
236
        $url
237 41
            ->validate()
238
            ->ifTrue(static function ($v): bool {
239 27
                return is_string($v) && !filter_var($v, FILTER_VALIDATE_URL);
240 41
            })
241
            ->then(static function (string $v): array {
242 2
                throw new \InvalidArgumentException(sprintf('URL "%s" must be valid.', $v));
243 41
            });
244
245 41
        $path = $database_node->children()->scalarNode('path');
246 41
        $path->isRequired();
247
248 41
        $database_node->fixXmlConfig('locale');
249 41
        $locales = $database_node->children()->arrayNode('locales');
250 41
        $locales->prototype('scalar');
251
        $locales
252 41
            ->treatNullLike([])
253 41
            ->requiresAtLeastOneElement()
254 41
            ->defaultValue(['en']);
255
256 41
        $database_node->children()->scalarNode('license');
257
258 41
        $database_node->children()->scalarNode('edition');
259
260 41
        return $root_node;
261
    }
262
}
263