Completed
Push — 2.1 ( 75349f...bf116e )
by Alexander
29:27
created

CompareValidator::getClientOptions()   B

Complexity

Conditions 4
Paths 6

Size

Total Lines 30
Code Lines 20

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 20

Importance

Changes 0
Metric Value
dl 0
loc 30
ccs 0
cts 18
cp 0
rs 8.5806
c 0
b 0
f 0
cc 4
eloc 20
nc 6
nop 2
crap 20
1
<?php
2
/**
3
 * @link http://www.yiiframework.com/
4
 * @copyright Copyright (c) 2008 Yii Software LLC
5
 * @license http://www.yiiframework.com/license/
6
 */
7
8
namespace yii\validators;
9
10
use Yii;
11
use yii\base\InvalidConfigException;
12
13
/**
14
 * CompareValidator compares the specified attribute value with another value.
15
 *
16
 * The value being compared with can be another attribute value
17
 * (specified via [[compareAttribute]]) or a constant (specified via
18
 * [[compareValue]]. When both are specified, the latter takes
19
 * precedence. If neither is specified, the attribute will be compared
20
 * with another attribute whose name is by appending "_repeat" to the source
21
 * attribute name.
22
 *
23
 * CompareValidator supports different comparison operators, specified
24
 * via the [[operator]] property.
25
 *
26
 * The default comparison function is based on string values, which means the values
27
 * are compared byte by byte. When comparing numbers, make sure to set the [[$type]]
28
 * to [[TYPE_NUMBER]] to enable numeric comparison.
29
 *
30
 * @author Qiang Xue <[email protected]>
31
 * @since 2.0
32
 */
