1
|
|
|
<?php |
2
|
|
|
|
3
|
|
|
/* |
4
|
|
|
* This file is part of the cfdi-xml project. |
5
|
|
|
* |
6
|
|
|
* (c) Kinedu |
7
|
|
|
* |
8
|
|
|
* For the full copyright and license information, please view the LICENSE |
9
|
|
|
* file that was distributed with this source code. |
10
|
|
|
*/ |
11
|
|
|
|
12
|
|
|
namespace Kinedu\CfdiXML\Common; |
13
|
|
|
|
14
|
|
|
use DOMElement; |
15
|
|
|
use DOMDocument; |
16
|
|
|
use DOMNodeList; |
17
|
|
|
|
18
|
|
|
class Node |
19
|
|
|
{ |
20
|
|
|
/** |
21
|
|
|
* Node document. |
22
|
|
|
* |
23
|
|
|
* @var DOMDocument |
24
|
|
|
*/ |
25
|
|
|
protected $document; |
26
|
|
|
|
27
|
|
|
/** |
28
|
|
|
* Node element. |
29
|
|
|
* |
30
|
|
|
* @var DOMElement |
31
|
|
|
*/ |
32
|
|
|
protected $element; |
33
|
|
|
|
34
|
|
|
/** |
35
|
|
|
* Define the parent node name. |
36
|
|
|
* |
37
|
|
|
* @var string|null |
38
|
|
|
*/ |
39
|
|
|
protected $parentNodeName = null; |
40
|
|
|
|
41
|
|
|
/** |
42
|
|
|
* Define the node name. |
43
|
|
|
* |
44
|
|
|
* @var string |
45
|
|
|
*/ |
46
|
|
|
protected $nodeName; |
47
|
|
|
|
48
|
|
|
/** |
49
|
|
|
* Node attributes. |
50
|
|
|
* |
51
|
|
|
* @var array |
52
|
|
|
*/ |
53
|
|
|
protected $attr = []; |
54
|
|
|
|
55
|
|
|
/** |
56
|
|
|
* Create a new node instance. |
57
|
|
|
* |
58
|
|
|
* @param array $attr |
59
|
|
|
*/ |
60
|
|
|
public function __construct(array ...$attr) |
61
|
|
|
{ |
62
|
|
|
$this->attr = $attr; |
63
|
|
|
|
64
|
|
|
$this->document = new DOMDocument('1.0', 'UTF-8'); |
65
|
|
|
$this->document->preserveWhiteSpace = false; |
66
|
|
|
$this->document->formatOutput = true; |
67
|
|
|
|
68
|
|
|
if ($nodeName = $this->getNodeName()) { |
69
|
|
|
$this->element = $this->document->createElement($nodeName); |
70
|
|
|
$this->document->appendChild($this->element); |
71
|
|
|
$this->setAttr($this->element, $this->getAttr()); |
72
|
|
|
} |
73
|
|
|
} |
74
|
|
|
|
75
|
|
|
/** |
76
|
|
|
* Add a new node. |
77
|
|
|
* |
78
|
|
|
* @param \Kinedu\CfdiXML\Common\Node $node |
79
|
|
|
* |
80
|
|
|
* @return void |
81
|
|
|
*/ |
82
|
|
|
public function add(Node $node) |
83
|
|
|
{ |
84
|
|
|
$wrapperElement = null; |
85
|
|
|
|
86
|
|
|
$nodeElement = $this->document->createElement($node->getNodeName()); |
87
|
|
|
$this->setAttr($nodeElement, $node->getAttr()); |
88
|
|
|
|
89
|
|
|
foreach ($node->element->childNodes as $child) { |
90
|
|
|
$nodeElement->appendChild( |
91
|
|
|
$this->document->importNode($child, true) |
92
|
|
|
); |
93
|
|
|
} |
94
|
|
|
|
95
|
|
|
if ($wrapperName = $node->getWrapperNodeName()) { |
96
|
|
|
$wrapperElement = $this->getDirectChildElementByName( |
97
|
|
|
$this->element->childNodes, |
98
|
|
|
$wrapperName |
99
|
|
|
); |
100
|
|
|
|
101
|
|
|
if (!$wrapperElement) { |
102
|
|
|
$wrapperElement = $this->document->createElement($wrapperName); |
103
|
|
|
$this->element->appendChild($wrapperElement); |
104
|
|
|
} |
105
|
|
|
|
106
|
|
|
$this->setAttr($wrapperElement, $node->getAttr('wrapper')); |
107
|
|
|
} |
108
|
|
|
|
109
|
|
|
if ($parentName = $node->getParentNodeName()) { |
110
|
|
|
$currentElement = ($wrapperElement) ? $wrapperElement : $this->element; |
111
|
|
|
|
112
|
|
|
$parentNode = $this->getDirectChildElementByName( |
113
|
|
|
$currentElement->childNodes, |
114
|
|
|
$parentName |
115
|
|
|
); |
116
|
|
|
|
117
|
|
|
if (!$parentNode) { |
118
|
|
|
$parentElement = $this->document->createElement($parentName); |
119
|
|
|
$currentElement->appendChild($parentElement); |
120
|
|
|
$parentElement->appendChild($nodeElement); |
121
|
|
|
$this->setAttr($parentElement, $node->getAttr('parent')); |
122
|
|
|
} else { |
123
|
|
|
$parentNode->appendChild($nodeElement); |
124
|
|
|
} |
125
|
|
|
} else { |
126
|
|
|
$this->element->appendChild($nodeElement); |
127
|
|
|
} |
128
|
|
|
} |
129
|
|
|
|
130
|
|
|
/** |
131
|
|
|
* Search the direct child of an element. |
132
|
|
|
* |
133
|
|
|
* @param DOMNodeList $children |
134
|
|
|
* @param string $find |
135
|
|
|
* |
136
|
|
|
* @return DOMElement|null |
137
|
|
|
*/ |
138
|
|
|
protected function getDirectChildElementByName(DOMNodeList $children, string $find) |
139
|
|
|
{ |
140
|
|
|
foreach ($children as $child) { |
141
|
|
|
if ($child->nodeName == $find) { |
142
|
|
|
return $child; |
143
|
|
|
} |
144
|
|
|
} |
145
|
|
|
|
146
|
|
|
return null; |
147
|
|
|
} |
148
|
|
|
|
149
|
|
|
/** |
150
|
|
|
* Get node attributes. |
151
|
|
|
* |
152
|
|
|
* @param string $index |
153
|
|
|
* |
154
|
|
|
* @return array|null |
155
|
|
|
*/ |
156
|
|
|
public function getAttr(string $index = 'node') |
157
|
|
|
{ |
158
|
|
|
$attrIndex = ['node', 'parent', 'wrapper']; |
159
|
|
|
|
160
|
|
|
$index = (in_array($index, $attrIndex)) |
161
|
|
|
? array_search($index, $attrIndex) |
162
|
|
|
: 0; |
163
|
|
|
|
164
|
|
|
return $this->attr[$index] ?? null; |
165
|
|
|
} |
166
|
|
|
|
167
|
|
|
/** |
168
|
|
|
* Adds attributes to an element. |
169
|
|
|
* |
170
|
|
|
* @param DOMElement $element |
171
|
|
|
* @param array $attr |
172
|
|
|
* |
173
|
|
|
* @return void |
174
|
|
|
*/ |
175
|
|
|
public function setAttr(DOMElement $element, array $attr = null) |
176
|
|
|
{ |
177
|
|
|
if (!is_null($attr)) { |
178
|
|
|
foreach ($attr as $key => $value) { |
179
|
|
|
$element->setAttribute($key, $value); |
180
|
|
|
} |
181
|
|
|
} |
182
|
|
|
} |
183
|
|
|
|
184
|
|
|
/** |
185
|
|
|
* Get element. |
186
|
|
|
* |
187
|
|
|
* @return DOMElement |
188
|
|
|
*/ |
189
|
|
|
public function getElement(): DOMElement |
190
|
|
|
{ |
191
|
|
|
return $this->element; |
192
|
|
|
} |
193
|
|
|
|
194
|
|
|
/** |
195
|
|
|
* Get document. |
196
|
|
|
* |
197
|
|
|
* @return DOMDocument |
198
|
|
|
*/ |
199
|
|
|
public function getDocument(): DOMDocument |
200
|
|
|
{ |
201
|
|
|
return $this->document; |
202
|
|
|
} |
203
|
|
|
|
204
|
|
|
/** |
205
|
|
|
* Get wrapper node name. |
206
|
|
|
* |
207
|
|
|
* @return string|null |
208
|
|
|
*/ |
209
|
|
|
public function getWrapperNodeName() |
210
|
|
|
{ |
211
|
|
|
return $this->wrapperNodeName ?? null; |
|
|
|
|
212
|
|
|
} |
213
|
|
|
|
214
|
|
|
/** |
215
|
|
|
* Get parent node name. |
216
|
|
|
* |
217
|
|
|
* @return string|null |
218
|
|
|
*/ |
219
|
|
|
public function getParentNodeName() |
220
|
|
|
{ |
221
|
|
|
return $this->parentNodeName ?? null; |
222
|
|
|
} |
223
|
|
|
|
224
|
|
|
/** |
225
|
|
|
* Get node name. |
226
|
|
|
* |
227
|
|
|
* @return string |
228
|
|
|
*/ |
229
|
|
|
public function getNodeName() |
230
|
|
|
{ |
231
|
|
|
return $this->nodeName ?? null; |
232
|
|
|
} |
233
|
|
|
} |
234
|
|
|
|
An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.
If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.