diff --git a/framework/validators/CompareValidator.php b/framework/validators/CompareValidator.php index 452b84e..9345b73 100644 --- a/framework/validators/CompareValidator.php +++ b/framework/validators/CompareValidator.php @@ -8,6 +8,8 @@ */ namespace yii\validators; +use Yii; +use yii\base\InvalidConfigException; /** * CompareValidator compares the specified attribute value with another value and validates if they are equal. @@ -30,11 +32,18 @@ namespace yii\validators; class CompareValidator extends Validator { /** - * @var string the name of the attribute to be compared with + * @var string the name of the attribute to be compared with. When both this property + * and [[compareValue]] are set, the latter takes precedence. If neither is set, + * it assumes the comparison is against another attribute whose name is formed by + * appending '_repeat' to the attribute being validated. For example, if 'password' is + * being validated, then the attribute to be compared would be 'password_repeat'. + * @see compareValue */ public $compareAttribute; /** - * @var string the constant value to be compared with + * @var string the constant value to be compared with. When both this property + * and [[compareAttribute]] are set, this property takes precedence. + * @see compareAttribute */ public $compareValue; /** @@ -50,16 +59,15 @@ class CompareValidator extends Validator /** * @var string the operator for comparison. Defaults to '='. * The followings are valid operators: - * + * + * - `=` or `==`: validates to see if the two values are equal. If [[strict]] is true, the comparison + * will be done in strict mode (i.e. checking value type as well). + * - `!=`: validates to see if the two values are NOT equal. If [[strict]] is true, the comparison + * will be done in strict mode (i.e. checking value type as well). + * - `>`: validates to see if the value being validated is greater than the value being compared with. + * - `>=`: validates to see if the value being validated is greater than or equal to the value being compared with. + * - `<`: validates to see if the value being validated is less than the value being compared with. + * - `<=`: validates to see if the value being validated is less than or equal to the value being compared with. */ public $operator = '='; @@ -68,7 +76,7 @@ class CompareValidator extends Validator * If there is any error, the error message is added to the object. * @param \yii\base\Model $object the object being validated * @param string $attribute the attribute being validated - * @throws \yii\base\Exception if CompareValidator::operator is invalid + * @throws InvalidConfigException if CompareValidator::operator is invalid */ public function validateAttribute($object, $attribute) { @@ -77,53 +85,53 @@ class CompareValidator extends Validator return; } if ($this->compareValue !== null) { - $compareTo = $compareValue = $this->compareValue; + $compareLabel = $compareValue = $this->compareValue; } else { - $compareAttribute = ($this->compareAttribute === null) ? $attribute . '_repeat' : $this->compareAttribute; + $compareAttribute = $this->compareAttribute === null ? $attribute . '_repeat' : $this->compareAttribute; $compareValue = $object->$compareAttribute; - $compareTo = $object->getAttributeLabel($compareAttribute); + $compareLabel = $object->getAttributeLabel($compareAttribute); } switch ($this->operator) { case '=': case '==': if (($this->strict && $value !== $compareValue) || (!$this->strict && $value != $compareValue)) { - $message = ($this->message !== null) ? $this->message : \Yii::t('yii', '{attribute} must be repeated exactly.'); - $this->addError($object, $attribute, $message, array('{compareAttribute}' => $compareTo)); + $message = ($this->message !== null) ? $this->message : Yii::t('yii', '{attribute} must be repeated exactly.'); + $this->addError($object, $attribute, $message, array('{compareAttribute}' => $compareLabel)); } break; case '!=': if (($this->strict && $value === $compareValue) || (!$this->strict && $value == $compareValue)) { - $message = ($this->message !== null) ? $this->message : \Yii::t('yii', '{attribute} must not be equal to "{compareValue}".'); - $this->addError($object, $attribute, $message, array('{compareAttribute}' => $compareTo, '{compareValue}' => $compareValue)); + $message = ($this->message !== null) ? $this->message : Yii::t('yii', '{attribute} must not be equal to "{compareValue}".'); + $this->addError($object, $attribute, $message, array('{compareAttribute}' => $compareLabel, '{compareValue}' => $compareValue)); } break; case '>': if ($value <= $compareValue) { - $message = ($this->message !== null) ? $this->message : \Yii::t('yii', '{attribute} must be greater than "{compareValue}".'); - $this->addError($object, $attribute, $message, array('{compareAttribute}' => $compareTo, '{compareValue}' => $compareValue)); + $message = ($this->message !== null) ? $this->message : Yii::t('yii', '{attribute} must be greater than "{compareValue}".'); + $this->addError($object, $attribute, $message, array('{compareAttribute}' => $compareLabel, '{compareValue}' => $compareValue)); } break; case '>=': if ($value < $compareValue) { - $message = ($this->message !== null) ? $this->message : \Yii::t('yii', '{attribute} must be greater than or equal to "{compareValue}".'); - $this->addError($object, $attribute, $message, array('{compareAttribute}' => $compareTo, '{compareValue}' => $compareValue)); + $message = ($this->message !== null) ? $this->message : Yii::t('yii', '{attribute} must be greater than or equal to "{compareValue}".'); + $this->addError($object, $attribute, $message, array('{compareAttribute}' => $compareLabel, '{compareValue}' => $compareValue)); } break; case '<': if ($value >= $compareValue) { - $message = ($this->message !== null) ? $this->message : \Yii::t('yii', '{attribute} must be less than "{compareValue}".'); - $this->addError($object, $attribute, $message, array('{compareAttribute}' => $compareTo, '{compareValue}' => $compareValue)); + $message = ($this->message !== null) ? $this->message : Yii::t('yii', '{attribute} must be less than "{compareValue}".'); + $this->addError($object, $attribute, $message, array('{compareAttribute}' => $compareLabel, '{compareValue}' => $compareValue)); } break; case '<=': if ($value > $compareValue) { - $message = ($this->message !== null) ? $this->message : \Yii::t('yii', '{attribute} must be less than or equal to "{compareValue}".'); - $this->addError($object, $attribute, $message, array('{compareAttribute}' => $compareTo, '{compareValue}' => $compareValue)); + $message = ($this->message !== null) ? $this->message : Yii::t('yii', '{attribute} must be less than or equal to "{compareValue}".'); + $this->addError($object, $attribute, $message, array('{compareAttribute}' => $compareLabel, '{compareValue}' => $compareValue)); } break; default: - throw new \yii\base\Exception('Invalid operator "' . $this->operator . '".'); + throw new InvalidConfigException("Unknown operator: {$this->operator}"); } } @@ -132,17 +140,17 @@ class CompareValidator extends Validator * @param \yii\base\Model $object the data object being validated * @param string $attribute the name of the attribute to be validated * @return string the client-side validation script - * @throws \yii\base\Exception if CompareValidator::operator is invalid + * @throws InvalidConfigException if CompareValidator::operator is invalid */ public function clientValidateAttribute($object, $attribute) { if ($this->compareValue !== null) { - $compareTo = $this->compareValue; + $compareLabel = $this->compareValue; $compareValue = json_encode($this->compareValue); } else { - $compareAttribute = ($this->compareAttribute === null) ? $attribute . '_repeat' : $this->compareAttribute; + $compareAttribute = $this->compareAttribute === null ? $attribute . '_repeat' : $this->compareAttribute; $compareValue = "\$('#" . (CHtml::activeId($object, $compareAttribute)) . "').val()"; - $compareTo = $object->getAttributeLabel($compareAttribute); + $compareLabel = $object->getAttributeLabel($compareAttribute); } $message = $this->message; @@ -150,47 +158,47 @@ class CompareValidator extends Validator case '=': case '==': if ($message === null) { - $message = \Yii::t('yii', '{attribute} must be repeated exactly.'); + $message = Yii::t('yii', '{attribute} must be repeated exactly.'); } $condition = 'value!=' . $compareValue; break; case '!=': if ($message === null) { - $message = \Yii::t('yii', '{attribute} must not be equal to "{compareValue}".'); + $message = Yii::t('yii', '{attribute} must not be equal to "{compareValue}".'); } $condition = 'value==' . $compareValue; break; case '>': if ($message === null) { - $message = \Yii::t('yii', '{attribute} must be greater than "{compareValue}".'); + $message = Yii::t('yii', '{attribute} must be greater than "{compareValue}".'); } $condition = 'value<=' . $compareValue; break; case '>=': if ($message === null) { - $message = \Yii::t('yii', '{attribute} must be greater than or equal to "{compareValue}".'); + $message = Yii::t('yii', '{attribute} must be greater than or equal to "{compareValue}".'); } $condition = 'value<' . $compareValue; break; case '<': if ($message === null) { - $message = \Yii::t('yii', '{attribute} must be less than "{compareValue}".'); + $message = Yii::t('yii', '{attribute} must be less than "{compareValue}".'); } $condition = 'value>=' . $compareValue; break; case '<=': if ($message === null) { - $message = \Yii::t('yii', '{attribute} must be less than or equal to "{compareValue}".'); + $message = Yii::t('yii', '{attribute} must be less than or equal to "{compareValue}".'); } $condition = 'value>' . $compareValue; break; default: - throw new \yii\base\Exception('Invalid operator "' . $this->operator . '".'); + throw new InvalidConfigException("Unknown operator: {$this->operator}"); } $message = strtr($message, array( '{attribute}' => $object->getAttributeLabel($attribute), - '{compareValue}' => $compareTo, + '{compareValue}' => $compareLabel, )); return " diff --git a/framework/validators/IntegerValidator.php b/framework/validators/IntegerValidator.php deleted file mode 100644 index d2356da..0000000 --- a/framework/validators/IntegerValidator.php +++ /dev/null @@ -1,52 +0,0 @@ - - * @since 2.0 - */ -class IntegerValidator extends NumberValidator -{ - /** - * @var string the regular expression for matching integers. - */ - public $pattern = '/^\s*[+-]?\d+\s*$/'; - - /** - * Validates the attribute of the object. - * If there is any error, the error message is added to the object. - * @param \yii\base\Model $object the object being validated - * @param string $attribute the attribute being validated - */ - public function validateAttribute($object, $attribute) - { - if ($this->message === null) { - $this->message = \Yii::t('yii', '{attribute} must be an integer.'); - } - parent::validateAttribute($object, $attribute); - } - - /** - * Returns the JavaScript needed for performing client-side validation. - * @param \yii\base\Model $object the data object being validated - * @param string $attribute the name of the attribute to be validated. - * @return string the client-side validation script. - */ - public function clientValidateAttribute($object, $attribute) - { - if ($this->message === null) { - $this->message = \Yii::t('yii', '{attribute} must be an integer.'); - } - return parent::clientValidateAttribute($object, $attribute); - } -} diff --git a/framework/validators/NumberValidator.php b/framework/validators/NumberValidator.php index 3e1cf97..4596fc1 100644 --- a/framework/validators/NumberValidator.php +++ b/framework/validators/NumberValidator.php @@ -9,6 +9,8 @@ namespace yii\validators; +use Yii; + /** * NumberValidator validates that the attribute value is a number. * @@ -22,6 +24,10 @@ namespace yii\validators; class NumberValidator extends Validator { /** + * @var boolean whether the attribute value can only be an integer. Defaults to false. + */ + public $integerOnly = false; + /** * @var boolean whether the attribute value can be null or empty. Defaults to true, * meaning that if the attribute is empty, it is considered valid. */ @@ -43,10 +49,14 @@ class NumberValidator extends Validator */ public $tooSmall; /** + * @var string the regular expression for matching integers. + */ + public $integerPattern = '/^\s*[+-]?\d+\s*$/'; + /** * @var string the regular expression for matching numbers. It defaults to a pattern * that matches floating numbers with optional exponential part (e.g. -1.23e-10). */ - public $pattern = '/^\s*[-+]?[0-9]*\.?[0-9]+([eE][-+]?[0-9]+)?\s*$/'; + public $numberPattern = '/^\s*[-+]?[0-9]*\.?[0-9]+([eE][-+]?[0-9]+)?\s*$/'; /** @@ -61,16 +71,23 @@ class NumberValidator extends Validator if ($this->allowEmpty && $this->isEmpty($value)) { return; } - if (!preg_match($this->pattern, "$value")) { - $message = ($this->message !== null) ? $this->message : \Yii::t('yii', '{attribute} must be a number.'); - $this->addError($object, $attribute, $message); + if ($this->integerOnly) { + if (!preg_match($this->integerPattern, "$value")) { + $message = $this->message !== null ? $this->message : Yii::t('yii', '{attribute} must be an integer.'); + $this->addError($object, $attribute, $message); + } + } else { + if (!preg_match($this->numberPattern, "$value")) { + $message = $this->message !== null ? $this->message : Yii::t('yii', '{attribute} must be a number.'); + $this->addError($object, $attribute, $message); + } } if ($this->min !== null && $value < $this->min) { - $message = ($this->tooSmall !== null) ? $this->tooSmall : \Yii::t('yii', '{attribute} is too small (minimum is {min}).'); + $message = $this->tooSmall !== null ? $this->tooSmall : Yii::t('yii', '{attribute} is too small (minimum is {min}).'); $this->addError($object, $attribute, $message, array('{min}' => $this->min)); } if ($this->max !== null && $value > $this->max) { - $message = ($this->tooBig !== null) ? $this->tooBig : \Yii::t('yii', '{attribute} is too big (maximum is {max}).'); + $message = $this->tooBig !== null ? $this->tooBig : Yii::t('yii', '{attribute} is too big (maximum is {max}).'); $this->addError($object, $attribute, $message, array('{max}' => $this->max)); } } @@ -84,49 +101,46 @@ class NumberValidator extends Validator public function clientValidateAttribute($object, $attribute) { $label = $object->getAttributeLabel($attribute); - $value = $object->$attribute; if (($message = $this->message) === null) { - $message = \Yii::t('yii', '{attribute} must be a number.'); + $message = $this->integerOnly ? Yii::t('yii', '{attribute} must be an integer.') + : Yii::t('yii', '{attribute} must be a number.'); } $message = strtr($message, array( '{attribute}' => $label, - '{value}' => $value, - )); - - if (($tooBig = $this->tooBig) === null) { - $tooBig = \Yii::t('yii', '{attribute} is too big (maximum is {max}).'); - } - $tooBig = strtr($tooBig, array( - '{attribute}' => $label, - '{value}' => $value, - '{max}' => $this->max, - )); - - if (($tooSmall = $this->tooSmall) === null) { - $tooSmall = \Yii::t('yii', '{attribute} is too small (minimum is {min}).'); - } - $tooSmall = strtr($tooSmall, array( - '{attribute}' => $label, - '{value}' => $value, - '{min}' => $this->min, )); + $pattern = $this->integerOnly ? $this->integerPattern : $this->numberPattern; $js = " -if(!value.match({$this->pattern})) { +if(!value.match($pattern)) { messages.push(" . json_encode($message) . "); } "; if ($this->min !== null) { + if (($tooSmall = $this->tooSmall) === null) { + $tooSmall = Yii::t('yii', '{attribute} is too small (minimum is {min}).'); + } + $tooSmall = strtr($tooSmall, array( + '{attribute}' => $label, + '{min}' => $this->min, + )); + $js .= " -if(value< {$this->min}) { +if(value<{$this->min}) { messages.push(" . json_encode($tooSmall) . "); } "; } if ($this->max !== null) { + if (($tooBig = $this->tooBig) === null) { + $tooBig = Yii::t('yii', '{attribute} is too big (maximum is {max}).'); + } + $tooBig = strtr($tooBig, array( + '{attribute}' => $label, + '{max}' => $this->max, + )); $js .= " -if(value> {$this->max}) { +if(value>{$this->max}) { messages.push(" . json_encode($tooBig) . "); } "; @@ -134,7 +148,7 @@ if(value> {$this->max}) { if ($this->allowEmpty) { $js = " -if($.trim(value)!='') { +if(jQuery.trim(value)!='') { $js } "; @@ -142,4 +156,4 @@ if($.trim(value)!='') { return $js; } -} +} \ No newline at end of file diff --git a/framework/validators/Validator.php b/framework/validators/Validator.php index a213ae4..a03da7a 100644 --- a/framework/validators/Validator.php +++ b/framework/validators/Validator.php @@ -59,8 +59,12 @@ abstract class Validator extends Component 'file' => 'yii\validators\FileValidator', 'filter' => 'yii\validators\FilterValidator', 'in' => 'yii\validators\RangeValidator', - 'integer' => 'yii\validators\IntegerValidator', + 'integer' => array( + 'class' => 'yii\validators\NumberValidator', + 'integerOnly' => true, + ), 'match' => 'yii\validators\RegularExpressionValidator', + 'number' => 'yii\validators\NumberValidator', 'required' => 'yii\validators\RequiredValidator', 'string' => 'yii\validators\StringValidator', 'unique' => 'yii\validators\UniqueValidator', @@ -120,6 +124,7 @@ abstract class Validator extends Component if (!is_array($attributes)) { $attributes = preg_split('/[\s,]+/', $attributes, -1, PREG_SPLIT_NO_EMPTY); } + $params['attributes'] = $attributes; if (isset($params['on']) && !is_array($params['on'])) { $params['on'] = preg_split('/[\s,]+/', $params['on'], -1, PREG_SPLIT_NO_EMPTY); @@ -131,25 +136,22 @@ abstract class Validator extends Component if (method_exists($object, $type)) { // method-based validator - $config = array( - 'class' => __NAMESPACE__ . '\InlineValidator', - 'method' => $type, - 'attributes' => $attributes, - ); + $params['class'] = __NAMESPACE__ . '\InlineValidator'; + $params['method'] = $type; } else { - if (is_string($type) && isset(self::$builtInValidators[$type])) { + if (isset(self::$builtInValidators[$type])) { $type = self::$builtInValidators[$type]; } - $config = array( - 'class' => $type, - 'attributes' => $attributes, - ); - } - foreach ($params as $name => $value) { - $config[$name] = $value; + if (is_array($type)) { + foreach ($type as $name => $value) { + $params[$name] = $value; + } + } else { + $params['class'] = $type; + } } - return \Yii::createObject($config); + return \Yii::createObject($params); } /** @@ -240,6 +242,6 @@ abstract class Validator extends Component public function isEmpty($value, $trim = false) { return $value === null || $value === array() || $value === '' - || $trim && is_scalar($value) && trim($value) === ''; + || $trim && is_scalar($value) && trim($value) === ''; } } diff --git a/todo.md b/todo.md index 400942e..7e5f256 100644 --- a/todo.md +++ b/todo.md @@ -13,9 +13,8 @@ - validators * FileValidator: depends on CUploadedFile * CaptchaValidator: depends on CaptchaAction - * type conversion rules - * CompareValidator::clientValidateAttribute(): search for "CHtml::activeId" - * DateValidator: TBD + * DateValidator: should we use CDateTimeParser, or simply use strtotime()? + * CompareValidator::clientValidateAttribute(): depends on CHtml::activeId() ---