Completed
Push — feature/issue-200 ( 2f17be )
by Mikaël
45:53
created

Struct::getTopInheritance()   A

Complexity

Conditions 4
Paths 2

Size

Total Lines 14
Code Lines 9

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 4
eloc 9
nc 2
nop 0
dl 0
loc 14
rs 9.9666
c 0
b 0
f 0
1
<?php
2
3
namespace WsdlToPhp\PackageGenerator\Model;
4
5
use WsdlToPhp\PackageGenerator\Generator\Utils;
6
use WsdlToPhp\PackageGenerator\Container\Model\StructValue as StructValueContainer;
7
use WsdlToPhp\PackageGenerator\Container\Model\StructAttribute as StructAttributeContainer;
8
use WsdlToPhp\PackageGenerator\Generator\Generator;
9
use WsdlToPhp\PackageGenerator\ConfigurationReader\StructReservedMethod;
10
use WsdlToPhp\PackageGenerator\ConfigurationReader\StructArrayReservedMethod;
11
12
/**
13
 * Class Struct stands for an available struct described in the WSDL
14
 */
15
class Struct extends AbstractModel
16
{
17
    /**
18
     * @var string
19
     */
20
    const DOC_SUB_PACKAGE_STRUCTS = 'Structs';
21
    /**
22
     * @var string
23
     */
24
    const DOC_SUB_PACKAGE_ENUMERATIONS = 'Enumerations';
25
    /**
26
     * @var string
27
     */
28
    const DOC_SUB_PACKAGE_ARRAYS = 'Arrays';
29
    /**
30
     * @var string
31
     */
32
    const DEFAULT_ENUM_TYPE = 'string';
33
    /**
34
     * Attributes of the struct
35
     * @var StructAttributeContainer
36
     */
37
    protected $attributes;
38
    /**
39
     * Is the struct a restriction with defined values  ?
40
     * @var bool
41
     */
42
    protected $isRestriction = false;
43
    /**
44
     * If the struct is a restriction with values, then store values
45
     * @var StructValueContainer
46
     */
47
    protected $values;
48
    /**
49
     * If the struct is a union with types, then store types
50
     * @var string[]
51
     */
52
    protected $types;
53
    /**
54
     * Defines if the current struct is a concrete struct or just a virtual struct to store meta information
55
     * @var bool
56
     */
57
    protected $isStruct = false;
58
    /**
59
     * Defines if the current struct is a list of a type or not.
60
     * If it is a list of a type, then the list property value is the type
61
     * @var string
62
     */
63
    protected $list = '';
64
    /**
65
     * Main constructor
66
     * @see AbstractModel::__construct()
67
     * @uses Struct::setStruct()
68
     * @param Generator $generator
69
     * @param string $name the original name
70
     * @param bool $isStruct defines if it's a real struct or not
71
     * @param bool $isRestriction defines if it's an enumeration or not
72
     */
73
    public function __construct(Generator $generator, $name, $isStruct = true, $isRestriction = false)
74
    {
75
        parent::__construct($generator, $name);
76
        $this
77
            ->setStruct($isStruct)
78
            ->setRestriction($isRestriction)
79
            ->setAttributes(new StructAttributeContainer($generator))
80
            ->setValues(new StructValueContainer($generator))
81
            ->setTypes([]);
82
    }
83
    /**
84
     * Returns the contextual part of the class name for the package
85
     * @see AbstractModel::getContextualPart()
86
     * @uses Struct::isRestriction()
87
     * @return string
88
     */
89
    public function getContextualPart()
90
    {
91
        $part = $this->getGenerator()->getOptionStructsFolder();
92
        if ($this->isRestriction()) {
93
            $part = $this->getGenerator()->getOptionEnumsFolder();
94
        } elseif ($this->isArray()) {
95
            $part = $this->getGenerator()->getOptionArraysFolder();
96
        }
97
        return $part;
98
    }
99
    /**
100
     * Returns the sub package name which the model belongs to
101
     * Must be overridden by sub classes
102
     * @see AbstractModel::getDocSubPackages()
103
     * @uses Struct::isRestriction()
104
     * @return array
105
     */
106
    public function getDocSubPackages()
107
    {
108
        $package = self::DOC_SUB_PACKAGE_STRUCTS;
109
        if ($this->isRestriction()) {
110
            $package = self::DOC_SUB_PACKAGE_ENUMERATIONS;
111
        } elseif ($this->isArray()) {
112
            $package = self::DOC_SUB_PACKAGE_ARRAYS;
113
        }
114
        return [
115
            $package,
116
        ];
117
    }
118
    /**
119
     * Returns true if the current struct is a collection of values (like an array or a list of values)
120
     * @uses AbstractModel::getName()
121
     * @uses Struct::countOwnAttributes()
122
     * @return bool
123
     */
124
    public function isArray()
125
    {
126
        return
127
        (
128
            (
129
                (
130
                    ($this->isStruct() && $this->countAllAttributes() === 1) ||
131
                    (!$this->isStruct() && $this->countOwnAttributes() <= 1)
132
                ) &&
133
                mb_stripos($this->getName(), 'array') !== false
134
            ) ||
135
            (!$this->isStruct() && $this->getMetaValueFirstSet(['arraytype', 'arrayType'], false) !== false)
136
        );
137
    }
138
    /**
139
     * Returns the attributes of the struct and potentially from the parent class
140
     * @uses AbstractModel::getInheritance()
141
     * @uses Struct::isStruct()
142
     * @uses Struct::getAttributes()
143
     * @param bool $includeInheritanceAttributes include the attributes of parent class, default parent attributes are not included. If true, then the array is an associative array containing and index "attribute" for the StructAttribute object and an index "model" for the Struct object.
144
     * @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
145
     * @return StructAttributeContainer
146
     */
147
    public function getAttributes($includeInheritanceAttributes = false, $requiredFirst = false)
148
    {
149
        if ($includeInheritanceAttributes === false && $requiredFirst === false) {
150
            $attributes = $this->attributes;
151
        } else {
152
            $attributes = $this->getAllAttributes($includeInheritanceAttributes, $requiredFirst);
153
        }
154
        return $attributes;
155
    }
156
    /**
157
     * @param bool $includeInheritanceAttributes
158
     * @param bool $requiredFirst
159
     * @return StructAttributeContainer
160
     */
161
    protected function getAllAttributes($includeInheritanceAttributes, $requiredFirst)
162
    {
163
        $allAttributes = new StructAttributeContainer($this->getGenerator());
164
        if ($includeInheritanceAttributes === true) {
165
            $this->addInheritanceAttributes($allAttributes);
166
        }
167
        foreach ($this->attributes as $attribute) {
168
            $allAttributes->add($attribute);
169
        }
170
        if ($requiredFirst === true) {
171
            $attributes = $this->putRequiredFirst($allAttributes);
172
        } else {
173
            $attributes = $allAttributes;
174
        }
175
        return $attributes;
176
    }
177
    /**
178
     * @param StructAttributeContainer $attributes
179
     */
180
    protected function addInheritanceAttributes(StructAttributeContainer $attributes)
181
    {
182
        if ($this->getInheritance() != '' && ($model = $this->getInheritanceStruct()) instanceof Struct) {
183
            while ($model instanceof Struct && $model->isStruct()) {
184
                foreach ($model->getAttributes() as $attribute) {
185
                    $attributes->add($attribute);
186
                }
187
                $model = $model->getInheritanceStruct();
188
            }
189
        }
190
    }
191
    /**
192
     * @param StructAttributeContainer $allAttributes
193
     * @return StructAttributeContainer
194
     */
195
    protected function putRequiredFirst(StructAttributeContainer $allAttributes)
196
    {
197
        $attributes = new StructAttributeContainer($this->getGenerator());
198
        $requiredAttributes = new StructAttributeContainer($this->getGenerator());
199
        $notRequiredAttributes = new StructAttributeContainer($this->getGenerator());
200
        foreach ($allAttributes as $attribute) {
201
            if ($attribute->isRequired()) {
202
                $requiredAttributes->add($attribute);
203
            } else {
204
                $notRequiredAttributes->add($attribute);
205
            }
206
        }
207
        foreach ($requiredAttributes as $attribute) {
208
            $attributes->add($attribute);
209
        }
210
        foreach ($notRequiredAttributes as $attribute) {
211
            $attributes->add($attribute);
212
        }
213
        unset($requiredAttributes, $notRequiredAttributes);
214
        return $attributes;
215
    }
216
    /**
217
     * Returns the number of own attributes
218
     * @uses Struct::getAttributes()
219
     * @return int
220
     */
221
    public function countOwnAttributes()
222
    {
223
        return $this->getAttributes(false, false)->count();
224
    }
225
    /**
226
     * Returns the number of all attributes
227
     * @uses Struct::getAttributes()
228
     * @return int
229
     */
230
    public function countAllAttributes()
231
    {
232
        return $this->getAttributes(true)->count();
233
    }
234
    /**
235
     * Sets the attributes of the struct
236
     * @param StructAttributeContainer $structAttributeContainer
237
     * @return Struct
238
     */
239
    public function setAttributes(StructAttributeContainer $structAttributeContainer)
240
    {
241
        $this->attributes = $structAttributeContainer;
242
        return $this;
243
    }
244
    /**
245
     * Adds attribute based on its original name
246
     * @throws \InvalidArgumentException
247
     * @param string $attributeName the attribute name
248
     * @param string $attributeType the attribute type
249
     * @return Struct
250
     */
251
    public function addAttribute($attributeName, $attributeType)
252
    {
253
        if (empty($attributeName) || empty($attributeType)) {
254
            throw new \InvalidArgumentException(sprintf('Attribute name "%s" and/or attribute type "%s" is invalid for Struct "%s"', $attributeName, $attributeType, $this->getName()), __LINE__);
255
        }
256
        if ($this->attributes->getStructAttributeByName($attributeName) === null) {
257
            $structAttribute = new StructAttribute($this->getGenerator(), $attributeName, $attributeType, $this);
258
            $this->attributes->add($structAttribute);
259
        }
260
        return $this;
261
    }
262
    /**
263
     * Returns the attribute by its name, otherwise null
264
     * @uses Struct::getAttributes()
265
     * @param string $attributeName the original attribute name
266
     * @return StructAttribute|null
267
     */
268
    public function getAttribute($attributeName)
269
    {
270
        return $this->attributes->getStructAttributeByName($attributeName);
271
    }
272
    /**
273
     * Returns the attribute by its cleaned name, otherwise null
274
     * @uses Struct::getAttributes()
275
     * @param string $attributeCleanName the cleaned attribute name
276
     * @return StructAttribute|null
277
     */
278
    public function getAttributeByCleanName($attributeCleanName)
279
    {
280
        return $this->attributes->getStructAttributeByCleanName($attributeCleanName);
281
    }
282
    /**
283
     * Returns the isRestriction value
284
     * @return bool
285
     */
286
    public function isRestriction()
287
    {
288
        return $this->isRestriction;
289
    }
290
    /**
291
     * Sets the isRestriction value
292
     * @param bool $isRestriction
293
     * @return Struct
294
     */
295
    public function setRestriction($isRestriction = true)
296
    {
297
        $this->isRestriction = $isRestriction;
298
        return $this;
299
    }
300
    /**
301
     * Returns the isStruct value
302
     * @return bool
303
     */
304
    public function isStruct()
305
    {
306
        return $this->isStruct;
307
    }
308
    /**
309
     * Sets the isStruct value
310
     * @param bool $isStruct
311
     * @return Struct
312
     */
313
    public function setStruct($isStruct = true)
314
    {
315
        $this->isStruct = $isStruct;
316
        return $this;
317
    }
318
    /**
319
     * Returns the list value
320
     * @return string
321
     */
322
    public function getList()
323
    {
324
        return $this->list;
325
    }
326
    /**
327
     * Returns if the current struct is a list
328
     * List are a set of basic-type values
329
     * @return bool
330
     */
331
    public function isList()
332
    {
333
        return !empty($this->list);
334
    }
335
    /**
336
     * Sets the list value
337
     * @param string $list
338
     * @return Struct
339
     */
340
    public function setList($list = '')
341
    {
342
        $this->list = $list;
343
        return $this;
344
    }
345
    /**
346
     * Returns the values for an enumeration
347
     * @return StructValueContainer
348
     */
349
    public function getValues()
350
    {
351
        return $this->values;
352
    }
353
    /**
354
     * Sets the values for an enumeration
355
     * @param StructValueContainer $structValueContainer
356
     * @return Struct
357
     */
358
    protected function setValues(StructValueContainer $structValueContainer)
359
    {
360
        $this->values = $structValueContainer;
361
        return $this;
362
    }
363
    /**
364
     * Adds value to values array
365
     * @uses Struct::getValue()
366
     * @uses Struct::getValues()
367
     * @param mixed $value the original value
368
     * @return Struct
369
     */
370
    public function addValue($value)
371
    {
372
        if ($this->getValue($value) === null) {
373
            // issue #177, rare case: a struct and an enum has the same name and the enum is not detected by the SoapClient,
374
            // then we need to create the enumeration struct in order to deduplicate the two structs
375
            // this is why enumerations has to be parsed before any other elements by the WSDL parsers
376
            if (0 < $this->countOwnAttributes()) {
377
                $enum = new static($this->getGenerator(), $this->getName(), true, true);
378
                $enum
379
                    ->setInheritance(self::DEFAULT_ENUM_TYPE)
380
                    ->getValues()->add(new StructValue($enum->getGenerator(), $value, $enum->getValues()->count(), $enum));
381
                $this->getGenerator()->getStructs()->add($enum);
382
                return $enum;
383
            } else {
384
                $this
385
                    ->setStruct(true)
386
                    ->setRestriction(true)
387
                    ->values->add(new StructValue($this->getGenerator(), $value, $this->getValues()->count(), $this));
388
            }
389
        }
390
        return $this;
391
    }
392
    /**
393
     * Gets the value object for the given value
394
     * @uses Struct::getValues()
395
     * @uses AbstractModel::getName()
396
     * @param string $value Value name
397
     * @return StructValue|null
398
     */
399
    public function getValue($value)
400
    {
401
        return $this->values->getStructValueByName($value);
402
    }
403
    /**
404
     * Allows to define from which class the current model extends
405
     * @param bool $short
406
     * @return string
407
     */
408
    public function getExtends($short = false)
409
    {
410
        $extends = '';
411
        if ($this->isArray()) {
412
            $extends = $this->getGenerator()->getOptionStructArrayClass();
413
        } elseif (!$this->isRestriction()) {
414
            $extends = $this->getGenerator()->getOptionStructClass();
415
        }
416
        return $short ? Utils::removeNamespace($extends) : $extends;
417
    }
418
    /**
419
     * @return Struct|null
420
     */
421
    public function getInheritanceStruct()
422
    {
423
        return $this->getName() === $this->getInheritance() ? null : $this->getGenerator()->getStructByName(str_replace('[]', '', $this->getInheritance()));
424
    }
425
    /**
426
     * @return string
427
     */
428
    public function getTopInheritance()
429
    {
430
        $inheritance = $this->getInheritance();
431
        if (!empty($inheritance)) {
432
            $struct = $this->getInheritanceStruct();
433
            while ($struct instanceof Struct) {
434
                $structInheritance = $struct->getInheritance();
435
                if (!empty($structInheritance)) {
436
                    $inheritance = $structInheritance;
437
                }
438
                $struct = $struct->getInheritanceStruct();
439
            }
440
        }
441
        return $inheritance;
442
    }
443
    /**
444
     * @return Struct|null
445
     */
446
    public function getTopInheritanceStruct()
447
    {
448
        $struct = $this->getInheritanceStruct();
449
        $latestValidStruct = $struct;
450
        while ($struct instanceof Struct) {
451
            $struct = $struct->getInheritanceStruct();
452
            if ($struct instanceof Struct) {
453
                $latestValidStruct = $struct;
454
            }
455
        }
456
        return $latestValidStruct;
457
    }
458
    /**
459
     * @see \WsdlToPhp\PackageGenerator\Model\AbstractModel::getMeta()
460
     * @return string[]
461
     */
462
    public function getMeta()
463
    {
464
        $inheritanceStruct = $this->getInheritanceStruct();
465
        return $this->mergeMeta(($inheritanceStruct && !$inheritanceStruct->isStruct()) ? $inheritanceStruct->getMeta() : [], parent::getMeta());
466
    }
467
    /**
468
     * @param $filename
469
     * @return StructReservedMethod|StructArrayReservedMethod
470
     */
471
    public function getReservedMethodsInstance($filename = null)
472
    {
473
        $instance = StructReservedMethod::instance($filename);
474
        if ($this->isArray()) {
475
            $instance = StructArrayReservedMethod::instance($filename);
476
        }
477
        return $instance;
478
    }
479
    /**
480
     * @return string[]
481
     */
482
    public function getTypes()
483
    {
484
        return $this->types;
485
    }
486
    /**
487
     * @return boolean
488
     */
489
    public function isUnion()
490
    {
491
        return count($this->types) > 0;
492
    }
493
    /**
494
     * @param string[] $types
495
     * @return Struct
496
     */
497
    public function setTypes(array $types)
498
    {
499
        $this->types = $types;
500
        return $this;
501
    }
502
    /**
503
     * {@inheritDoc}
504
     * @see \WsdlToPhp\PackageGenerator\Model\AbstractModel::toJsonSerialize()
505
     */
506
    protected function toJsonSerialize()
507
    {
508
        return [
509
            'attributes' => $this->attributes,
510
            'restriction' => $this->isRestriction,
511
            'struct' => $this->isStruct,
512
            'types' => $this->types,
513
            'values' => $this->values,
514
            'list' => $this->list,
515
        ];
516
    }
517
    /**
518
     * @param array $attributes
519
     */
520
    public function setAttributesFromSerializedJson(array $attributes)
521
    {
522
        foreach ($attributes as $attribute) {
523
            $this->attributes->add(self::instanceFromSerializedJson($this->generator, $attribute)->setOwner($this));
524
        }
525
    }
526
    /**
527
     * @param array $values
528
     */
529
    public function setValuesFromSerializedJson(array $values)
530
    {
531
        foreach ($values as $value) {
532
            $this->values->add(self::instanceFromSerializedJson($this->generator, $value)->setOwner($this));
533
        }
534
    }
535
}
536