Passed
Push — feature/issue-124 ( a8c837...f8e59e )
by Mikaël
09:39
created

Struct::addStructMethodGet()   A

Complexity

Conditions 4
Paths 6

Size

Total Lines 33
Code Lines 21

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 18
CRAP Score 4

Importance

Changes 0
Metric Value
cc 4
eloc 21
nc 6
nop 1
dl 0
loc 33
ccs 18
cts 18
cp 1
crap 4
rs 9.584
c 0
b 0
f 0
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 131
    public function setModel(AbstractModel $model): self
25
    {
26 131
        if (!$model instanceof StructModel) {
27 2
            throw new InvalidArgumentException('Model must be an instance of a Struct', __LINE__);
28
        }
29
30 129
        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 121
    protected function defineUseStatements(): self
34
    {
35
        // @todo: only add `use InvalidArgumentException` if it's used!
36 121
        if ($this->getGenerator()->getOptionValidation()) {
37 118
            $this->getFile()->addUse(InvalidArgumentException::class, null, false);
38
        }
39
40 121
        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...
41
    }
42
43 105
    protected function fillClassConstants(ConstantContainer $constants): void
44
    {
45 105
    }
46
47
    protected function getConstantAnnotationBlock(PhpConstant $constant): ?PhpAnnotationBlock
48
    {
49
    }
50
51 121
    protected function getModelAttributes(): StructAttributeContainer
52
    {
53 121
        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

53
        return $this->getModel()->/** @scrutinizer ignore-call */ getProperAttributes(true);
Loading history...
54
    }
55
56 121
    protected function fillClassProperties(PropertyContainer $properties): void
57
    {
58 121
        foreach ($this->getModelAttributes() as $attribute) {
59 101
            $properties->add(
60 101
                new PhpProperty(
61 101
                    $attribute->getCleanName(),
62 101
                    $attribute->isArray() ? [] : null,
63 101
                    PhpProperty::ACCESS_PUBLIC,
64 101
                    $attribute->isArray() ? self::TYPE_ARRAY : '?'.$this->getStructAttributeTypeAsPhpType($attribute)
65
                )
66
            );
67
        }
68 121
    }
69
70 101
    protected function getPropertyAnnotationBlock(PhpProperty $property): ?PhpAnnotationBlock
71
    {
72 101
        $annotationBlock = new PhpAnnotationBlock();
73 101
        $annotationBlock->addChild(sprintf('The %s', $property->getName()));
74 101
        $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

74
        $attribute = $this->getModel()->/** @scrutinizer ignore-call */ getAttribute($property->getName());
Loading history...
75 101
        if (!$attribute instanceof StructAttributeModel) {
76 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

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