Passed
Push — main ( 1a7f0e...7d39cf )
by Oscar
03:17
created

Icon::configureOptions()   A

Complexity

Conditions 3
Paths 1

Size

Total Lines 58
Code Lines 41

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 44
CRAP Score 3

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 41
c 1
b 0
f 0
dl 0
loc 58
ccs 44
cts 44
cp 1
rs 9.264
cc 3
nc 1
nop 1
crap 3

How to fix   Long Method   

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
3
/*
4
 * This file is part of ocubom/twig-svg-extension
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\Twig\Extension\Svg\Library\FontAwesome;
13
14
use function BenTools\IterableFunctions\iterable_to_array;
15
16
use Ocubom\Twig\Extension\Svg\Exception\ParseException;
17
use Ocubom\Twig\Extension\Svg\Library\FontAwesome;
18
use Ocubom\Twig\Extension\Svg\Processor\ClassProcessor;
19
use Ocubom\Twig\Extension\Svg\Processor\RemoveAttributeProcessor;
20
use Ocubom\Twig\Extension\Svg\Svg;
21
use Ocubom\Twig\Extension\Svg\Util\DomHelper;
22
use Symfony\Component\OptionsResolver\Options;
23
use Symfony\Component\OptionsResolver\OptionsResolver;
24
25
class Icon extends Svg
26
{
27
    /**
28
     * Full path to the icon.
29
     */
30
    protected \SplFileInfo $path;
31
32
    /**
33
     * @param mixed $data The FontAwesome Icon data
34
     */
35 2
    public function __construct($data, iterable $options = null)
36
    {
37
        try {
38
            switch (true) {
39 2
                case $data instanceof Icon: // "Copy" constructor
40
                    $this->path = $data->path;
41
                    break;
42
43 2
                case $data instanceof \SplFileInfo:
44 2
                    $this->path = $data;
45 2
                    break;
46
47
                case is_string($data):
0 ignored issues
show
Unused Code introduced by
is_string($data) is not reachable.

This check looks for unreachable code. It uses sophisticated control flow analysis techniques to find statements which will never be executed.

Unreachable code is most often the result of return, die or exit statements that have been added for debug purposes.

function fx() {
    try {
        doSomething();
        return true;
    }
    catch (\Exception $e) {
        return false;
    }

    return false;
}

In the above example, the last return false will never be executed, because a return statement has already been met in every possible execution path.

Loading history...
48
                    $this->path = new \SplFileInfo($data);
49
                    break;
50
51
                default:
52
                    throw new ParseException(sprintf('Unable to create "%s" from "%s"', __CLASS__, get_debug_type($data)));
53
            }
54
55
            /** @var array $options */
56 2
            $options = iterable_to_array($options ?? []);
57
58
            // Construct from path
59 2
            parent::__construct($this->path, array_merge($options, [
60 2
                'class_default' => array_merge($options['class_default'] ?? [], [
61 2
                    FontAwesome::INLINE_CLASS, // Add inlined class
62 2
                    'fa-'.$this->getName(), // Add icon name class
63 2
                ]),
64 2
                'class_block' => array_merge($options['class_block'] ?? [], [
65 2
                    $this->getStyle(), // Block style
66 2
                    $this->getStyleClass(), // Block current classes
67 2
                    $this->getStyleClass('5.0'), // Block pre-6.0 classes
68 2
                ]),
69 2
            ]));
70
71
            // Add Font Awesome data-*
72 2
            $this->svg->setAttribute('data-prefix', $this->getStyleClass('5.0'));
73 2
            $this->svg->setAttribute('data-icon', $this->getName());
74
        } catch (ParseException $exc) {
75
            throw new ParseException(sprintf('Unable to create a FontAwesome Icon from "%s"', get_debug_type($data)), 0, $exc);
76
        }
77
    }
78
79
    /**
80
     * @codeCoverageIgnore
81
     */
82
    public function getFaId(): string
83
    {
84
        return sprintf(
85
            'fa-%s-%s',
86
            $this->getStyle(),
87
            $this->getName(),
88
        );
89
    }
90
91 2
    public function getName(): string
92
    {
93 2
        return $this->path->getBasename('.svg');
94
    }
95
96 2
    public function getStyle(): string
97
    {
98 2
        $path = $this->path->getPathInfo();
99
        assert($path instanceof \SplFileInfo);
100
101 2
        return $path->getBasename();
102
    }
103
104 2
    public function getStyleClass(string $version = '6.0'): string
