Validate::validate()   A
last analyzed

Complexity

Conditions 3
Paths 3

Size

Total Lines 26
Code Lines 13

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 15
CRAP Score 3

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 13
c 1
b 0
f 0
dl 0
loc 26
ccs 15
cts 15
cp 1
rs 9.8333
cc 3
nc 3
nop 3
crap 3
1
<?php
2
3
namespace Bmatovu\Ussd\Commands;
4
5
use Illuminate\Console\Command;
6
7
class Validate extends Command
8
{
9
    /**
10
     * The name and signature of the console command.
11
     *
12
     * @var string
13
     */
14
    protected $signature = 'ussd:validate
15
                                {--f|file=menu.xml : Main menu file.}
16
                                {--s|schema=menu.xsd : XSD to validate against.}';
17
18
    /**
19
     * The console command description.
20
     *
21
     * @var string
22
     */
23
    protected $description = 'Validate ussd menus.';
24
25
    /**
26
     * Execute the console command.
27
     */
28 2
    public function handle(): void
29
    {
30 2
        $file = $this->option('file');
31 2
        $schema = $this->option('schema');
32
33 2
        $xml = file_exists($file) ? $file : menu_path($file);
34 2
        $xsd = file_exists($schema) ? $schema : menu_path($schema);
35
36 2
        if (! file_exists($xsd)) {
37 2
            $xsd = __DIR__.'/../../menus/menu.xsd';
38 2
            $this->line("Using '{$xsd}'");
39
        }
40
41 2
        $errors = $this->validate($xml, $xsd);
42
43 2
        if (! $errors) {
0 ignored issues
show
introduced by
$errors is an empty array, thus ! $errors is always true.
Loading history...
Bug Best Practice introduced by
The expression $errors of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
44 1
            $this->info('OK');
45
46 1
            return;
47
        }
48
49 1
        foreach ($errors as $file => $messages) {
50 1
            $this->error('File: '.$file);
51 1
            $this->table(['Line', 'Element', 'Message'], $messages);
52
        }
53
    }
54
55
    /**
56
     * @see https://www.php.net/manual/en/class.simplexmlelement.php#107869
57
     */
58 2
    public function validate(string $xmlFile, string $xsdFile, int $flags = 0): array
59
    {
60 2
        libxml_use_internal_errors(true);
61
62 2
        $domDocument = new \DOMDocument();
63
64 2
        $domDocument->load($xmlFile);
65
66 2
        $errors = [];
67
68 2
        if ($domDocument->schemaValidate($xsdFile, $flags)) {
69 1
            return $errors;
70
        }
71
72 1
        foreach (libxml_get_errors() as $error) {
73
            // level, code, column, message, file, line
74 1
            $errors[$error->file][] = [
75 1
                $error->line,
76 1
                $this->getElement($error->message),
77 1
                $this->getMessage($error->message),
78 1
            ];
79
        }
80
81 1
        libxml_clear_errors();
82
83 1
        return $errors;
84
    }
85
86
    /**
87
     * Get element from message.
88
     */
89 1
    protected function getElement(string $message): ?string
90
    {
91 1
        $matches = [];
92
93 1
        preg_match("/'([-_\\w]+)'/", $message, $matches);
94
95 1
        return array_pop($matches);
96
    }
97
98
    /**
99
     * Get refined message.
100
     */
101 1
    protected function getMessage(string $message): string
102
    {
103 1
        $parts = explode(':', $message);
104
105 1
        return trim(array_pop($parts));
106
    }
107
}
108