Passed
Push — latest ( 570e9a...8e76fa )
by Mark
03:33
created

Configuration::defineExclude()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 14
Code Lines 7

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 6
CRAP Score 1

Importance

Changes 0
Metric Value
eloc 7
c 0
b 0
f 0
dl 0
loc 14
ccs 6
cts 6
cp 1
rs 10
cc 1
nc 1
nop 1
crap 1
1
<?php
2
3
declare(strict_types=1);
4
5
namespace UnicornFail\Emoji;
6
7
use Dflydev\DotAccessData\Data;
8
use Symfony\Component\OptionsResolver\Exception\InvalidOptionsException;
9
use Symfony\Component\OptionsResolver\Options;
10
use Symfony\Component\OptionsResolver\OptionsResolver;
11
use UnicornFail\Emoji\Emojibase\DatasetInterface;
12
use UnicornFail\Emoji\Emojibase\ShortcodeInterface;
13
use UnicornFail\Emoji\Exception\InvalidConfigurationException;
14
use UnicornFail\Emoji\Util\Normalize;
15
16
class Configuration extends Data implements ConfigurationInterface
17
{
18
    /**
19
     * @param mixed[]|\Traversable $configuration
20
     */
21 699
    public function __construct(?iterable $configuration = null)
22
    {
23 699
        parent::__construct([]);
24
25
        /** @var string[] $data */
26 699
        $data = $configuration !== null ? (new \ArrayObject($configuration))->getArrayCopy() : [];
0 ignored issues
show
Bug introduced by
$configuration of type iterable is incompatible with the type array|object expected by parameter $input of ArrayObject::__construct(). ( Ignorable by Annotation )

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

26
        $data = $configuration !== null ? (new \ArrayObject(/** @scrutinizer ignore-type */ $configuration))->getArrayCopy() : [];
Loading history...
27 699
        foreach ($data as $key => $value) {
28 678
            $this->set((string) $key, $value);
29
        }
30
31
        try {
32 699
            $resolver = new OptionsResolver();
33 699
            $this->configureOptions($resolver);
34 699
            $this->data = $resolver->resolve($this->data);
35 18
        } catch (\Throwable $throwable) {
36 18
            throw new InvalidConfigurationException($throwable->getMessage(), (int) $throwable->getCode(), $throwable->getPrevious());
37
        }
38 681
    }
39
40
    /**
41
     * @param mixed[]|\Traversable $configuration
42
     */
43 699
    public static function create(?iterable $configuration = null): ConfigurationInterface
44
    {
45 699
        if ($configuration instanceof ConfigurationInterface) {
46 3
            return $configuration;
47
        }
48
49 696
        return new self($configuration);
50
    }
51
52 699
    public function configureOptions(OptionsResolver $resolver): void
53
    {
54 699
        $this->defineConvertEmoticons($resolver);
55 699
        $this->defineExclude($resolver);
56 699
        $this->defineLocale($resolver);
57 699
        $this->defineNative($resolver);
58 699
        $this->definePresentation($resolver);
59 699
        $this->definePreset($resolver);
60 699
        $this->defineStringableType($resolver);
61 699
    }
62
63 699
    protected function defineConvertEmoticons(OptionsResolver $resolver): void
64
    {
65 699
        $resolver->define('convertEmoticons')
66 699
            ->allowedTypes('bool')
67 699
            ->default(true);
68 699
    }
69
70 699
    protected function defineExclude(OptionsResolver $resolver): void
71
    {
72
        $resolver->setDefault('exclude', static function (OptionsResolver $resolver): void {
73 699
            $resolver->define('shortcodes')
74 699
                ->allowedTypes('string', 'string[]')
75 699
                ->default([])
76 699
                ->normalize(
77
                /**
78
                 * @param string|string[] $value
79
                 *
80
                 * @return string[]
81
                 */
82
                    static function (Options $options, $value): array {
83 699
                        return Normalize::shortcodes($value);
84 699
                    }
85
                );
86 699
        });
87 699
    }
88
89 699
    protected function defineLocale(OptionsResolver $resolver): void
90
    {
91 699
        $resolver->define('locale')
92 699
            ->allowedTypes('string')
93
            ->allowedValues(static function (string $value): bool {
94 699
                return ! ! Normalize::locale($value);
95 699
            })
96 699
            ->default('en')
97
            ->normalize(static function (Options $options, string $value): string {
98 690
                return Normalize::locale($value);
99 699
            });
100 699
    }
101
102 699
    protected function defineNative(OptionsResolver $resolver): void
103
    {
104 699
        $resolver->define('native')
105 699
            ->allowedTypes('bool')
106
            ->default(static function (Options $options): bool {
107 147
                return \in_array($options['locale'], DatasetInterface::NON_LATIN_LOCALES, true);
108 699
            })
109
            ->normalize(static function (Options $options, bool $value) {
110 690
                return $value && \in_array($options['locale'], DatasetInterface::NON_LATIN_LOCALES, true);
111 699
            });
112 699
    }
113
114 699
    protected function definePresentation(OptionsResolver $resolver): void
115
    {
116 699
        $resolver->define('presentation')
117 699
            ->allowedTypes('int', 'null')
118 699
            ->allowedValues(...DatasetInterface::SUPPORTED_PRESENTATIONS)
119 699
            ->default(DatasetInterface::EMOJI);
120 699
    }
121
122 699
    protected function definePreset(OptionsResolver $resolver): void
123
    {
124 699
        $resolver->define('preset')
125 699
            ->allowedTypes('string', 'string[]')
126 699
            ->allowedValues(\Closure::fromCallable([$this, 'definePresetAllowedValues']))
127 699
            ->default(ShortcodeInterface::DEFAULT_PRESETS)
128 699
            ->normalize(\Closure::fromCallable([$this, 'definePresetNormalize']));
129 699
    }
130
131
    /**
132
     * @param mixed $values
133
     */
134 690
    protected function definePresetAllowedValues($values): bool
135
    {
136 690
        foreach ((array) $values as $value) {
137
            \assert(\is_string($value));
138 690
            if (! \in_array($value, ShortcodeInterface::SUPPORTED_PRESETS, true)) {
139 9
                throw new InvalidOptionsException(\sprintf(
140
                    'The option "preset" with value "%s" is invalid. Accepted values are: %s.',
141 9
                    $value,
142
                    \implode(', ', \array_map(static function ($s) {
143 9
                        return \sprintf('"%s"', $s);
144 9
                    }, ShortcodeInterface::SUPPORTED_PRESETS))
145
                ));
146
            }
147
        }
148
149 681
        return true;
150
    }
151
152
    /**
153
     * @param mixed $value
154
     *
155
     * @return string[]
156
     */
157 681
    protected function definePresetNormalize(Options $options, $value): array
158
    {
159
        // Presets.
160 681
        $presets = [];
161 681
        foreach ((array) $value as $preset) {
162
            \assert(\is_string($preset));
163 681
            if (isset(ShortcodeInterface::PRESET_ALIASES[$preset])) {
164 18
                $presets[] = ShortcodeInterface::PRESET_ALIASES[$preset];
165 663
            } elseif (isset(ShortcodeInterface::PRESETS[$preset])) {
166 663
                $presets[] = ShortcodeInterface::PRESETS[$preset];
167
            }
168
        }
169
170
        // Prepend the native preset if local is requires it and enabled.
171 681
        if ($options['native']) {
172 3
            \array_unshift($presets, ShortcodeInterface::PRESET_CLDR_NATIVE);
173
        }
174
175 681
        return \array_values(\array_unique($presets));
176
    }
177
178 699
    protected function defineStringableType(OptionsResolver $resolver): void
179
    {
180 699
        $resolver->define('stringableType')
181 699
            ->allowedTypes('int')
182 699
            ->allowedValues(Lexer::T_EMOTICON, Lexer::T_HTML_ENTITY, Lexer::T_SHORTCODE, Lexer::T_UNICODE)
183 699
            ->default(Lexer::T_UNICODE);
184 699
    }
185
186 72
    public function getIterator(): \ArrayObject
187
    {
188 72
        return new \ArrayObject($this->export());
189
    }
190
}
191