Code Coverage |
||||||||||
Lines |
Functions and Methods |
Classes and Traits |
||||||||
Total | |
100.00% |
59 / 59 |
|
100.00% |
5 / 5 |
CRAP | |
100.00% |
1 / 1 |
UnionRule | |
100.00% |
59 / 59 |
|
100.00% |
5 / 5 |
18 | |
100.00% |
1 / 1 |
name | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
testConditions | |
100.00% |
5 / 5 |
|
100.00% |
1 / 1 |
3 | |||
exceptionMessageOnTestFailure | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
getErrorMessageVariableName | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
addValidationMethod | |
100.00% |
51 / 51 |
|
100.00% |
1 / 1 |
12 |
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 | public function name(): string |
20 | { |
21 | return self::NAME; |
22 | } |
23 | |
24 | public function testConditions(string $parameterName, $value, bool $itemType = false): string |
25 | { |
26 | $test = ''; |
27 | if (is_array($value) && 0 < count($value)) { |
28 | $this->addValidationMethod($parameterName, $value); |
29 | $test = sprintf('\'\' !== (%s = self::%s($%s))', self::getErrorMessageVariableName($parameterName), $this->getValidationMethodName($parameterName), $parameterName); |
30 | } |
31 | |
32 | return $test; |
33 | } |
34 | |
35 | public function exceptionMessageOnTestFailure(string $parameterName, $value, bool $itemType = false): string |
36 | { |
37 | return self::getErrorMessageVariableName($parameterName); |
38 | } |
39 | |
40 | public static function getErrorMessageVariableName(string $parameterName): string |
41 | { |
42 | return sprintf('$%sUnionErrorMessage', $parameterName); |
43 | } |
44 | |
45 | protected function addValidationMethod(string $parameterName, array $unionValues): void |
46 | { |
47 | $method = new PhpMethod('temp'); |
48 | $rules = clone $this->getRules(); |
49 | $rules->setMethod($method); |
50 | |
51 | // gather validation rules |
52 | foreach ($unionValues as $unionValue) { |
53 | $attribute = new StructAttribute($this->getGenerator(), 'any', $unionValue); |
54 | $attribute->setOwner($this->getAttribute()->getOwner()); |
55 | $rules |
56 | ->setAttribute($attribute) |
57 | ->applyRules('value') |
58 | ; |
59 | 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 | $exceptions = 0; |
65 | $exceptionsTests = []; |
66 | $exceptionsArray = []; |
67 | $children = []; |
68 | $methodChildren = $method->getChildren(); |
69 | $childrenCount = count($methodChildren); |
70 | $existingValidationRules = []; |
71 | for ($i = 0; $i < $childrenCount; $i += 4) { |
72 | $validationRules = array_slice($methodChildren, ((int) ($i / 4)) * 4, 4); |
73 | if (!in_array($validationRules, $existingValidationRules)) { |
74 | 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 | if (0 === $validationRuleIndex) { |
77 | $ruleParts = []; |
78 | preg_match(sprintf('/%s\s(\w*)(.*)?/', self::VALIDATION_RULE_COMMENT_SENTENCE), $validationRule, $ruleParts); |
79 | if (3 === count($ruleParts) && !empty($ruleParts[1]) && $rules->getRule($ruleParts[1]) instanceof AbstractRule && Rules::hasRuleBeenAppliedToAttribute($rules->getRule($ruleParts[1]), $ruleParts[2], $this->getAttribute())) { |
80 | continue 2; |
81 | } |
82 | } |
83 | |
84 | if (is_string($validationRule) && false !== mb_strpos($validationRule, 'throw new')) { |
85 | $exceptionName = sprintf('$exception%d', $exceptions++); |
86 | $validationRule = str_replace('throw new', sprintf('%s = new', $exceptionName), $validationRule); |
87 | $exceptionsTests[] = sprintf('isset(%s)', $exceptionName); |
88 | $exceptionsArray[] = $exceptionName; |
89 | } |
90 | |
91 | $children[] = $validationRule; |
92 | } |
93 | } |
94 | $existingValidationRules[] = $validationRules; |
95 | } |
96 | |
97 | // populate final validation method |
98 | $method = new PhpMethod($this->getValidationMethodName($parameterName), [ |
99 | new PhpFunctionParameter('value', PhpFunctionParameter::NO_VALUE), |
100 | ], AbstractModelFile::TYPE_STRING, PhpMethod::ACCESS_PUBLIC, false, true); |
101 | $method->addChild('$message = \'\';'); |
102 | array_walk($children, [ |
103 | $method, |
104 | 'addChild', |
105 | ]); |
106 | |
107 | $method |
108 | ->addChild(sprintf('if (%s) {', implode(' && ', $exceptionsTests))) |
109 | ->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 | ->addChild('}') |
111 | ->addChild(sprintf('unset(%s);', implode(', ', $exceptionsArray))) |
112 | ->addChild('') |
113 | ->addChild('return $message;') |
114 | ; |
115 | $this->getMethods()->add($method); |
116 | } |
117 | } |