UnionRule::addValidationMethod()   C
last analyzed

Complexity

Conditions 12
Paths 8

Size

Total Lines 71
Code Lines 48

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 52
CRAP Score 12

Importance

Changes 1
Bugs 0 Features 1
Metric Value
cc 12
eloc 48
c 1
b 0
f 1
nc 8
nop 2
dl 0
loc 71
ccs 52
cts 52
cp 1
crap 12
rs 6.9666

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
3
declare(strict_types=1);
4
5
namespace WsdlToPhp\PackageGenerator\File\Validation;
6
7
use WsdlToPhp\PackageGenerator\File\AbstractModelFile;
8
use WsdlToPhp\PackageGenerator\Model\StructAttribute;
9
use WsdlToPhp\PhpGenerator\Element\PhpFunctionParameter;
10
use WsdlToPhp\PhpGenerator\Element\PhpMethod;
11
12
/**
13
 * @see https://www.w3.org/TR/xmlschema-2/#union-datatypes
14
 */
15
final class UnionRule extends AbstractRule
16
{
17
    public const NAME = 'union';
18
19 4
    public function name(): string
20
    {
21 4
        return self::NAME;
22
    }
23
24 4
    public function testConditions(string $parameterName, $value, bool $itemType = false): string
25
    {
26 4
        $test = '';
27 4
        if (is_array($value) && 0 < count($value)) {
28 4
            $this->addValidationMethod($parameterName, $value);
29 4
            $test = sprintf('\'\' !== (%s = self::%s($%s))', self::getErrorMessageVariableName($parameterName), $this->getValidationMethodName($parameterName), $parameterName);
30
        }
31
32 4
        return $test;
33
    }
34
35 4
    public function exceptionMessageOnTestFailure(string $parameterName, $value, bool $itemType = false): string
36
    {
37 4
        return self::getErrorMessageVariableName($parameterName);
38
    }
39
40 4
    public static function getErrorMessageVariableName(string $parameterName): string
41
    {
42 4
        return sprintf('$%sUnionErrorMessage', $parameterName);
43
    }
44
45 4
    protected function addValidationMethod(string $parameterName, array $unionValues): void
46
    {
47 4
        $method = new PhpMethod('temp');
48 4
        $rules = clone $this->getRules();
49 4
        $rules->setMethod($method);
50
51
        // gather validation rules
52 4
        foreach ($unionValues as $unionValue) {
53 4
            $attribute = new StructAttribute($this->getGenerator(), 'any', $unionValue);
54 4
            $attribute->setOwner($this->getAttribute()->getOwner());
55 4
            $rules
56 4
                ->setAttribute($attribute)
57 4
                ->applyRules('value')
58 4
            ;
59 4
            unset($attribute);
60
        }
61
62
        // Adapt content, remove duplicated rules
63
        // The duplicated rules are based on the fact that validation rules are composed by 4 lines so we check existing rule every 4-line block of text
64 4
        $exceptions = 0;
65 4
        $exceptionsTests = [];
66 4
        $exceptionsArray = [];
67 4
        $children = [];
68 4
        $methodChildren = $method->getChildren();
69 4
        $childrenCount = count($methodChildren);
70 4
        $existingValidationRules = [];
71 4
        for ($i = 0; $i < $childrenCount; $i += 4) {
72 4
            $validationRules = array_slice($methodChildren, ((int) ($i / 4)) * 4, 4);
73 4
            if (!in_array($validationRules, $existingValidationRules)) {
74 4
                foreach ($validationRules as $validationRuleIndex => $validationRule) {
75
                    // avoid having a validation rule that has already been applied to the attribute within the method which is calling the validate method
76 4
                    if (0 === $validationRuleIndex) {
77 4
                        $ruleParts = [];
78 4
                        preg_match(sprintf('/%s\s(\w*)(.*)?/', self::VALIDATION_RULE_COMMENT_SENTENCE), $validationRule, $ruleParts);
79 4
                        if (3 === count($ruleParts) && !empty($ruleParts[1]) && $rules->getRule($ruleParts[1]) instanceof AbstractRule && Rules::hasRuleBeenAppliedToAttribute($rules->getRule($ruleParts[1]), $ruleParts[2], $this->getAttribute())) {
0 ignored issues
show
Bug introduced by
It seems like $rules->getRule($ruleParts[1]) can also be of type null; however, parameter $rule of WsdlToPhp\PackageGenerat...eenAppliedToAttribute() does only seem to accept WsdlToPhp\PackageGenerat...Validation\AbstractRule, maybe add an additional type check? ( Ignorable by Annotation )

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

79
                        if (3 === count($ruleParts) && !empty($ruleParts[1]) && $rules->getRule($ruleParts[1]) instanceof AbstractRule && Rules::hasRuleBeenAppliedToAttribute(/** @scrutinizer ignore-type */ $rules->getRule($ruleParts[1]), $ruleParts[2], $this->getAttribute())) {
Loading history...
80 4
                            continue 2;
81
                        }
82
                    }
83
84 4
                    if (is_string($validationRule) && false !== mb_strpos($validationRule, 'throw new')) {
85 4
                        $exceptionName = sprintf('$exception%d', $exceptions++);
86 4
                        $validationRule = str_replace('throw new', sprintf('%s = new', $exceptionName), $validationRule);
87 4
                        $exceptionsTests[] = sprintf('isset(%s)', $exceptionName);
88 4
                        $exceptionsArray[] = $exceptionName;
89
                    }
90
91 4
                    $children[] = $validationRule;
92
                }
93
            }
94 4
            $existingValidationRules[] = $validationRules;
95
        }
96
97
        // populate final validation method
98 4
        $method = new PhpMethod($this->getValidationMethodName($parameterName), [
99 4
            new PhpFunctionParameter('value', PhpFunctionParameter::NO_VALUE),
100 4
        ], AbstractModelFile::TYPE_STRING, PhpMethod::ACCESS_PUBLIC, false, true);
101 4
        $method->addChild('$message = \'\';');
102 4
        array_walk($children, [
103 4
            $method,
104 4
            'addChild',
105 4
        ]);
106
107 4
        $method
108 4
            ->addChild(sprintf('if (%s) {', implode(' && ', $exceptionsTests)))
109 4
            ->addChild($method->getIndentedString(sprintf('$message = sprintf("The value %%s does not match any of the union rules: %s. See following errors:\n%%s", var_export($value, true), implode("\n", array_map(function(InvalidArgumentException $e) { return sprintf(\' - %%s\', $e->getMessage()); }, [%s])));', implode(', ', $unionValues), implode(', ', $exceptionsArray)), 1))
110 4
            ->addChild('}')
111 4
            ->addChild(sprintf('unset(%s);', implode(', ', $exceptionsArray)))
112 4
            ->addChild('')
113 4
            ->addChild('return $message;')
114 4
        ;
115 4
        $this->getMethods()->add($method);
116
    }
117
}
118