Passed
Push — develop ( 0a8b55...80d7ca )
by Mikaël
06:50
created

Struct::addStructMethodAddTo()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 16
Code Lines 11

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 11
CRAP Score 2

Importance

Changes 0
Metric Value
cc 2
eloc 11
c 0
b 0
f 0
nc 2
nop 1
dl 0
loc 16
ccs 11
cts 11
cp 1
crap 2
rs 9.9
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 132
    public function setModel(AbstractModel $model): self
25
    {
26 132
        if (!$model instanceof StructModel) {
27 2
            throw new InvalidArgumentException('Model must be an instance of a Struct', __LINE__);
28
        }
29
30 130
        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 106
    protected function defineUseStatements(): self
34
    {
35 106
        if ($this->getGenerator()->getOptionValidation()) {
36 104
            $this->getFile()->addUse(InvalidArgumentException::class, null, false);
37
        }
38
39 106
        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 106
    protected function fillClassConstants(ConstantContainer $constants): void
43
    {
44 106
    }
45
46
    protected function getConstantAnnotationBlock(PhpConstant $constant): ?PhpAnnotationBlock
47
    {
48
    }
49
50 122
    protected function getModelAttributes(): StructAttributeContainer
51
    {
52 122
        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 122
    protected function fillClassProperties(PropertyContainer $properties): void
56
    {
57
        /** @var StructAttributeModel $attribute */
58 122
        foreach ($this->getModelAttributes() as $attribute) {
59
            switch (true) {
60 102
                case $attribute->isXml():
61 4
                    $type = null;
62
63 4
                    break;
64
65
                default:
66 102
                    $type = ($attribute->isRequired() || $attribute->isArray() ? '' : '?').$this->getStructAttributeTypeAsPhpType($attribute);
67
68 102
                    break;
69
            }
70
71 102
            $properties->add(
72 102
                new PhpProperty(
73 102
                    $attribute->getCleanName(),
74 102
                    $attribute->isArray() ? [] : ($attribute->isRequired() ? PhpProperty::NO_VALUE : null),
75 102
                    $this->getGenerator()->getOptionValidation() ? PhpProperty::ACCESS_PROTECTED : PhpProperty::ACCESS_PUBLIC,
76
                    $type
77
                )
78
            );
79
        }
80 122
    }
81
82 102
    protected function getPropertyAnnotationBlock(PhpProperty $property): ?PhpAnnotationBlock
83
    {
84 102
        $annotationBlock = new PhpAnnotationBlock();
85 102
        $annotationBlock->addChild(sprintf('The %s', $property->getName()));
86 102
        $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 102
        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 102
        if ($attribute instanceof StructAttributeModel) {
91 102
            $this->defineModelAnnotationsFromWsdl($annotationBlock, $attribute);
92 102
            $annotationBlock->addChild(new PhpAnnotation(self::ANNOTATION_VAR, $this->getStructAttributeTypeGetAnnotation($attribute)));
93
        }
94
95 102
        return $annotationBlock;
96
    }
97
98 106
    protected function fillClassMethods(): void
99
    {
100
        $this
101 106
            ->addStructMethodConstruct()
102 106
            ->addStructMethodsSetAndGet()
103
        ;
104 106
    }
105
106 106
    protected function addStructMethodConstruct(): self
107
    {
108 106
        if (0 < count($parameters = $this->getStructMethodParametersValues())) {
109 102
            $method = new PhpMethod(self::METHOD_CONSTRUCT, $parameters);
110 102
            $this->addStructMethodConstructBody($method);
111 102
            $this->methods->add($method);
112
        }
113
114 106
        return $this;
115
    }
116
117 102
    protected function addStructMethodConstructBody(PhpMethod $method): self
118
    {
119 102
        $count = $this->getModelAttributes()->count();
120 102
        foreach ($this->getModelAttributes() as $index => $attribute) {
121 102
            if (0 === $index) {
122 102
                $method->addChild('$this');
123
            }
124 102
            $this->addStructMethodConstructBodyForAttribute($method, $attribute, $count - 1 === $index);
125
        }
126
127 102
        return $this;
128
    }
129
130 102
    protected function addStructMethodConstructBodyForAttribute(PhpMethod $method, StructAttributeModel $attribute, bool $isLast): self
131
    {
132 102
        $uniqueString = $attribute->getUniqueString($attribute->getCleanName(), 'method');
133 102
        $method->addChild($method->getIndentedString(sprintf('->%s($%s)%s', $attribute->getSetterName(), lcfirst($uniqueString), $isLast ? ';' : ''), 1));
134
135 102
        return $this;
136
    }
137
138 106
    protected function getStructMethodParametersValues(): array
139
    {
140 106
        $parametersValues = [];
141 106
        foreach ($this->getModelAttributes() as $attribute) {
142 102
            $parametersValues[] = $this->getStructMethodParameter($attribute);
143
        }
144
145 106
        return $parametersValues;
146
    }
147
148 102
    protected function getStructMethodParameter(StructAttributeModel $attribute): PhpFunctionParameter
149
    {
150
        switch (true) {
151 102
            case $attribute->isXml():
152 102
            case $attribute->isList():
153 10
                $type = null;
154
155 10
                break;
156
157
            default:
158 102
                $type = ($attribute->isRequired() || $attribute->isArray() ? '' : '?').$this->getStructAttributeTypeAsPhpType($attribute);
159
160 102
                break;
161
        }
162
163
        try {
164 102
            return new PhpFunctionParameter(
165 102
                lcfirst($attribute->getUniqueString($attribute->getCleanName(), 'method')),
166 102
                $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 106
    protected function addStructMethodsSetAndGet(): self
176
    {
177 106
        foreach ($this->getModelAttributes() as $attribute) {
178
            $this
179 102
                ->addStructMethodGet($attribute)
180 102
                ->addStructMethodSet($attribute)
181 102
                ->addStructMethodAddTo($attribute)
182
            ;
183
        }
184
185 106
        return $this;
186
    }
187
188 92
    protected function addStructMethodAddTo(StructAttributeModel $attribute): self
189
    {
190 92
        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 92
        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 102
    protected function addStructMethodSet(StructAttributeModel $attribute): self
228
    {
229 102
        $method = new PhpMethod($attribute->getSetterName(), [
230 102
            $this->getStructMethodParameter($attribute),
231 102
        ], self::TYPE_SELF);
232 102
        $this->addStructMethodSetBody($method, $attribute);
233 102
        $this->methods->add($method);
234
235 102
        return $this;
236
    }
237
238 102
    protected function addStructMethodSetBody(PhpMethod $method, StructAttributeModel $attribute): self
239
    {
240 102
        $parameters = $method->getParameters();
241 102
        $parameter = array_shift($parameters);
242 102
        $parameterName = is_string($parameter) ? $parameter : $parameter->getName();
243 102
        if ($this->getGenerator()->getOptionValidation()) {
244 100
            $this->applyRules($method, $attribute, $parameterName);
245
        }
246
247
        return $this
248 102
            ->addStructMethodSetBodyAssignment($method, $attribute, $parameterName)
249 102
            ->addStructMethodSetBodyReturn($method)
250
        ;
251
    }
252
253 102
    protected function addStructMethodSetBodyAssignment(PhpMethod $method, StructAttributeModel $attribute, string $parameterName): self
254
    {
255 102
        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 98
            $method->addChild($this->getStructMethodSetBodyAssignment($attribute, $parameterName));
265
        }
266
267 102
        return $this;
268
    }
269
270 102
    protected function addStructMethodSetBodyReturn(PhpMethod $method): self
271
    {
272
        $method
273 102
            ->addChild('')
274 102
            ->addChild('return $this;')
275
        ;
276
277 102
        return $this;
278
    }
279
280 102
    protected function getStructMethodSetBodyAssignment(StructAttributeModel $attribute, string $parameterName): string
281
    {
282 102
        $prefix = '$';
283 102
        if ($attribute->isList()) {
284 6
            $prefix = '';
285 6
            $parameterName = sprintf('is_array($%1$s) ? implode(\' \', $%1$s) : $%1$s', $parameterName);
286 102
        } 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 102
        if ($attribute->nameIsClean()) {
292 102
            $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 102
        return $assignment;
298
    }
299
300 102
    protected function addStructMethodGetBody(PhpMethod $method, StructAttributeModel $attribute, string $thisAccess): self
301
    {
302 102
        return $this->addStructMethodGetBodyReturn($method, $attribute, $thisAccess);
303
    }
304
305 102
    protected function addStructMethodGetBodyReturn(PhpMethod $method, StructAttributeModel $attribute, string $thisAccess): self
306
    {
307 102
        $return = sprintf('return $this->%s;', $thisAccess);
308 102
        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 102
        } elseif ($attribute->getRemovableFromRequest() || $attribute->isAChoice()) {
322 18
            $return = sprintf('return isset($this->%1$s) ? $this->%1$s : null;', $thisAccess);
323
        }
324 102
        $method->addChild($return);
325
326 102
        return $this;
327
    }
328
329 102
    protected function addStructMethodGet(StructAttributeModel $attribute): self
330
    {
331
        switch (true) {
332
            // it can either be a string, a DOMDocument or null...
333 102
            case $attribute->isXml():
334 4
                $returnType = '';
335
336 4
                break;
337
338
            default:
339 102
                $returnType = (!$attribute->getRemovableFromRequest() && ($attribute->isRequired() || $attribute->isArray()) ? '' : '?').$this->getStructAttributeTypeAsPhpType($attribute);
340
341 102
                break;
342
        }
343
344 102
        $method = new PhpMethod(
345 102
            $attribute->getGetterName(),
346 102
            $this->getStructMethodGetParameters($attribute),
347
            $returnType
348
        );
349 102
        if ($attribute->nameIsClean()) {
350 102
            $thisAccess = sprintf('%s', $attribute->getName());
351
        } else {
352 2
            $thisAccess = sprintf('{\'%s\'}', addslashes($attribute->getName()));
353
        }
354 102
        $this->addStructMethodGetBody($method, $attribute, $thisAccess);
355 102
        $this->methods->add($method);
356
357 102
        return $this;
358
    }
359
360 102
    protected function getStructMethodGetParameters(StructAttributeModel $attribute): array
361
    {
362 102
        $parameters = [];
363 102
        if ($attribute->isXml()) {
364 4
            $parameters[] = new PhpFunctionParameter('asDomDocument', false, self::TYPE_BOOL, $attribute);
365
        }
366
367 102
        return $parameters;
368
    }
369
370 102
    protected function getMethodAnnotationBlock(PhpMethod $method): ?PhpAnnotationBlock
371
    {
372 102
        return $this->getStructMethodAnnotationBlock($method);
373
    }
374
375 102
    protected function getStructMethodAnnotationBlock(PhpMethod $method): ?PhpAnnotationBlock
376
    {
377 102
        $annotationBlock = null;
378
379 102
        switch ($method->getName()) {
380 102
            case self::METHOD_CONSTRUCT:
381 102
                $annotationBlock = $this->getStructMethodConstructAnnotationBlock();
382
383 102
                break;
384
385 102
            case 0 === mb_strpos($method->getName(), 'get'):
386 102
            case 0 === mb_strpos($method->getName(), 'set'):
387 102
                $annotationBlock = $this->getStructMethodsSetAndGetAnnotationBlock($method);
388
389 102
                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 102
        return $annotationBlock;
428
    }
429
430 102
    protected function getStructMethodConstructAnnotationBlock(): PhpAnnotationBlock
431
    {
432 102
        $annotationBlock = new PhpAnnotationBlock([
433 102
            sprintf('Constructor method for %s', $this->getModel()->getName()),
434
        ]);
435 102
        $this->addStructPropertiesToAnnotationBlock($annotationBlock);
436
437 102
        return $annotationBlock;
438
    }
439
440 102
    protected function getStructMethodsSetAndGetAnnotationBlock(PhpMethod $method): PhpAnnotationBlock
441
    {
442 102
        $parameters = $method->getParameters();
443 102
        $setOrGet = mb_strtolower(mb_substr($method->getName(), 0, 3));
444 102
        $parameter = array_shift($parameters);
445
        // Only set parameter must be based on a potential PhpFunctionParameter
446 102
        if ($parameter instanceof PhpFunctionParameter && 'set' === $setOrGet) {
447 102
            $parameterName = ucfirst($parameter->getName());
448
        } else {
449 102
            $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 102
        $parameterName = preg_replace('/(_\d+)/', '', $parameterName);
455 102
        $attribute = $this->getModel()->getAttribute($parameterName);
456 102
        if (!$attribute instanceof StructAttributeModel) {
457 42
            $attribute = $this->getModel()->getAttributeByCleanName($parameterName);
458
        }
459 102
        if (!$attribute instanceof StructAttributeModel) {
460 42
            $parameterName = lcfirst($parameterName);
461 42
            $attribute = $this->getModel()->getAttribute($parameterName);
462 42
            if (!$attribute instanceof StructAttributeModel) {
463 4
                $attribute = $this->getModel()->getAttributeByCleanName($parameterName);
464
            }
465
        }
466 102
        $setValueAnnotation = '%s %s value';
467 102
        $annotationBlock = new PhpAnnotationBlock();
468 102
        if ($attribute instanceof StructAttributeModel) {
469 102
            $annotationBlock->addChild(sprintf($setValueAnnotation, ucfirst($setOrGet), $parameterName));
470 102
            $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 102
        return $annotationBlock;
477
    }
478
479 102
    protected function addStructMethodsSetAndGetAnnotationBlockFromStructAttribute(string $setOrGet, PhpAnnotationBlock $annotationBlock, StructAttributeModel $attribute): self
480
    {
481 102
        switch ($setOrGet) {
482 102
            case 'set':
483 102
                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 102
                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 102
                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 102
                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 102
                $this->addStructMethodsSetAnnotationBlock($annotationBlock, $this->getStructAttributeTypeSetAnnotation($attribute, false), lcfirst($attribute->getCleanName()));
511
512 102
                break;
513
514 102
            case 'get':
515 102
                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 102
                    ->addStructMethodsGetAnnotationBlockFromXmlAttribute($annotationBlock, $attribute)
520 102
                    ->addStructMethodsGetAnnotationBlock($annotationBlock, $this->getStructAttributeTypeGetAnnotation($attribute))
521
                ;
522
523 102
                break;
524
        }
525
526 102
        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 102
    protected function addStructMethodsSetAnnotationBlock(PhpAnnotationBlock $annotationBlock, string $type, string $name): self
547
    {
548
        $annotationBlock
549 102
            ->addChild(new PhpAnnotation(self::ANNOTATION_PARAM, sprintf('%s $%s', $type, $name)))
550 102
            ->addChild(new PhpAnnotation(self::ANNOTATION_RETURN, $this->getModel()->getPackagedName(true)))
551
        ;
552
553 102
        return $this;
554
    }
555
556 102
    protected function addStructMethodsGetAnnotationBlock(PhpAnnotationBlock $annotationBlock, string $attributeType): self
557
    {
558 102
        $annotationBlock->addChild(new PhpAnnotation(self::ANNOTATION_RETURN, $attributeType));
559
560 102
        return $this;
561
    }
562
563 102
    protected function addStructMethodsGetAnnotationBlockFromXmlAttribute(PhpAnnotationBlock $annotationBlock, StructAttributeModel $attribute): self
564
    {
565 102
        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 102
        return $this;
573
    }
574
575 102
    protected function addStructPropertiesToAnnotationBlock(PhpAnnotationBlock $annotationBlock): self
576
    {
577
        return $this
578 102
            ->addStructPropertiesToAnnotationBlockUses($annotationBlock)
579 102
            ->addStructPropertiesToAnnotationBlockParams($annotationBlock)
580
        ;
581
    }
582
583 102
    protected function addStructPropertiesToAnnotationBlockUses(PhpAnnotationBlock $annotationBlock): self
584
    {
585 102
        foreach ($this->getModelAttributes() as $attribute) {
586 102
            $annotationBlock->addChild(new PhpAnnotation(self::ANNOTATION_USES, sprintf('%s::%s()', $this->getModel()->getPackagedName(), $attribute->getSetterName())));
587
        }
588
589 102
        return $this;
590
    }
591
592 102
    protected function addStructPropertiesToAnnotationBlockParams(PhpAnnotationBlock $annotationBlock): self
593
    {
594 102
        foreach ($this->getModelAttributes() as $attribute) {
595 102
            $annotationBlock->addChild(new PhpAnnotation(self::ANNOTATION_PARAM, sprintf('%s $%s', $this->getStructAttributeTypeSetAnnotation($attribute, false), lcfirst($attribute->getCleanName()))));
596
        }
597
598 102
        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