Validator   A
last analyzed

Complexity

Total Complexity 20

Size/Duplication

Total Lines 141
Duplicated Lines 0 %

Test Coverage

Coverage 100%

Importance

Changes 5
Bugs 0 Features 0
Metric Value
wmc 20
eloc 51
c 5
b 0
f 0
dl 0
loc 141
ccs 55
cts 55
cp 1
rs 10

9 Methods

Rating   Name   Duplication   Size   Complexity  
A isXMLValid() 0 15 2
A getVersion() 0 3 1
A checkEmptyWhenTrimmed() 0 4 2
A isXMLFileValid() 0 23 6
A setVersion() 0 3 1
A parseErrors() 0 16 3
A getEncoding() 0 3 1
A setEncoding() 0 3 1
A isXMLStringValid() 0 9 3
1
<?php declare(strict_types=1);
2
3
namespace Hyperized\Xml;
4
5
use DOMDocument;
6
use Hyperized\Xml\Constants\ErrorMessages;
7
use Hyperized\Xml\Constants\Strings;
8
use Hyperized\Xml\Exceptions\FileCouldNotBeOpenedException;
9
use Hyperized\Xml\Exceptions\InvalidXml;
10
use Hyperized\Xml\Exceptions\EmptyFile;
11
use Hyperized\Xml\Exceptions\FileDoesNotExist;
12
use Hyperized\Xml\Types\Files\Xml;
13
use Hyperized\Xml\Types\Files\Xsd;
14
use function is_string;
15
use LibXMLError;
16
17
/**
18
 * Class Validator
19
 *
20
 * @package Hyperized\Xml
21
 * Based on: http://stackoverflow.com/a/30058598/1757763
22
 */
23
final class Validator implements ValidatorInterface
24
{
25
    /**
26
     * @var string
27
     */
28
    private $version = Strings::VERSION;
29
    /**
30
     * @var string
31
     */
32
    private $encoding = Strings::UTF_8;
33
34 16
    public function isXMLFileValid(string $xmlPath, string $xsdPath = null): bool
35
    {
36
        try {
37 16
            $string = (new Xml($xmlPath))
38 14
                ->getContents();
39 6
        } catch (EmptyFile $e) {
40 2
            return false;
41 4
        } catch (FileCouldNotBeOpenedException $e) {
42 2
            return false;
43 2
        } catch (FileDoesNotExist $e) {
44 2
            return false;
45
        }
46
47 10
        if ($xsdPath !== null) {
48
            try {
49 6
                $xsdPath = (new Xsd($xsdPath))
50 4
                    ->getPath();
51 2
            } catch (FileDoesNotExist $e) {
52 2
                return false;
53
            }
54
        }
55
56 8
        return $this->isXMLStringValid($string, $xsdPath);
57
    }
58
59
    /**
60
     * @param  string      $xml
61
     * @param  string|null $xsdPath
62
     * @return bool
63
     */
64 14
    public function isXMLStringValid(string $xml, string $xsdPath = null): bool
65
    {
66
        try {
67 14
            if (is_string($xsdPath)) {
68 4
                return $this->isXMLValid($xml, $xsdPath);
69
            }
70 10
            return $this->isXMLValid($xml);
71 8
        } catch (InvalidXml $e) {
72 8
            return false;
73
        }
74
    }
75
76
    /**
77
     * @param  string      $xmlContent
78
     * @param  string|null $xsdPath
79
     * @return bool
80
     * @throws InvalidXml
81
     */
82 14
    private function isXMLValid(string $xmlContent, string $xsdPath = null): bool
83
    {
84 14
        self::checkEmptyWhenTrimmed($xmlContent);
85
86 12
        libxml_use_internal_errors(true);
87
88 12
        $document = new DOMDocument($this->version, $this->encoding);
89 12
        $document->loadXML($xmlContent);
90 12
        if (isset($xsdPath)) {
91 4
            $document->schemaValidate($xsdPath);
92
        }
93 12
        $errors = libxml_get_errors();
94 12
        libxml_clear_errors();
95 12
        self::parseErrors($errors);
96 6
        return true;
97
    }
98
99
    /**
100
     * @param  string $xmlContent
101
     * @throws InvalidXml
102
     */
103 14
    private static function checkEmptyWhenTrimmed(string $xmlContent): void
104
    {
105 14
        if (trim($xmlContent) === '') {
106 2
            throw new InvalidXml(ErrorMessages::XML_EMPTY_TRIMMED);
107
        }
108 12
    }
109
110
    /**
111
     * @param  array<LibXMLError>|null $errors
112
     * @throws InvalidXml
113
     */
114 12
    private static function parseErrors(?array $errors): void
115
    {
116 12
        if (!empty($errors)) {
117 6
            $reduced = array_reduce(
118 6
                $errors,
119
                static function (
120
                    ?array $carry,
121
                    LibXMLError $item
122
                ): array {
123 6
                    $carry[] = trim($item->message);
124 6
                    return $carry;
125 6
                }
126
            );
127
128 6
            if (!empty($reduced)) {
129 6
                throw new InvalidXml(implode(Strings::NEW_LINE, $reduced));
130
            }
131
        }
132 6
    }
133
134
    /**
135
     * @return string
136
     */
137 2
    public function getVersion(): string
138
    {
139 2
        return $this->version;
140
    }
141
142
    /**
143
     * @param string $version
144
     */
145 2
    public function setVersion(string $version): void
146
    {
147 2
        $this->version = $version;
148 2
    }
149
150
    /**
151
     * @return string
152
     */
153 2
    public function getEncoding(): string
154
    {
155 2
        return $this->encoding;
156
    }
157
158
    /**
159
     * @param string $encoding
160
     */
161 2
    public function setEncoding(string $encoding): void
162
    {
163 2
        $this->encoding = $encoding;
164 2
    }
165
}
166