ValidatePublicationTypesCommand::outputJson()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 1
nc 1
nop 0
dl 0
loc 3
rs 10
c 0
b 0
f 0
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Hyde\Publications\Commands;
6
7
use Hyde\Hyde;
8
use Hyde\Publications\Actions\PublicationSchemaValidator;
9
use Hyde\Publications\Publications;
10
use InvalidArgumentException;
11
use LaravelZero\Framework\Commands\Command;
12
13
use function array_filter;
14
use function basename;
15
use function count;
16
use function dirname;
17
use function glob;
18
use function json_encode;
19
use function memory_get_peak_usage;
20
use function microtime;
21
use function next;
22
use function round;
23
use 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
 */
32
class 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);
0 ignored issues
show
Bug introduced by
It seems like $timeStart can also be of type string; however, parameter $timeStart of Hyde\Publications\Comman...ommand::outputSummary() does only seem to accept double, maybe add an additional type check? ( Ignorable by Annotation )

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

58
            $this->outputSummary(/** @scrutinizer ignore-type */ $timeStart);
Loading history...
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');
0 ignored issues
show
Bug introduced by
The method path() does not exist on Hyde\Hyde. Since you implemented __callStatic, consider adding a @method annotation. ( Ignorable by Annotation )

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

71
        $schemaFiles = glob(Hyde::/** @scrutinizer ignore-call */ path(Hyde::getSourceRoot()).'/*/schema.json');
Loading history...
Bug introduced by
The method getSourceRoot() does not exist on Hyde\Hyde. Since you implemented __callStatic, consider adding a @method annotation. ( Ignorable by Annotation )

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

71
        $schemaFiles = glob(Hyde::path(Hyde::/** @scrutinizer ignore-call */ getSourceRoot()).'/*/schema.json');
Loading history...
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();
0 ignored issues
show
Unused Code introduced by
The call to Hyde\Publications\Action...SchemaValidator::call() has too many arguments starting with false. ( Ignorable by Annotation )

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

79
            $this->results[$publicationName] = PublicationSchemaValidator::/** @scrutinizer ignore-call */ call($publicationName, false)->errors();

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress. Please note the @ignore annotation hint above.

Loading history...
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
}
154