Passed
Pull Request — master (#81)
by Def
01:28
created

Number::getOptions()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 11
Code Lines 8

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 9
CRAP Score 1

Importance

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