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 | 434 | public function __construct(Generator $generator, $name, $isStruct = true, $isRestriction = false) |
|
59 | { |
||
60 | 434 | parent::__construct($generator, $name); |
|
61 | 434 | $this |
|
62 | 434 | ->setStruct($isStruct) |
|
63 | 434 | ->setRestriction($isRestriction) |
|
64 | 434 | ->setAttributes(new StructAttributeContainer($generator)) |
|
65 | 434 | ->setValues(new StructValueContainer($generator)) |
|
66 | 434 | ; |
|
67 | } |
||
68 | |||
69 | 232 | public function getContextualPart(): string |
|
70 | { |
||
71 | 232 | $part = $this->getGenerator()->getOptionStructsFolder(); |
|
72 | 232 | if ($this->isRestriction()) { |
|
73 | 76 | $part = $this->getGenerator()->getOptionEnumsFolder(); |
|
74 | 210 | } elseif ($this->isArray()) { |
|
75 | 34 | $part = $this->getGenerator()->getOptionArraysFolder(); |
|
76 | } |
||
77 | |||
78 | 232 | return $part; |
|
79 | } |
||
80 | |||
81 | 136 | public function getDocSubPackages(): array |
|
82 | { |
||
83 | 136 | $package = self::DOC_SUB_PACKAGE_STRUCTS; |
|
84 | 136 | if ($this->isRestriction()) { |
|
85 | 46 | $package = self::DOC_SUB_PACKAGE_ENUMERATIONS; |
|
86 | 116 | } elseif ($this->isArray()) { |
|
87 | 20 | $package = self::DOC_SUB_PACKAGE_ARRAYS; |
|
88 | } |
||
89 | |||
90 | 136 | return [ |
|
91 | 136 | $package, |
|
92 | 136 | ]; |
|
93 | } |
||
94 | |||
95 | 248 | public function isArray(): bool |
|
96 | { |
||
97 | 248 | return |
|
98 | 248 | ( |
|
99 | 248 | ( |
|
100 | 248 | ($this->isStruct() && 1 === $this->countAllAttributes()) |
|
101 | 248 | || (!$this->isStruct() && 1 >= $this->countOwnAttributes()) |
|
102 | 248 | ) |
|
103 | 248 | && false !== mb_stripos($this->getName(), 'array') |
|
104 | 248 | ) |
|
105 | 248 | || (!$this->isStruct() && false !== $this->getMetaValueFirstSet(['arraytype', 'arrayType'], false)) |
|
106 | 248 | ; |
|
107 | } |
||
108 | |||
109 | 282 | public function getAttributes(bool $includeInheritanceAttributes = false, bool $requiredFirst = false): StructAttributeContainer |
|
110 | { |
||
111 | 282 | if (!$includeInheritanceAttributes && !$requiredFirst) { |
|
112 | 192 | $attributes = $this->attributes; |
|
113 | } else { |
||
114 | 242 | $attributes = $this->getAllAttributes($includeInheritanceAttributes, $requiredFirst); |
|
115 | } |
||
116 | |||
117 | 282 | 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 | 138 | public function getProperAttributes(bool $requiredFirst = false): StructAttributeContainer |
|
127 | { |
||
128 | 138 | $properAttributes = new StructAttributeContainer($this->getGenerator()); |
|
129 | 138 | $parentAttributes = new StructAttributeContainer($this->getGenerator()); |
|
130 | |||
131 | 138 | if (!empty($this->getInheritance()) && ($model = $this->getInheritanceStruct()) instanceof Struct) { |
|
132 | 20 | while ($model instanceof Struct && $model->isStruct()) { |
|
133 | 18 | foreach ($model->getAttributes() as $attribute) { |
|
134 | 16 | $parentAttributes->add($attribute); |
|
135 | } |
||
136 | 18 | $model = $model->getInheritanceStruct(); |
|
137 | } |
||
138 | } |
||
139 | |||
140 | /** @var StructAttribute $attribute */ |
||
141 | 138 | foreach ($this->getAttributes() as $attribute) { |
|
142 | 118 | if ($parentAttributes->getStructAttributeByName($attribute->getName())) { |
|
143 | 4 | continue; |
|
144 | } |
||
145 | 114 | $properAttributes->add($attribute); |
|
146 | } |
||
147 | |||
148 | 138 | return $requiredFirst ? $this->putRequiredAttributesFirst($properAttributes) : $properAttributes; |
|
149 | } |
||
150 | |||
151 | 108 | public function countOwnAttributes(): int |
|
152 | { |
||
153 | 108 | return $this->getAttributes()->count(); |
|
154 | } |
||
155 | |||
156 | 238 | public function countAllAttributes(): int |
|
157 | { |
||
158 | 238 | return $this->getAttributes(true)->count(); |
|
159 | } |
||
160 | |||
161 | 434 | public function setAttributes(StructAttributeContainer $structAttributeContainer): self |
|
162 | { |
||
163 | 434 | $this->attributes = $structAttributeContainer; |
|
164 | |||
165 | 434 | return $this; |
|
166 | } |
||
167 | |||
168 | 146 | public function addAttribute(string $attributeName, string $attributeType): self |
|
169 | { |
||
170 | 146 | if (empty($attributeName) || empty($attributeType)) { |
|
171 | 4 | throw new \InvalidArgumentException(sprintf('Attribute name "%s" and/or attribute type "%s" is invalid for Struct "%s"', $attributeName, $attributeType, $this->getName()), __LINE__); |
|
172 | } |
||
173 | 142 | if (is_null($this->attributes->getStructAttributeByName($attributeName))) { |
|
174 | 142 | $structAttribute = new StructAttribute($this->getGenerator(), $attributeName, $attributeType, $this); |
|
175 | 142 | $this->attributes->add($structAttribute); |
|
176 | } |
||
177 | |||
178 | 142 | return $this; |
|
179 | } |
||
180 | |||
181 | 164 | public function getAttribute(string $attributeName): ?StructAttribute |
|
182 | { |
||
183 | 164 | return $this->attributes->getStructAttributeByName($attributeName); |
|
184 | } |
||
185 | |||
186 | 46 | public function getAttributeByCleanName(string $attributeCleanName): ?StructAttribute |
|
187 | { |
||
188 | 46 | return $this->attributes->getStructAttributeByCleanName($attributeCleanName); |
|
189 | } |
||
190 | |||
191 | 246 | public function isRestriction(): bool |
|
192 | { |
||
193 | 246 | return $this->isRestriction; |
|
194 | } |
||
195 | |||
196 | 434 | public function setRestriction($isRestriction = true): self |
|
197 | { |
||
198 | 434 | $this->isRestriction = $isRestriction; |
|
199 | |||
200 | 434 | return $this; |
|
201 | } |
||
202 | |||
203 | 280 | public function isStruct(): bool |
|
204 | { |
||
205 | 280 | return $this->isStruct; |
|
206 | } |
||
207 | |||
208 | 434 | public function setStruct(bool $isStruct = true): self |
|
209 | { |
||
210 | 434 | $this->isStruct = $isStruct; |
|
211 | |||
212 | 434 | return $this; |
|
213 | } |
||
214 | |||
215 | 10 | public function getList(): string |
|
216 | { |
||
217 | 10 | return $this->list; |
|
218 | } |
||
219 | |||
220 | 112 | public function isList(): bool |
|
221 | { |
||
222 | 112 | return !empty($this->list); |
|
223 | } |
||
224 | |||
225 | 222 | public function setList(string $list = ''): self |
|
226 | { |
||
227 | 222 | $this->list = $list; |
|
228 | |||
229 | 222 | return $this; |
|
230 | } |
||
231 | |||
232 | 66 | public function getValues(): StructValueContainer |
|
233 | { |
||
234 | 66 | return $this->values; |
|
235 | } |
||
236 | |||
237 | 34 | public function addValue($value): self |
|
238 | { |
||
239 | 34 | 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 | 34 | 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 | 34 | $this |
|
252 | 34 | ->setStruct(true) |
|
253 | 34 | ->setRestriction(true) |
|
254 | 34 | ->getValues()->add(new StructValue($this->getGenerator(), $value, $this->getValues()->count(), $this)); |
|
255 | } |
||
256 | |||
257 | 34 | return $this; |
|
258 | } |
||
259 | |||
260 | 66 | public function getValue($value): ?StructValue |
|
261 | { |
||
262 | 66 | return $this->values->getStructValueByName($value); |
|
263 | } |
||
264 | |||
265 | 132 | public function getExtends(bool $short = false): string |
|
266 | { |
||
267 | 132 | if ($this->isArray()) { |
|
268 | 20 | $extends = $this->getGenerator()->getOptionStructArrayClass(); |
|
269 | 118 | } elseif ($this->isRestriction()) { |
|
270 | 44 | $extends = $this->getGenerator()->getOptionStructEnumClass(); |
|
271 | } else { |
||
272 | 100 | $extends = $this->getGenerator()->getOptionStructClass(); |
|
273 | } |
||
274 | |||
275 | 132 | return $short ? Utils::removeNamespace($extends) : $extends; |
|
276 | } |
||
277 | |||
278 | 186 | public function getInheritanceStruct(): ?Struct |
|
279 | { |
||
280 | 186 | return $this->getName() === $this->getInheritance() ? null : $this->getGenerator()->getStructByName(str_replace('[]', '', $this->getInheritance())); |
|
281 | } |
||
282 | |||
283 | 116 | public function getTopInheritance(): string |
|
284 | { |
||
285 | 116 | $inheritance = $this->getInheritance(); |
|
286 | 116 | if (!empty($inheritance)) { |
|
287 | 88 | $struct = $this->getInheritanceStruct(); |
|
288 | 88 | while ($struct instanceof Struct) { |
|
289 | 46 | $structInheritance = $struct->getInheritance(); |
|
290 | 46 | if (!empty($structInheritance)) { |
|
291 | 28 | $inheritance = $structInheritance; |
|
292 | } |
||
293 | 46 | $struct = $struct->getInheritanceStruct(); |
|
294 | } |
||
295 | } |
||
296 | |||
297 | 116 | return $inheritance; |
|
298 | } |
||
299 | |||
300 | 8 | public function getTopInheritanceStruct(): ?Struct |
|
301 | { |
||
302 | 8 | $struct = $this->getInheritanceStruct(); |
|
303 | 8 | $latestValidStruct = $struct; |
|
304 | 8 | while ($struct instanceof Struct) { |
|
305 | 4 | $struct = $struct->getInheritanceStruct(); |
|
306 | 4 | if ($struct instanceof Struct) { |
|
307 | $latestValidStruct = $struct; |
||
308 | } |
||
309 | } |
||
310 | |||
311 | 8 | return $latestValidStruct; |
|
312 | } |
||
313 | |||
314 | 172 | public function getMeta(): array |
|
315 | { |
||
316 | 172 | $inheritanceStruct = $this->getInheritanceStruct(); |
|
317 | |||
318 | 172 | return $this->mergeMeta(($inheritanceStruct && !$inheritanceStruct->isStruct()) ? $inheritanceStruct->getMeta() : [], parent::getMeta()); |
|
319 | } |
||
320 | |||
321 | 118 | public function getReservedMethodsInstance(?string $filename = null): AbstractReservedWord |
|
322 | { |
||
323 | 118 | $instance = StructReservedMethod::instance($filename); |
|
324 | 118 | if ($this->isArray()) { |
|
325 | 22 | $instance = StructArrayReservedMethod::instance($filename); |
|
326 | } |
||
327 | |||
328 | 118 | return $instance; |
|
0 ignored issues
–
show
Bug
Best Practice
introduced
by
![]() |
|||
329 | } |
||
330 | |||
331 | 2 | public function getTypes(): array |
|
332 | { |
||
333 | 2 | return $this->types; |
|
334 | } |
||
335 | |||
336 | 110 | public function isUnion(): bool |
|
337 | { |
||
338 | 110 | return 0 < count($this->types); |
|
339 | } |
||
340 | |||
341 | 234 | public function setTypes(array $types): self |
|
342 | { |
||
343 | 234 | $this->types = $types; |
|
344 | |||
345 | 234 | return $this; |
|
346 | } |
||
347 | |||
348 | 214 | public function setAttributesFromSerializedJson(array $attributes): void |
|
349 | { |
||
350 | 214 | foreach ($attributes as $attribute) { |
|
351 | 212 | $this->attributes->add(self::instanceFromSerializedJson($this->generator, $attribute)->setOwner($this)); |
|
352 | } |
||
353 | } |
||
354 | |||
355 | 214 | public function setValuesFromSerializedJson(array $values): void |
|
356 | { |
||
357 | 214 | foreach ($values as $value) { |
|
358 | 198 | $this->values->add(self::instanceFromSerializedJson($this->generator, $value)->setOwner($this)); |
|
359 | } |
||
360 | } |
||
361 | |||
362 | 242 | protected function getAllAttributes(bool $includeInheritanceAttributes, bool $requiredFirst): StructAttributeContainer |
|
363 | { |
||
364 | 242 | $allAttributes = new StructAttributeContainer($this->getGenerator()); |
|
365 | 242 | if ($includeInheritanceAttributes) { |
|
366 | 242 | $this->addInheritanceAttributes($allAttributes); |
|
367 | } |
||
368 | |||
369 | 242 | foreach ($this->attributes as $attribute) { |
|
370 | 212 | $allAttributes->add($attribute); |
|
371 | } |
||
372 | |||
373 | 242 | if ($requiredFirst) { |
|
374 | 2 | $attributes = $this->putRequiredAttributesFirst($allAttributes); |
|
375 | } else { |
||
376 | 242 | $attributes = $allAttributes; |
|
377 | } |
||
378 | |||
379 | 242 | return $attributes; |
|
380 | } |
||
381 | |||
382 | 242 | protected function addInheritanceAttributes(StructAttributeContainer $attributes): void |
|
383 | { |
||
384 | 242 | if (!empty($this->getInheritance()) && ($model = $this->getInheritanceStruct()) instanceof Struct) { |
|
385 | 46 | while ($model instanceof Struct && $model->isStruct()) { |
|
386 | 38 | foreach ($model->getAttributes() as $attribute) { |
|
387 | 36 | $attributes->add($attribute); |
|
388 | } |
||
389 | 38 | $model = $model->getInheritanceStruct(); |
|
390 | } |
||
391 | } |
||
392 | } |
||
393 | |||
394 | 132 | protected function putRequiredAttributesFirst(StructAttributeContainer $allAttributes): StructAttributeContainer |
|
395 | { |
||
396 | 132 | $attributes = new StructAttributeContainer($this->getGenerator()); |
|
397 | 132 | $requiredAttributes = []; |
|
398 | 132 | $notRequiredAttributes = []; |
|
399 | 132 | $nullableNotRequiredAttributes = []; |
|
400 | |||
401 | /** @var StructAttribute $attribute */ |
||
402 | 132 | foreach ($allAttributes as $attribute) { |
|
403 | 110 | if ($attribute->isRequired() && !$attribute->isNullable()) { |
|
404 | 32 | $requiredAttributes[] = $attribute; |
|
405 | 100 | } elseif (!$attribute->isNullable()) { |
|
406 | 96 | $notRequiredAttributes[] = $attribute; |
|
407 | } else { |
||
408 | 18 | $nullableNotRequiredAttributes[] = $attribute; |
|
409 | } |
||
410 | } |
||
411 | |||
412 | 132 | array_walk($requiredAttributes, [$attributes, 'add']); |
|
413 | 132 | array_walk($notRequiredAttributes, [$attributes, 'add']); |
|
414 | 132 | array_walk($nullableNotRequiredAttributes, [$attributes, 'add']); |
|
415 | |||
416 | 132 | unset($requiredAttributes, $notRequiredAttributes, $nullableNotRequiredAttributes); |
|
417 | |||
418 | 132 | return $attributes; |
|
419 | } |
||
420 | |||
421 | 434 | protected function setValues(StructValueContainer $structValueContainer): self |
|
422 | { |
||
423 | 434 | $this->values = $structValueContainer; |
|
424 | |||
425 | 434 | return $this; |
|
426 | } |
||
427 | |||
428 | 2 | protected function toJsonSerialize(): array |
|
429 | { |
||
430 | 2 | return [ |
|
431 | 2 | 'attributes' => $this->attributes, |
|
432 | 2 | 'restriction' => $this->isRestriction, |
|
433 | 2 | 'struct' => $this->isStruct, |
|
434 | 2 | 'types' => $this->types, |
|
435 | 2 | 'values' => $this->values, |
|
436 | 2 | 'list' => $this->list, |
|
437 | 2 | ]; |
|
438 | } |
||
439 | } |
||
440 |