Passed
Push — master ( 642672...0bc667 )
by Brian
02:41
created

Validate::getElement()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 7
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 4
CRAP Score 1

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 3
c 1
b 0
f 0
dl 0
loc 7
ccs 4
cts 4
cp 1
rs 10
cc 1
nc 1
nop 1
crap 1
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
        $xml = file_exists($this->option('file')) ? $this->option('file') : menus_path($this->option('file'));
31 2
        $xsd = file_exists($this->option('schema')) ? $this->option('schema') : menus_path($this->option('schema'));
32
33 2
        if (! file_exists($xsd)) {
34 2
            $xsd = __DIR__.'/../../menus/menu.xsd';
35 2
            $this->line("Using '{$xsd}'");
36
        }
37
38 2
        $errors = $this->validate($xml, $xsd);
39
40 2
        if (! $errors) {
0 ignored issues
show
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...
introduced by
$errors is an empty array, thus ! $errors is always true.
Loading history...
41 1
            $this->info('OK');
42
43 1
            return;
44
        }
45
46 1
        foreach ($errors as $file => $messages) {
47 1
            $this->error('File: '.$file);
48 1
            $this->table(['Line', 'Element', 'Message'], $messages);
49
        }
50
    }
51
52
    /**
53
     * @see https://www.php.net/manual/en/class.simplexmlelement.php#107869
54
     */
55 2
    public function validate(string $xmlFile, string $xsdFile, int $flags = 0): array
56
    {
57 2
        libxml_use_internal_errors(true);
58
59 2
        $domDocument = new \DOMDocument();
60
61 2
        $domDocument->load($xmlFile);
62
63 2
        $errors = [];
64
65 2
        if ($domDocument->schemaValidate($xsdFile, $flags)) {
66 1
            return $errors;
67
        }
68
69 1
        foreach (libxml_get_errors() as $error) {
70
            // level, code, column, message, file, line
71 1
            $errors[$error->file][] = [
72 1
                $error->line,
73 1
                $this->getElement($error->message),
74 1
                $this->getMessage($error->message),
75
            ];
76
        }
77
78 1
        libxml_clear_errors();
79
80 1
        return $errors;
81
    }
82
83
    /**
84
     * Get element from message.
85
     */
86 1
    protected function getElement(string $message): ?string
87
    {
88 1
        $matches = [];
89
90 1
        preg_match("/'([-_\\w]+)'/", $message, $matches);
91
92 1
        return array_pop($matches);
93
    }
94
95
    /**
96
     * Get refined message.
97
     */
98 1
    protected function getMessage(string $message): string
99
    {
100 1
        $parts = explode(':', $message);
101
102 1
        return trim(array_pop($parts));
103
    }
104
}
105