Passed
Push — master ( 5c2907...37dc07 )
by Sergei
24:35 queued 21:56
created

CompareHandler::compareValues()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 19
Code Lines 16

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 14
CRAP Score 2.0078

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 16
c 1
b 0
f 0
dl 0
loc 19
ccs 14
cts 16
cp 0.875
rs 9.7333
cc 2
nc 2
nop 4
crap 2.0078
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 69
    public function validate(mixed $value, object $rule, ValidationContext $context): Result
28
    {
29 69
        if (!$rule instanceof Compare) {
30 1
            throw new UnexpectedRuleException(Compare::class, $rule);
31
        }
32
33 68
        $result = new Result();
34 68
        $targetAttribute = $rule->getTargetAttribute();
35 68
        $targetValue = $rule->getTargetValue();
36
37 68
        if ($targetValue === null && $targetAttribute !== null) {
38 4
            $targetValue = $context->getDataSet()?->getAttributeValue($targetAttribute);
39
        }
40
41 68
        if (!$this->compareValues($rule->getOperator(), $rule->getType(), $value, $targetValue)) {
42 38
            $result->addError(
43 38
                $rule->getMessage(),
44
                [
45 38
                    'attribute' => $context->getAttribute(),
46 38
                    'targetValue' => $rule->getTargetValue(),
47 38
                    'targetAttribute' => $rule->getTargetAttribute(),
48 38
                    'targetValueOrAttribute' => $targetValue ?? $targetAttribute,
49
                    'value' => $value,
50
                ],
51
            );
52
        }
53
54 68
        return $result;
55
    }
56
57
    /**
58
     * Compares two values with the specified operator.
59
     *
60
     * @param string $operator The comparison operator.
61
     * @param string $type The type of the values being compared.
62
     * @param mixed $value The value being compared.
63
     * @param mixed $targetValue Another value being compared.
64
     *
65
     * @return bool Whether the comparison using the specified operator is true.
66
     */
67 68
    private function compareValues(string $operator, string $type, mixed $value, mixed $targetValue): bool
68
    {
69 68
        if ($type === Compare::TYPE_NUMBER) {
70
            $value = (float)$value;
71
            $targetValue = (float)$targetValue;
72
        } else {
73 68
            $value = (string)$value;
74 68
            $targetValue = (string)$targetValue;
75
        }
76 68
        return match ($operator) {
77 13
            '==' => $value == $targetValue,
78 6
            '===' => $value === $targetValue,
79 8
            '!=' => $value != $targetValue,
80 6
            '!==' => $value !== $targetValue,
81 8
            '>' => $value > $targetValue,
82 8
            '>=' => $value >= $targetValue,
83 8
            '<' => $value < $targetValue,
84 11
            '<=' => $value <= $targetValue,
85 68
            default => false,
86
        };
87
    }
88
}
89