Passed
Push — feature/issue-124 ( 91e4aa...dde646 )
by Mikaël
09:46
created

Struct::addStructMethodGet()   A

Complexity

Conditions 6
Paths 14

Size

Total Lines 29
Code Lines 18

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 15
CRAP Score 6

Importance

Changes 0
Metric Value
cc 6
eloc 18
c 0
b 0
f 0
nc 14
nop 1
dl 0
loc 29
ccs 15
cts 15
cp 1
crap 6
rs 9.0444
1
<?php
2
3
declare(strict_types=1);
4
5
namespace WsdlToPhp\PackageGenerator\File;
6
7
use InvalidArgumentException;
8
use WsdlToPhp\PackageGenerator\Container\Model\StructAttribute as StructAttributeContainer;
9
use WsdlToPhp\PackageGenerator\Container\PhpElement\Constant as ConstantContainer;
10
use WsdlToPhp\PackageGenerator\Container\PhpElement\Property as PropertyContainer;
11
use WsdlToPhp\PackageGenerator\File\Element\PhpFunctionParameter;
12
use WsdlToPhp\PackageGenerator\File\Validation\Rules;
13
use WsdlToPhp\PackageGenerator\Model\AbstractModel;
14
use WsdlToPhp\PackageGenerator\Model\Struct as StructModel;
15
use WsdlToPhp\PackageGenerator\Model\StructAttribute as StructAttributeModel;
16
use WsdlToPhp\PhpGenerator\Element\PhpAnnotation;
17
use WsdlToPhp\PhpGenerator\Element\PhpAnnotationBlock;
18
use WsdlToPhp\PhpGenerator\Element\PhpConstant;
19
use WsdlToPhp\PhpGenerator\Element\PhpMethod;
20
use WsdlToPhp\PhpGenerator\Element\PhpProperty;
21
22
class Struct extends AbstractModelFile
23
{
24 133
    public function setModel(AbstractModel $model): self
25
    {
26 133
        if (!$model instanceof StructModel) {
27 2
            throw new InvalidArgumentException('Model must be an instance of a Struct', __LINE__);
28
        }
29
30 131
        return parent::setModel($model);
0 ignored issues
show
Bug Best Practice introduced by
The expression return parent::setModel($model) returns the type WsdlToPhp\PackageGenerator\File\AbstractModelFile which includes types incompatible with the type-hinted return WsdlToPhp\PackageGenerator\File\Struct.
Loading history...
31
    }
32
33 123
    protected function defineUseStatements(): self
34
    {
35 123
        if ($this->getGenerator()->getOptionValidation()) {
36 120
            $this->getFile()->addUse(InvalidArgumentException::class, null, false);
37
        }
38
39 123
        return parent::defineUseStatements();
0 ignored issues
show
Bug Best Practice introduced by
The expression return parent::defineUseStatements() returns the type WsdlToPhp\PackageGenerator\File\AbstractModelFile which includes types incompatible with the type-hinted return WsdlToPhp\PackageGenerator\File\Struct.
Loading history...
40
    }
41
42 107
    protected function fillClassConstants(ConstantContainer $constants): void
43
    {
44 107
    }
45
46
    protected function getConstantAnnotationBlock(PhpConstant $constant): ?PhpAnnotationBlock
47
    {
48
    }
49
50 123
    protected function getModelAttributes(): StructAttributeContainer
51
    {
52 123
        return $this->getModel()->getProperAttributes(true);
0 ignored issues
show
Bug introduced by
The method getProperAttributes() does not exist on WsdlToPhp\PackageGenerator\Model\AbstractModel. It seems like you code against a sub-type of WsdlToPhp\PackageGenerator\Model\AbstractModel such as WsdlToPhp\PackageGenerator\Model\Struct. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

52
        return $this->getModel()->/** @scrutinizer ignore-call */ getProperAttributes(true);
Loading history...
53
    }
54
55 123
    protected function fillClassProperties(PropertyContainer $properties): void
56
    {
57
        /** @var StructAttributeModel $attribute */
58 123
        foreach ($this->getModelAttributes() as $attribute) {
59
            switch (true) {
60 103
                case $attribute->isXml():
61 4
                    $type = null;
62
63 4
                    break;
64
65
                default:
66 103
                    $type = ($attribute->isRequired() || $attribute->isArray() ? '' : '?').$this->getStructAttributeTypeAsPhpType($attribute);
67
68 103
                    break;
69
            }
70
71 103
            $properties->add(
72 103
                new PhpProperty(
73 103
                    $attribute->getCleanName(),
74 103
                    $attribute->isArray() ? [] : ($attribute->isRequired() ? PhpProperty::NO_VALUE : null),
75 103
                    $this->getGenerator()->getOptionValidation() ? PhpProperty::ACCESS_PROTECTED : PhpProperty::ACCESS_PUBLIC,
76
                    $type
77
                )
78
            );
79
        }
80 123
    }
81
82 103
    protected function getPropertyAnnotationBlock(PhpProperty $property): ?PhpAnnotationBlock
83
    {
84 103
        $annotationBlock = new PhpAnnotationBlock();
85 103
        $annotationBlock->addChild(sprintf('The %s', $property->getName()));
86 103
        $attribute = $this->getModel()->getAttribute($property->getName());
0 ignored issues
show
Bug introduced by
The method getAttribute() does not exist on WsdlToPhp\PackageGenerator\Model\AbstractModel. It seems like you code against a sub-type of WsdlToPhp\PackageGenerator\Model\AbstractModel such as WsdlToPhp\PackageGenerator\Model\Struct. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

86
        $attribute = $this->getModel()->/** @scrutinizer ignore-call */ getAttribute($property->getName());
Loading history...
87 103
        if (!$attribute instanceof StructAttributeModel) {
88 2
            $attribute = $this->getModel()->getAttributeByCleanName($property->getName());
0 ignored issues
show
Bug introduced by
The method getAttributeByCleanName() does not exist on WsdlToPhp\PackageGenerator\Model\AbstractModel. It seems like you code against a sub-type of WsdlToPhp\PackageGenerator\Model\AbstractModel such as WsdlToPhp\PackageGenerator\Model\Struct. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

88
            $attribute = $this->getModel()->/** @scrutinizer ignore-call */ getAttributeByCleanName($property->getName());
Loading history...
89
        }
90 103
        if ($attribute instanceof StructAttributeModel) {
91 103
            $this->defineModelAnnotationsFromWsdl($annotationBlock, $attribute);
92 103
            $annotationBlock->addChild(new PhpAnnotation(self::ANNOTATION_VAR, $this->getStructAttributeTypeGetAnnotation($attribute)));
93
        }
94
95 103
        return $annotationBlock;
96
    }
97
98 107
    protected function fillClassMethods(): void
99
    {
100
        $this
101 107
            ->addStructMethodConstruct()
102 107
            ->addStructMethodsSetAndGet()
103
        ;
104 107
    }
105
106 107
    protected function addStructMethodConstruct(): self
107
    {
108 107
        if (0 < count($parameters = $this->getStructMethodParametersValues())) {
109 103
            $method = new PhpMethod(self::METHOD_CONSTRUCT, $parameters);
110 103
            $this->addStructMethodConstructBody($method);
111 103
            $this->methods->add($method);
112
        }
113
114 107
        return $this;
115
    }
116
117 103
    protected function addStructMethodConstructBody(PhpMethod $method): self
118
    {
119 103
        $count = $this->getModelAttributes()->count();
120 103
        foreach ($this->getModelAttributes() as $index => $attribute) {
121 103
            if (0 === $index) {
122 103
                $method->addChild('$this');
123
            }
124 103
            $this->addStructMethodConstructBodyForAttribute($method, $attribute, $count - 1 === $index);
125
        }
126
127 103
        return $this;
128
    }
129
130 103
    protected function addStructMethodConstructBodyForAttribute(PhpMethod $method, StructAttributeModel $attribute, bool $isLast): self
131
    {
132 103
        $uniqueString = $attribute->getUniqueString($attribute->getCleanName(), 'method');
133 103
        $method->addChild($method->getIndentedString(sprintf('->%s($%s)%s', $attribute->getSetterName(), lcfirst($uniqueString), $isLast ? ';' : ''), 1));
134
135 103
        return $this;
136
    }
137
138 107
    protected function getStructMethodParametersValues(): array
139
    {
140 107
        $parametersValues = [];
141 107
        foreach ($this->getModelAttributes() as $attribute) {
142 103
            $parametersValues[] = $this->getStructMethodParameter($attribute);
143
        }
144
145 107
        return $parametersValues;
146
    }
147
148 103
    protected function getStructMethodParameter(StructAttributeModel $attribute): PhpFunctionParameter
149
    {
150
        switch (true) {
151 103
            case $attribute->isXml():
152 103
            case $attribute->isList():
153 10
                $type = null;
154
155 10
                break;
156
157
            default:
158 103
                $type = ($attribute->isRequired() || $attribute->isArray() ? '' : '?').$this->getStructAttributeTypeAsPhpType($attribute);
159
160 103
                break;
161
        }
162
163
        try {
164 103
            return new PhpFunctionParameter(
165 103
                lcfirst($attribute->getUniqueString($attribute->getCleanName(), 'method')),
166 103
                $attribute->isRequired() ? PhpFunctionParameter::NO_VALUE : $attribute->getDefaultValue(),
167
                $type,
168
                $attribute
169
            );
170
        } catch (InvalidArgumentException $exception) {
171
            throw new InvalidArgumentException(sprintf('Unable to create function parameter for struct "%s" with type "%s" for attribute "%s"', $this->getModel()->getName(), var_export($this->getStructAttributeTypeAsPhpType($attribute), true), $attribute->getName()), __LINE__, $exception);
172
        }
173
    }
174
175 107
    protected function addStructMethodsSetAndGet(): self
176
    {
177 107
        foreach ($this->getModelAttributes() as $attribute) {
178
            $this
179 103
                ->addStructMethodGet($attribute)
180 103
                ->addStructMethodSet($attribute)
181 103
                ->addStructMethodAddTo($attribute)
182
            ;
183
        }
184
185 107
        return $this;
186
    }
187
188 93
    protected function addStructMethodAddTo(StructAttributeModel $attribute): self
189
    {
190 93
        if ($attribute->isArray()) {
191 36
            $method = new PhpMethod(sprintf('addTo%s', ucfirst($attribute->getCleanName())), [
192 36
                new PhpFunctionParameter(
193 36
                    'item',
194 36
                    PhpFunctionParameter::NO_VALUE,
195 36
                    $this->getStructAttributeTypeAsPhpType($attribute, false),
196
                    $attribute
197
                ),
198 36
            ], self::TYPE_SELF);
199 36
            $this->addStructMethodAddToBody($method, $attribute);
200 36
            $this->methods->add($method);
201
        }
202
203 93
        return $this;
204
    }
205
206 36
    protected function addStructMethodAddToBody(PhpMethod $method, StructAttributeModel $attribute): self
207
    {
208 36
        if ($this->getGenerator()->getOptionValidation()) {
209 36
            $this->applyRules($method, $attribute, 'item', true);
210
        }
211
212 36
        if ($attribute->nameIsClean()) {
213 36
            $assignment = sprintf('$this->%s[] = $item;', $attribute->getCleanName());
214
        } else {
215
            $assignment = sprintf('$this->%s[] = $this->{\'%s\'}[] = $item;', $attribute->getCleanName(), addslashes($attribute->getName()), $attribute->getCleanName());
216
        }
217
218
        $method
219 36
            ->addChild($assignment)
220 36
            ->addChild('')
221 36
            ->addChild('return $this;')
222
        ;
223
224 36
        return $this;
225
    }
226
227 103
    protected function addStructMethodSet(StructAttributeModel $attribute): self
228
    {
229 103
        $method = new PhpMethod($attribute->getSetterName(), [
230 103
            $this->getStructMethodParameter($attribute),
231 103
        ], self::TYPE_SELF);
232 103
        $this->addStructMethodSetBody($method, $attribute);
233 103
        $this->methods->add($method);
234
235 103
        return $this;
236
    }
237
238 103
    protected function addStructMethodSetBody(PhpMethod $method, StructAttributeModel $attribute): self
239
    {
240 103
        $parameters = $method->getParameters();
241 103
        $parameter = array_shift($parameters);
242 103
        $parameterName = is_string($parameter) ? $parameter : $parameter->getName();
243 103
        if ($this->getGenerator()->getOptionValidation()) {
244 100
            $this->applyRules($method, $attribute, $parameterName);
245
        }
246
247
        return $this
248 103
            ->addStructMethodSetBodyAssignment($method, $attribute, $parameterName)
249 103
            ->addStructMethodSetBodyReturn($method)
250
        ;
251
    }
252
253 103
    protected function addStructMethodSetBodyAssignment(PhpMethod $method, StructAttributeModel $attribute, string $parameterName): self
254
    {
255 103
        if ($attribute->getRemovableFromRequest() || $attribute->isAChoice()) {
256
            $method
257 18
                ->addChild(sprintf('if (is_null($%1$s) || (is_array($%1$s) && empty($%1$s))) {', $parameterName))
258 18
                ->addChild($method->getIndentedString(sprintf('unset($this->%1$s%2$s);', $attribute->getCleanName(), $attribute->nameIsClean() ? '' : sprintf(', $this->{\'%s\'}', addslashes($attribute->getName()))), 1))
259 18
                ->addChild('} else {')
260 18
                ->addChild($method->getIndentedString($this->getStructMethodSetBodyAssignment($attribute, $parameterName), 1))
261 18
                ->addChild('}')
262
            ;
263
        } else {
264 99
            $method->addChild($this->getStructMethodSetBodyAssignment($attribute, $parameterName));
265
        }
266
267 103
        return $this;
268
    }
269
270 103
    protected function addStructMethodSetBodyReturn(PhpMethod $method): self
271
    {
272
        $method
273 103
            ->addChild('')
274 103
            ->addChild('return $this;')
275
        ;
276
277 103
        return $this;
278
    }
279
280 103
    protected function getStructMethodSetBodyAssignment(StructAttributeModel $attribute, string $parameterName): string
281
    {
282 103
        $prefix = '$';
283 103
        if ($attribute->isList()) {
284 6
            $prefix = '';
285 6
            $parameterName = sprintf('is_array($%1$s) ? implode(\' \', $%1$s) : $%1$s', $parameterName);
286 103
        } elseif ($attribute->isXml()) {
287 4
            $prefix = '';
288 4
            $parameterName = sprintf('($%1$s instanceof \DOMDocument) ? $%1$s->saveXML($%1$s->hasChildNodes() ? $%1$s->childNodes->item(0) : null) : $%1$s', $parameterName);
289
        }
290
291 103
        if ($attribute->nameIsClean()) {
292 103
            $assignment = sprintf('$this->%s = %s%s;', $attribute->getName(), $prefix, $parameterName);
293
        } else {
294 2
            $assignment = sprintf('$this->%s = $this->{\'%s\'} = %s%s;', $attribute->getCleanName(), addslashes($attribute->getName()), $prefix, $parameterName);
295
        }
296
297 103
        return $assignment;
298
    }
299
300 103
    protected function addStructMethodGetBody(PhpMethod $method, StructAttributeModel $attribute, string $thisAccess): self
301
    {
302 103
        return $this->addStructMethodGetBodyReturn($method, $attribute, $thisAccess);
303
    }
304
305 103
    protected function addStructMethodGetBodyReturn(PhpMethod $method, StructAttributeModel $attribute, string $thisAccess): self
306
    {
307 103
        $return = sprintf('return $this->%s;', $thisAccess);
308 103
        if ($attribute->isXml()) {
309
            $method
310 4
                ->addChild('$domDocument = null;')
311 4
                ->addChild(sprintf('if (!empty($this->%1$s) && $asDomDocument) {', $thisAccess))
312 4
                ->addChild($method->getIndentedString('$domDocument = new \DOMDocument(\'1.0\', \'UTF-8\');', 1))
313 4
                ->addChild($method->getIndentedString(sprintf('$domDocument->loadXML($this->%s);', $thisAccess), 1))
314 4
                ->addChild('}')
315
            ;
316 4
            if ($attribute->getRemovableFromRequest() || $attribute->isAChoice()) {
317
                $return = sprintf('return $asDomDocument ? $domDocument : (isset($this->%1$s) ? $this->%1$s : null);', $thisAccess);
318
            } else {
319 4
                $return = sprintf('return $asDomDocument ? $domDocument : $this->%1$s;', $thisAccess);
320
            }
321 103
        } elseif ($attribute->getRemovableFromRequest() || $attribute->isAChoice()) {
322 18
            $return = sprintf('return isset($this->%1$s) ? $this->%1$s : null;', $thisAccess);
323
        }
324 103
        $method->addChild($return);
325
326 103
        return $this;
327
    }
328
329 103
    protected function addStructMethodGet(StructAttributeModel $attribute): self
330
    {
331
        switch (true) {
332
            // it can either be a string, a DOMDocument or null...
333 103
            case $attribute->isXml():
334 4
                $returnType = '';
335
336 4
                break;
337
338
            default:
339 103
                $returnType = (!$attribute->getRemovableFromRequest() && ($attribute->isRequired() || $attribute->isArray()) ? '' : '?').$this->getStructAttributeTypeAsPhpType($attribute);
340
341 103
                break;
342
        }
343
344 103
        $method = new PhpMethod(
345 103
            $attribute->getGetterName(),
346 103
            $this->getStructMethodGetParameters($attribute),
347
            $returnType
348
        );
349 103
        if ($attribute->nameIsClean()) {
350 103
            $thisAccess = sprintf('%s', $attribute->getName());
351
        } else {
352 2
            $thisAccess = sprintf('{\'%s\'}', addslashes($attribute->getName()));
353
        }
354 103
        $this->addStructMethodGetBody($method, $attribute, $thisAccess);
355 103
        $this->methods->add($method);
356
357 103
        return $this;
358
    }
359
360 103
    protected function getStructMethodGetParameters(StructAttributeModel $attribute): array
361
    {
362 103
        $parameters = [];
363 103
        if ($attribute->isXml()) {
364 4
            $parameters[] = new PhpFunctionParameter('asDomDocument', false, self::TYPE_BOOL, $attribute);
365
        }
366
367 103
        return $parameters;
368
    }
369
370 103
    protected function getMethodAnnotationBlock(PhpMethod $method): ?PhpAnnotationBlock
371
    {
372 103
        return $this->getStructMethodAnnotationBlock($method);
373
    }
374
375 103
    protected function getStructMethodAnnotationBlock(PhpMethod $method): ?PhpAnnotationBlock
376
    {
377 103
        $annotationBlock = null;
378
379 103
        switch ($method->getName()) {
380 103
            case self::METHOD_CONSTRUCT:
381 103
                $annotationBlock = $this->getStructMethodConstructAnnotationBlock();
382
383 103
                break;
384
385 103
            case 0 === mb_strpos($method->getName(), 'get'):
386 103
            case 0 === mb_strpos($method->getName(), 'set'):
387 103
                $annotationBlock = $this->getStructMethodsSetAndGetAnnotationBlock($method);
388
389 103
                break;
390
391 66
            case 0 === mb_strpos($method->getName(), 'addTo'):
392 36
                $annotationBlock = $this->getStructMethodsAddToAnnotationBlock($method);
393
394 36
                break;
395
396 66
            case false !== mb_strpos($method->getName(), 'ForUnionConstraintsFrom'):
397 4
                $annotationBlock = $this->getStructMethodsValidateUnionAnnotationBlock($method);
398
399 4
                break;
400
401 62
            case false !== mb_strpos($method->getName(), 'ForArrayConstraintsFrom'):
402 56
                $annotationBlock = $this->getStructMethodsValidateArrayAnnotationBlock($method);
403
404 56
                break;
405
406 12
            case false !== mb_strpos($method->getName(), 'ForChoiceConstraintsFrom'):
407 8
                $annotationBlock = $this->getStructMethodsValidateChoiceAnnotationBlock($method);
408
409 8
                break;
410
411 4
            case false !== mb_strpos($method->getName(), 'MaxLengthConstraintFrom'):
412 4
                $annotationBlock = $this->getStructMethodsValidateLengthAnnotationBlock($method, 'max');
413
414 4
                break;
415
416 4
            case false !== mb_strpos($method->getName(), 'MinLengthConstraintFrom'):
417 4
                $annotationBlock = $this->getStructMethodsValidateLengthAnnotationBlock($method, 'min');
418
419 4
                break;
420
421
            case false !== mb_strpos($method->getName(), 'LengthConstraintFrom'):
422
                $annotationBlock = $this->getStructMethodsValidateLengthAnnotationBlock($method);
423
424
                break;
425
        }
426
427 103
        return $annotationBlock;
428
    }
429
430 103
    protected function getStructMethodConstructAnnotationBlock(): PhpAnnotationBlock
431
    {
432 103
        $annotationBlock = new PhpAnnotationBlock([
433 103
            sprintf('Constructor method for %s', $this->getModel()->getName()),
434
        ]);
435 103
        $this->addStructPropertiesToAnnotationBlock($annotationBlock);
436
437 103
        return $annotationBlock;
438
    }
439
440 103
    protected function getStructMethodsSetAndGetAnnotationBlock(PhpMethod $method): PhpAnnotationBlock
441
    {
442 103
        $parameters = $method->getParameters();
443 103
        $setOrGet = mb_strtolower(mb_substr($method->getName(), 0, 3));
444 103
        $parameter = array_shift($parameters);
445
        // Only set parameter must be based on a potential PhpFunctionParameter
446 103
        if ($parameter instanceof PhpFunctionParameter && 'set' === $setOrGet) {
447 103
            $parameterName = ucfirst($parameter->getName());
448
        } else {
449 103
            $parameterName = mb_substr($method->getName(), 3);
450
        }
451
        /**
452
         * Since properties can be duplicated with different case, we assume that _\d+ is replaceable by an empty string as methods are "duplicated" with this suffix.
453
         */
454 103
        $parameterName = preg_replace('/(_\d+)/', '', $parameterName);
455 103
        $attribute = $this->getModel()->getAttribute($parameterName);
456 103
        if (!$attribute instanceof StructAttributeModel) {
457 43
            $attribute = $this->getModel()->getAttributeByCleanName($parameterName);
458
        }
459 103
        if (!$attribute instanceof StructAttributeModel) {
460 43
            $parameterName = lcfirst($parameterName);
461 43
            $attribute = $this->getModel()->getAttribute($parameterName);
462 43
            if (!$attribute instanceof StructAttributeModel) {
463 4
                $attribute = $this->getModel()->getAttributeByCleanName($parameterName);
464
            }
465
        }
466 103
        $setValueAnnotation = '%s %s value';
467 103
        $annotationBlock = new PhpAnnotationBlock();
468 103
        if ($attribute instanceof StructAttributeModel) {
469 103
            $annotationBlock->addChild(sprintf($setValueAnnotation, ucfirst($setOrGet), $parameterName));
470 103
            $this->addStructMethodsSetAndGetAnnotationBlockFromStructAttribute($setOrGet, $annotationBlock, $attribute);
471
        } elseif (empty($attribute)) {
472 2
            $annotationBlock->addChild(sprintf($setValueAnnotation, ucfirst($setOrGet), lcfirst($parameterName)));
473 2
            $this->addStructMethodsSetAndGetAnnotationBlockFromScalar($setOrGet, $annotationBlock, $parameterName);
474
        }
475
476 103
        return $annotationBlock;
477
    }
478
479 103
    protected function addStructMethodsSetAndGetAnnotationBlockFromStructAttribute(string $setOrGet, PhpAnnotationBlock $annotationBlock, StructAttributeModel $attribute): self
480
    {
481 103
        switch ($setOrGet) {
482 103
            case 'set':
483 103
                if ($attribute->getRemovableFromRequest()) {
484 10
                    $annotationBlock->addChild('This property is removable from request (nillable=true+minOccurs=0), therefore if the value assigned to this property is null, it is removed from this object');
485
                }
486 103
                if ($attribute->isAChoice()) {
487 8
                    $annotationBlock->addChild('This property belongs to a choice that allows only one property to exist. It is therefore removable from the request, consequently if the value assigned to this property is null, the property is removed from this object');
488
                }
489 103
                if ($attribute->isXml()) {
490
                    $annotationBlock
491 4
                        ->addChild(new PhpAnnotation(self::ANNOTATION_USES, '\DOMDocument::hasChildNodes()'))
492 4
                        ->addChild(new PhpAnnotation(self::ANNOTATION_USES, '\DOMDocument::saveXML()'))
493 4
                        ->addChild(new PhpAnnotation(self::ANNOTATION_USES, '\DOMNode::item()'))
494
                    ;
495
                }
496 103
                if ($this->getGenerator()->getOptionValidation()) {
497 100
                    if ($attribute->isAChoice()) {
498 8
                        $annotationBlock->addChild(new PhpAnnotation(self::ANNOTATION_THROWS, InvalidArgumentException::class));
499
                    }
500 100
                    if (($model = $this->getRestrictionFromStructAttribute($attribute)) instanceof StructModel) {
501
                        $annotationBlock
502 48
                            ->addChild(new PhpAnnotation(self::ANNOTATION_USES, sprintf('%s::%s()', $model->getPackagedName(true), StructEnum::METHOD_VALUE_IS_VALID)))
503 48
                            ->addChild(new PhpAnnotation(self::ANNOTATION_USES, sprintf('%s::%s()', $model->getPackagedName(true), StructEnum::METHOD_GET_VALID_VALUES)))
504 48
                            ->addChild(new PhpAnnotation(self::ANNOTATION_THROWS, InvalidArgumentException::class))
505
                        ;
506 98
                    } elseif ($attribute->isArray()) {
507 50
                        $annotationBlock->addChild(new PhpAnnotation(self::ANNOTATION_THROWS, InvalidArgumentException::class));
508
                    }
509
                }
510 103
                $this->addStructMethodsSetAnnotationBlock($annotationBlock, $this->getStructAttributeTypeSetAnnotation($attribute, false), lcfirst($attribute->getCleanName()));
511
512 103
                break;
513
514 103
            case 'get':
515 103
                if ($attribute->getRemovableFromRequest()) {
516 10
                    $annotationBlock->addChild('An additional test has been added (isset) before returning the property value as this property may have been unset before, due to the fact that this property is removable from the request (nillable=true+minOccurs=0)');
517
                }
518
                $this
519 103
                    ->addStructMethodsGetAnnotationBlockFromXmlAttribute($annotationBlock, $attribute)
520 103
                    ->addStructMethodsGetAnnotationBlock($annotationBlock, $this->getStructAttributeTypeGetAnnotation($attribute))
521
                ;
522
523 103
                break;
524
        }
525
526 103
        return $this;
527
    }
528
529 2
    protected function addStructMethodsSetAndGetAnnotationBlockFromScalar(string $setOrGet, PhpAnnotationBlock $annotationBlock, string $attributeName): self
530
    {
531 2
        switch ($setOrGet) {
532 2
            case 'set':
533 2
                $this->addStructMethodsSetAnnotationBlock($annotationBlock, lcfirst($attributeName), lcfirst($attributeName));
534
535 2
                break;
536
537 2
            case 'get':
538 2
                $this->addStructMethodsGetAnnotationBlock($annotationBlock, lcfirst($attributeName));
539
540 2
                break;
541
        }
542
543 2
        return $this;
544
    }
545
546 103
    protected function addStructMethodsSetAnnotationBlock(PhpAnnotationBlock $annotationBlock, string $type, string $name): self
547
    {
548
        $annotationBlock
549 103
            ->addChild(new PhpAnnotation(self::ANNOTATION_PARAM, sprintf('%s $%s', $type, $name)))
550 103
            ->addChild(new PhpAnnotation(self::ANNOTATION_RETURN, $this->getModel()->getPackagedName(true)))
551
        ;
552
553 103
        return $this;
554
    }
555
556 103
    protected function addStructMethodsGetAnnotationBlock(PhpAnnotationBlock $annotationBlock, string $attributeType): self
557
    {
558 103
        $annotationBlock->addChild(new PhpAnnotation(self::ANNOTATION_RETURN, $attributeType));
559
560 103
        return $this;
561
    }
562
563 103
    protected function addStructMethodsGetAnnotationBlockFromXmlAttribute(PhpAnnotationBlock $annotationBlock, StructAttributeModel $attribute): self
564
    {
565 103
        if ($attribute->isXml()) {
566
            $annotationBlock
567 4
                ->addChild(new PhpAnnotation(self::ANNOTATION_USES, '\DOMDocument::loadXML()'))
568 4
                ->addChild(new PhpAnnotation(self::ANNOTATION_PARAM, 'bool $asString true: returns XML string, false: returns \DOMDocument'))
569
            ;
570
        }
571
572 103
        return $this;
573
    }
574
575 103
    protected function addStructPropertiesToAnnotationBlock(PhpAnnotationBlock $annotationBlock): self
576
    {
577
        return $this
578 103
            ->addStructPropertiesToAnnotationBlockUses($annotationBlock)
579 103
            ->addStructPropertiesToAnnotationBlockParams($annotationBlock)
580
        ;
581
    }
582
583 103
    protected function addStructPropertiesToAnnotationBlockUses(PhpAnnotationBlock $annotationBlock): self
584
    {
585 103
        foreach ($this->getModelAttributes() as $attribute) {
586 103
            $annotationBlock->addChild(new PhpAnnotation(self::ANNOTATION_USES, sprintf('%s::%s()', $this->getModel()->getPackagedName(), $attribute->getSetterName())));
587
        }
588
589 103
        return $this;
590
    }
591
592 103
    protected function addStructPropertiesToAnnotationBlockParams(PhpAnnotationBlock $annotationBlock): self
593
    {
594 103
        foreach ($this->getModelAttributes() as $attribute) {
595 103
            $annotationBlock->addChild(new PhpAnnotation(self::ANNOTATION_PARAM, sprintf('%s $%s', $this->getStructAttributeTypeSetAnnotation($attribute, false), lcfirst($attribute->getCleanName()))));
596
        }
597
598 103
        return $this;
599
    }
600
601 36
    protected function getStructMethodsAddToAnnotationBlock(PhpMethod $method): PhpAnnotationBlock
602
    {
603 36
        $methodParameters = $method->getParameters();
604 36
        $firstParameter = array_shift($methodParameters);
605 36
        $attribute = $this->getModel()->getAttribute($firstParameter->getModel()->getName());
606 36
        $annotationBlock = new PhpAnnotationBlock();
607 36
        if ($attribute instanceof StructAttributeModel) {
608 36
            $model = $this->getRestrictionFromStructAttribute($attribute);
609 36
            $annotationBlock->addChild(sprintf('Add item to %s value', $attribute->getCleanName()));
610 36
            if ($model instanceof StructModel) {
611
                $annotationBlock
612 2
                    ->addChild(new PhpAnnotation(self::ANNOTATION_USES, sprintf('%s::%s()', $model->getPackagedName(true), StructEnum::METHOD_VALUE_IS_VALID)))
613 2
                    ->addChild(new PhpAnnotation(self::ANNOTATION_USES, sprintf('%s::%s()', $model->getPackagedName(true), StructEnum::METHOD_GET_VALID_VALUES)))
614
                ;
615
            }
616
            $annotationBlock
617 36
                ->addChild(new PhpAnnotation(self::ANNOTATION_THROWS, InvalidArgumentException::class))
618 36
                ->addChild(new PhpAnnotation(self::ANNOTATION_PARAM, sprintf('%s $item', $this->getStructAttributeTypeSetAnnotation($attribute, false, true))))
619 36
                ->addChild(new PhpAnnotation(self::ANNOTATION_RETURN, $this->getModel()->getPackagedName(true)))
620
            ;
621
        }
622
623 36
        return $annotationBlock;
624
    }
625
626 56
    protected function getStructMethodsValidateArrayAnnotationBlock(PhpMethod $method): PhpAnnotationBlock
627
    {
628 56
        $methodName = lcfirst(mb_substr($method->getName(), mb_strpos($method->getName(), 'ForArrayConstraintsFrom') + mb_strlen('ForArrayConstraintsFrom')));
629
630 56
        return new PhpAnnotationBlock([
631 56
            new PhpAnnotation(PhpAnnotation::NO_NAME, sprintf('This method is responsible for validating the values passed to the %s method', $methodName), self::ANNOTATION_LONG_LENGTH),
632 56
            new PhpAnnotation(PhpAnnotation::NO_NAME, sprintf('This method is willingly generated in order to preserve the one-line inline validation within the %s method', $methodName), self::ANNOTATION_LONG_LENGTH),
633 56
            new PhpAnnotation(self::ANNOTATION_PARAM, 'array $values'),
634 56
            new PhpAnnotation(self::ANNOTATION_RETURN, 'string A non-empty message if the values does not match the validation rules'),
635
        ]);
636
    }
637
638 4
    protected function getStructMethodsValidateUnionAnnotationBlock(PhpMethod $method): PhpAnnotationBlock
639
    {
640 4
        $methodName = lcfirst(mb_substr($method->getName(), mb_strpos($method->getName(), 'ForUnionConstraintsFrom') + mb_strlen('ForUnionConstraintsFrom')));
641
642 4
        return new PhpAnnotationBlock([
643 4
            new PhpAnnotation(PhpAnnotation::NO_NAME, sprintf('This method is responsible for validating the value passed to the %s method', $methodName), self::ANNOTATION_LONG_LENGTH),
644 4
            new PhpAnnotation(PhpAnnotation::NO_NAME, sprintf('This method is willingly generated in order to preserve the one-line inline validation within the %s method', $methodName), self::ANNOTATION_LONG_LENGTH),
645 4
            new PhpAnnotation(PhpAnnotation::NO_NAME, sprintf('This is a set of validation rules based on the union types associated to the property being set by the %s method', $methodName), self::ANNOTATION_LONG_LENGTH),
646 4
            new PhpAnnotation(self::ANNOTATION_PARAM, 'mixed $value'),
647 4
            new PhpAnnotation(self::ANNOTATION_RETURN, 'string A non-empty message if the values does not match the validation rules'),
648
        ]);
649
    }
650
651 8
    protected function getStructMethodsValidateChoiceAnnotationBlock(PhpMethod $method): PhpAnnotationBlock
652
    {
653 8
        $methodName = lcfirst(mb_substr($method->getName(), mb_strpos($method->getName(), 'ForChoiceConstraintsFrom') + mb_strlen('ForChoiceConstraintsFrom')));
654
655 8
        return new PhpAnnotationBlock([
656 8
            new PhpAnnotation(PhpAnnotation::NO_NAME, sprintf('This method is responsible for validating the value passed to the %s method', $methodName), self::ANNOTATION_LONG_LENGTH),
657 8
            new PhpAnnotation(PhpAnnotation::NO_NAME, sprintf('This method is willingly generated in order to preserve the one-line inline validation within the %s method', $methodName), self::ANNOTATION_LONG_LENGTH),
658 8
            new PhpAnnotation(PhpAnnotation::NO_NAME, 'This has to validate that the property which is being set is the only one among the given choices', self::ANNOTATION_LONG_LENGTH),
659 8
            new PhpAnnotation(self::ANNOTATION_PARAM, 'mixed $value'),
660 8
            new PhpAnnotation(self::ANNOTATION_RETURN, 'string A non-empty message if the values does not match the validation rules'),
661
        ]);
662
    }
663
664 4
    protected function getStructMethodsValidateLengthAnnotationBlock(PhpMethod $method, string $type = ''): PhpAnnotationBlock
665
    {
666 4
        $replace = sprintf('%sLengthConstraintFrom', ucfirst($type));
667 4
        $methodName = lcfirst(mb_substr($method->getName(), mb_strpos($method->getName(), $replace) + mb_strlen($replace)));
668
669 4
        return new PhpAnnotationBlock([
670 4
            new PhpAnnotation(PhpAnnotation::NO_NAME, sprintf('This method is responsible for validating the value passed to the %s method', $methodName), self::ANNOTATION_LONG_LENGTH),
671 4
            new PhpAnnotation(PhpAnnotation::NO_NAME, sprintf('This method is willingly generated in order to preserve the one-line inline validation within the %s method', $methodName), self::ANNOTATION_LONG_LENGTH),
672 4
            new PhpAnnotation(PhpAnnotation::NO_NAME, 'This has to validate that the items contained by the array match the length constraint', self::ANNOTATION_LONG_LENGTH),
673 4
            new PhpAnnotation(self::ANNOTATION_PARAM, 'mixed $values'),
674 4
            new PhpAnnotation(self::ANNOTATION_RETURN, 'string A non-empty message if the values does not match the validation rules'),
675
        ]);
676
    }
677
678 100
    protected function applyRules(PhpMethod $method, StructAttributeModel $attribute, string $parameterName, bool $itemType = false): void
679
    {
680 100
        if ($this->getGenerator()->getOptionValidation()) {
681 100
            $rules = new Rules($this, $method, $attribute, $this->methods);
682 100
            $rules->applyRules($parameterName, $itemType);
683
        }
684 100
    }
685
}
686