105
    {
106 2
        return version_compare($version, '6.0', '<')
107 2
            ? 'fa'.$this->getStyle()[0]
108 2
            : 'fa-'.$this->getStyle();
109
    }
110
111 1
    public function getHtmlTag(iterable $options = null): \DOMElement
112
    {
113
        // Create the HTML Tag node
114 1
        $node = DomHelper::createElement(FontAwesome::HTML_TAG);
115
        // Copy options as attributes
116 1
        foreach ($options ?? [] as $key => $val) {
117 1
            if (!empty($val)) {
118 1
                $val = is_iterable($val) ? implode(' ', iterable_to_array($val)) : (string) $val;
119
120 1
                $node->setAttribute($key, $val);
121
            }
122
        }
123
124
        // Process classes
125 1
        $processor = new ClassProcessor();
126 1
        $processor($node, [
127 1
            'class' => [
128 1
                $this->getStyleClass(),
129 1
                'fa-'.$this->getName(),
130 1
            ],
131 1
            'class_banned' => [
132 1
                FontAwesome::INLINE_CLASS,
133 1
            ],
134 1
        ]);
135
136 1
        return $node;
137
    }
138
139
    /**
140
     * @return array<string, array<int, callable>|callable>
141
     *
142
     * @psalm-suppress InvalidScope
143
     */
144 1
    protected static function getProcessors(): array
145
    {
146 1
        return array_merge(parent::getProcessors(), [
147
            // Options will be ignored & removed
148 1
            'class_default' => new RemoveAttributeProcessor('class_default'),
149 1
            'class_block' => new RemoveAttributeProcessor('class_block'),
150 1
            'fill' => new RemoveAttributeProcessor('fill'),
151 1
            'opacity' => new RemoveAttributeProcessor('opacity'),
152 1
            'primary_fill' => new RemoveAttributeProcessor('primary_fill'),
153 1
            'primary_opacity' => new RemoveAttributeProcessor('primary_opacity'),
154 1
            'secondary_fill' => new RemoveAttributeProcessor('secondary_fill'),
155 1
            'secondary_opacity' => new RemoveAttributeProcessor('secondary_opacity'),
156
157
            // Remove special attributes
158 1
            'data-fa-title-id' => new RemoveAttributeProcessor('data-fa-title-id'),
159 1
        ]);
160
    }
161
162 2
    public static function configureOptions(OptionsResolver $resolver = null): OptionsResolver
163
    {
164 2
        $resolver = parent::configureOptions($resolver);
165
166 2
        $resolver->define('class_default')
167 2
            ->default([])
168 2
            ->allowedTypes('string[]')
169 2
            ->info('Default classes to add unless null');
170
171 2
        $resolver->define('fill')
172 2
            ->default('currentColor')
173 2
            ->allowedTypes('null', 'string')
174 2
            ->info('Default fill color for paths');
175
176 2
        $resolver->define('opacity')
177 2
            ->default(null)
178 2
            ->allowedTypes('null', 'float')
179 2
            ->info('Default opacity color for paths');
180
181 2
        $resolver->define('primary_fill')
182 2
            ->default(null)
183 2
            ->allowedTypes('null', 'string')
184 2
            ->info('Default fill color for primary paths (duotone)');
185
186 2
        $resolver->define('primary_opacity')
187 2
            ->default(null)
188 2
            ->allowedTypes('null', 'float')
189 2
            ->info('Default opacity color for primary paths (duotone)');
190
191 2
        $resolver->define('secondary_fill')
192 2
            ->default(null)
193 2
            ->allowedTypes('null', 'string')
194 2
            ->info('Default fill color for secondary paths (duotone)');
195
196 2
        $resolver->define('secondary_opacity')
197 2
            ->default(null)
198 2
            ->allowedTypes('null', 'float')
199 2
            ->info('Default opacity color for secondary paths (duotone)');
200
201 2
        $resolver->define('data-fa-title-id')
202 2
            ->default(null)
203 2
            ->allowedTypes('null', 'string')
204 2
            ->info('Set the icon title id instead of generate a new one');
205
206
        // Uses data-fa-title-id as aria-labelledby if not defined
207 2
        $resolver->addNormalizer(
208 2
            'aria-labelledby',
209 2
            function (Options $options, ?string $value): ?string {
210 2
                if (empty($value) && !empty($options['data-fa-title-id'])) {
211 1
                    return $options['data-fa-title-id'];
212
                }
213
214 2
                return $value;
215 2
            },
216 2
            true
217 2
        );
218
219 2
        return $resolver;
220
    }
221
}
222