Completed
Pull Request — master (#175)
by
unknown
02:02 queued 02:02
created

Number::getOptions()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 9
Code Lines 7

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 5
CRAP Score 1

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 1
eloc 7
c 1
b 0
f 0
nc 1
nop 0
dl 0
loc 9
ccs 5
cts 5
cp 1
crap 1
rs 10
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Yiisoft\Validator\Rule;
6
7
use Attribute;
8
use Yiisoft\Strings\NumericHelper;
9
use Yiisoft\Validator\FormatterInterface;
10
use Yiisoft\Validator\Result;
11
use Yiisoft\Validator\Rule;
12
use Yiisoft\Validator\ValidationContext;
13
14
/**
15
 * Validates that the value is a number.
16
 *
17
 * The format of the number must match the regular expression specified in {@see Number::$integerPattern}
18
 * or {@see Number::$numberPattern}. Optionally, you may configure the {@see Number::min()} and {@see Number::max()}
19
 * to ensure the number is within certain range.
20
 */
21
#[Attribute(Attribute::TARGET_PROPERTY)]
22
final class Number extends Rule
23
{
24
    public function __construct(
25
        /**
26
         * @var bool whether the value can only be an integer. Defaults to false.
27
         */
28
        private bool $asInteger = false,
29
        /**
30
         * @var float|int lower limit of the number. Defaults to null, meaning no lower limit.
31
         *
32
         * @see tooSmallMessage for the customized message used when the number is too small.
33
         */
34
        private $min = null,
35
        /**
36
         * @var float|int upper limit of the number. Defaults to null, meaning no upper limit.
37
         *
38
         * @see tooBigMessage for the customized message used when the number is too big.
39
         */
40
        private $max = null,
41
        /**
42
         * @var string user-defined error message used when the value is smaller than {@link $min}.
43
         */
44
        private string $tooSmallMessage = 'Value must be no less than {min}.',
45
        /**
46
         * @var string user-defined error message used when the value is bigger than {@link $max}.
47
         */
48
        private string $tooBigMessage = 'Value must be no greater than {max}.',
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 38
         * that matches floating numbers with optional exponential part (e.g. -1.23e-10).
56
         */
57 38
        private string $numberPattern = '/^\s*[-+]?\d*\.?\d+([eE][-+]?\d+)?\s*$/',
58
        ?FormatterInterface $formatter = null,
59
        bool $skipOnEmpty = false,
60 39
        bool $skipOnError = false,
61
        /**
62 39
         * @var callable|null
63
         */
64 39
        $when = null,
65 5
    ) {
66 5
        parent::__construct(formatter: $formatter, skipOnEmpty: $skipOnEmpty, skipOnError: $skipOnError, when: $when);
67
    }
68
69 34
    protected function validateValue($value, ?ValidationContext $context = null): Result
70
    {
71 34
        $result = new Result();
72 9
73 31
        if (is_bool($value) || !is_scalar($value)) {
74 14
            $result->addError($this->formatMessage($this->getNotANumberMessage(), ['value' => $value]));
75 25
            return $result;
76 9
        }
77
78
        $pattern = $this->asInteger ? $this->integerPattern : $this->numberPattern;
79 34
80
        if (!preg_match($pattern, NumericHelper::normalize($value))) {
81
            $result->addError($this->formatMessage($this->getNotANumberMessage(), ['value' => $value]));
82 9
        } elseif ($this->min !== null && $value < $this->min) {
83
            $result->addError($this->formatMessage($this->tooSmallMessage, ['min' => $this->min]));
84 9
        } elseif ($this->max !== null && $value > $this->max) {
85 9
            $result->addError($this->formatMessage($this->tooBigMessage, ['max' => $this->max]));
86 9
        }
87
88
        return $result;
89 16
    }
90
91 16
    private function getNotANumberMessage(): string
92 16
    {
93 16
        return $this->asInteger ? 'Value must be an integer.' : 'Value must be a number.';
94
    }
95
96 17
    public function getOptions(): array
97
    {
98 17
        return array_merge(parent::getOptions(), [
99 17
            'asInteger' => $this->asInteger,
100 17
            'min' => $this->min,
101
            'max' => $this->max,
102
            'notANumberMessage' => $this->formatMessage($this->getNotANumberMessage()),
103 1
            'tooSmallMessage' => $this->formatMessage($this->tooSmallMessage, ['min' => $this->min]),
104
            'tooBigMessage' => $this->formatMessage($this->tooBigMessage, ['max' => $this->max]),
105 1
        ]);
106 1
    }
107
}
108