Completed
Push — master ( 9b8f8b...ad8621 )
by Mikaël
29:42
created

UnionRule::getErrorMessageVariableName()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1

Importance

Changes 0
Metric Value
cc 1
eloc 1
nc 1
nop 1
dl 0
loc 3
ccs 2
cts 2
cp 1
crap 1
rs 10
c 0
b 0
f 0
1
<?php
2
3
namespace WsdlToPhp\PackageGenerator\File\Validation;
4
5
use WsdlToPhp\PackageGenerator\Model\StructAttribute;
6
use WsdlToPhp\PhpGenerator\Element\PhpFunctionParameter;
7
use WsdlToPhp\PhpGenerator\Element\PhpMethod;
8
9
/**
10
 * Class ListRule
11
 * @link https://www.w3.org/TR/xmlschema-2/#union-datatypes
12
 */
13
class UnionRule extends AbstractRule
14
{
15
16
    /**
17
     * @return string
18
     */
19 12
    public function name()
20
    {
21 12
        return 'union';
22
    }
23
24
    /**
25
     * @param string $parameterName
26
     * @param mixed $value
27
     * @param bool $itemType
28
     * @return string
29
     */
30 12
    public function testConditions($parameterName, $value, $itemType = false)
31
    {
32 12
        $test = '';
33 12
        if (is_array($value) && 0 < count($value)) {
34 12
            $this->addValidationMethod($parameterName, $value);
35 12
            $test = sprintf('\'\' !== (%s = self::%s($%s))', self::getErrorMessageVariableName($parameterName), $this->getValidationMethodName($parameterName), $parameterName);
36 6
        }
37 12
        return $test;
38
    }
39
40
    /**
41
     * @param string $parameterName
42
     * @param mixed $value
43
     * @param bool $itemType
44
     * @return string
45
     */
46 12
    public function exceptionMessageOnTestFailure($parameterName, $value, $itemType = false)
47
    {
48 12
        return self::getErrorMessageVariableName($parameterName);
49
    }
50
51
    /**
52
     * @param string $parameterName
53
     * @param string[] $unionValues
54
     */
55 12
    protected function addValidationMethod($parameterName, array $unionValues)
56
    {
57 12
        $method = new PhpMethod('temp');
58 12
        $rules = clone $this->getRules();
59 12
        $rules->setMethod($method);
60
61
        // gather validation rules
62 12
        foreach ($unionValues as $unionValue) {
63 12
            $attribute = new StructAttribute($this->getGenerator(), 'any', $unionValue);
64 12
            $attribute->setOwner($this->getAttribute()->getOwner());
65
            $rules
66 12
                ->setAttribute($attribute)
67 12
                ->applyRules('value');
68 12
            unset($attribute);
69 6
        }
70
71
        // adapt content, remove duplicated rules
72
        // duplicated rules is base don the fact that validation rules are composed by 4 lines so we check existing rule every 4-line block of text
73 12
        $exceptions = 0;
74 12
        $exceptionsTests = [];
75 12
        $exceptionsArray = [];
76 12
        $children = [];
77 12
        $methodChildren = $method->getChildren();
78 12
        $childrenCount = count($methodChildren);
79 12
        $existingValidationRules = [];
80 12
        for ($i = 0;$i < $childrenCount;$i += 4) {
81 12
            $validationRules = array_slice($methodChildren, ((int) $i / 4) * 4, 4);
82 12
            if (!in_array($validationRules, $existingValidationRules)) {
83 12
                foreach ($validationRules as $validationRuleIndex => $validationRule) {
84
85
                    // avoid having a validation rule that has already been applied to the attribute within the method which is calling the validate method
86 12
                    if (0 === $validationRuleIndex) {
87 12
                        $ruleParts = [];
88 12
                        preg_match(sprintf('/%s\s(\w*)(.*)?/', self::VALIDATION_RULE_COMMENT_SENTENCE), $validationRule, $ruleParts);
89 12
                        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

89
                        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...
90 12
                            continue(2);
91
                        }
92 6
                    }
93
94 12
                    if (is_string($validationRule) && false !== mb_strpos($validationRule, 'throw new')) {
95 12
                        $exceptionName = sprintf('$exception%d', $exceptions++);
96 12
                        $validationRule = str_replace('throw new', sprintf('%s = new', $exceptionName), $validationRule);
97 12
                        $exceptionsTests[] = sprintf('isset(%s)', $exceptionName);
98 12
                        $exceptionsArray[] = $exceptionName;
99 6
                    }
100
101 12
                    $children[] = $validationRule;
102 6
                }
103 6
            }
104 12
            $existingValidationRules[] = $validationRules;
105 6
        }
106
107
        // populate final validation method
108 12
        $method = new PhpMethod($this->getValidationMethodName($parameterName), [
109 12
            new PhpFunctionParameter('value', PhpFunctionParameter::NO_VALUE),
110 12
        ], PhpMethod::ACCESS_PUBLIC, false, true);
111 12
        $method->addChild('$message = \'\';');
112 12
        array_walk($children, [
113 12
            $method,
114 12
            'addChild',
115 6
        ]);
116
        $method
117 12
            ->addChild(sprintf('if (%s) {', implode(' && ', $exceptionsTests)))
118 12
            ->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))
119 12
            ->addChild('}')
120 12
            ->addChild(sprintf('unset(%s);', implode(', ', $exceptionsArray)))
121 12
            ->addChild('return $message;');
122 12
        $this->getMethods()->add($method);
123 12
    }
124
125
    /**
126
     * @param string $parameterName
127
     * @return string
128
     */
129 12
    protected function getValidationMethodName($parameterName)
130
    {
131 12
        return sprintf('validate%sForUnionConstraintsFrom%s', ucfirst($parameterName), ucFirst($this->getMethod()->getName()));
132
    }
133
134
    /**
135
     * @param string $parameterName
136
     * @return string
137
     */
138 12
    public static function getErrorMessageVariableName($parameterName)
139
    {
140 12
        return sprintf('$%sUnionErrorMessage', $parameterName);
141
    }
142
}
143