1
|
|
|
<?php |
2
|
|
|
|
3
|
|
|
namespace Xml\Impl\Type; |
4
|
|
|
|
5
|
|
|
use Xml\{ |
6
|
|
|
ModelInterface, |
7
|
|
|
ModelInstanceInterface |
8
|
|
|
}; |
9
|
|
|
use Xml\Exception\{ |
10
|
|
|
ModelException, |
11
|
|
|
ModelTypeException |
12
|
|
|
}; |
13
|
|
|
use Xml\Type\Child\ChildElementCollectionInterface; |
14
|
|
|
use Xml\Impl\ModelImpl; |
15
|
|
|
use Xml\Impl\Instance\ModelTypeInstanceContext; |
16
|
|
|
use Xml\Impl\Util\ModelUtil; |
17
|
|
|
use Xml\Instance\{ |
18
|
|
|
DomDocumentInterface, |
19
|
|
|
DomElementInterface, |
20
|
|
|
ModelElementInstanceInterface |
21
|
|
|
}; |
22
|
|
|
use Xml\Type\{ |
23
|
|
|
ModelElementTypeInterface, |
24
|
|
|
ModelTypeInstanceProviderInterface |
25
|
|
|
}; |
26
|
|
|
use Xml\Type\Attribute\AttributeInterface; |
27
|
|
|
|
28
|
|
|
class ModelElementTypeImpl implements ModelElementTypeInterface |
29
|
|
|
{ |
30
|
|
|
private $model; |
31
|
|
|
private $typeName; |
32
|
|
|
private $instanceType; |
33
|
|
|
private $typeNamespace; |
34
|
|
|
private $baseType; |
35
|
|
|
private $extendingTypes = []; |
36
|
|
|
private $attributes = []; |
37
|
|
|
private $childElementTypes = []; |
38
|
|
|
private $childElementCollections = []; |
39
|
|
|
private $instanceProvider; |
40
|
|
|
private $isAbstract; |
41
|
|
|
|
42
|
|
|
public function __construct(ModelImpl $model, string $name, string $instanceType) |
43
|
|
|
{ |
44
|
|
|
$this->model = $model; |
45
|
|
|
$this->typeName = $name; |
46
|
|
|
$this->instanceType = $instanceType; |
47
|
|
|
} |
48
|
|
|
|
49
|
|
|
public function newInstance( |
50
|
|
|
ModelInstanceInterface $modelInstance, |
51
|
|
|
?DomElementInterface $domElement = null |
52
|
|
|
): ModelElementInstanceInterface { |
53
|
|
|
if ($domElement !== null) { |
54
|
|
|
$modelTypeInstanceContext = new ModelTypeInstanceContext($domElement, $modelInstance, $this); |
55
|
|
|
return $this->createModelElementInstance($modelTypeInstanceContext); |
56
|
|
|
} else { |
57
|
|
|
$document = $modelInstance->getDocument(); |
58
|
|
|
$domElement = $document->createElement($this->typeNamespace, $this->typeName); |
59
|
|
|
return $this->newInstance($modelInstance, $domElement); |
60
|
|
|
} |
61
|
|
|
} |
62
|
|
|
|
63
|
|
|
public function registerAttribute(AttributeInterface $attribute): void |
64
|
|
|
{ |
65
|
|
|
if (!in_array($attribute, $this->attributes)) { |
66
|
|
|
$this->attributes[] = $attribute; |
67
|
|
|
} |
68
|
|
|
} |
69
|
|
|
|
70
|
|
|
public function registerChildElementType(ModelElementTypeInterface $childElementType): void |
71
|
|
|
{ |
72
|
|
|
if (!in_array($childElementType, $this->childElementTypes)) { |
73
|
|
|
$this->childElementTypes[] = $childElementType; |
74
|
|
|
} |
75
|
|
|
} |
76
|
|
|
|
77
|
|
|
public function registerChildElementCollection(ChildElementCollectionInterface $childElementCollection): void |
78
|
|
|
{ |
79
|
|
|
if (!in_array($childElementCollection, $this->childElementCollections)) { |
80
|
|
|
$this->childElementCollections[] = $childElementCollection; |
81
|
|
|
} |
82
|
|
|
} |
83
|
|
|
|
84
|
|
|
public function registerExtendingType(ModelElementTypeInterface $modelType): void |
85
|
|
|
{ |
86
|
|
|
if (!in_array($modelType, $this->extendingTypes)) { |
87
|
|
|
$this->extendingTypes[] = $modelType; |
88
|
|
|
} |
89
|
|
|
} |
90
|
|
|
|
91
|
|
|
protected function createModelElementInstance( |
92
|
|
|
ModelTypeInstanceContext $instanceContext |
93
|
|
|
): ModelElementInstanceInterface { |
94
|
|
|
if ($this->isAbstract) { |
95
|
|
|
throw new ModelTypeException( |
96
|
|
|
sprintf( |
97
|
|
|
"Model element type %s is abstract and no instances can be created.", |
98
|
|
|
$this->getTypeName() |
99
|
|
|
) |
100
|
|
|
); |
101
|
|
|
} else { |
102
|
|
|
return $this->instanceProvider->newInstance($instanceContext); |
103
|
|
|
} |
104
|
|
|
} |
105
|
|
|
|
106
|
|
|
public function getAttributes(): array |
107
|
|
|
{ |
108
|
|
|
return $this->attributes; |
109
|
|
|
} |
110
|
|
|
|
111
|
|
|
public function getTypeName(): string |
112
|
|
|
{ |
113
|
|
|
return $this->typeName; |
114
|
|
|
} |
115
|
|
|
|
116
|
|
|
public function getInstanceType(): string |
117
|
|
|
{ |
118
|
|
|
return $this->instanceType; |
119
|
|
|
} |
120
|
|
|
|
121
|
|
|
public function setTypeNamespace(?string $typeNamespace): void |
122
|
|
|
{ |
123
|
|
|
$this->typeNamespace = $typeNamespace; |
124
|
|
|
} |
125
|
|
|
|
126
|
|
|
public function getTypeNamespace(): ?string |
127
|
|
|
{ |
128
|
|
|
return $this->typeNamespace; |
129
|
|
|
} |
130
|
|
|
|
131
|
|
|
public function setBaseType(ModelElementTypeImpl $baseType): void |
132
|
|
|
{ |
133
|
|
|
if ($this->baseType === null) { |
134
|
|
|
$this->baseType = $baseType; |
135
|
|
|
} elseif ($this->baseType != $baseType) { |
136
|
|
|
throw new ModelException( |
137
|
|
|
sprintf( |
138
|
|
|
"Type can not have multiple base types. %s already extends type %s and can not also extend type %s", |
139
|
|
|
get_class($this), |
140
|
|
|
get_class($this->baseType), |
141
|
|
|
get_class($this) |
142
|
|
|
) |
143
|
|
|
); |
144
|
|
|
} |
145
|
|
|
} |
146
|
|
|
|
147
|
|
|
public function setInstanceProvider(ModelTypeInstanceProviderInterface $instanceProvider): void |
148
|
|
|
{ |
149
|
|
|
$this->instanceProvider = $instanceProvider; |
150
|
|
|
} |
151
|
|
|
|
152
|
|
|
public function isAbstract(): bool |
153
|
|
|
{ |
154
|
|
|
return $this->isAbstract ?? false; |
155
|
|
|
} |
156
|
|
|
|
157
|
|
|
public function setAbstract(bool $isAbstract): void |
158
|
|
|
{ |
159
|
|
|
$this->isAbstract = $isAbstract; |
160
|
|
|
} |
161
|
|
|
|
162
|
|
|
public function getExtendingTypes(): array |
163
|
|
|
{ |
164
|
|
|
return $this->extendingTypes; |
165
|
|
|
} |
166
|
|
|
|
167
|
|
|
public function getAllExtendingTypes(): array |
168
|
|
|
{ |
169
|
|
|
$extendingTypes = []; |
170
|
|
|
$extendingTypes[] = $this; |
171
|
|
|
$this->resolveExtendingTypes($extendingTypes); |
172
|
|
|
return $extendingTypes; |
173
|
|
|
} |
174
|
|
|
|
175
|
|
|
public function resolveExtendingTypes(array &$allExtendingTypes): void |
176
|
|
|
{ |
177
|
|
|
foreach ($this->extendingTypes as $modelElementTypeImpl) { |
178
|
|
|
if (!in_array($modelElementTypeImpl, $allExtendingTypes)) { |
179
|
|
|
$allExtendingTypes[] = $modelElementTypeImpl; |
180
|
|
|
$modelElementTypeImpl->resolveExtendingTypes($allExtendingTypes); |
181
|
|
|
} |
182
|
|
|
} |
183
|
|
|
} |
184
|
|
|
|
185
|
|
|
public function resolveBaseTypes(array &$baseTypes): void |
186
|
|
|
{ |
187
|
|
|
if ($this->baseType !== null) { |
188
|
|
|
$baseTypes[] = $this->baseType; |
189
|
|
|
$this->baseType->resolveBaseTypes($baseTypes); |
190
|
|
|
} |
191
|
|
|
} |
192
|
|
|
|
193
|
|
|
public function getBaseType(): ?ModelElementTypeInterface |
194
|
|
|
{ |
195
|
|
|
return $this->baseType; |
196
|
|
|
} |
197
|
|
|
|
198
|
|
|
public function getModel(): ModelInterface |
199
|
|
|
{ |
200
|
|
|
return $this->model; |
201
|
|
|
} |
202
|
|
|
|
203
|
|
|
public function getChildElementTypes(): array |
204
|
|
|
{ |
205
|
|
|
return $this->childElementTypes; |
206
|
|
|
} |
207
|
|
|
|
208
|
|
|
public function getAllChildElementTypes(): array |
209
|
|
|
{ |
210
|
|
|
$allChildElementTypes = []; |
211
|
|
|
if ($this->baseType !== null) { |
212
|
|
|
$allChildElementTypes = array_merge($allChildElementTypes, $this->baseType->getAllChildElementTypes()); |
213
|
|
|
} |
214
|
|
|
$allChildElementTypes = array_merge($allChildElementTypes, $this->childElementTypes); |
215
|
|
|
return $allChildElementTypes; |
216
|
|
|
} |
217
|
|
|
|
218
|
|
|
public function getChildElementCollections(): array |
219
|
|
|
{ |
220
|
|
|
return $this->childElementCollections; |
221
|
|
|
} |
222
|
|
|
|
223
|
|
|
public function getAllChildElementCollections(): array |
224
|
|
|
{ |
225
|
|
|
$allChildElementCollections = []; |
226
|
|
|
if ($this->baseType !== null) { |
227
|
|
|
$allChildElementCollections = array_merge( |
228
|
|
|
$allChildElementCollections, |
229
|
|
|
$this->baseType->getAllChildElementCollections() |
230
|
|
|
); |
231
|
|
|
} |
232
|
|
|
$allChildElementCollections = array_merge($allChildElementCollections, $this->childElementCollections); |
233
|
|
|
return $allChildElementCollections; |
234
|
|
|
} |
235
|
|
|
|
236
|
|
|
public function getInstances(ModelInstanceInterface $modelInstanceImpl): array |
237
|
|
|
{ |
238
|
|
|
$document = $modelInstanceImpl->getDocument(); |
239
|
|
|
|
240
|
|
|
$elements = $this->getElementsByNameNs($document, $this->typeNamespace); |
241
|
|
|
|
242
|
|
|
$resultList = []; |
243
|
|
|
foreach ($elements as $element) { |
244
|
|
|
$resultList[] = ModelUtil::getModelElement($element, $modelInstanceImpl, $this); |
245
|
|
|
} |
246
|
|
|
return $resultList; |
247
|
|
|
} |
248
|
|
|
|
249
|
|
|
protected function getElementsByNameNs(DomDocumentInterface $document, string $namespaceURI): array |
250
|
|
|
{ |
251
|
|
|
$elements = $document->getElementsByNameNs($namespaceURI, $this->typeName); |
252
|
|
|
|
253
|
|
|
if (empty($elements)) { |
254
|
|
|
$alternativeNamespaces = $this->getModel()->getAlternativeNamespaces($namespaceURI); |
255
|
|
|
|
256
|
|
|
if (!empty($alternativeNamespaces)) { |
257
|
|
|
foreach ($alternativeNamespaces as $namespace) { |
258
|
|
|
$elements = $this->getElementsByNameNs($document, $namespace); |
259
|
|
|
if (!empty($elements)) { |
260
|
|
|
break; |
261
|
|
|
} |
262
|
|
|
} |
263
|
|
|
} |
264
|
|
|
} |
265
|
|
|
|
266
|
|
|
return $elements; |
267
|
|
|
} |
268
|
|
|
|
269
|
|
|
public function isBaseTypeOf(ModelElementTypeInterface $elementType): bool |
270
|
|
|
{ |
271
|
|
|
if ($this == $elementType) { |
272
|
|
|
return true; |
273
|
|
|
} else { |
274
|
|
|
$baseTypes = ModelUtil::calculateAllBaseTypes($elementType); |
275
|
|
|
return in_array($this, $baseTypes); |
276
|
|
|
} |
277
|
|
|
} |
278
|
|
|
|
279
|
|
|
public function getAllAttributes(): array |
280
|
|
|
{ |
281
|
|
|
$allAttributes = array_merge([], $this->getAttributes()); |
282
|
|
|
$baseTypes = ModelUtil::calculateAllBaseTypes($this); |
283
|
|
|
foreach ($baseTypes as $baseType) { |
284
|
|
|
$allAttributes = array_merge($allAttributes, $baseType->getAttributes()); |
285
|
|
|
} |
286
|
|
|
return $allAttributes; |
287
|
|
|
} |
288
|
|
|
|
289
|
|
|
public function getAttribute(string $attributeName): ?AttributeInterface |
290
|
|
|
{ |
291
|
|
|
foreach ($this->getAllAttributes() as $attribute) { |
292
|
|
|
if ($attribute->getAttributeName() == $attributeName) { |
293
|
|
|
return $attribute; |
294
|
|
|
} |
295
|
|
|
} |
296
|
|
|
return null; |
297
|
|
|
} |
298
|
|
|
|
299
|
|
|
public function getChildElementCollection( |
300
|
|
|
ModelElementTypeInterface $childElementType |
301
|
|
|
): ChildElementCollectionInterface { |
302
|
|
|
foreach ($this->getChildElementCollections() as $childElementCollection) { |
303
|
|
|
if ($childElementType == $childElementCollection->getChildElementType($this->model)) { |
304
|
|
|
return $childElementCollection; |
305
|
|
|
} |
306
|
|
|
} |
307
|
|
|
return []; |
|
|
|
|
308
|
|
|
} |
309
|
|
|
} |
310
|
|
|
|