Passed
Pull Request — master (#41)
by Alexander
01:57 queued 36s
created

Number   A

Complexity

Total Complexity 25

Size/Duplication

Total Lines 120
Duplicated Lines 0 %

Test Coverage

Coverage 95.24%

Importance

Changes 0
Metric Value
eloc 42
dl 0
loc 120
ccs 40
cts 42
cp 0.9524
rs 10
c 0
b 0
f 0
wmc 25

9 Methods

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