Passed
Pull Request — master (#124)
by Rustam
07:20
created

Number::getNotANumberMessage()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 6
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 4
CRAP Score 2

Importance

Changes 0
Metric Value
cc 2
dl 0
loc 6
rs 10
c 0
b 0
f 0
eloc 3
nc 2
nop 0
ccs 4
cts 4
cp 1
crap 2
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Yiisoft\Validator\Rule;
6
7
use Yiisoft\Strings\NumericHelper;
8
use Yiisoft\Validator\Result;
9
use Yiisoft\Validator\Rule;
10
use Yiisoft\Validator\ValidationContext;
11
12
/**
13
 * NumberValidator validates that the attribute value is a number.
14
 *
15
 * The format of the number must match the regular expression specified in {@see Number::$integerPattern}
16
 * or {@see Number::$numberPattern}. Optionally, you may configure the {@see Number::max()} and {@see Number::min()}
17
 * to ensure the number is within certain range.
18
 */
19
class Number extends Rule
20
{
21
    /**
22
     * @var bool whether the attribute value can only be an integer. Defaults to false.
23
     */
24
    private bool $asInteger = false;
25
    /**
26
     * @var bool whether to check the attribute value in strict mode. Defaults to false.
27
     */
28
    private bool $strict = false;
29
    /**
30
     * @var float|int upper limit of the number. Defaults to null, meaning no upper limit.
31
     *
32
     * @see tooBigMessage for the customized message used when the number is too big.
33
     */
34
    private $max;
35
    /**
36
     * @var float|int lower limit of the number. Defaults to null, meaning no lower limit.
37
     *
38
     * @see tooSmallMessage for the customized message used when the number is too small.
39
     */
40
    private $min;
41
    /**
42
     * @var string user-defined error message used when the value is bigger than {@link $max}.
43
     */
44
    private string $tooBigMessage = 'Value must be no greater than {max}.';
45
    /**
46
     * @var string user-defined error message used when the value is smaller than {@link $min}.
47
     */
48
    private string $tooSmallMessage = 'Value must be no less than {min}.';
49
    /**
50
     * @var string the regular expression for matching integers.
51
     */
52
    private string $integerPattern = '/^\s*[+-]?\d+\s*$/';
53
    /**
54
     * @var string the regular expression for matching numbers. It defaults to a pattern
55
     * that matches floating numbers with optional exponential part (e.g. -1.23e-10).
56
     */
57
    private string $numberPattern = '/^\s*[-+]?\d*\.?\d+([eE][-+]?\d+)?\s*$/';
58
59 36
    protected function validateValue($value, ValidationContext $context = null): Result
60
    {
61 36
        $result = new Result();
62
63 36
        if (($this->strict && is_bool($value)) || !is_scalar($value)) {
64 5
            $result->addError($this->formatMessage($this->getNotANumberMessage(), ['value' => $value]));
65 5
            return $result;
66
        }
67
68 31
        $pattern = $this->asInteger ? $this->integerPattern : $this->numberPattern;
69
70 31
        if (!preg_match($pattern, NumericHelper::normalize($value))) {
71 9
            $result->addError($this->formatMessage($this->getNotANumberMessage(), ['value' => $value]));
72 28
        } elseif ($this->min !== null && $value < $this->min) {
73 12
            $result->addError($this->formatMessage($this->tooSmallMessage, ['min' => $this->min]));
74 23
        } elseif ($this->max !== null && $value > $this->max) {
75 7
            $result->addError($this->formatMessage($this->tooBigMessage, ['max' => $this->max]));
76
        }
77
78 31
        return $result;
79
    }
80
81 9
    public function integer(): self
82
    {
83 9
        $new = clone $this;
84 9
        $new->asInteger = true;
85 9
        return $new;
86
    }
87
88 1
    public function strict(): self
89
    {
90 1
        $new = clone $this;
91 1
        $new->strict = true;
92 1
        return $new;
93
    }
94
95 13
    public function min($value): self
96
    {
97 13
        $new = clone $this;
98 13
        $new->min = $value;
99 13
        return $new;
100
    }
101
102 14
    public function max($value): self
103
    {
104 14
        $new = clone $this;
105 14
        $new->max = $value;
106 14
        return $new;
107
    }
108
109 1
    public function tooSmallMessage(string $message): self
110
    {
111 1
        $new = clone $this;
112 1
        $new->tooSmallMessage = $message;
113 1
        return $new;
114
    }
115
116
    public function tooBigMessage(string $message): self
117
    {
118
        $new = clone $this;
119
        $new->tooBigMessage = $message;
120
        return $new;
121
    }
122
123 22
    private function getNotANumberMessage(): string
124
    {
125 22
        if ($this->asInteger === true) {
126 9
            return 'Value must be an integer.';
127
        }
128 14
        return 'Value must be a number.';
129
    }
130
131 8
    public function getOptions(): array
132
    {
133 8
        return array_merge(
134 8
            parent::getOptions(),
135
            [
136 8
                'notANumberMessage' => $this->formatMessage($this->getNotANumberMessage()),
137 8
                'asInteger' => $this->asInteger,
138 8
                'min' => $this->min,
139 8
                'tooSmallMessage' => $this->formatMessage($this->tooSmallMessage, ['min' => $this->min]),
140 8
                'max' => $this->max,
141 8
                'tooBigMessage' => $this->formatMessage($this->tooBigMessage, ['max' => $this->max]),
142
            ],
143
        );
144
    }
145
}
146