Struct   F
last analyzed

Complexity

Total Complexity 123

Size/Duplication

Total Lines 668
Duplicated Lines 0 %

Test Coverage

Coverage 98.51%

Importance

Changes 9
Bugs 1 Features 2
Metric Value
eloc 347
c 9
b 1
f 2
dl 0
loc 668
ccs 396
cts 402
cp 0.9851
rs 2
wmc 123

42 Methods

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