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 | } |