Passed
Push — master ( e0a8ac...1d0e74 )
by Théo
02:19
created

retrieveExposedElements()   A

Complexity

Conditions 5
Paths 5

Size

Total Lines 34
Code Lines 18

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 5
eloc 18
nc 5
nop 1
dl 0
loc 34
rs 9.3554
c 0
b 0
f 0
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Humbug\PhpScoper\Configuration;
6
7
use Humbug\PhpScoper\RegexChecker;
8
use Humbug\PhpScoper\Whitelist;
9
use InvalidArgumentException;
10
use function array_key_exists;
11
use function array_keys;
12
use function array_values;
13
use function gettype;
14
use function is_array;
15
use function is_bool;
16
use function is_string;
17
use function Safe\sprintf;
18
19
final class ConfigurationWhitelistFactory
20
{
21
    private RegexChecker $regexChecker;
22
23
    public function __construct(RegexChecker $regexChecker)
24
    {
25
        $this->regexChecker = $regexChecker;
26
    }
27
28
    public function createWhitelist(array $config): Whitelist
29
    {
30
        [
31
            $excludedNamespaceRegexes,
32
            $excludedNamespaceNames,
33
        ] = $this->retrieveExcludedNamespaces($config);
34
35
        $exposedElements = self::retrieveExposedElements($config);
36
37
        $exposeGlobalConstants = self::retrieveExposeGlobalSymbol(
38
            $config,
39
            ConfigurationKeys::EXPOSE_GLOBAL_CONSTANTS_KEYWORD,
40
        );
41
        $exposeGlobalClasses = self::retrieveExposeGlobalSymbol(
42
            $config,
43
            ConfigurationKeys::EXPOSE_GLOBAL_CLASSES_KEYWORD,
44
        );
45
        $exposeGlobalFunctions = self::retrieveExposeGlobalSymbol(
46
            $config,
47
            ConfigurationKeys::EXPOSE_GLOBAL_FUNCTIONS_KEYWORD,
48
        );
49
50
        return Whitelist::create(
51
            $exposeGlobalConstants,
52
            $exposeGlobalClasses,
53
            $exposeGlobalFunctions,
54
            $excludedNamespaceRegexes,
55
            $excludedNamespaceNames,
56
            ...$exposedElements,
57
        );
58
    }
59
60
    /**
61
     * @return array{string[], string[]}
0 ignored issues
show
Documentation Bug introduced by
The doc comment array{string[], string[]} at position 2 could not be parsed: Expected ':' at position 2, but found 'string'.
Loading history...
62
     */
63
    private function retrieveExcludedNamespaces(array $config): array
64
    {
65
        $key = ConfigurationKeys::EXCLUDE_NAMESPACES_KEYWORD;
66
67
        if (!array_key_exists($key, $config)) {
68
            return [[], []];
69
        }
70
71
        $regexesAndNamespaceNames = $config[$key];
72
73
        if (!is_array($regexesAndNamespaceNames)) {
74
            throw new InvalidArgumentException(
75
                sprintf(
76
                    'Expected "%s" to be an array of strings, got "%s" instead.',
77
                    $key,
78
                    gettype($regexesAndNamespaceNames),
79
                ),
80
            );
81
        }
82
83
        // Store the strings in the keys for avoiding a unique check later on
84
        $regexes = [];
85
        $namespaceNames = [];
86
87
        foreach ($regexesAndNamespaceNames as $index => $regexOrNamespaceName) {
88
            if (!is_string($regexOrNamespaceName)) {
89
                throw new InvalidArgumentException(
90
                    sprintf(
91
                        'Expected "%s" to be an array of strings, got "%s" for the element with the index "%s".',
92
                        $key,
93
                        gettype($regexOrNamespaceName),
94
                        $index,
95
                    ),
96
                );
97
            }
98
99
            if (!$this->regexChecker->isRegexLike($regexOrNamespaceName)) {
100
                $namespaceNames[$regexOrNamespaceName] = null;
101
102
                continue;
103
            }
104
105
            $excludeNamespaceRegex = $regexOrNamespaceName;
106
107
            $errorMessage = $this->regexChecker->validateRegex($excludeNamespaceRegex);
108
109
            if (null !== $errorMessage) {
110
                throw new InvalidArgumentException(
111
                    sprintf(
112
                        'Expected "%s" to be an array of valid regexes. The element "%s" with the index "%s" is not: %s.',
113
                        $key,
114
                        $excludeNamespaceRegex,
115
                        $index,
116
                        $errorMessage,
117
                    ),
118
                );
119
            }
120
121
            // Ensure namespace comparisons are always case-insensitive
122
            $excludeNamespaceRegex .= 'i';
123
            $regexes[$excludeNamespaceRegex] = null;
124
        }
125
126
        return [
127
            array_keys($regexes),
128
            array_keys($namespaceNames),
129
        ];
130
    }
131
132
    /**
133
     * return list<string>
134
     */
135
    private static function retrieveExposedElements(array $config): array
136
    {
137
        $key = ConfigurationKeys::WHITELIST_KEYWORD;
138
139
        if (!array_key_exists($key, $config)) {
140
            return [];
141
        }
142
143
        $whitelist = $config[$key];
144
145
        if (!is_array($whitelist)) {
146
            throw new InvalidArgumentException(
147
                sprintf(
148
                    'Expected "%s" to be an array of strings, found "%s" instead.',
149
                    $key,
150
                    gettype($whitelist),
151
                ),
152
            );
153
        }
154
155
        foreach ($whitelist as $index => $className) {
156
            if (is_string($className)) {
157
                continue;
158
            }
159
160
            throw new InvalidArgumentException(
161
                sprintf(
162
                    'Expected whitelist to be an array of string, the "%d" element is not.',
163
                    $index,
164
                ),
165
            );
166
        }
167
168
        return array_values($whitelist);
169
    }
170
171
    private static function retrieveExposeGlobalSymbol(array $config, string $key): bool
172
    {
173
        if (!array_key_exists($key, $config)) {
174
            return false;
175
        }
176
177
        $value = $config[$key];
178
179
        if (!is_bool($value)) {
180
            throw new InvalidArgumentException(
181
                sprintf(
182
                    'Expected %s to be a boolean, found "%s" instead.',
183
                    $key,
184
                    gettype($value),
185
                ),
186
            );
187
        }
188
189
        return $value;
190
    }
191
}
192