Passed
Pull Request — master (#364)
by
unknown
02:54
created

CompareHandler::validate()   B

Complexity

Conditions 7
Paths 8

Size

Total Lines 40
Code Lines 23

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 21
CRAP Score 7.0322

Importance

Changes 3
Bugs 0 Features 0
Metric Value
eloc 23
c 3
b 0
f 0
dl 0
loc 40
ccs 21
cts 23
cp 0.913
rs 8.6186
cc 7
nc 8
nop 3
crap 7.0322
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Yiisoft\Validator\Rule;
6
7
use Yiisoft\Validator\Exception\UnexpectedRuleException;
8
use Yiisoft\Validator\Result;
9
use Yiisoft\Validator\RuleHandlerInterface;
10
use Yiisoft\Validator\ValidationContext;
11
12
/**
13
 * Compares the specified value with another value.
14
 *
15
 * The value being compared with {@see Compare::$targetValue} or {@see Compare::$targetAttribute}, which is set
16
 * in the constructor.
17
 *
18
 * It supports different comparison operators, specified
19
 * via the {@see Compare::$operator}.
20
 *
21
 * The default comparison function is based on string values, which means the values
22
 * are compared byte by byte. When comparing numbers, make sure to change {@see Compare::$type} to
23
 * {@see Compare::TYPE_NUMBER} to enable numeric comparison.
24
 */
25
final class CompareHandler implements RuleHandlerInterface
26
{
27 73
    public function validate(mixed $value, object $rule, ValidationContext $context): Result
28
    {
29 73
        if (!$rule instanceof Compare) {
30 1
            throw new UnexpectedRuleException(Compare::class, $rule);
31
        }
32
33 72
        $result = new Result();
34 72
        $targetAttribute = $rule->getTargetAttribute();
35 72
        $targetValue = $rule->getTargetValue();
36
37 72
        if ($targetValue === null && $targetAttribute !== null) {
38
            /** @var mixed $targetValue */
39 5
            $targetValue = $context->getDataSet()?->getAttributeValue($targetAttribute);
40 5
            if (!is_scalar($targetValue)) {
41 1
                return $result->addError($rule->getIncorrectDataSetTypeMessage(), [
42 1
                    'attribute' => $context->getAttribute(),
43 1
                    'type' => get_debug_type($targetValue),
44
                ]);
45
            }
46
        }
47
48 71
        if ($this->compareValues($rule->getOperator(), $rule->getType(), $value, $targetValue)) {
49 32
            return $result;
50
        }
51
52 39
        $parameters = [
53 39
            'attribute' => $context->getAttribute(),
54 39
            'targetValue' => $rule->getTargetValue(),
55 39
            'targetAttribute' => $rule->getTargetAttribute(),
56
            'targetValueOrAttribute' => $targetValue ?? $targetAttribute,
57
        ];
58 39
        if (is_scalar($value)) {
59 39
            $parameters['value'] = $value;
60
61 39
            return $result->addError($rule->getScalarMessage(), $parameters);
62
        }
63
64
        $parameters['type'] = get_debug_type($value);
65
66
        return $result->addError($rule->getNonScalarMessage(), $parameters);
67
    }
68
69
    /**
70
     * Compares two values with the specified operator.
71
     *
72
     * @param string $operator The comparison operator.
73
     * @param string $type The type of the values being compared.
74
     * @param mixed $value The value being compared.
75
     * @param mixed $targetValue Another value being compared.
76
     *
77
     * @return bool Whether the comparison using the specified operator is true.
78
     */
79 71
    private function compareValues(string $operator, string $type, mixed $value, mixed $targetValue): bool
80
    {
81 71
        if ($type === Compare::TYPE_NUMBER) {
82 2
            $value = (float) $value;
83 2
            $targetValue = (float) $targetValue;
84
        } else {
85 69
            $value = (string) $value;
86 69
            $targetValue = (string) $targetValue;
87
        }
88
89 71
        return match ($operator) {
90 14
            '==' => $value == $targetValue,
91 8
            '===' => $value === $targetValue,
92 8
            '!=' => $value != $targetValue,
93 6
            '!==' => $value !== $targetValue,
94 8
            '>' => $value > $targetValue,
95 8
            '>=' => $value >= $targetValue,
96 8
            '<' => $value < $targetValue,
97 71
            '<=' => $value <= $targetValue,
98
        };
99
    }
100
}
101