Passed
Pull Request — develop (#273)
by Mikaël
05:05 queued 02:27
created

Struct   F

Complexity

Total Complexity 125

Size/Duplication

Total Lines 670
Duplicated Lines 0 %

Test Coverage

Coverage 97.42%

Importance

Changes 9
Bugs 1 Features 2
Metric Value
eloc 345
c 9
b 1
f 2
dl 0
loc 670
ccs 340
cts 349
cp 0.9742
rs 2
wmc 125

44 Methods

Rating   Name   Duplication   Size   Complexity  
B getStructMethodParameter() 0 26 9
A fillClassConstants() 0 2 1
A addStructPropertiesToAnnotationBlockParams() 0 7 2
A getModel() 0 3 1
A addStructMethodsSetAndGetAnnotationBlockFromScalar() 0 15 3
A addStructPropertiesToAnnotationBlockUses() 0 7 2
A getStructMethodsValidateUnionAnnotationBlock() 0 10 1
A getStructMethodsAddToAnnotationBlock() 0 24 3
A addStructMethodAddToBody() 0 19 3
A addStructMethodGet() 0 29 6
A getStructMethodsValidateChoiceAnnotationBlock() 0 10 1
A defineUseStatements() 0 7 2
A addStructMethodGetBody() 0 3 1
A addStructMethodSetBodyReturn() 0 8 1
A getModelAttributes() 0 3 1
A addStructMethodSet() 0 9 1
A addStructMethodsGetAnnotationBlockFromXmlAttribute() 0 10 2
A addStructMethodConstructBodyForAttribute() 0 6 2
A getStructMethodParametersValues() 0 8 2
A addStructMethodGetBodyReturn() 0 22 6
A getStructMethodsValidateLengthAnnotationBlock() 0 11 1
A addStructMethodSetBody() 0 12 3
B getStructMethodAnnotationBlock() 0 53 11
A getStructMethodsValidateArrayAnnotationBlock() 0 9 1
A getMethodAnnotationBlock() 0 3 1
B addStructMethodsSetAndGetAnnotationBlockFromStructAttribute() 0 48 11
A fillClassMethods() 0 5 1
A addStructPropertiesToAnnotationBlock() 0 5 1
A addStructMethodsGetAnnotationBlock() 0 5 1
A getStructMethodGetParameters() 0 8 2
A getConstantAnnotationBlock() 0 3 1
A getPropertyAnnotationBlock() 0 14 3
A getStructMethodConstructAnnotationBlock() 0 8 1
A getStructMethodSetBodyAssignment() 0 18 4
A addStructMethodSetBodyAssignment() 0 15 4
A setModel() 0 7 2
A addStructMethodAddTo() 0 16 2
A applyRules() 0 5 2
A addStructMethodConstruct() 0 9 2
B getStructMethodsSetAndGetAnnotationBlock() 0 37 8
A addStructMethodConstructBody() 0 11 3
A addStructMethodsSetAndGet() 0 11 2
A addStructMethodsSetAnnotationBlock() 0 8 1
B fillClassProperties() 0 22 7

How to fix   Complexity   

Complex Class

Complex classes like Struct often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use Struct, and based on these observations, apply Extract Interface, too.

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