Passed
Push — master ( ab6b67...a48167 )
by Mikaël
74:03 queued 50:14
created

Struct::getReservedMethodsInstance()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 7
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 6
CRAP Score 2

Importance

Changes 0
Metric Value
cc 2
eloc 4
nc 2
nop 1
dl 0
loc 7
ccs 6
cts 6
cp 1
crap 2
rs 10
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 1210
    public function __construct(Generator $generator, $name, $isStruct = true, $isRestriction = false)
74
    {
75 1210
        parent::__construct($generator, $name);
76 606
        $this
77 1210
            ->setStruct($isStruct)
78 1210
            ->setRestriction($isRestriction)
79 1210
            ->setAttributes(new StructAttributeContainer($generator))
80 1210
            ->setValues(new StructValueContainer($generator))
81 1210
            ->setTypes([]);
82 1210
    }
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 630
    public function getContextualPart()
90
    {
91 630
        $part = $this->getGenerator()->getOptionStructsFolder();
92 630
        if ($this->isRestriction()) {
93 216
            $part = $this->getGenerator()->getOptionEnumsFolder();
94 600
        } elseif ($this->isArray()) {
95 90
            $part = $this->getGenerator()->getOptionArraysFolder();
96 45
        }
97 630
        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 360
    public function getDocSubPackages()
107
    {
108 360
        $package = self::DOC_SUB_PACKAGE_STRUCTS;
109 360
        if ($this->isRestriction()) {
110 132
            $package = self::DOC_SUB_PACKAGE_ENUMERATIONS;
111 333
        } elseif ($this->isArray()) {
112 48
            $package = self::DOC_SUB_PACKAGE_ARRAYS;
113 24
        }
114
        return [
115 360
            $package,
116 180
        ];
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 684
    public function isArray()
125
    {
126
        return
127
        (
128
            (
129
                (
130 684
                    ($this->isStruct() && $this->countAllAttributes() === 1) ||
131 660
                    (!$this->isStruct() && $this->countOwnAttributes() <= 1)
132 342
                ) &&
133 408
                mb_stripos($this->getName(), 'array') !== false
134 204
            ) ||
135 669
            (!$this->isStruct() && $this->getMetaValueFirstSet(['arraytype', 'arrayType'], false) !== false)
136 342
        );
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 774
    public function getAttributes($includeInheritanceAttributes = false, $requiredFirst = false)
148
    {
149 774
        if ($includeInheritanceAttributes === false && $requiredFirst === false) {
150 522
            $attributes = $this->attributes;
151 261
        } else {
152 648
            $attributes = $this->getAllAttributes($includeInheritanceAttributes, $requiredFirst);
153
        }
154 774
        return $attributes;
155
    }
156
    /**
157
     * @param bool $includeInheritanceAttributes
158
     * @param bool $requiredFirst
159
     * @return StructAttributeContainer
160
     */
161 648
    protected function getAllAttributes($includeInheritanceAttributes, $requiredFirst)
162
    {
163 648
        $allAttributes = new StructAttributeContainer($this->getGenerator());
164 648
        if ($includeInheritanceAttributes === true) {
165 648
            $this->addInheritanceAttributes($allAttributes);
166 324
        }
167 648
        foreach ($this->attributes as $attribute) {
168 582
            $allAttributes->add($attribute);
169 324
        }
170 648
        if ($requiredFirst === true) {
171 300
            $attributes = $this->putRequiredFirst($allAttributes);
172 150
        } else {
173 648
            $attributes = $allAttributes;
174
        }
175 648
        return $attributes;
176
    }
177
    /**
178
     * @param StructAttributeContainer $attributes
179
     */
180 648
    protected function addInheritanceAttributes(StructAttributeContainer $attributes)
181
    {
182 648
        if ($this->getInheritance() != '' && ($model = $this->getInheritanceStruct()) instanceof Struct) {
183 120
            while ($model instanceof Struct && $model->isStruct()) {
184 96
                foreach ($model->getAttributes() as $attribute) {
185 90
                    $attributes->add($attribute);
186 48
                }
187 96
                $model = $model->getInheritanceStruct();
188 48
            }
189 60
        }
190 648
    }
191
    /**
192
     * @param StructAttributeContainer $allAttributes
193
     * @return StructAttributeContainer
194
     */
195 300
    protected function putRequiredFirst(StructAttributeContainer $allAttributes)
196
    {
197 300
        $attributes = new StructAttributeContainer($this->getGenerator());
198 300
        $requiredAttributes = new StructAttributeContainer($this->getGenerator());
199 300
        $notRequiredAttributes = new StructAttributeContainer($this->getGenerator());
200 300
        foreach ($allAttributes as $attribute) {
201 294
            if ($attribute->isRequired()) {
202 90
                $requiredAttributes->add($attribute);
203 45
            } else {
204 278
                $notRequiredAttributes->add($attribute);
205
            }
206 150
        }
207 300
        foreach ($requiredAttributes as $attribute) {
208 90
            $attributes->add($attribute);
209 150
        }
210 300
        foreach ($notRequiredAttributes as $attribute) {
211 270
            $attributes->add($attribute);
212 150
        }
213 300
        unset($requiredAttributes, $notRequiredAttributes);
214 300
        return $attributes;
215
    }
216
    /**
217
     * Returns the number of own attributes
218
     * @uses Struct::getAttributes()
219
     * @return int
220
     */
221 306
    public function countOwnAttributes()
222
    {
223 306
        return $this->getAttributes(false, false)->count();
224
    }
225
    /**
226
     * Returns the number of all attributes
227
     * @uses Struct::getAttributes()
228
     * @return int
229
     */
230 648
    public function countAllAttributes()
231
    {
232 648
        return $this->getAttributes(true)->count();
233
    }
234
    /**
235
     * Sets the attributes of the struct
236
     * @param StructAttributeContainer $structAttributeContainer
237
     * @return Struct
238
     */
239 1210
    public function setAttributes(StructAttributeContainer $structAttributeContainer)
240
    {
241 1210
        $this->attributes = $structAttributeContainer;
242 1210
        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 432
    public function addAttribute($attributeName, $attributeType)
252
    {
253 432
        if (empty($attributeName) || empty($attributeType)) {
254 12
            throw new \InvalidArgumentException(sprintf('Attribute name "%s" and/or attribute type "%s" is invalid for Struct "%s"', $attributeName, $attributeType, $this->getName()), __LINE__);
255
        }
256 420
        if ($this->attributes->getStructAttributeByName($attributeName) === null) {
257 420
            $structAttribute = new StructAttribute($this->getGenerator(), $attributeName, $attributeType, $this);
258 420
            $this->attributes->add($structAttribute);
259 210
        }
260 420
        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 450
    public function getAttribute($attributeName)
269
    {
270 450
        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 120
    public function getAttributeByCleanName($attributeCleanName)
279
    {
280 120
        return $this->attributes->getStructAttributeByCleanName($attributeCleanName);
281
    }
282
    /**
283
     * Returns the isRestriction value
284
     * @return bool
285
     */
286 672
    public function isRestriction()
287
    {
288 672
        return $this->isRestriction;
289
    }
290
    /**
291
     * Sets the isRestriction value
292
     * @param bool $isRestriction
293
     * @return Struct
294
     */
295 1210
    public function setRestriction($isRestriction = true)
296
    {
297 1210
        $this->isRestriction = $isRestriction;
298 1210
        return $this;
299
    }
300
    /**
301
     * Returns the isStruct value
302
     * @return bool
303
     */
304 750
    public function isStruct()
305
    {
306 750
        return $this->isStruct;
307
    }
308
    /**
309
     * Sets the isStruct value
310
     * @param bool $isStruct
311
     * @return Struct
312
     */
313 1210
    public function setStruct($isStruct = true)
314
    {
315 1210
        $this->isStruct = $isStruct;
316 1210
        return $this;
317
    }
318
    /**
319
     * Returns the list value
320
     * @return string
321
     */
322 30
    public function getList()
323
    {
324 30
        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 306
    public function isList()
332
    {
333 306
        return !empty($this->list);
334
    }
335
    /**
336
     * Sets the list value
337
     * @param string $list
338
     * @return Struct
339
     */
340 570
    public function setList($list = '')
341
    {
342 570
        $this->list = $list;
343 570
        return $this;
344
    }
345
    /**
346
     * Returns the values for an enumeration
347
     * @return StructValueContainer
348
     */
349 198
    public function getValues()
350
    {
351 198
        return $this->values;
352
    }
353
    /**
354
     * Sets the values for an enumeration
355
     * @param StructValueContainer $structValueContainer
356
     * @return Struct
357
     */
358 1210
    protected function setValues(StructValueContainer $structValueContainer)
359
    {
360 1210
        $this->values = $structValueContainer;
361 1210
        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 108
    public function addValue($value)
371
    {
372 108
        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 108
            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 54
                $this
385 108
                    ->setStruct(true)
386 108
                    ->setRestriction(true)
387 108
                    ->values->add(new StructValue($this->getGenerator(), $value, $this->getValues()->count(), $this));
388
            }
389 54
        }
390 108
        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 198
    public function getValue($value)
400
    {
401 198
        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 348
    public function getExtends($short = false)
409
    {
410 348
        $extends = '';
411 348
        if ($this->isArray()) {
412 48
            $extends = $this->getGenerator()->getOptionStructArrayClass();
413 333
        } elseif ($this->isRestriction()) {
414 126
            $extends = $this->getGenerator()->getOptionStructEnumClass();
415 63
        } else {
416 270
            $extends = $this->getGenerator()->getOptionStructClass();
417
        }
418 348
        return $short ? Utils::removeNamespace($extends) : $extends;
419
    }
420
    /**
421
     * @return Struct|null
422
     */
423 486
    public function getInheritanceStruct()
424
    {
425 486
        return $this->getName() === $this->getInheritance() ? null : $this->getGenerator()->getStructByName(str_replace('[]', '', $this->getInheritance()));
426
    }
427
    /**
428
     * @return string
429
     */
430 330
    public function getTopInheritance()
431
    {
432 330
        $inheritance = $this->getInheritance();
433 330
        if (!empty($inheritance)) {
434 258
            $struct = $this->getInheritanceStruct();
435 258
            while ($struct instanceof Struct) {
436 138
                $structInheritance = $struct->getInheritance();
437 138
                if (!empty($structInheritance)) {
438 84
                    $inheritance = $structInheritance;
439 42
                }
440 138
                $struct = $struct->getInheritanceStruct();
441 69
            }
442 129
        }
443 330
        return $inheritance;
444
    }
445
    /**
446
     * @return Struct|null
447
     */
448 24
    public function getTopInheritanceStruct()
449
    {
450 24
        $struct = $this->getInheritanceStruct();
451 24
        $latestValidStruct = $struct;
452 24
        while ($struct instanceof Struct) {
453 12
            $struct = $struct->getInheritanceStruct();
454 12
            if ($struct instanceof Struct) {
455
                $latestValidStruct = $struct;
456
            }
457 6
        }
458 24
        return $latestValidStruct;
459
    }
460
    /**
461
     * @see \WsdlToPhp\PackageGenerator\Model\AbstractModel::getMeta()
462
     * @return string[]
463
     */
464 456
    public function getMeta()
465
    {
466 456
        $inheritanceStruct = $this->getInheritanceStruct();
467 456
        return $this->mergeMeta(($inheritanceStruct && !$inheritanceStruct->isStruct()) ? $inheritanceStruct->getMeta() : [], parent::getMeta());
468
    }
469
    /**
470
     * @param $filename
471
     * @return StructReservedMethod|StructArrayReservedMethod
472
     */
473 318
    public function getReservedMethodsInstance($filename = null)
474
    {
475 318
        $instance = StructReservedMethod::instance($filename);
476 318
        if ($this->isArray()) {
477 54
            $instance = StructArrayReservedMethod::instance($filename);
478 27
        }
479 318
        return $instance;
480
    }
481
    /**
482
     * @return string[]
483
     */
484 6
    public function getTypes()
485
    {
486 6
        return $this->types;
487
    }
488
    /**
489
     * @return boolean
490
     */
491 294
    public function isUnion()
492
    {
493 294
        return count($this->types) > 0;
494
    }
495
    /**
496
     * @param string[] $types
497
     * @return Struct
498
     */
499 1210
    public function setTypes(array $types)
500
    {
501 1210
        $this->types = $types;
502 1210
        return $this;
503
    }
504
    /**
505
     * {@inheritDoc}
506
     * @see \WsdlToPhp\PackageGenerator\Model\AbstractModel::toJsonSerialize()
507
     */
508 6
    protected function toJsonSerialize()
509
    {
510
        return [
511 6
            'attributes' => $this->attributes,
512 6
            'restriction' => $this->isRestriction,
513 6
            'struct' => $this->isStruct,
514 6
            'types' => $this->types,
515 6
            'values' => $this->values,
516 6
            'list' => $this->list,
517 3
        ];
518
    }
519
    /**
520
     * @param array $attributes
521
     */
522 546
    public function setAttributesFromSerializedJson(array $attributes)
523
    {
524 546
        foreach ($attributes as $attribute) {
525 540
            $this->attributes->add(self::instanceFromSerializedJson($this->generator, $attribute)->setOwner($this));
526 273
        }
527 546
    }
528
    /**
529
     * @param array $values
530
     */
531 546
    public function setValuesFromSerializedJson(array $values)
532
    {
533 546
        foreach ($values as $value) {
534 510
            $this->values->add(self::instanceFromSerializedJson($this->generator, $value)->setOwner($this));
535 273
        }
536 546
    }
537
}
538