Code Coverage |
||||||||||
Lines |
Functions and Methods |
Classes and Traits |
||||||||
Total | |
96.23% |
153 / 159 |
|
94.74% |
36 / 38 |
CRAP | |
0.00% |
0 / 1 |
Struct | |
96.23% |
153 / 159 |
|
94.74% |
36 / 38 |
89 | |
0.00% |
0 / 1 |
__construct | |
100.00% |
7 / 7 |
|
100.00% |
1 / 1 |
1 | |||
getContextualPart | |
100.00% |
6 / 6 |
|
100.00% |
1 / 1 |
3 | |||
getDocSubPackages | |
100.00% |
8 / 8 |
|
100.00% |
1 / 1 |
3 | |||
isArray | |
100.00% |
10 / 10 |
|
100.00% |
1 / 1 |
7 | |||
getAttributes | |
100.00% |
4 / 4 |
|
100.00% |
1 / 1 |
3 | |||
getProperAttributes | |
100.00% |
12 / 12 |
|
100.00% |
1 / 1 |
9 | |||
countOwnAttributes | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
countAllAttributes | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
setAttributes | |
100.00% |
2 / 2 |
|
100.00% |
1 / 1 |
1 | |||
addAttribute | |
100.00% |
6 / 6 |
|
100.00% |
1 / 1 |
4 | |||
getAttribute | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
getAttributeByCleanName | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
isRestriction | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
setRestriction | |
100.00% |
2 / 2 |
|
100.00% |
1 / 1 |
1 | |||
isStruct | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
setStruct | |
100.00% |
2 / 2 |
|
100.00% |
1 / 1 |
1 | |||
getList | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
isList | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
setList | |
100.00% |
2 / 2 |
|
100.00% |
1 / 1 |
1 | |||
getValues | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
addValue | |
58.33% |
7 / 12 |
|
0.00% |
0 / 1 |
3.65 | |||
getValue | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
getExtends | |
100.00% |
6 / 6 |
|
100.00% |
1 / 1 |
4 | |||
getInheritanceStruct | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
2 | |||
getTopInheritance | |
100.00% |
9 / 9 |
|
100.00% |
1 / 1 |
4 | |||
getTopInheritanceStruct | |
85.71% |
6 / 7 |
|
0.00% |
0 / 1 |
3.03 | |||
getMeta | |
100.00% |
2 / 2 |
|
100.00% |
1 / 1 |
3 | |||
getReservedMethodsInstance | |
100.00% |
4 / 4 |
|
100.00% |
1 / 1 |
2 | |||
getTypes | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
isUnion | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
setTypes | |
100.00% |
2 / 2 |
|
100.00% |
1 / 1 |
1 | |||
setAttributesFromSerializedJson | |
100.00% |
2 / 2 |
|
100.00% |
1 / 1 |
2 | |||
setValuesFromSerializedJson | |
100.00% |
2 / 2 |
|
100.00% |
1 / 1 |
2 | |||
getAllAttributes | |
100.00% |
9 / 9 |
|
100.00% |
1 / 1 |
4 | |||
addInheritanceAttributes | |
100.00% |
5 / 5 |
|
100.00% |
1 / 1 |
6 | |||
putRequiredAttributesFirst | |
100.00% |
15 / 15 |
|
100.00% |
1 / 1 |
5 | |||
setValues | |
100.00% |
2 / 2 |
|
100.00% |
1 / 1 |
1 | |||
toJsonSerialize | |
100.00% |
8 / 8 |
|
100.00% |
1 / 1 |
1 |
1 | <?php |
2 | |
3 | declare(strict_types=1); |
4 | |
5 | namespace WsdlToPhp\PackageGenerator\Model; |
6 | |
7 | use WsdlToPhp\PackageGenerator\ConfigurationReader\AbstractReservedWord; |
8 | use WsdlToPhp\PackageGenerator\ConfigurationReader\StructArrayReservedMethod; |
9 | use WsdlToPhp\PackageGenerator\ConfigurationReader\StructReservedMethod; |
10 | use WsdlToPhp\PackageGenerator\Container\Model\StructAttribute as StructAttributeContainer; |
11 | use WsdlToPhp\PackageGenerator\Container\Model\StructValue as StructValueContainer; |
12 | use WsdlToPhp\PackageGenerator\Generator\Generator; |
13 | use WsdlToPhp\PackageGenerator\Generator\Utils; |
14 | |
15 | /** |
16 | * Class Struct stands for an available struct described in the WSDL. |
17 | */ |
18 | final class Struct extends AbstractModel |
19 | { |
20 | public const DOC_SUB_PACKAGE_STRUCTS = 'Structs'; |
21 | public const DOC_SUB_PACKAGE_ENUMERATIONS = 'Enumerations'; |
22 | public const DOC_SUB_PACKAGE_ARRAYS = 'Arrays'; |
23 | public const DEFAULT_ENUM_TYPE = 'string'; |
24 | |
25 | /** |
26 | * Attributes of the struct. |
27 | */ |
28 | protected StructAttributeContainer $attributes; |
29 | |
30 | /** |
31 | * Is the struct a restriction with defined values ? |
32 | */ |
33 | protected bool $isRestriction = false; |
34 | |
35 | /** |
36 | * If the struct is a restriction with values, then store values. |
37 | */ |
38 | protected StructValueContainer $values; |
39 | |
40 | /** |
41 | * If the struct is a union with types, then store types. |
42 | * |
43 | * @var string[] |
44 | */ |
45 | protected array $types = []; |
46 | |
47 | /** |
48 | * Defines if the current struct is a concrete struct or just a virtual struct to store meta information. |
49 | */ |
50 | protected bool $isStruct = false; |
51 | |
52 | /** |
53 | * Defines if the current struct is a list of a type or not. |
54 | * If it is a list of a type, then the list property value is the type. |
55 | */ |
56 | protected string $list = ''; |
57 | |
58 | public function __construct(Generator $generator, $name, $isStruct = true, $isRestriction = false) |
59 | { |
60 | parent::__construct($generator, $name); |
61 | $this |
62 | ->setStruct($isStruct) |
63 | ->setRestriction($isRestriction) |
64 | ->setAttributes(new StructAttributeContainer($generator)) |
65 | ->setValues(new StructValueContainer($generator)) |
66 | ; |
67 | } |
68 | |
69 | public function getContextualPart(): string |
70 | { |
71 | $part = $this->getGenerator()->getOptionStructsFolder(); |
72 | if ($this->isRestriction()) { |
73 | $part = $this->getGenerator()->getOptionEnumsFolder(); |
74 | } elseif ($this->isArray()) { |
75 | $part = $this->getGenerator()->getOptionArraysFolder(); |
76 | } |
77 | |
78 | return $part; |
79 | } |
80 | |
81 | public function getDocSubPackages(): array |
82 | { |
83 | $package = self::DOC_SUB_PACKAGE_STRUCTS; |
84 | if ($this->isRestriction()) { |
85 | $package = self::DOC_SUB_PACKAGE_ENUMERATIONS; |
86 | } elseif ($this->isArray()) { |
87 | $package = self::DOC_SUB_PACKAGE_ARRAYS; |
88 | } |
89 | |
90 | return [ |
91 | $package, |
92 | ]; |
93 | } |
94 | |
95 | public function isArray(): bool |
96 | { |
97 | return |
98 | ( |
99 | ( |
100 | ($this->isStruct() && 1 === $this->countAllAttributes()) |
101 | || (!$this->isStruct() && 1 >= $this->countOwnAttributes()) |
102 | ) |
103 | && false !== mb_stripos($this->getName(), 'array') |
104 | ) |
105 | || (!$this->isStruct() && false !== $this->getMetaValueFirstSet(['arraytype', 'arrayType'], false)) |
106 | ; |
107 | } |
108 | |
109 | public function getAttributes(bool $includeInheritanceAttributes = false, bool $requiredFirst = false): StructAttributeContainer |
110 | { |
111 | if (!$includeInheritanceAttributes && !$requiredFirst) { |
112 | $attributes = $this->attributes; |
113 | } else { |
114 | $attributes = $this->getAllAttributes($includeInheritanceAttributes, $requiredFirst); |
115 | } |
116 | |
117 | return $attributes; |
118 | } |
119 | |
120 | /** |
121 | * Returns the attributes of the struct and not the ones that are declared by the parent struct if this struct inherits from a Struct |
122 | * This means it removes from the attributes this Struct has the attributes declared by its parent class(es). |
123 | * |
124 | * @param bool $requiredFirst places the required attributes first, then the not required in order to have the _construct method with the required attribute at first |
125 | */ |
126 | public function getProperAttributes(bool $requiredFirst = false): StructAttributeContainer |
127 | { |
128 | $properAttributes = new StructAttributeContainer($this->getGenerator()); |
129 | $parentAttributes = new StructAttributeContainer($this->getGenerator()); |
130 | |
131 | if (!empty($this->getInheritance()) && ($model = $this->getInheritanceStruct()) instanceof Struct) { |
132 | while ($model instanceof Struct && $model->isStruct()) { |
133 | foreach ($model->getAttributes() as $attribute) { |
134 | $parentAttributes->add($attribute); |
135 | } |
136 | $model = $model->getInheritanceStruct(); |
137 | } |
138 | } |
139 | |
140 | /** @var StructAttribute $attribute */ |
141 | foreach ($this->getAttributes() as $attribute) { |
142 | if ($parentAttributes->getStructAttributeByName($attribute->getName())) { |
143 | continue; |
144 | } |
145 | $properAttributes->add($attribute); |
146 | } |
147 | |
148 | return $requiredFirst ? $this->putRequiredAttributesFirst($properAttributes) : $properAttributes; |
149 | } |
150 | |
151 | public function countOwnAttributes(): int |
152 | { |
153 | return $this->getAttributes()->count(); |
154 | } |
155 | |
156 | public function countAllAttributes(): int |
157 | { |
158 | return $this->getAttributes(true)->count(); |
159 | } |
160 | |
161 | public function setAttributes(StructAttributeContainer $structAttributeContainer): self |
162 | { |
163 | $this->attributes = $structAttributeContainer; |
164 | |
165 | return $this; |
166 | } |
167 | |
168 | public function addAttribute(string $attributeName, string $attributeType): self |
169 | { |
170 | if (empty($attributeName) || empty($attributeType)) { |
171 | throw new \InvalidArgumentException(sprintf('Attribute name "%s" and/or attribute type "%s" is invalid for Struct "%s"', $attributeName, $attributeType, $this->getName()), __LINE__); |
172 | } |
173 | if (is_null($this->attributes->getStructAttributeByName($attributeName))) { |
174 | $structAttribute = new StructAttribute($this->getGenerator(), $attributeName, $attributeType, $this); |
175 | $this->attributes->add($structAttribute); |
176 | } |
177 | |
178 | return $this; |
179 | } |
180 | |
181 | public function getAttribute(string $attributeName): ?StructAttribute |
182 | { |
183 | return $this->attributes->getStructAttributeByName($attributeName); |
184 | } |
185 | |
186 | public function getAttributeByCleanName(string $attributeCleanName): ?StructAttribute |
187 | { |
188 | return $this->attributes->getStructAttributeByCleanName($attributeCleanName); |
189 | } |
190 | |
191 | public function isRestriction(): bool |
192 | { |
193 | return $this->isRestriction; |
194 | } |
195 | |
196 | public function setRestriction($isRestriction = true): self |
197 | { |
198 | $this->isRestriction = $isRestriction; |
199 | |
200 | return $this; |
201 | } |
202 | |
203 | public function isStruct(): bool |
204 | { |
205 | return $this->isStruct; |
206 | } |
207 | |
208 | public function setStruct(bool $isStruct = true): self |
209 | { |
210 | $this->isStruct = $isStruct; |
211 | |
212 | return $this; |
213 | } |
214 | |
215 | public function getList(): string |
216 | { |
217 | return $this->list; |
218 | } |
219 | |
220 | public function isList(): bool |
221 | { |
222 | return !empty($this->list); |
223 | } |
224 | |
225 | public function setList(string $list = ''): self |
226 | { |
227 | $this->list = $list; |
228 | |
229 | return $this; |
230 | } |
231 | |
232 | public function getValues(): StructValueContainer |
233 | { |
234 | return $this->values; |
235 | } |
236 | |
237 | public function addValue($value): self |
238 | { |
239 | if (is_null($this->getValue($value))) { |
240 | // issue #177, rare case: a struct and an enum has the same name and the enum is not detected by the SoapClient, |
241 | // then we need to create the enumeration struct in order to deduplicate the two structs |
242 | // this is why enumerations has to be parsed before any other elements by the WSDL parsers |
243 | if (0 < $this->countOwnAttributes()) { |
244 | $enum = new Struct($this->getGenerator(), $this->getName(), true, true); |
245 | $enum->setInheritance(self::DEFAULT_ENUM_TYPE); |
246 | $enum->getValues()->add(new StructValue($enum->getGenerator(), $value, $enum->getValues()->count(), $enum)); |
247 | $this->getGenerator()->getStructs()->add($enum); |
248 | |
249 | return $enum; |
250 | } |
251 | $this |
252 | ->setStruct(true) |
253 | ->setRestriction(true) |
254 | ->getValues()->add(new StructValue($this->getGenerator(), $value, $this->getValues()->count(), $this)); |
255 | } |
256 | |
257 | return $this; |
258 | } |
259 | |
260 | public function getValue($value): ?StructValue |
261 | { |
262 | return $this->values->getStructValueByName($value); |
263 | } |
264 | |
265 | public function getExtends(bool $short = false): string |
266 | { |
267 | if ($this->isArray()) { |
268 | $extends = $this->getGenerator()->getOptionStructArrayClass(); |
269 | } elseif ($this->isRestriction()) { |
270 | $extends = $this->getGenerator()->getOptionStructEnumClass(); |
271 | } else { |
272 | $extends = $this->getGenerator()->getOptionStructClass(); |
273 | } |
274 | |
275 | return $short ? Utils::removeNamespace($extends) : $extends; |
276 | } |
277 | |
278 | public function getInheritanceStruct(): ?Struct |
279 | { |
280 | return $this->getName() === $this->getInheritance() ? null : $this->getGenerator()->getStructByName(str_replace('[]', '', $this->getInheritance())); |
281 | } |
282 | |
283 | public function getTopInheritance(): string |
284 | { |
285 | $inheritance = $this->getInheritance(); |
286 | if (!empty($inheritance)) { |
287 | $struct = $this->getInheritanceStruct(); |
288 | while ($struct instanceof Struct) { |
289 | $structInheritance = $struct->getInheritance(); |
290 | if (!empty($structInheritance)) { |
291 | $inheritance = $structInheritance; |
292 | } |
293 | $struct = $struct->getInheritanceStruct(); |
294 | } |
295 | } |
296 | |
297 | return $inheritance; |
298 | } |
299 | |
300 | public function getTopInheritanceStruct(): ?Struct |
301 | { |
302 | $struct = $this->getInheritanceStruct(); |
303 | $latestValidStruct = $struct; |
304 | while ($struct instanceof Struct) { |
305 | $struct = $struct->getInheritanceStruct(); |
306 | if ($struct instanceof Struct) { |
307 | $latestValidStruct = $struct; |
308 | } |
309 | } |
310 | |
311 | return $latestValidStruct; |
312 | } |
313 | |
314 | public function getMeta(): array |
315 | { |
316 | $inheritanceStruct = $this->getInheritanceStruct(); |
317 | |
318 | return $this->mergeMeta(($inheritanceStruct && !$inheritanceStruct->isStruct()) ? $inheritanceStruct->getMeta() : [], parent::getMeta()); |
319 | } |
320 | |
321 | public function getReservedMethodsInstance(?string $filename = null): AbstractReservedWord |
322 | { |
323 | $instance = StructReservedMethod::instance($filename); |
324 | if ($this->isArray()) { |
325 | $instance = StructArrayReservedMethod::instance($filename); |
326 | } |
327 | |
328 | return $instance; |
329 | } |
330 | |
331 | public function getTypes(): array |
332 | { |
333 | return $this->types; |
334 | } |
335 | |
336 | public function isUnion(): bool |
337 | { |
338 | return 0 < count($this->types); |
339 | } |
340 | |
341 | public function setTypes(array $types): self |
342 | { |
343 | $this->types = $types; |
344 | |
345 | return $this; |
346 | } |
347 | |
348 | public function setAttributesFromSerializedJson(array $attributes): void |
349 | { |
350 | foreach ($attributes as $attribute) { |
351 | $this->attributes->add(self::instanceFromSerializedJson($this->generator, $attribute)->setOwner($this)); |
352 | } |
353 | } |
354 | |
355 | public function setValuesFromSerializedJson(array $values): void |
356 | { |
357 | foreach ($values as $value) { |
358 | $this->values->add(self::instanceFromSerializedJson($this->generator, $value)->setOwner($this)); |
359 | } |
360 | } |
361 | |
362 | protected function getAllAttributes(bool $includeInheritanceAttributes, bool $requiredFirst): StructAttributeContainer |
363 | { |
364 | $allAttributes = new StructAttributeContainer($this->getGenerator()); |
365 | if ($includeInheritanceAttributes) { |
366 | $this->addInheritanceAttributes($allAttributes); |
367 | } |
368 | |
369 | foreach ($this->attributes as $attribute) { |
370 | $allAttributes->add($attribute); |
371 | } |
372 | |
373 | if ($requiredFirst) { |
374 | $attributes = $this->putRequiredAttributesFirst($allAttributes); |
375 | } else { |
376 | $attributes = $allAttributes; |
377 | } |
378 | |
379 | return $attributes; |
380 | } |
381 | |
382 | protected function addInheritanceAttributes(StructAttributeContainer $attributes): void |
383 | { |
384 | if (!empty($this->getInheritance()) && ($model = $this->getInheritanceStruct()) instanceof Struct) { |
385 | while ($model instanceof Struct && $model->isStruct()) { |
386 | foreach ($model->getAttributes() as $attribute) { |
387 | $attributes->add($attribute); |
388 | } |
389 | $model = $model->getInheritanceStruct(); |
390 | } |
391 | } |
392 | } |
393 | |
394 | protected function putRequiredAttributesFirst(StructAttributeContainer $allAttributes): StructAttributeContainer |
395 | { |
396 | $attributes = new StructAttributeContainer($this->getGenerator()); |
397 | $requiredAttributes = []; |
398 | $notRequiredAttributes = []; |
399 | $nullableNotRequiredAttributes = []; |
400 | |
401 | /** @var StructAttribute $attribute */ |
402 | foreach ($allAttributes as $attribute) { |
403 | if ($attribute->isRequired() && !$attribute->isNullable()) { |
404 | $requiredAttributes[] = $attribute; |
405 | } elseif (!$attribute->isNullable()) { |
406 | $notRequiredAttributes[] = $attribute; |
407 | } else { |
408 | $nullableNotRequiredAttributes[] = $attribute; |
409 | } |
410 | } |
411 | |
412 | array_walk($requiredAttributes, [$attributes, 'add']); |
413 | array_walk($notRequiredAttributes, [$attributes, 'add']); |
414 | array_walk($nullableNotRequiredAttributes, [$attributes, 'add']); |
415 | |
416 | unset($requiredAttributes, $notRequiredAttributes, $nullableNotRequiredAttributes); |
417 | |
418 | return $attributes; |
419 | } |
420 | |
421 | protected function setValues(StructValueContainer $structValueContainer): self |
422 | { |
423 | $this->values = $structValueContainer; |
424 | |
425 | return $this; |
426 | } |
427 | |
428 | protected function toJsonSerialize(): array |
429 | { |
430 | return [ |
431 | 'attributes' => $this->attributes, |
432 | 'restriction' => $this->isRestriction, |
433 | 'struct' => $this->isStruct, |
434 | 'types' => $this->types, |
435 | 'values' => $this->values, |
436 | 'list' => $this->list, |
437 | ]; |
438 | } |
439 | } |