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