Passed
Pull Request — master (#293)
by
unknown
02:21
created

CompareHandler   A

Complexity

Total Complexity 8

Size/Duplication

Total Lines 66
Duplicated Lines 0 %

Test Coverage

Coverage 94.12%

Importance

Changes 1
Bugs 0 Features 0
Metric Value
wmc 8
eloc 34
c 1
b 0
f 0
dl 0
loc 66
ccs 32
cts 34
cp 0.9412
rs 10

3 Methods

Rating   Name   Duplication   Size   Complexity  
A validate() 0 29 5
A __construct() 0 2 1
A compareValues() 0 19 2
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Yiisoft\Validator\Rule;
6
7
use Yiisoft\Translator\TranslatorInterface;
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 82
    public function __construct(private TranslatorInterface $translator)
29
    {
30
    }
31
32 75
    public function validate(mixed $value, object $rule, ValidationContext $context): Result
33
    {
34 75
        if (!$rule instanceof Compare) {
35 7
            throw new UnexpectedRuleException(Compare::class, $rule);
36
        }
37
38 68
        $result = new Result();
39 68
        $targetAttribute = $rule->getTargetAttribute();
40 68
        $targetValue = $rule->getTargetValue();
41
42 68
        if ($targetValue === null && $targetAttribute !== null) {
43 4
            $targetValue = $context->getDataSet()?->getAttributeValue($targetAttribute);
44
        }
45
46 68
        if (!$this->compareValues($rule->getOperator(), $rule->getType(), $value, $targetValue)) {
47 38
            $formattedMessage = $this->translator->translate(
48 38
                $rule->getMessage(),
49
                [
50 38
                    'attribute' => $context->getAttribute(),
51 38
                    'targetValue' => $rule->getTargetValue(),
52 38
                    'targetAttribute' => $rule->getTargetAttribute(),
53 38
                    'targetValueOrAttribute' => $targetValue ?? $targetAttribute,
54
                    'value' => $value,
55
                ]
56
            );
57 38
            $result->addError($formattedMessage);
58
        }
59
60 68
        return $result;
61
    }
62
63
    /**
64
     * Compares two values with the specified operator.
65
     *
66
     * @param string $operator The comparison operator.
67
     * @param string $type The type of the values being compared.
68
     * @param mixed $value The value being compared.
69
     * @param mixed $targetValue Another value being compared.
70
     *
71
     * @return bool Whether the comparison using the specified operator is true.
72
     */
73 68
    private function compareValues(string $operator, string $type, mixed $value, mixed $targetValue): bool
74
    {
75 68
        if ($type === Compare::TYPE_NUMBER) {
76
            $value = (float)$value;
77
            $targetValue = (float)$targetValue;
78
        } else {
79 68
            $value = (string)$value;
80 68
            $targetValue = (string)$targetValue;
81
        }
82 68
        return match ($operator) {
83 13
            '==' => $value == $targetValue,
84 6
            '===' => $value === $targetValue,
85 8
            '!=' => $value != $targetValue,
86 6
            '!==' => $value !== $targetValue,
87 8
            '>' => $value > $targetValue,
88 8
            '>=' => $value >= $targetValue,
89 8
            '<' => $value < $targetValue,
90 11
            '<=' => $value <= $targetValue,
91 68
            default => false,
92
        };
93
    }
94
}
95