33
class CompareValidator extends Validator
34
{
35
    /**
36
     * Constant for specifying the comparison [[type]] by numeric values.
37
     * @since 2.0.11
38
     * @see type
39
     */
40
    const TYPE_STRING = 'string';
41
    /**
42
     * Constant for specifying the comparison [[type]] by numeric values.
43
     * @since 2.0.11
44
     * @see type
45
     */
46
    const TYPE_NUMBER = 'number';
47
48
    /**
49
     * @var string the name of the attribute to be compared with. When both this property
50
     * and [[compareValue]] are set, the latter takes precedence. If neither is set,
51
     * it assumes the comparison is against another attribute whose name is formed by
52
     * appending '_repeat' to the attribute being validated. For example, if 'password' is
53
     * being validated, then the attribute to be compared would be 'password_repeat'.
54
     * @see compareValue
55
     */
56
    public $compareAttribute;
57
    /**
58
     * @var mixed the constant value to be compared with. When both this property
59
     * and [[compareAttribute]] are set, this property takes precedence.
60
     * @see compareAttribute
61
     */
62
    public $compareValue;
63
    /**
64
     * @var string the type of the values being compared. The follow types are supported:
65
     *
66
     * - [[TYPE_STRING|string]]: the values are being compared as strings. No conversion will be done before comparison.
67
     * - [[TYPE_NUMBER|number]]: the values are being compared as numbers. String values will be converted into numbers before comparison.
68
     */
69
    public $type = self::TYPE_STRING;
70
    /**
71
     * @var string the operator for comparison. The following operators are supported:
72
     *
73
     * - `==`: check if two values are equal. The comparison is done is non-strict mode.
74
     * - `===`: check if two values are equal. The comparison is done is strict mode.
75
     * - `!=`: check if two values are NOT equal. The comparison is done is non-strict mode.
76
     * - `!==`: check if two values are NOT equal. The comparison is done is strict mode.
77
     * - `>`: check if value being validated is greater than the value being compared with.
78
     * - `>=`: check if value being validated is greater than or equal to the value being compared with.
79
     * - `<`: check if value being validated is less than the value being compared with.
80
     * - `<=`: check if value being validated is less than or equal to the value being compared with.
81
     *
82
     * When you want to compare numbers, make sure to also set [[type]] to `number`.
83
     */
84
    public $operator = '==';
85
    /**
86
     * @var string the user-defined error message. It may contain the following placeholders which
87
     * will be replaced accordingly by the validator:
88
     *
89
     * - `{attribute}`: the label of the attribute being validated
90
     * - `{value}`: the value of the attribute being validated
91
     * - `{compareValue}`: the value or the attribute label to be compared with
92
     * - `{compareAttribute}`: the label of the attribute to be compared with
93
     * - `{compareValueOrAttribute}`: the value or the attribute label to be compared with
94
     */
95
    public $message;
96
97
98
    /**
99
     * @inheritdoc
100
     */
101 7
    public function init()
102
    {
103 7
        parent::init();
104 7
        if ($this->message === null) {
105 7
            switch ($this->operator) {
106 7
                case '==':
107 5
                    $this->message = Yii::t('yii', '{attribute} must be equal to "{compareValueOrAttribute}".');
108 5
                    break;
109 4
                case '===':
110 3
                    $this->message = Yii::t('yii', '{attribute} must be equal to "{compareValueOrAttribute}".');
111 3
                    break;
112 4
                case '!=':
113 4
                    $this->message = Yii::t('yii', '{attribute} must not be equal to "{compareValueOrAttribute}".');
114 4
                    break;
115 3
                case '!==':
116 3
                    $this->message = Yii::t('yii', '{attribute} must not be equal to "{compareValueOrAttribute}".');
117 3
                    break;
118 3
                case '>':
119 3
                    $this->message = Yii::t('yii', '{attribute} must be greater than "{compareValueOrAttribute}".');
120 3
                    break;
121 3
                case '>=':
122 3
                    $this->message = Yii::t('yii', '{attribute} must be greater than or equal to "{compareValueOrAttribute}".');
123 3
                    break;
124 3
                case '<':
125 3
                    $this->message = Yii::t('yii', '{attribute} must be less than "{compareValueOrAttribute}".');
126 3
                    break;
127 3
                case '<=':
128 3
                    $this->message = Yii::t('yii', '{attribute} must be less than or equal to "{compareValueOrAttribute}".');
129 3
                    break;
130
                default:
131 1
                    throw new InvalidConfigException("Unknown operator: {$this->operator}");
132
            }
133
        }
134 7
    }
135
136
    /**
137
     * @inheritdoc
138
     */
139 4
    public function validateAttribute($model, $attribute)
140
    {
141 4
        $value = $model->$attribute;
142 4
        if (is_array($value)) {
143 1
            $this->addError($model, $attribute, Yii::t('yii', '{attribute} is invalid.'));
144
145 1
            return;
146
        }
147 4
        if ($this->compareValue !== null) {
148 3
            $compareLabel = $compareValue = $compareValueOrAttribute = $this->compareValue;
149
        } else {
150 3
            $compareAttribute = $this->compareAttribute === null ? $attribute . '_repeat' : $this->compareAttribute;
151 3
            $compareValue = $model->$compareAttribute;
152 3
            $compareLabel = $compareValueOrAttribute = $model->getAttributeLabel($compareAttribute);
153
        }
154
155 4
        if (!$this->compareValues($this->operator, $this->type, $value, $compareValue)) {
156 4
            $this->addError($model, $attribute, $this->message, [
157 4
                'compareAttribute' => $compareLabel,
158 4
                'compareValue' => $compareValue,
159 4
                'compareValueOrAttribute' => $compareValueOrAttribute,
160
            ]);
161
        }
162 4
    }
163
164
    /**
165
     * @inheritdoc
166
     */
167 2
    protected function validateValue($value)
168
    {
169 2
        if ($this->compareValue === null) {
170 1
            throw new InvalidConfigException('CompareValidator::compareValue must be set.');
171
        }
172 1
        if (!$this->compareValues($this->operator, $this->type, $value, $this->compareValue)) {
173 1
            return [$this->message, [
174 1
                'compareAttribute' => $this->compareValue,
175 1
                'compareValue' => $this->compareValue,
176 1
                'compareValueOrAttribute' => $this->compareValue,
177
            ]];
178
        }
179
180 1
        return null;
181
    }
182
183
    /**
184
     * Compares two values with the specified operator.
185
     * @param string $operator the comparison operator
186
     * @param string $type the type of the values being compared
187
     * @param mixed $value the value being compared
188
     * @param mixed $compareValue another value being compared
189
     * @return bool whether the comparison using the specified operator is true.
190
     */
191 5
    protected function compareValues($operator, $type, $value, $compareValue)
192
    {
193 5
        if ($type === self::TYPE_NUMBER) {
194
            $value = (float) $value;
195
            $compareValue = (float) $compareValue;
196
        } else {
197 5
            $value = (string) $value;
198 5
            $compareValue = (string) $compareValue;
199
        }
200
        switch ($operator) {
201 5
            case '==':
202 4
                return $value == $compareValue;
203 5
            case '===':
204 3
                return $value === $compareValue;
205 5
            case '!=':
206 4
                return $value != $compareValue;
207 4
            case '!==':
208 3
                return $value !== $compareValue;
209 4
            case '>':
210 3
                return $value > $compareValue;
211 4
            case '>=':
212 3
                return $value >= $compareValue;
213 4
            case '<':
214 3
                return $value < $compareValue;
215 4
            case '<=':
216 3
                return $value <= $compareValue;
217
            default:
218 1
                return false;
219
        }
220
    }
221
}
222