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

CompareHandler::validate()   B

Complexity

Conditions 7
Paths 8

Size

Total Lines 34
Code Lines 20

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 17
CRAP Score 7.1653

Importance

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