Passed
Push — master ( 2a3d19...5e9e4e )
by Caen
05:36 queued 13s
created

ValidatePublicationTypesCommand::displayResults()   B

Complexity

Conditions 8
Paths 9

Size

Total Lines 31
Code Lines 21

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 8
eloc 21
nc 9
nop 0
dl 0
loc 31
rs 8.4444
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);
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();
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->line(sprintf('  <fg=red>Found %s top-level schema errors:</>', count($schemaErrors)));
93
                foreach ($schemaErrors as $error) {
94
                    $this->line(sprintf('    <fg=red>%s</> <comment>%s</comment>', self::CROSS_MARK, $error));
95
                }
96
            }
97
98
            $schemaFields = $errors['fields'];
99
            if (empty(array_filter($schemaFields))) {
100
                $this->line('<info>  No field-level schema errors found</info>');
101
            } else {
102
                $this->newLine();
103
                $this->line(sprintf('  <fg=red>Found errors in %s field definitions:</>', count($schemaFields)));
104
                foreach ($schemaFields as $fieldNumber => $fieldErrors) {
105
                    $this->line(sprintf('    <fg=cyan>Field #%s:</>', $fieldNumber + 1));
106
                    foreach ($fieldErrors as $error) {
107
                        $this->line(sprintf('      <fg=red>%s</> <comment>%s</comment>', self::CROSS_MARK, $error));
108
                    }
109
                }
110
            }
111
112
            if (next($this->results)) {
113
                $this->newLine();
114
            }
115
        }
116
    }
117
118
    protected function outputSummary($timeStart): void
119
    {
120
        $this->newLine();
121
        $this->info(sprintf('All done in %sms using %sMB peak memory!',
122
            round((microtime(true) - $timeStart) * 1000),
123
            round(memory_get_peak_usage() / 1024 / 1024)
124
        ));
125
    }
126
127
    protected function outputJson(): void
128
    {
129
        $this->output->writeln(json_encode($this->results, JSON_PRETTY_PRINT));
130
    }
131
132
    protected function countErrors(): int
133
    {
134
        $errors = 0;
135
136
        foreach ($this->results as $results) {
137
            $errors += count($results['schema']);
138
            $errors += count(array_filter($results['fields']));
139
        }
140
141
        return $errors;
142
    }
143
}
144