Passed
Pull Request — master (#138)
by
unknown
22:34
created

Validator::getErrorMessage()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 7
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 6

Importance

Changes 0
Metric Value
eloc 3
c 0
b 0
f 0
dl 0
loc 7
ccs 0
cts 0
cp 0
rs 10
cc 2
nc 2
nop 0
crap 6
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Hyperized\Xml;
6
7
use DOMDocument;
8
use Hyperized\Xml\Constants\ErrorMessages;
9
use Hyperized\Xml\Constants\Strings;
10
use Hyperized\Xml\Exceptions\FileCouldNotBeOpenedException;
11
use Hyperized\Xml\Exceptions\InvalidXml;
12
use Hyperized\Xml\Exceptions\EmptyFile;
13
use Hyperized\Xml\Exceptions\FileDoesNotExist;
14
use Hyperized\Xml\Types\Files\Xml;
15
use Hyperized\Xml\Types\Files\Xsd;
16
use function is_string;
17
use LibXMLError;
18
19
/**
20
 * Class Validator
21
 *
22
 * @package Hyperized\Xml
23
 * Based on: http://stackoverflow.com/a/30058598/1757763
24
 */
25
final class Validator implements ValidatorInterface
26
{
27
    /**
28
     * @var string
29
     */
30
    private $version = Strings::VERSION;
31
    /**
32
     * @var string
33
     */
34 16
    private $encoding = Strings::UTF_8;
35
36
    /**
37 16
     * @var null|\Exception
38 14
     */
39 6
    private $error = null;
40 2
41 4
    public function isXMLFileValid(string $xmlPath, string $xsdPath = null): bool
42 2
    {
43 2
        try {
44 2
            $string = (new Xml($xmlPath))
45
                ->getContents();
46
        } catch (EmptyFile | FileCouldNotBeOpenedException | FileDoesNotExist $e) {
47 10
            $this->error = $e;
48
            return false;
49 6
        }
50 4
51 2
        if ($xsdPath !== null) {
52 2
            try {
53
                $xsdPath = (new Xsd($xsdPath))
54
                    ->getPath();
55
            } catch (FileDoesNotExist $e) {
56 8
                $this->error = $e;
57
                return false;
58
            }
59
        }
60
61
        return $this->isXMLStringValid($string, $xsdPath);
62
    }
63
64 14
    /**
65
     * @param  string      $xml
66
     * @param  string|null $xsdPath
67 14
     * @param  bool $returnError
68 4
     * @return bool
69
     */
70 10
    public function isXMLStringValid(string $xml, string $xsdPath = null): bool
71 8
    {
72 8
        try {
73
            if (is_string($xsdPath)) {
74
                return $this->isXMLValid($xml, $xsdPath);
75
            }
76
            return $this->isXMLValid($xml);
77
        } catch (InvalidXml $e) {
78
            $this->error = $e;
79
            return false;
80
        }
81
    }
82 14
83
    /**
84 14
     * @param  string      $xmlContent
85
     * @param  string|null $xsdPath
86 12
     * @return bool
87
     * @throws InvalidXml
88 12
     */
89 12
    private function isXMLValid(string $xmlContent, string $xsdPath = null): bool
90 12
    {
91 4
        self::checkEmptyWhenTrimmed($xmlContent);
92
93 12
        libxml_use_internal_errors(true);
94 12
95 12
        $document = new DOMDocument($this->version, $this->encoding);
96 6
        $document->loadXML($xmlContent);
97
        if (isset($xsdPath)) {
98
            $document->schemaValidate($xsdPath);
99
        }
100
        $errors = libxml_get_errors();
101
        libxml_clear_errors();
102
        self::parseErrors($errors);
103 14
        return true;
104
    }
105 14
106 2
    /**
107
     * @param  string $xmlContent
108 12
     * @throws InvalidXml
109
     */
110
    private static function checkEmptyWhenTrimmed(string $xmlContent): void
111
    {
112
        if (trim($xmlContent) === '') {
113
            throw new InvalidXml(ErrorMessages::XML_EMPTY_TRIMMED);
114 12
        }
115
    }
116 12
117 6
    /**
118 6
     * @param  array<LibXMLError>|null $errors
119
     * @throws InvalidXml
120
     */
121
    private static function parseErrors(?array $errors): void
122
    {
123 6
        if (!empty($errors)) {
124 6
            $reduced = array_reduce(
125 6
                $errors,
126
                static function (
127
                    ?array $carry,
128 6
                    LibXMLError $item
129 6
                ): array {
130
                    $carry[] = trim($item->message);
131
                    return $carry;
132 6
                }
133
            );
134
135
            if (!empty($reduced)) {
136
                throw new InvalidXml(implode(Strings::NEW_LINE, $reduced));
137 2
            }
138
        }
139 2
    }
140
141
    /**
142
     * @return string
143
     */
144
    public function getVersion(): string
145 2
    {
146
        return $this->version;
147 2
    }
148 2
149
    /**
150
     * @param string $version
151
     */
152
    public function setVersion(string $version): void
153 2
    {
154
        $this->version = $version;
155 2
    }
156
157
    /**
158
     * @return string
159
     */
160
    public function getEncoding(): string
161 2
    {
162
        return $this->encoding;
163 2
    }
164 2
165
    /**
166
     * @param string $encoding
167
     */
168
    public function setEncoding(string $encoding): void
169
    {
170
        $this->encoding = $encoding;
171
    }
172
173
    /**
174
     * @return int Will return 0 when no error has occurred
175
     */
176
    public function getErrorCode(): int
177
    {
178
        if (null !== $this->error) {
179
            return $this->error->getCode();
180
        }
181
182
        return 0;
183
    }
184
185
    /**
186
     * @return string Will return empty string when no error has occurred
187
     */
188
    public function getErrorMessage(): string
189
    {
190
        if (null !== $this->error) {
191
            return $this->error->getMessage();
192
        }
193
194
        return '';
195
    }
196
197
    public function getErrorType(): null|string
198
    {
199
        if (null !== $this->error) {
200
            return get_class($this->error);
201
        }
202
203
        return null;
204
    }
205
}
206