Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
100.00% covered (success)
100.00%
49 / 49
100.00% covered (success)
100.00%
8 / 8
CRAP
100.00% covered (success)
100.00%
1 / 1
ValidatePublicationTypesCommand
100.00% covered (success)
100.00%
49 / 49
100.00% covered (success)
100.00%
8 / 8
21
100.00% covered (success)
100.00%
1 / 1
 safeHandle
100.00% covered (success)
100.00%
11 / 11
100.00% covered (success)
100.00%
1 / 1
4
 validateSchemaFiles
100.00% covered (success)
100.00%
6 / 6
100.00% covered (success)
100.00%
1 / 1
3
 displayResults
100.00% covered (success)
100.00%
13 / 13
100.00% covered (success)
100.00%
1 / 1
5
 displayTopLevelSchemaErrors
100.00% covered (success)
100.00%
3 / 3
100.00% covered (success)
100.00%
1 / 1
2
 displayFieldDefinitionErrors
100.00% covered (success)
100.00%
5 / 5
100.00% covered (success)
100.00%
1 / 1
3
 outputSummary
100.00% covered (success)
100.00%
5 / 5
100.00% covered (success)
100.00%
1 / 1
1
 outputJson
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 countErrors
100.00% covered (success)
100.00%
5 / 5
100.00% covered (success)
100.00%
1 / 1
2
1<?php
2
3declare(strict_types=1);
4
5namespace Hyde\Publications\Commands;
6
7use Hyde\Hyde;
8use Hyde\Publications\Actions\PublicationSchemaValidator;
9use Hyde\Publications\Publications;
10use InvalidArgumentException;
11use LaravelZero\Framework\Commands\Command;
12
13use function array_filter;
14use function basename;
15use function count;
16use function dirname;
17use function glob;
18use function json_encode;
19use function memory_get_peak_usage;
20use function microtime;
21use function next;
22use function round;
23use function sprintf;
24
25/**
26 * Hyde command to validate all publication schema file..
27 *
28 * @see \Hyde\Publications\Testing\Feature\ValidatePublicationTypesCommandTest
29 *
30 * @internal This command is not part of the public API and may change without notice.
31 */
32class ValidatePublicationTypesCommand extends ValidatingCommand
33{
34    protected const CROSS_MARK = 'x';
35
36    /** @var string */
37    protected $signature = 'validate:publicationTypes {--json : Display results as JSON.}';
38
39    /** @var string */
40    protected $description = 'Validate all publication schema files.';
41
42    protected array $results = [];
43
44    public function safeHandle(): int
45    {
46        $timeStart = microtime(true);
47
48        if (! $this->option('json')) {
49            $this->title('Validating publication schemas!');
50        }
51
52        $this->validateSchemaFiles();
53
54        if ($this->option('json')) {
55            $this->outputJson();
56        } else {
57            $this->displayResults();
58            $this->outputSummary($timeStart);
59        }
60
61        if ($this->countErrors() > 0) {
62            return Command::FAILURE;
63        }
64
65        return Command::SUCCESS;
66    }
67
68    protected function validateSchemaFiles(): void
69    {
70        /** Uses the same glob pattern as {@see Publications::getSchemaFiles()} */
71        $schemaFiles = glob(Hyde::path(Hyde::getSourceRoot()).'/*/schema.json');
72
73        if (empty($schemaFiles)) {
74            throw new InvalidArgumentException('No publication types to validate!');
75        }
76
77        foreach ($schemaFiles as $schemaFile) {
78            $publicationName = basename(dirname($schemaFile));
79            $this->results[$publicationName] = PublicationSchemaValidator::call($publicationName, false)->errors();
80        }
81    }
82
83    protected function displayResults(): void
84    {
85        foreach ($this->results as $name => $errors) {
86            $this->infoComment("Validating schema file for [$name]");
87
88            $schemaErrors = $errors['schema'];
89            if (empty($schemaErrors)) {
90                $this->line('<info>  No top-level schema errors found</info>');
91            } else {
92                $this->displayTopLevelSchemaErrors($schemaErrors);
93            }
94
95            $schemaFields = $errors['fields'];
96            if (empty(array_filter($schemaFields))) {
97                $this->line('<info>  No field-level schema errors found</info>');
98            } else {
99                $this->newLine();
100                $this->displayFieldDefinitionErrors($schemaFields);
101            }
102
103            if (next($this->results)) {
104                $this->newLine();
105            }
106        }
107    }
108
109    protected function displayTopLevelSchemaErrors(array $schemaErrors): void
110    {
111        $this->line(sprintf('  <fg=red>Found %s top-level schema errors:</>', count($schemaErrors)));
112        foreach ($schemaErrors as $error) {
113            $this->line(sprintf('    <fg=red>%s</> <comment>%s</comment>', self::CROSS_MARK, $error));
114        }
115    }
116
117    protected function displayFieldDefinitionErrors(array $schemaFields): void
118    {
119        $this->line(sprintf('  <fg=red>Found errors in %s field definitions:</>', count($schemaFields)));
120        foreach ($schemaFields as $fieldNumber => $fieldErrors) {
121            $this->line(sprintf('    <fg=cyan>Field #%s:</>', $fieldNumber + 1));
122            foreach ($fieldErrors as $error) {
123                $this->line(sprintf('      <fg=red>%s</> <comment>%s</comment>', self::CROSS_MARK, $error));
124            }
125        }
126    }
127
128    protected function outputSummary(float $timeStart): void
129    {
130        $this->newLine();
131        $this->info(sprintf('All done in %sms using %sMB peak memory!',
132            round((microtime(true) - $timeStart) * 1000),
133            round(memory_get_peak_usage() / 1024 / 1024)
134        ));
135    }
136
137    protected function outputJson(): void
138    {
139        $this->output->writeln(json_encode($this->results, JSON_PRETTY_PRINT));
140    }
141
142    protected function countErrors(): int
143    {
144        $errors = 0;
145
146        foreach ($this->results as $results) {
147            $errors += count($results['schema']);
148            $errors += count(array_filter($results['fields']));
149        }
150
151        return $errors;
152    }
153}