CheckSuite   A
last analyzed

Complexity

Total Complexity 30

Size/Duplication

Total Lines 319
Duplicated Lines 0 %

Importance

Changes 5
Bugs 1 Features 1
Metric Value
eloc 69
c 5
b 1
f 1
dl 0
loc 319
rs 10
wmc 30

21 Methods

Rating   Name   Duplication   Size   Complexity  
A getCheckDetail() 0 9 2
A addCheckDetail() 0 4 1
A setRepositorySlug() 0 4 1
A run() 0 17 4
A getScore() 0 3 1
A buildChecks() 0 18 4
A setCheckDetails() 0 4 1
A getCheckDetails() 0 3 1
A getCheckClasses() 0 7 2
A getLogger() 0 3 1
A addPoints() 0 4 1
A processCheck() 0 11 1
A setChecks() 0 4 1
A getPoints() 0 3 1
A addCheck() 0 4 1
A getModuleRoot() 0 3 1
A setPoints() 0 4 1
A getRepositorySlug() 0 3 1
A getChecks() 0 6 2
A setModuleRoot() 0 4 1
A setLogger() 0 4 1
1
<?php
2
3
namespace SilverStripe\ModuleRatings;
4
5
use Exception;
6
use InvalidArgumentException;
7
use Psr\Log\LoggerInterface;
8
use Symfony\Component\Yaml\Yaml;
9
10
class CheckSuite
11
{
12
    /**
13
     * @var Check[]|null
14
     */
15
    protected $checks = null;
16
17
    /**
18
     * @var array
19
     */
20
    protected $checkDetails = [];
21
22
    /**
23
     * @var int
24
     */
25
    protected $points = 0;
26
27
    /**
28
     * The physical filepath to the module's code
29
     *
30
     * @var string
31
     */
32
    protected $moduleRoot;
33
34
    /**
35
     * @var string
36
     */
37
    protected $repositorySlug = '';
38
39
    /**
40
     * @var LoggerInterface
41
     */
42
    protected $logger;
43
44
    /**
45
     * Runs the check suite and processes the result of each
46
     *
47
     * @param callable $checkCallback If provided, will be called before each individual check is run, and will be
48
     *                                passed the Check instance as the first argument, and a delegatable callback
49
     *                                as the second argument for the consumer to control where the progressCheck()
50
     *                                method is called in their logic
51
     * @throws Exception              If no checks are defined
52
     */
53
    public function run(callable $checkCallback = null)
54
    {
55
        // Reset internal data collation; important if the suite is being used more than once
56
        $this->setPoints(0);
57
        $this->setCheckDetails([]);
58
59
        if (!$this->getChecks()) {
60
            throw new Exception('No checks have been defined! Please set some in config.yml.');
61
        }
62
        foreach ($this->getChecks() as $check) {
63
            /** @var Check $check */
64
            if (is_callable($checkCallback)) {
65
                $checkCallback($check, function () use ($check) {
66
                    $this->processCheck($check);
67
                });
68
            } else {
69
                $this->processCheck($check);
70
            }
71
        }
72
    }
73
74
    /**
75
     * Run the check and handle its results
76
     *
77
     * @param Check $check
78
     */
79
    protected function processCheck(Check $check)
80
    {
81
        $check->run();
82
83
        $this->addPoints($check->getResult());
84
        $this->addCheckDetail(
85
            $check->getKey(),
86
            [
87
                'description' => $check->getDescription(),
88
                'points' => $check->getResult(),
89
                'maximum' => $check->getPoints(),
90
            ]
91
        );
92
    }
93
94
    /**
95
     * Use the calculator class to get a relative score for the total number of points possible out of 100
96
     *
97
     * @return int
98
     */
99
    public function getScore()
100
    {
101
        return Calculator::getInstance()->calculate($this->getPoints());
102
    }
103
104
    /**
105
     * Get the number of points for this module's rating
106
     *
107
     * @return int
108
     */
109
    public function getPoints()
110
    {
111
        return (int) $this->points;
112
    }
113
114
    /**
115
     * Set the number of points for this module's rating
116
     *
117
     * @param int $points
118
     * @return $this
119
     */
120
    public function setPoints($points)
121
    {
122
        $this->points = (int) $points;
123
        return $this;
124
    }
125
126
    /**
127
     * Add the number of points to this module's rating
128
     *
129
     * @param int $points
130
     * @return $this
131
     */
132
    public function addPoints($points)
133
    {
134
        $this->setPoints($this->getPoints() + (int) $points);
135
        return $this;
136
    }
137
138
    /**
139
     * Set the detailed result for the checks in this suite
140
     *
141
     * @param array $checkResults
142
     * @return $this
143
     */
144
    public function setCheckDetails(array $checkDetails)
145
    {
146
        $this->checkDetails = $checkDetails;
147
        return $this;
148
    }
149
150
    /**
151
     * Add some metrics (description, points, etc) result for a check in this suite
152
     *
153
     * @param string $key
154
     * @param array $metrics
155
     * @return $this
156
     */
157
    public function addCheckDetail($key, array $metrics)
158
    {
159
        $this->checkDetails[$key] = $metrics;
160
        return $this;
161
    }
162
163
    /**
164
     * Get the detailed results for the checks in this suite
165
     * @return array
166
     */
167
    public function getCheckDetails()
168
    {
169
        return $this->checkDetails;
170
    }
171
172
    /**
173
     * Get the detailed result for one of the checks in this suite
174
     *
175
     * @param string $key
176
     * @return array
177
     * @throws Exception If the check was not in the details
178
     */
179
    public function getCheckDetail($key)
180
    {
181
        $checks = $this->getCheckDetails();
182
183
        if (isset($checks[$key])) {
184
            return $checks[$key];
185
        }
186
187
        throw new Exception('Check with code ' . $key . ' was not found');
188
    }
189
190
    /**
191
     * Get the registered check class instances
192
     *
193
     * @return Check[]
194
     */
195
    public function getChecks()
196
    {
197
        if ($this->checks === null) {
198
            $this->buildChecks();
199
        }
200
        return $this->checks;
201
    }
202
203
    /**
204
     * Set the registered check class instances
205
     *
206
     * @param Check[] $checks
207
     * @return $this
208
     */
209
    public function setChecks(array $checks = [])
210
    {
211
        $this->checks = $checks;
212
        return $this;
213
    }
214
215
    /**
216
     * Get the registered check class names and try to instantiate and add them
217
     *
218
     * @throws InvalidArgumentException If a registered check class does not exist
219
     */
220
    protected function buildChecks()
221
    {
222
        $checkClasses = $this->getCheckClasses();
223
        foreach ($checkClasses as $checkClass => $config) {
224
            if (!class_exists($checkClass)) {
225
                throw new InvalidArgumentException('Registered check class ' . $checkClass . ' not found!');
226
            }
227
228
            if (!isset($config['points'])) {
229
                $config['points'] = 0;
230
            }
231
232
            /** @var Check $check */
233
            $check = new $checkClass();
234
            $check->setSuite($this);
235
            $check->setPoints($config['points']);
236
237
            $this->addCheck($check);
238
        }
239
    }
240
241
    /**
242
     * Load the config.yml file and get the check class names from it
243
     *
244
     * @return array[]
245
     */
246
    protected function getCheckClasses()
247
    {
248
        $config = Yaml::parse(file_get_contents(dirname(__FILE__) . '/../config.yml'));
249
        if (empty($config[self::class]['checks'])) {
250
            return [];
251
        }
252
        return (array) $config[self::class]['checks'];
253
    }
254
255
    /**
256
     * Add a new check to the stack
257
     *
258
     * @param Check $check
259
     * @return $this
260
     */
261
    public function addCheck(Check $check)
262
    {
263
        $this->checks[] = $check;
264
        return $this;
265
    }
266
267
    /**
268
     * Set the path to the module's root folder that we're going to examine
269
     *
270
     * @param string $moduleRoot
271
     * @return $this
272
     */
273
    public function setModuleRoot($moduleRoot)
274
    {
275
        $this->moduleRoot = (string) rtrim($moduleRoot, '/');
276
        return $this;
277
    }
278
279
    /**
280
     * Get the path to the module's root folder
281
     *
282
     * @return string
283
     */
284
    public function getModuleRoot()
285
    {
286
        return $this->moduleRoot;
287
    }
288
289
    /**
290
     * Set the repository slug from/for the URL
291
     *
292
     * @param string $repositorySlug
293
     * @return $this
294
     */
295
    public function setRepositorySlug($repositorySlug)
296
    {
297
        $this->repositorySlug = (string) $repositorySlug;
298
        return $this;
299
    }
300
301
    /**
302
     * Get the repository slug for the URL
303
     *
304
     * @return string
305
     */
306
    public function getRepositorySlug()
307
    {
308
        return $this->repositorySlug;
309
    }
310
311
    /**
312
     * Set a PSR-3 compatible logger
313
     *
314
     * @param LoggerInterface $logger
315
     * @return $this
316
     */
317
    public function setLogger(LoggerInterface $logger)
318
    {
319
        $this->logger = $logger;
320
        return $this;
321
    }
322
323
    /**
324
     * Get a PSR-3 compatible logger, if one is provided
325
     */
326
    public function getLogger()
327
    {
328
        return $this->logger;
329
    }
330
}
331