Issues (83)

src/Config/ConfigManager.php (1 issue)

Labels
Severity
1
<?php
2
3
declare(strict_types=1);
4
5
namespace hanneskod\readmetester\Config;
6
7
final class ConfigManager
8
{
9
    /** @var array<string, mixed> */
10
    private array $configs = [];
11
12
    /** @var array<RepositoryInterface> */
13
    private array $repositories = [];
14
15
    /** @var array<Suite> */
16
    private array $suites = [];
17
18
    public function __construct(RepositoryInterface ...$repos)
19
    {
20
        foreach ($repos as $repo) {
21
            $this->loadRepository($repo);
22
        }
23
    }
24
25
    public function loadRepository(RepositoryInterface $repository): void
26
    {
27
        // Reset configs to trigger rebuild
28
        $this->configs = [];
29
30
        $this->repositories[] = $repository;
31
    }
32
33
    /** @return iterable<string> */
34
    public function getLoadedRepositoryNames(): iterable
35
    {
36
        foreach ($this->repositories as $repository) {
37
            if ($repository->getRepositoryName()) {
38
                yield $repository->getRepositoryName();
39
            }
40
        }
41
    }
42
43
    public function getBootstrap(): string
44
    {
45
        $bootstrap = $this->readConfig(Configs::BOOTSTRAP);
46
47
        if ($bootstrap && (!is_file($bootstrap) || !is_readable($bootstrap))) {
48
            throw new \RuntimeException("Unable to load bootstrap: $bootstrap");
49
        }
50
51
        return $bootstrap;
52
    }
53
54
    /** @return iterable<string> */
55
    public function getSubscribers(): iterable
56
    {
57
        yield from $this->readConfigList(Configs::SUBSCRIBERS);
58
        yield Configs::expand(Configs::OUTPUT_ID, $this->readConfig(Configs::OUTPUT));
59
    }
60
61
    public function getSuite(string $name): Suite
62
    {
63
        foreach ($this->getUnfilteredSuites() as $suite) {
64
            if ($suite->getSuiteName() == $name) {
65
                return $suite;
66
            }
67
        }
68
69
        throw new \RuntimeException("Unknown suite $name");
70
    }
71
72
    /** @return iterable<Suite> */
73
    public function getAllSuites(): iterable
74
    {
75
        foreach ($this->getUnfilteredSuites() as $suite) {
76
            if ($suite->isActive()) {
77
                yield $suite;
78
            }
79
        }
80
    }
81
82
    /** @return iterable<Suite> */
83
    private function getUnfilteredSuites(): iterable
84
    {
85
        $this->rebuildConfigsIfOutdated();
86
        yield from $this->suites;
87
    }
88
89
    private function readConfig(string $name): string
90
    {
91
        $this->rebuildConfigsIfOutdated();
92
93
        $value = $this->configs[$name] ?? '';
94
95
        if (!is_scalar($value)) {
96
            throw new \RuntimeException("Configuration for '$name invalid.");
97
        }
98
99
        return (string)$value;
100
    }
101
102
    /** @return array<string> */
103
    private function readConfigList(string $name): array
104
    {
105
        $this->rebuildConfigsIfOutdated();
106
107
        $list = $this->configs[$name] ?? [];
108
109
        if (!is_array($list)) {
110
            throw new \RuntimeException("Configuration list for '$name' invalid.");
111
        }
112
113
        $values = [];
114
115
        foreach ($list as $key => $value) {
116
            if (!is_scalar($value)) {
117
                throw new \RuntimeException(sprintf("Configuration for '%s[%s]' missing.", $name, $key));
118
            }
119
120
            $values[] = (string)$value;
121
        }
122
123
        return $values;
124
    }
125
126
    private function rebuildConfigsIfOutdated(): void
127
    {
128
        // Only rebuild if neccesary
129
        if ($this->configs) {
130
            return;
131
        }
132
133
        // Base configs
134
        $configs = [
135
            Configs::SUITES => [],
136
            Configs::CLI => [],
137
        ];
138
139
        $defaults = [];
140
141
        // Merge with repositories
142
        foreach ($this->repositories as $repository) {
143
            $configs = array_merge($configs, $repository->getConfigs());
144
145
            // Merge defaults separatly to account for multiple default definitions
146
            $defaults = array_merge(
147
                $defaults,
148
                (array)($repository->getConfigs()[Configs::DEFAULTS] ?? [])
149
            );
150
        }
151
152
        // Create default suite if none exists
153
        if (empty($configs[Configs::SUITES])) {
154
            $configs[Configs::SUITES][Configs::DEFAULT_SUITE_NAME] = [];
155
        }
156
157
        // Build suite objects
158
        $this->suites = [];
159
160
        foreach ($configs[Configs::SUITES] as $name => $suite) {
161
            // Merge suite with default configs
162
            $suite = array_merge($defaults, (array)$suite);
163
164
            // Merge suite with cli configs
165
            $suite = array_merge($suite, (array)$configs[Configs::CLI]);
166
167
            // Build suite
168
            $this->suites[] = new Suite(
169
                name: (string)$name,
0 ignored issues
show
A parse error occurred: Syntax error, unexpected ':', expecting ',' or ')' on line 169 at column 20
Loading history...
170
                active: (bool)($suite[Configs::ACTIVE] ?? true),
171
                inputLanguage: (string)($suite[Configs::INPUT_LANGUAGE] ?? ''),
172
                runner: (string)($suite[Configs::RUNNER] ?? ''),
173
                includePaths: (array)($suite[Configs::INCLUDE_PATHS] ?? []),
174
                excludePaths: (array)($suite[Configs::EXCLUDE_PATHS] ?? []),
175
                fileExtensions: (array)($suite[Configs::FILE_EXTENSIONS] ?? []),
176
                stopOnFailure: (bool)($suite[Configs::STOP_ON_FAILURE] ?? false),
177
                globalAttributes: (array)($suite[Configs::GLOBAL_ATTRIBUTES] ?? []),
178
                filter: (string)($suite[Configs::FILTER] ?? ''),
179
                readFromStdin: (bool)($suite[Configs::STDIN] ?? false),
180
            );
181
        }
182
183
        // Store configs
184
        $this->configs = array_merge($configs, $configs[Configs::CLI]);
185
    }
186
}
187