Passed
Push — main ( 97d8d6...d31f66 )
by Stefan
11:26
created

XMLForm::setSchemaValidation()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 1
nc 1
nop 1
dl 0
loc 3
rs 10
c 0
b 0
f 0
1
<?php
2
declare(strict_types=1);
3
4
namespace SKien\Formgenerator;
5
6
7
/**
8
 *
9
 *
10
 * @package Formgenerator
11
 * @author Stefanius <[email protected]>
12
 * @copyright MIT License - see the LICENSE file for details
13
 */
14
class XMLForm extends FormGenerator
15
{
16
    const E_OK = 0;
17
    const E_FILE_NOT_EXIST = 1;
18
    const E_XML_ERROR = 2;
19
    const E_XSD_ERROR = 3;
20
    const E_MISSING_ROOT = 4;
21
    const E_MISSING_FORM = 5;
22
    const E_UNKNOWN_FORM_ELEMENT = 5;
23
24
    const XML_SCHEMA = 'FormGenerator.xsd';
25
26
    /** @var string error message     */
27
    protected string $strErrorMsg = '';
28
    /** @var bool error message as plain text (\n instead of &lt;br/&gt;) */
29
    protected bool $bPlainError = false;
30
    /** @var bool check xml file against the FormGenerator XSD schema */
31
    protected bool $bSchemaValidate = true;
32
33
    /**
34
     * no constructor - always use the constructor of the parent!
35
     */
36
37
    /**
38
     * Load form from the given XML file.
39
     * @param string $strXMLFile
40
     * @return int
41
     */
42
    public function loadXML(string $strXMLFile) : int
43
    {
44
        if (!file_exists($strXMLFile)) {
45
            // if file not exist, there is nothing more to do...
46
            $this->strErrorMsg = 'Missing form file: ' . $strXMLFile;
47
            return self::E_FILE_NOT_EXIST;
48
        }
49
        // to get more detailed information about XML errors and XML schema validation
50
        libxml_use_internal_errors(true);
51
        $iResult = self::E_XML_ERROR;
52
        $oXMLForm = new \DOMDocument();
53
        if ($oXMLForm->load($strXMLFile)) {
54
            $iResult = self::E_OK;
0 ignored issues
show
Unused Code introduced by
The assignment to $iResult is dead and can be removed.
Loading history...
55
            // the XML schema is allways expected in the same directory as the XML file itself
56
            $strXSDFile = pathinfo($strXMLFile, PATHINFO_DIRNAME) . DIRECTORY_SEPARATOR . self::XML_SCHEMA;
0 ignored issues
show
Bug introduced by
Are you sure pathinfo($strXMLFile, SK...rator\PATHINFO_DIRNAME) of type array|string can be used in concatenation? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

56
            $strXSDFile = /** @scrutinizer ignore-type */ pathinfo($strXMLFile, PATHINFO_DIRNAME) . DIRECTORY_SEPARATOR . self::XML_SCHEMA;
Loading history...
57
            $oRoot = $oXMLForm->documentElement;
58
            if ($this->bSchemaValidate && !$oXMLForm->schemaValidate($strXSDFile)) {
59
                $iResult = self::E_XSD_ERROR;
60
            } elseif ($oRoot->nodeName != 'FormGenerator') {
61
                $this->strErrorMsg = 'Missing document root &lt;FormGenerator&gt; in form file: ' . $strXMLFile;
62
                $iResult = self::E_MISSING_ROOT;
63
            } elseif (($oForm = $this->getXMLChild($oRoot, 'Form')) === null) {
64
                $this->strErrorMsg = 'Missing form elemnt &lt;Form&gt; as first child of the root: ' . $strXMLFile;
65
                $iResult = self::E_MISSING_FORM;
66
            } else {
67
                // First we read some general infos for the form
68
                $this->readAdditionalXML($oForm);
69
70
                // and iterate recursive through the child elements
71
                $iResult = $this->createChildElements($oForm, $this);
72
            }
73
        }
74
        if ($iResult != self::E_OK && strlen($this->strErrorMsg) == 0) {
75
            $this->strErrorMsg = ($iResult != self::E_XSD_ERROR ? 'XML error: ' : 'XSD Schema validation error: ');
76
            $this->strErrorMsg .= $this->getFormatedXMLError($this->bPlainError);
77
        }
78
        libxml_clear_errors();
79
        return $iResult;
80
    }
81
82
    /**
83
     * Iterate through all childs of the given parent node and create the according element.
84
     * This method cals itself recursive for all collection elements.
85
     * @param \DOMElement $oXMLParent the DOM Element containing the infos for the formelement to create
86
     * @param FormCollection $oFormParent the parent element in the form
87
     * @return int
88
     */
89
    protected function createChildElements(\DOMElement $oXMLParent, FormCollection $oFormParent) : int
90
    {
91
        $iResult = self::E_OK;
92
        if (!$oXMLParent->hasChildNodes()) {
93
            return $iResult;
94
        }
95
        foreach ($oXMLParent->childNodes as $oXMLChild) {
96
            if (strtolower($oXMLChild->nodeName) == '#text') {
97
                continue;
98
            }
99
            $strClassname = __NAMESPACE__ . '\Form' . $oXMLChild->nodeName;
100
            if (class_exists($strClassname) && is_subclass_of($strClassname, __NAMESPACE__ . '\FormElement')) {
101
                $oFormElement = $strClassname::fromXML($oXMLChild, $oFormParent);
102
                // recursive call for collection element (div, fieldset, line)
103
                if ($oFormElement instanceof FormCollection) {
104
                    $iResult = $this->createChildElements($oXMLChild, $oFormElement);
105
                }
106
            } else {
107
                $this->strErrorMsg = 'Unknown form element: ' . $oXMLChild->nodeName;
108
                $iResult = self::E_UNKNOWN_FORM_ELEMENT;
109
            }
110
            if ($iResult != self::E_OK) {
111
                break;
112
            }
113
        }
114
        return $iResult;
115
    }
116
117
    /**
118
     * Get message to error occured.
119
     * May contain multiple lines in case of any XML formating errors.
120
     * @return string
121
     */
122
    public function getErrorMsg() : string
123
    {
124
        return $this->strErrorMsg;
125
    }
126
127
    /**
128
     * Format error message as plain text (\n instead of <br/> for multiline errors)
129
     * @param bool $bPlainError
130
     */
131
    public function setPlainError(bool $bPlainError) : void
132
    {
133
        $this->bPlainError = $bPlainError;
134
    }
135
136
    /**
137
     * enable/disable the schema validation (default set to true)
138
     * @param bool $bSchemaValidate
139
     */
140
    public function setSchemaValidation(bool $bSchemaValidate) : void
141
    {
142
        $this->bSchemaValidate = $bSchemaValidate;
143
    }
144
}
145