Passed
Pull Request — master (#99)
by Def
02:08
created

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