Passed
Push — main ( 972a96...378c88 )
by Oscar
11:50
created

Configuration   A

Complexity

Total Complexity 20

Size/Duplication

Total Lines 352
Duplicated Lines 0 %

Test Coverage

Coverage 99.28%

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 250
dl 0
loc 352
ccs 274
cts 276
cp 0.9928
rs 10
c 1
b 0
f 0
wmc 20

6 Methods

Rating   Name   Duplication   Size   Complexity  
A addHtmlSection() 0 26 1
A addHttpHeaderSection() 0 50 1
A getConfigTreeBuilder() 0 17 2
A addWebpackEncoreSection() 0 14 1
C addSvgSection() 0 217 13
A createSectionNode() 0 16 2
1
<?php
2
3
/*
4
 * This file is part of ocubom/twig-extra-bundle
5
 *
6
 * © Oscar Cubo Medina <https://ocubom.github.io>
7
 *
8
 * For the full copyright and license information, please view the LICENSE
9
 * file that was distributed with this source code.
10
 */
11
12
namespace Ocubom\TwigExtraBundle\DependencyInjection;
13
14
use Iconify\IconsJSON\Finder as IconifyFinder;
1 ignored issue
show
Bug introduced by
The type Iconify\IconsJSON\Finder was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
15
use Ocubom\TwigExtraBundle\Extensions;
16
use Symfony\Component\Config\Definition\Builder\ArrayNodeDefinition;
17
use Symfony\Component\Config\Definition\Builder\BooleanNodeDefinition;
18
use Symfony\Component\Config\Definition\Builder\NodeBuilder;
19
use Symfony\Component\Config\Definition\Builder\TreeBuilder;
20
use Symfony\Component\Config\Definition\ConfigurationInterface;
21
22
class Configuration implements ConfigurationInterface
23
{
24 12
    public function getConfigTreeBuilder(): TreeBuilder
25
    {
26 12
        $builder = new TreeBuilder('ocubom_twig_extra');
27 12
        $root = $builder->getRootNode();
28
29
        // Register available extensions
30 12
        foreach (Extensions::getClasses() as $name => $class) {
31 12
            $call = str_replace(' ', '', ucwords(str_replace(['-', '_'], ' ', $name)));
32 12
            $this->{'add'.$call.'Section'}(
33 12
                $this->createSectionNode($root, $name, class_exists($class))
34 12
            );
35
        }
36
37
        // Headers listener included on this bundle
38 12
        $this->addHttpHeaderSection($root);
39
40 12
        return $builder;
41
    }
42
43 12
    private function createSectionNode(
44
        ArrayNodeDefinition $root,
45
        string $name,
46
        bool $canBeDisabled = true
47
    ): ArrayNodeDefinition {
48 12
        $node = $root->children()->arrayNode($name);
49
        assert($node instanceof ArrayNodeDefinition);
50
51 12
        $node->info(sprintf('Twig %s Extension', ucfirst($name)));
52 12
        $node->{$canBeDisabled ? 'canBeDisabled' : 'canBeEnabled'}();
53
54 12
        $enabled = $node->find('enabled');
55
        assert($enabled instanceof BooleanNodeDefinition);
56 12
        $enabled->info('Enable or disable this extension');
57
58 12
        return $node;
59
    }
60
61 12
    private function addHttpHeaderSection(ArrayNodeDefinition $root): void
62
    {
63 12
        $root
64 12
            ->fixXmlConfig('http_header')
65 12
            ->children()
66 12
                ->arrayNode('http_headers')
67 12
                    ->info(implode("\n", [
68 12
                        'HTTP headers that must be set.',
69 12
                        'The listener will only be registered if at least one rule is enabled.',
70 12
                    ]))
71 12
                    ->prototype('array')
72 12
                        ->treatFalseLike(['enabled' => false])
73 12
                        ->treatTrueLike(['enabled' => true])
74 12
                        ->treatNullLike(['enabled' => true])
75 12
                        ->children()
76 12
                            ->booleanNode('enabled')
77 12
                                ->info('Enable or disable this rule')
78 12
                                ->defaultTrue()
79 12
                            ->end()
80 12
                            ->scalarNode('name')
81 12
                                ->info('The header name to be added.')
82 12
                                ->example('X-UA-Compatible')
83 12
                                ->isRequired()
84 12
                                ->cannotBeEmpty()
85 12
                            ->end()
86 12
                            ->scalarNode('pattern')
87 12
                                ->info('A regular expression to extract the header value.')
88 12
                                ->example('@@[\p{Zs}]*<meta\s+(?:http-equiv="X-UA-Compatible"\s+content="([^"]+)"|content="([^"]+)"\s+http-equiv="X-UA-Compatible")\s*>\p{Zs}*\n?@i')
89 12
                                ->isRequired()
90 12
                                ->cannotBeEmpty()
91 12
                            ->end()
92 12
                            ->scalarNode('value')
93 12
                                ->info('The format of the value (printf processed using the matched value).')
94 12
                                ->example('%2$s')
95 12
                                ->isRequired()
96 12
                                ->cannotBeEmpty()
97 12
                            ->end()
98 12
                            ->scalarNode('replace')
99 12
                                ->info('The text that replaces the match in the original (printf processed using the matched value).')
100 12
                                ->defaultValue('%s')
101 12
                            ->end()
102 12
                            ->arrayNode('formats')
103 12
                                ->info('The response formats when this replacement must be done.')
104 12
                                ->example('["text/html"]')
105 12
                                ->prototype('scalar')->end()
106 12
                            ->end()
107 12
                        ->end()
108 12
                    ->end()
109 12
                ->end()
110 12
            ->end();
111
    }
112
113 12
    private function addHtmlSection(ArrayNodeDefinition $root): void
114
    {
115 12
        $children = $root
116 12
            ->children()
117 12
                ->arrayNode('compression')
118 12
                    ->info('Compress HTML output')
119 12
                    ->addDefaultsIfNotSet()
120 12
                    ->children();
121
122 12
        $children
123 12
            ->booleanNode('force')
124 12
                ->info('Force compression')
125 12
                ->defaultFalse()
126 12
            ->end();
127
128 12
        $children
129 12
            ->enumNode('level')
130 12
                ->info('The level of compression to use')
131 12
                ->defaultValue('smallest')
132 12
                ->values([
133 12
                    'none',
134 12
                    'fastest',
135 12
                    'normal',
136 12
                    'smallest',
137 12
                ])
138 12
            ->end();
139
    }
140
141 12
    private function addSvgSection(ArrayNodeDefinition $root): void
142
    {
143 12
        $providers = [
144 12
            'file_system' => [
145 12
                'name' => 'Local File System',
146 12
                'paths' => [
147 12
                    '%kernel.project_dir%/assets',
148 12
                    '%kernel.project_dir%/node_modules',
149 12
                ],
150 12
            ],
151 12
            'font_awesome' => [
152 12
                'name' => 'FontAwesome',
153 12
                'paths' => [
154 12
                    '%kernel.project_dir%/node_modules/@fortawesome/fontawesome-pro/svgs',
155 12
                    '%kernel.project_dir%/node_modules/@fortawesome/fontawesome-free/svgs',
156 12
                    '%kernel.project_dir%/vendor/fortawesome/font-awesome/svgs/',
157 12
                ],
158 12
            ],
159 12
            'iconify' => [
160 12
                'name' => 'Iconify',
161 12
                'paths' => [
162 12
                    '%kernel.project_dir%/node_modules/node_modules/@iconify-json/',
163 12
                    '%kernel.project_dir%/node_modules/node_modules/@iconify/json/',
164 12
                    '%kernel.project_dir%/vendor/iconify/json/',
165 12
                    class_exists(IconifyFinder::class) ? IconifyFinder::rootDir() : '',
166 12
                ],
167 12
                'runtime' => function (NodeBuilder $parent): void {
168 12
                    $parent
169 12
                        ->arrayNode('svg_framework')
170 12
                            ->info('Enable SVG Framework Server Side Rendering on classes (empty to disable).')
171 12
                            ->defaultValue(['iconify', 'iconify-inline'])
172 12
                            ->prototype('scalar')->end()
173 12
                        ->end();
1 ignored issue
show
Bug introduced by
The method end() does not exist on Symfony\Component\Config...der\NodeParentInterface. It seems like you code against a sub-type of said class. However, the method does not exist in Symfony\Component\Config...ion\Builder\TreeBuilder. Are you sure you never get one of those? ( Ignorable by Annotation )

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

173
                        ->/** @scrutinizer ignore-call */ end();
Loading history...
174
175 12
                    $parent
176 12
                        ->arrayNode('web_component')
177 12
                            ->info('Enable Web Component Server Side Rendering on tags (empty to disable).')
178 12
                            ->defaultValue(['icon', 'iconify-icon'])
179 12
                            ->prototype('scalar')->end()
180 12
                        ->end();
181 12
                },
182 12
                'loader' => function (NodeBuilder $parent): void {
183 12
                    $parent
184 12
                        ->scalarNode('cache_dir')
185 12
                            ->info('Enable cache on this path (empty to disable).')
186 12
                            ->defaultValue('%kernel.cache_dir%/iconify')
187 12
                        ->end();
188 12
                },
189 12
            ],
190 12
        ];
191
192 12
        $root
193 12
            ->beforeNormalization()
194 12
                ->always(static function ($v) {
195
                    // Convert to finders (1.x) configuration
196 12
                    $v['finders'] = $v['finders'] ?? [];
197
                    // Default finder
198 12
                    $v['finders']['default'] = $v['finders']['default'] ?? $v['search_path'] ?? [];
199 12
                    unset($v['search_path']);
200
                    // FontAwesome
201 12
                    $v['finders']['fontawesome'] = $v['finders']['fontawesome'] ?? $v['fontawesome']['search_path'] ?? [];
202 12
                    unset($v['fontawesome']);
203
204
                    // Convert to providers (2.x) configuration
205 12
                    foreach ($v['finders'] as $key => $val) {
206 12
                        if (empty($val)) {
207 10
                            continue;
208
                        }
209
210
                        switch ($key) {
211 2
                            case 'default':
212 2
                                $v['providers']['file_system']['paths'] = $v['providers']['file_system']['paths'] ?? $val;
213 2
                                break;
214
215 2
                            case 'fontawesome':
216 2
                                $v['providers']['font_awesome']['paths'] = $v['providers']['font_awesome']['paths'] ?? $val;
217 2
                                break;
218
219
                            default:
220
                                $v['providers'][$key]['paths'] = $v['providers'][$key]['paths'] ?? $val;
221
                                break;
222
                        }
223
                    }
224 12
                    unset($v['finders']);
225
226 12
                    return $v;
227 12
                })
228 12
            ->end()
229 12
            ->validate()
230 12
                ->always(function ($v) {
231
                    // Clean deprecated configuration
232 12
                    unset($v['search_path']);
233 12
                    unset($v['fontawesome']);
234 12
                    unset($v['finders']);
235
236
                    // Enable/Disable providers
237 12
                    $enabled = 0;
238 12
                    foreach (array_keys($v['providers'] ?? []) as $key) {
239 12
                        $v['providers'][$key]['paths'] = array_filter($v['providers'][$key]['paths'] ?? []);
240 12
                        $v['providers'][$key]['enabled'] = $v['providers'][$key]['enabled'] && count($v['providers'][$key]['paths']) > 0;
241
242 12
                        if ($v['providers'][$key]['enabled']) {
243 12
                            ++$enabled;
244
                        }
245
                    }
246
247
                    // Disable if no provider are enabled
248 12
                    $v['enabled'] = $v['enabled'] && $enabled > 0;
249
250 12
                    return $v;
251 12
                })
252 12
            ->end();
253
254
        // Add providers (2.x) configuration
255 12
        $parent = $root
256 12
            ->fixXmlConfig('provider')
257 12
            ->children()
258 12
                ->arrayNode('providers')
259 12
                    ->info('SVG providers.')
260 12
                    ->addDefaultsIfNotSet();
261
262 12
        foreach ($providers as $key => $val) {
263 12
            $provider = $parent
264 12
                ->children()
265 12
                    ->arrayNode($key);
266
267 12
            $children = $provider
268 12
                    ->info(sprintf('%s provider.', $val['name']))
269 12
                    ->canBeDisabled()
270 12
                    ->children();
271
272 12
            $enabled = $provider->find('enabled');
273
            assert($enabled instanceof BooleanNodeDefinition);
274 12
            $enabled->info('Enable or disable this provider.');
275
276
            // Provider paths
277 12
            $provider->fixXmlConfig('path');
278 12
            $children
279 12
                ->arrayNode('paths')
280 12
                    ->info(sprintf('The paths where the %s files will be searched for.', $val['name']))
281 12
                    // ->example(sprintf('["%s"]', implode('", "', $val['paths'])))
282 12
                    ->defaultValue($val['paths'])
283 12
                    ->prototype('scalar')->end()
284 12
                ->end();
285
286
            // Extra configuration
287 12
            if (is_callable($val['loader'] ?? null)) {
288 12
                $val['loader']($children->arrayNode('loader')
289 12
                    ->info(sprintf('Loader configuration options for %s', $val['name']))
290 12
                    ->addDefaultsIfNotSet()
291 12
                    ->children()
292 12
                );
293
            }
294
295 12
            if (is_callable($val['runtime'] ?? null)) {
296 12
                $val['runtime']($children->arrayNode('runtime')
297 12
                    ->info(sprintf('Runtime configuration options for %s', $val['name']))
298 12
                    ->addDefaultsIfNotSet()
299 12
                    ->children()
300 12
                );
301
            }
302
        }
303
304
        // Add finders (1.x) configuration
305 12
        $root
306 12
            ->fixXmlConfig('finder')
307 12
            ->children()
308 12
                ->arrayNode('finders')
309 12
                    ->setDeprecated(
310 12
                        'ocubom/twig-extra-bundle',
311 12
                        '1.3',
312 12
                        'The "%node%" option is deprecated. Use "providers" instead.'
313 12
                    )
314 12
                    ->info('The paths where SVG files will be searched for.')
315 12
                    ->children()
316 12
                        ->arrayNode('default')
317 12
                            ->info('The default paths where the SVG files will be searched for.')
318 12
                            ->example(sprintf('["%s"]', implode('", "', $providers['file_system']['paths'])))
319 12
                            // ->defaultValue($providers['file_system']['paths'])
320 12
                            ->prototype('scalar')->end()
321 12
                        ->end()
322 12
                        ->arrayNode('fontawesome')
323 12
                            ->info('The paths where the FontAwesome files will be searched for.')
324 12
                            ->example(sprintf('["%s"]', implode('", "', $providers['font_awesome']['paths'])))
325 12
                            // ->defaultValue($providers['font_awesome']['paths'])
326 12
                            ->prototype('scalar')->end()
327 12
                        ->end()
328 12
                    ->end()
329 12
                ->end()
330 12
                ->arrayNode('search_path')
331 12
                    ->setDeprecated(
332 12
                        'ocubom/twig-extra-bundle',
333 12
                        '1.2',
334 12
                        'The "%node%" option is deprecated. Use "providers.filesystem" instead.'
335 12
                    )
336 12
                    ->info('The paths where the SVG files will be searched for.')
337 12
                    ->example(sprintf('["%s"]', implode('", "', $providers['file_system']['paths'])))
338 12
                    // ->defaultValue($providers['file_system']['paths'])
339 12
                    ->prototype('scalar')->end()
340 12
                ->end()
341 12
                ->arrayNode('fontawesome')
342 12
                    ->setDeprecated(
343 12
                        'ocubom/twig-extra-bundle',
344 12
                        '1.2',
345 12
                        'The "%node%" option is deprecated. Use "providers.fontawesome" instead.'
346 12
                    )
347 12
                    ->info('Configuration for FontAwesome.')
348 12
                    ->children()
349 12
                        ->arrayNode('search_path')
350 12
                            ->info('The paths where the FontAwesome files will be searched for.')
351 12
                            ->example(sprintf('["%s"]', implode('", "', $providers['font_awesome']['paths'])))
352 12
                            // ->defaultValue($providers['font_awesome']['paths'])
353 12
                            ->prototype('scalar')->end()
354 12
                        ->end()
355 12
                    ->end()
356 12
                ->end()
357 12
            ->end();
358
    }
359
360 12
    private function addWebpackEncoreSection(ArrayNodeDefinition $root): void
361
    {
362 12
        $defaultPaths = [
363 12
            '%kernel.project_dir%/public/build',
364 12
        ];
365
366 12
        $root
367 12
            ->children()
368 12
                ->arrayNode('output_paths')
369 12
                    ->info('Paths where Symfony Encore will generate its output.')
370 12
                    ->example(sprintf('["%s"]', implode('", "', $defaultPaths)))
371 12
                    // ->defaultValue($defaultPaths)
372 12
                    ->prototype('scalar')->end()
373 12
            ->end();
374
    }
375
}
376