Passed
Push — feature/issue-124 ( 167236...6b1eff )
by Mikaël
07:01
created

Struct::setValuesFromSerializedJson()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 3
CRAP Score 2

Importance

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