Commit 3bd186de by Qiang Xue

refactored validators.

parent b5b1d91e
...@@ -580,8 +580,9 @@ abstract class Module extends Component ...@@ -580,8 +580,9 @@ abstract class Module extends Component
* instance of it. * instance of it.
* *
* @param string $route the route consisting of module, controller and action IDs. * @param string $route the route consisting of module, controller and action IDs.
* @return array|boolean if the controller is created successfully, it will be returned together * @return array|boolean If the controller is created successfully, it will be returned together
* with the remainder of the route which represents the action ID. Otherwise false will be returned. * with the requested action ID. Otherwise false will be returned.
* @throws InvalidConfigException if the controller class and its file do not match.
*/ */
public function createController($route) public function createController($route)
{ {
......
...@@ -7,6 +7,8 @@ ...@@ -7,6 +7,8 @@
namespace yii\validators; namespace yii\validators;
use Yii;
/** /**
* BooleanValidator checks if the attribute value is a boolean value. * BooleanValidator checks if the attribute value is a boolean value.
* *
...@@ -32,11 +34,6 @@ class BooleanValidator extends Validator ...@@ -32,11 +34,6 @@ class BooleanValidator extends Validator
* Defaults to false, meaning only the value needs to be matched. * Defaults to false, meaning only the value needs to be matched.
*/ */
public $strict = false; public $strict = 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.
*/
public $allowEmpty = true;
/** /**
* Validates the attribute of the object. * Validates the attribute of the object.
...@@ -47,12 +44,8 @@ class BooleanValidator extends Validator ...@@ -47,12 +44,8 @@ class BooleanValidator extends Validator
public function validateAttribute($object, $attribute) public function validateAttribute($object, $attribute)
{ {
$value = $object->$attribute; $value = $object->$attribute;
if ($this->allowEmpty && $this->isEmpty($value)) { if (!$this->validateValue($value)) {
return; $message = $this->message !== null ? $this->message : Yii::t('yii|{attribute} must be either "{true}" or "{false}".');
}
if (!$this->strict && $value != $this->trueValue && $value != $this->falseValue
|| $this->strict && $value !== $this->trueValue && $value !== $this->falseValue) {
$message = ($this->message !== null) ? $this->message : \Yii::t('yii|{attribute} must be either {true} or {false}.');
$this->addError($object, $attribute, $message, array( $this->addError($object, $attribute, $message, array(
'{true}' => $this->trueValue, '{true}' => $this->trueValue,
'{false}' => $this->falseValue, '{false}' => $this->falseValue,
...@@ -60,13 +53,15 @@ class BooleanValidator extends Validator ...@@ -60,13 +53,15 @@ class BooleanValidator extends Validator
} }
} }
/**
* Validates the given value.
* @param mixed $value the value to be validated.
* @return boolean whether the value is valid.
*/
public function validateValue($value) public function validateValue($value)
{ {
if ($this->allowEmpty && $this->isEmpty($value)) { return $this->strict && ($value == $this->trueValue || $value == $this->falseValue)
return; || !$this->strict && ($value === $this->trueValue || $value === $this->falseValue);
}
return ($this->strict || $value == $this->trueValue || $value == $this->falseValue)
&& (!$this->strict || $value === $this->trueValue || $value === $this->falseValue);
} }
/** /**
...@@ -77,7 +72,7 @@ class BooleanValidator extends Validator ...@@ -77,7 +72,7 @@ class BooleanValidator extends Validator
*/ */
public function clientValidateAttribute($object, $attribute) public function clientValidateAttribute($object, $attribute)
{ {
$message = ($this->message !== null) ? $this->message : \Yii::t('yii|{attribute} must be either {true} or {false}.'); $message = ($this->message !== null) ? $this->message : Yii::t('yii|{attribute} must be either "{true}" or "{false}".');
$message = strtr($message, array( $message = strtr($message, array(
'{attribute}' => $object->getAttributeLabel($attribute), '{attribute}' => $object->getAttributeLabel($attribute),
'{value}' => $object->$attribute, '{value}' => $object->$attribute,
......
...@@ -7,6 +7,9 @@ ...@@ -7,6 +7,9 @@
namespace yii\validators; namespace yii\validators;
use Yii;
use yii\base\InvalidConfigException;
/** /**
* CaptchaValidator validates that the attribute value is the same as the verification code displayed in the CAPTCHA. * CaptchaValidator validates that the attribute value is the same as the verification code displayed in the CAPTCHA.
* *
...@@ -22,16 +25,10 @@ class CaptchaValidator extends Validator ...@@ -22,16 +25,10 @@ class CaptchaValidator extends Validator
*/ */
public $caseSensitive = false; public $caseSensitive = false;
/** /**
* @var string the ID of the action that renders the CAPTCHA image. Defaults to 'captcha', * @var string the route of the controller action that renders the CAPTCHA image.
* meaning the `captcha` action declared in the current controller.
* This can also be a route consisting of controller ID and action ID (e.g. 'site/captcha').
*/
public $captchaAction = 'captcha';
/**
* @var boolean whether the attribute value can be null or empty.
* Defaults to false, meaning the attribute is invalid if it is empty.
*/ */
public $allowEmpty = false; public $captchaAction = 'site/captcha';
/** /**
* Validates the attribute of the object. * Validates the attribute of the object.
...@@ -42,36 +39,39 @@ class CaptchaValidator extends Validator ...@@ -42,36 +39,39 @@ class CaptchaValidator extends Validator
public function validateAttribute($object, $attribute) public function validateAttribute($object, $attribute)
{ {
$value = $object->$attribute; $value = $object->$attribute;
if ($this->allowEmpty && $this->isEmpty($value)) { if (!$this->validateValue($value)) {
return; $message = $this->message !== null ? $this->message : Yii::t('yii|The verification code is incorrect.');
}
$captcha = $this->getCaptchaAction();
if (!$captcha->validate($value, $this->caseSensitive)) {
$message = $this->message !== null ? $this->message : \Yii::t('yii|The verification code is incorrect.');
$this->addError($object, $attribute, $message); $this->addError($object, $attribute, $message);
} }
} }
/** /**
* Validates the given value.
* @param mixed $value the value to be validated.
* @return boolean whether the value is valid.
*/
public function validateValue($value)
{
$captcha = $this->getCaptchaAction();
return $captcha->validate($value, $this->caseSensitive);
}
/**
* Returns the CAPTCHA action object. * Returns the CAPTCHA action object.
* @return CCaptchaAction the action object * @return CaptchaAction the action object
*/ */
public function getCaptchaAction() public function getCaptchaAction()
{ {
if (strpos($this->captchaAction, '/') !== false) { // contains controller or module $ca = Yii::$app->createController($this->captchaAction);
$ca = \Yii::$app->createController($this->captchaAction); if ($ca !== false) {
if ($ca !== null) { /** @var \yii\base\Controller $controller */
list($controller, $actionID) = $ca; list($controller, $actionID) = $ca;
$action = $controller->createAction($actionID); $action = $controller->createAction($actionID);
if ($action !== null) {
return $action;
} }
} else {
$action = \Yii::$app->getController()->createAction($this->captchaAction);
}
if ($action === null) {
throw new \yii\base\Exception('Invalid captcha action ID: ' . $this->captchaAction);
} }
return $action; throw new InvalidConfigException('Invalid CAPTCHA action ID: ' . $this->captchaAction);
} }
/** /**
......
...@@ -6,6 +6,7 @@ ...@@ -6,6 +6,7 @@
*/ */
namespace yii\validators; namespace yii\validators;
use Yii; use Yii;
use yii\base\InvalidConfigException; use yii\base\InvalidConfigException;
...@@ -45,23 +46,12 @@ class CompareValidator extends Validator ...@@ -45,23 +46,12 @@ class CompareValidator extends Validator
*/ */
public $compareValue; public $compareValue;
/** /**
* @var boolean whether the comparison is strict (both value and type must be the same.) * @var string the operator for comparison. The following operators are supported:
* Defaults to false. *
*/ * - '==': validates to see if the two values are equal. The comparison is done is non-strict mode.
public $strict = false; * - '===': validates to see if the two values are equal. The comparison is done is strict mode.
/** * - '!=': validates to see if the two values are NOT equal. The comparison is done is non-strict mode.
* @var boolean whether the attribute value can be null or empty. Defaults to false. * - '!==': validates to see if the two values are NOT equal. The comparison is done is strict mode.
* If this is true, it means the attribute is considered valid when it is empty.
*/
public $allowEmpty = false;
/**
* @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 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 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 the value being compared with.
...@@ -79,9 +69,6 @@ class CompareValidator extends Validator ...@@ -79,9 +69,6 @@ class CompareValidator extends Validator
public function validateAttribute($object, $attribute) public function validateAttribute($object, $attribute)
{ {
$value = $object->$attribute; $value = $object->$attribute;
if ($this->allowEmpty && $this->isEmpty($value)) {
return;
}
if ($this->compareValue !== null) { if ($this->compareValue !== null) {
$compareLabel = $compareValue = $this->compareValue; $compareLabel = $compareValue = $this->compareValue;
} else { } else {
...@@ -91,15 +78,26 @@ class CompareValidator extends Validator ...@@ -91,15 +78,26 @@ class CompareValidator extends Validator
} }
switch ($this->operator) { switch ($this->operator) {
case '=':
case '==': case '==':
if (($this->strict && $value !== $compareValue) || (!$this->strict && $value != $compareValue)) { if ($value != $compareValue) {
$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 ($value !== $compareValue) {
$message = ($this->message !== null) ? $this->message : Yii::t('yii|{attribute} must be repeated exactly.'); $message = ($this->message !== null) ? $this->message : Yii::t('yii|{attribute} must be repeated exactly.');
$this->addError($object, $attribute, $message, array('{compareAttribute}' => $compareLabel)); $this->addError($object, $attribute, $message, array('{compareAttribute}' => $compareLabel));
} }
break; break;
case '!=': case '!=':
if (($this->strict && $value === $compareValue) || (!$this->strict && $value == $compareValue)) { if ($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}' => $compareLabel, '{compareValue}' => $compareValue));
}
break;
case '!==':
if ($value === $compareValue) {
$message = ($this->message !== null) ? $this->message : Yii::t('yii|{attribute} must not be equal to "{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)); $this->addError($object, $attribute, $message, array('{compareAttribute}' => $compareLabel, '{compareValue}' => $compareValue));
} }
...@@ -134,6 +132,31 @@ class CompareValidator extends Validator ...@@ -134,6 +132,31 @@ class CompareValidator extends Validator
} }
/** /**
* Validates the given value.
* @param mixed $value the value to be validated.
* @return boolean whether the value is valid.
*/
public function validateValue($value)
{
if ($this->compareValue === null) {
throw new InvalidConfigException('CompareValidator::compareValue must be set.');
}
switch ($this->operator) {
case '==': return $value == $this->compareValue;
case '===': return $value === $this->compareValue;
case '!=': return $value != $this->compareValue;
case '!==': return $value !== $this->compareValue;
case '>': return $value > $this->compareValue;
case '>=': return $value >= $this->compareValue;
case '<': return $value < $this->compareValue;
case '<=': return $value <= $this->compareValue;
default:
throw new InvalidConfigException("Unknown operator \"{$this->operator}\"");
}
}
/**
* Returns the JavaScript needed for performing client-side validation. * Returns the JavaScript needed for performing client-side validation.
* @param \yii\base\Model $object the data object being validated * @param \yii\base\Model $object the data object being validated
* @param string $attribute the name of the attribute to be validated * @param string $attribute the name of the attribute to be validated
......
...@@ -10,12 +10,8 @@ namespace yii\validators; ...@@ -10,12 +10,8 @@ namespace yii\validators;
/** /**
* DefaultValueValidator sets the attribute to be the specified default value. * DefaultValueValidator sets the attribute to be the specified default value.
* *
* By default, when the attribute being validated is [[isEmpty|empty]], the validator
* will assign a default [[value]] to it. However, if [[setOnEmpty]] is false, the validator
* will always assign the default [[value]] to the attribute, no matter it is empty or not.
*
* DefaultValueValidator is not really a validator. It is provided mainly to allow * DefaultValueValidator is not really a validator. It is provided mainly to allow
* specifying attribute default values in a dynamic way. * specifying attribute default values when they are empty.
* *
* @author Qiang Xue <qiang.xue@gmail.com> * @author Qiang Xue <qiang.xue@gmail.com>
* @since 2.0 * @since 2.0
...@@ -27,11 +23,10 @@ class DefaultValueValidator extends Validator ...@@ -27,11 +23,10 @@ class DefaultValueValidator extends Validator
*/ */
public $value; public $value;
/** /**
* @var boolean whether to set the default [[value]] only when the attribute is [[isEmpty|empty]]. * @var boolean this property is overwritten to be false so that this validator will
* Defaults to true. If false, the attribute will always be assigned with the default [[value]], * be applied when the value being validated is empty.
* no matter it is empty or not.
*/ */
public $setOnEmpty = true; public $skipOnEmpty = false;
/** /**
* Validates the attribute of the object. * Validates the attribute of the object.
...@@ -40,7 +35,7 @@ class DefaultValueValidator extends Validator ...@@ -40,7 +35,7 @@ class DefaultValueValidator extends Validator
*/ */
public function validateAttribute($object, $attribute) public function validateAttribute($object, $attribute)
{ {
if (!$this->setOnEmpty || $this->isEmpty($object->$attribute)) { if ($this->isEmpty($object->$attribute)) {
$object->$attribute = $this->value; $object->$attribute = $this->value;
} }
} }
......
...@@ -42,11 +42,6 @@ class EmailValidator extends Validator ...@@ -42,11 +42,6 @@ class EmailValidator extends Validator
* Defaults to false. * Defaults to false.
*/ */
public $checkPort = false; public $checkPort = 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.
*/
public $allowEmpty = true;
/** /**
* Validates the attribute of the object. * Validates the attribute of the object.
...@@ -57,9 +52,6 @@ class EmailValidator extends Validator ...@@ -57,9 +52,6 @@ class EmailValidator extends Validator
public function validateAttribute($object, $attribute) public function validateAttribute($object, $attribute)
{ {
$value = $object->$attribute; $value = $object->$attribute;
if ($this->allowEmpty && $this->isEmpty($value)) {
return;
}
if (!$this->validateValue($value)) { if (!$this->validateValue($value)) {
$message = ($this->message !== null) ? $this->message : \Yii::t('yii|{attribute} is not a valid email address.'); $message = ($this->message !== null) ? $this->message : \Yii::t('yii|{attribute} is not a valid email address.');
$this->addError($object, $attribute, $message); $this->addError($object, $attribute, $message);
...@@ -67,11 +59,9 @@ class EmailValidator extends Validator ...@@ -67,11 +59,9 @@ class EmailValidator extends Validator
} }
/** /**
* Validates a static value to see if it is a valid email. * Validates the given value.
* Note that this method does not respect [[allowEmpty]] property. * @param mixed $value the value to be validated.
* This method is provided so that you can call it directly without going through the model validation rule mechanism. * @return boolean whether the value is valid.
* @param mixed $value the value to be validated
* @return boolean whether the value is a valid email
*/ */
public function validateValue($value) public function validateValue($value)
{ {
......
...@@ -6,6 +6,8 @@ ...@@ -6,6 +6,8 @@
*/ */
namespace yii\validators; namespace yii\validators;
use Yii;
use yii\base\InvalidConfigException; use yii\base\InvalidConfigException;
/** /**
...@@ -34,11 +36,6 @@ class ExistValidator extends Validator ...@@ -34,11 +36,6 @@ class ExistValidator extends Validator
* @see className * @see className
*/ */
public $attributeName; public $attributeName;
/**
* @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.
*/
public $allowEmpty = true;
/** /**
* Validates the attribute of the object. * Validates the attribute of the object.
...@@ -46,29 +43,41 @@ class ExistValidator extends Validator ...@@ -46,29 +43,41 @@ class ExistValidator extends Validator
* *
* @param \yii\db\ActiveRecord $object the object being validated * @param \yii\db\ActiveRecord $object the object being validated
* @param string $attribute the attribute being validated * @param string $attribute the attribute being validated
* @throws InvalidConfigException if table doesn't have column specified
*/ */
public function validateAttribute($object, $attribute) public function validateAttribute($object, $attribute)
{ {
$value = $object->$attribute; $value = $object->$attribute;
if ($this->allowEmpty && $this->isEmpty($value)) {
return;
}
/** @var $className \yii\db\ActiveRecord */ /** @var $className \yii\db\ActiveRecord */
$className = ($this->className === null) ? get_class($object) : \Yii::import($this->className); $className = $this->className === null ? get_class($object) : Yii::import($this->className);
$attributeName = ($this->attributeName === null) ? $attribute : $this->attributeName; $attributeName = $this->attributeName === null ? $attribute : $this->attributeName;
$table = $className::getTableSchema();
if (($column = $table->getColumn($attributeName)) === null) {
throw new InvalidConfigException('Table "' . $table->name . '" does not have a column named "' . $attributeName . '"');
}
$query = $className::find(); $query = $className::find();
$query->where(array($column->name => $value)); $query->where(array($attributeName => $value));
if (!$query->exists()) { if (!$query->exists()) {
$message = ($this->message !== null) ? $this->message : \Yii::t('yii|{attribute} "{value}" is invalid.'); $message = $this->message !== null ? $this->message : Yii::t('yii|{attribute} "{value}" is invalid.');
$this->addError($object, $attribute, $message); $this->addError($object, $attribute, $message);
} }
} }
/**
* Validates the given value.
* @param mixed $value the value to be validated.
* @return boolean whether the value is valid.
* @throws InvalidConfigException if either [[className]] or [[attributeName]] is not set.
*/
public function validateValue($value)
{
if ($this->className === null) {
throw new InvalidConfigException('The "className" property must be set.');
}
if ($this->attributeName === null) {
throw new InvalidConfigException('The "attributeName" property must be set.');
}
/** @var $className \yii\db\ActiveRecord */
$className = $this->className;
$query = $className::find();
$query->where(array($this->attributeName => $value));
return $query->exists();
}
} }
...@@ -38,6 +38,23 @@ class FilterValidator extends Validator ...@@ -38,6 +38,23 @@ class FilterValidator extends Validator
* ~~~ * ~~~
*/ */
public $filter; public $filter;
/**
* @var boolean this property is overwritten to be false so that this validator will
* be applied when the value being validated is empty.
*/
public $skipOnEmpty = false;
/**
* Initializes the validator.
* @throws InvalidConfigException if [[filter]] is not set.
*/
public function init()
{
parent::init();
if ($this->filter === null) {
throw new InvalidConfigException('The "filter" property must be set.');
}
}
/** /**
* Validates the attribute of the object. * Validates the attribute of the object.
...@@ -48,9 +65,6 @@ class FilterValidator extends Validator ...@@ -48,9 +65,6 @@ class FilterValidator extends Validator
*/ */
public function validateAttribute($object, $attribute) public function validateAttribute($object, $attribute)
{ {
if ($this->filter === null) {
throw new InvalidConfigException('The "filter" property must be specified with a valid callback.');
}
$object->$attribute = call_user_func($this->filter, $object->$attribute); $object->$attribute = call_user_func($this->filter, $object->$attribute);
} }
} }
...@@ -25,8 +25,9 @@ namespace yii\validators; ...@@ -25,8 +25,9 @@ namespace yii\validators;
class InlineValidator extends Validator class InlineValidator extends Validator
{ {
/** /**
* @var string the name of the validation method defined in the * @var string|\Closure an anonymous function or the name of a model class method that will be
* \yii\base\Model class * called to perform the actual validation. Note that if you use anonymous function, you cannot
* use `$this` in it unless you are using PHP 5.4 or above.
*/ */
public $method; public $method;
/** /**
...@@ -34,8 +35,8 @@ class InlineValidator extends Validator ...@@ -34,8 +35,8 @@ class InlineValidator extends Validator
*/ */
public $params; public $params;
/** /**
* @var string the name of the method that returns the client validation code (see [[clientValidateAttribute()]] * @var string|\Closure an anonymous function or the name of a model class method that returns the client validation code.
* for details on how to return client validation code). The signature of the method should be like the following: * The signature of the method should be like the following:
* *
* ~~~ * ~~~
* function foo($attribute) * function foo($attribute)
...@@ -45,6 +46,8 @@ class InlineValidator extends Validator ...@@ -45,6 +46,8 @@ class InlineValidator extends Validator
* ~~~ * ~~~
* *
* where `$attribute` refers to the attribute name to be validated. * where `$attribute` refers to the attribute name to be validated.
*
* Please refer to [[clientValidateAttribute()]] for details on how to return client validation code.
*/ */
public $clientValidate; public $clientValidate;
...@@ -56,7 +59,10 @@ class InlineValidator extends Validator ...@@ -56,7 +59,10 @@ class InlineValidator extends Validator
public function validateAttribute($object, $attribute) public function validateAttribute($object, $attribute)
{ {
$method = $this->method; $method = $this->method;
$object->$method($attribute, $this->params); if (is_string($method)) {
$method = array($object, $method);
}
call_user_func($method, $attribute, $this->params);
} }
/** /**
...@@ -82,7 +88,10 @@ class InlineValidator extends Validator ...@@ -82,7 +88,10 @@ class InlineValidator extends Validator
{ {
if ($this->clientValidate !== null) { if ($this->clientValidate !== null) {
$method = $this->clientValidate; $method = $this->clientValidate;
return $object->$method($attribute); if (is_string($method)) {
$method = array($object, $method);
}
return call_user_func($method, $attribute);
} else { } else {
return null; return null;
} }
......
...@@ -26,11 +26,6 @@ class NumberValidator extends Validator ...@@ -26,11 +26,6 @@ class NumberValidator extends Validator
*/ */
public $integerOnly = 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.
*/
public $allowEmpty = true;
/**
* @var integer|float upper limit of the number. Defaults to null, meaning no upper limit. * @var integer|float upper limit of the number. Defaults to null, meaning no upper limit.
*/ */
public $max; public $max;
...@@ -66,9 +61,6 @@ class NumberValidator extends Validator ...@@ -66,9 +61,6 @@ class NumberValidator extends Validator
public function validateAttribute($object, $attribute) public function validateAttribute($object, $attribute)
{ {
$value = $object->$attribute; $value = $object->$attribute;
if ($this->allowEmpty && $this->isEmpty($value)) {
return;
}
if ($this->integerOnly) { if ($this->integerOnly) {
if (!preg_match($this->integerPattern, "$value")) { if (!preg_match($this->integerPattern, "$value")) {
$message = $this->message !== null ? $this->message : Yii::t('yii|{attribute} must be an integer.'); $message = $this->message !== null ? $this->message : Yii::t('yii|{attribute} must be an integer.');
...@@ -81,16 +73,28 @@ class NumberValidator extends Validator ...@@ -81,16 +73,28 @@ class NumberValidator extends Validator
} }
} }
if ($this->min !== null && $value < $this->min) { 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} must be no less than {min}.');
$this->addError($object, $attribute, $message, array('{min}' => $this->min)); $this->addError($object, $attribute, $message, array('{min}' => $this->min));
} }
if ($this->max !== null && $value > $this->max) { 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} must be no greater than {max}.');
$this->addError($object, $attribute, $message, array('{max}' => $this->max)); $this->addError($object, $attribute, $message, array('{max}' => $this->max));
} }
} }
/** /**
* Validates the given value.
* @param mixed $value the value to be validated.
* @return boolean whether the value is valid.
*/
public function validateValue($value)
{
return preg_match($this->integerOnly ? $this->integerPattern : $this->numberPattern, "$value")
&& ($this->min === null || $value >= $this->min)
&& ($this->max === null || $value <= $this->max);
}
/**
* Returns the JavaScript needed for performing client-side validation. * Returns the JavaScript needed for performing client-side validation.
* @param \yii\base\Model $object the data object being validated * @param \yii\base\Model $object the data object being validated
* @param string $attribute the name of the attribute to be validated. * @param string $attribute the name of the attribute to be validated.
...@@ -116,7 +120,7 @@ if(!value.match($pattern)) { ...@@ -116,7 +120,7 @@ if(!value.match($pattern)) {
"; ";
if ($this->min !== null) { if ($this->min !== null) {
if (($tooSmall = $this->tooSmall) === null) { if (($tooSmall = $this->tooSmall) === null) {
$tooSmall = Yii::t('yii|{attribute} is too small (minimum is {min}).'); $tooSmall = Yii::t('yii|{attribute} must be no less than {min}.');
} }
$tooSmall = strtr($tooSmall, array( $tooSmall = strtr($tooSmall, array(
'{attribute}' => $label, '{attribute}' => $label,
...@@ -131,7 +135,7 @@ if(value<{$this->min}) { ...@@ -131,7 +135,7 @@ if(value<{$this->min}) {
} }
if ($this->max !== null) { if ($this->max !== null) {
if (($tooBig = $this->tooBig) === null) { if (($tooBig = $this->tooBig) === null) {
$tooBig = Yii::t('yii|{attribute} is too big (maximum is {max}).'); $tooBig = Yii::t('yii|{attribute} must be no greater than {max}.');
} }
$tooBig = strtr($tooBig, array( $tooBig = strtr($tooBig, array(
'{attribute}' => $label, '{attribute}' => $label,
......
...@@ -29,56 +29,61 @@ class RangeValidator extends Validator ...@@ -29,56 +29,61 @@ class RangeValidator extends Validator
*/ */
public $strict = false; public $strict = 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.
*/
public $allowEmpty = true;
/**
* @var boolean whether to invert the validation logic. Defaults to false. If set to true, * @var boolean whether to invert the validation logic. Defaults to false. If set to true,
* the attribute value should NOT be among the list of values defined via [[range]]. * the attribute value should NOT be among the list of values defined via [[range]].
**/ **/
public $not = false; public $not = false;
/** /**
* Initializes the validator.
* @throws InvalidConfigException if [[range]] is not set.
*/
public function init()
{
parent::init();
if (!is_array($this->range)) {
throw new InvalidConfigException('The "range" property must be set.');
}
}
/**
* Validates the attribute of the object. * Validates the attribute of the object.
* If there is any error, the error message is added to 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 \yii\base\Model $object the object being validated
* @param string $attribute the attribute being validated * @param string $attribute the attribute being validated
* @throws InvalidConfigException if the "range" property is not an array
*/ */
public function validateAttribute($object, $attribute) public function validateAttribute($object, $attribute)
{ {
$value = $object->$attribute; $value = $object->$attribute;
if ($this->allowEmpty && $this->isEmpty($value)) { $message = $this->message !== null ? $this->message : \Yii::t('yii|{attribute} is invalid.');
return;
}
if (!is_array($this->range)) {
throw new InvalidConfigException('The "range" property must be specified as an array.');
}
if (!$this->not && !in_array($value, $this->range, $this->strict)) { if (!$this->not && !in_array($value, $this->range, $this->strict)) {
$message = ($this->message !== null) ? $this->message : \Yii::t('yii|{attribute} should be in the list.');
$this->addError($object, $attribute, $message); $this->addError($object, $attribute, $message);
} elseif ($this->not && in_array($value, $this->range, $this->strict)) { } elseif ($this->not && in_array($value, $this->range, $this->strict)) {
$message = ($this->message !== null) ? $this->message : \Yii::t('yii|{attribute} should NOT be in the list.');
$this->addError($object, $attribute, $message); $this->addError($object, $attribute, $message);
} }
} }
/** /**
* Validates the given value.
* @param mixed $value the value to be validated.
* @return boolean whether the value is valid.
*/
public function validateValue($value)
{
return !$this->not && in_array($value, $this->range, $this->strict)
|| $this->not && !in_array($value, $this->range, $this->strict);
}
/**
* Returns the JavaScript needed for performing client-side validation. * Returns the JavaScript needed for performing client-side validation.
* @param \yii\base\Model $object the data object being validated * @param \yii\base\Model $object the data object being validated
* @param string $attribute the name of the attribute to be validated. * @param string $attribute the name of the attribute to be validated.
* @return string the client-side validation script. * @return string the client-side validation script.
* @throws InvalidConfigException if the "range" property is not an array
*/ */
public function clientValidateAttribute($object, $attribute) public function clientValidateAttribute($object, $attribute)
{ {
if (!is_array($this->range)) {
throw new InvalidConfigException('The "range" property must be specified as an array.');
}
if (($message = $this->message) === null) { if (($message = $this->message) === null) {
$message = $this->not ? \Yii::t('yii|{attribute} should NOT be in the list.') : \Yii::t('yii|{attribute} should be in the list.'); $message = \Yii::t('yii|{attribute} is invalid.');
} }
$message = strtr($message, array( $message = strtr($message, array(
'{attribute}' => $object->getAttributeLabel($attribute), '{attribute}' => $object->getAttributeLabel($attribute),
......
...@@ -7,6 +7,8 @@ ...@@ -7,6 +7,8 @@
namespace yii\validators; namespace yii\validators;
use yii\base\InvalidConfigException;
/** /**
* RegularExpressionValidator validates that the attribute value matches the specified [[pattern]]. * RegularExpressionValidator validates that the attribute value matches the specified [[pattern]].
* *
...@@ -22,32 +24,33 @@ class RegularExpressionValidator extends Validator ...@@ -22,32 +24,33 @@ class RegularExpressionValidator extends Validator
*/ */
public $pattern; public $pattern;
/** /**
* @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.
*/
public $allowEmpty = true;
/**
* @var boolean whether to invert the validation logic. Defaults to false. If set to true, * @var boolean whether to invert the validation logic. Defaults to false. If set to true,
* the regular expression defined via [[pattern]] should NOT match the attribute value. * the regular expression defined via [[pattern]] should NOT match the attribute value.
* @throws InvalidConfigException if the "pattern" is not a valid regular expression
**/ **/
public $not = false; public $not = false;
/** /**
* Initializes the validator.
* @throws InvalidConfigException if [[pattern]] is not set.
*/
public function init()
{
parent::init();
if ($this->pattern === null) {
throw new InvalidConfigException('The "pattern" property must be set.');
}
}
/**
* Validates the attribute of the object. * Validates the attribute of the object.
* If there is any error, the error message is added to 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 \yii\base\Model $object the object being validated
* @param string $attribute the attribute being validated * @param string $attribute the attribute being validated
* @throws \yii\base\Exception if the "pattern" is not a valid regular expression
*/ */
public function validateAttribute($object, $attribute) public function validateAttribute($object, $attribute)
{ {
$value = $object->$attribute; $value = $object->$attribute;
if ($this->allowEmpty && $this->isEmpty($value)) {
return;
}
if ($this->pattern === null) {
throw new \yii\base\Exception('The "pattern" property must be specified with a valid regular expression.');
}
if ((!$this->not && !preg_match($this->pattern, $value)) || ($this->not && preg_match($this->pattern, $value))) { if ((!$this->not && !preg_match($this->pattern, $value)) || ($this->not && preg_match($this->pattern, $value))) {
$message = ($this->message !== null) ? $this->message : \Yii::t('yii|{attribute} is invalid.'); $message = ($this->message !== null) ? $this->message : \Yii::t('yii|{attribute} is invalid.');
$this->addError($object, $attribute, $message); $this->addError($object, $attribute, $message);
...@@ -55,18 +58,25 @@ class RegularExpressionValidator extends Validator ...@@ -55,18 +58,25 @@ class RegularExpressionValidator extends Validator
} }
/** /**
* Validates the given value.
* @param mixed $value the value to be validated.
* @return boolean whether the value is valid.
*/
public function validateValue($value)
{
return !$this->not && preg_match($this->pattern, $value)
|| $this->not && !preg_match($this->pattern, $value);
}
/**
* Returns the JavaScript needed for performing client-side validation. * Returns the JavaScript needed for performing client-side validation.
* @param \yii\base\Model $object the data object being validated * @param \yii\base\Model $object the data object being validated
* @param string $attribute the name of the attribute to be validated. * @param string $attribute the name of the attribute to be validated.
* @return string the client-side validation script. * @return string the client-side validation script.
* @throws \yii\base\Exception if the "pattern" is not a valid regular expression * @throws InvalidConfigException if the "pattern" is not a valid regular expression
*/ */
public function clientValidateAttribute($object, $attribute) public function clientValidateAttribute($object, $attribute)
{ {
if ($this->pattern === null) {
throw new \yii\base\Exception('The "pattern" property must be specified with a valid regular expression.');
}
$message = ($this->message !== null) ? $this->message : \Yii::t('yii|{attribute} is invalid.'); $message = ($this->message !== null) ? $this->message : \Yii::t('yii|{attribute} is invalid.');
$message = strtr($message, array( $message = strtr($message, array(
'{attribute}' => $object->getAttributeLabel($attribute), '{attribute}' => $object->getAttributeLabel($attribute),
......
...@@ -16,6 +16,10 @@ namespace yii\validators; ...@@ -16,6 +16,10 @@ namespace yii\validators;
class RequiredValidator extends Validator class RequiredValidator extends Validator
{ {
/** /**
* @var boolean whether to skip this validator if the value being validated is empty.
*/
public $skipOnEmpty = false;
/**
* @var mixed the desired value that the attribute must have. * @var mixed the desired value that the attribute must have.
* If this is null, the validator will validate that the specified attribute is not empty. * If this is null, the validator will validate that the specified attribute is not empty.
* If this is set as a value that is not null, the validator will validate that * If this is set as a value that is not null, the validator will validate that
...@@ -59,6 +63,23 @@ class RequiredValidator extends Validator ...@@ -59,6 +63,23 @@ class RequiredValidator extends Validator
} }
/** /**
* Validates the given value.
* @param mixed $value the value to be validated.
* @return boolean whether the value is valid.
*/
public function validateValue($value)
{
if ($this->requiredValue === null) {
if ($this->strict && $value !== null || !$this->strict && !$this->isEmpty($value, true)) {
return true;
}
} elseif (!$this->strict && $value == $this->requiredValue || $this->strict && $value === $this->requiredValue) {
return true;
}
return false;
}
/**
* Returns the JavaScript needed for performing client-side validation. * Returns the JavaScript needed for performing client-side validation.
* @param \yii\base\Model $object the data object being validated * @param \yii\base\Model $object the data object being validated
* @param string $attribute the name of the attribute to be validated. * @param string $attribute the name of the attribute to be validated.
......
...@@ -7,6 +7,8 @@ ...@@ -7,6 +7,8 @@
namespace yii\validators; namespace yii\validators;
use Yii;
/** /**
* StringValidator validates that the attribute value is of certain length. * StringValidator validates that the attribute value is of certain length.
* *
...@@ -46,19 +48,22 @@ class StringValidator extends Validator ...@@ -46,19 +48,22 @@ class StringValidator extends Validator
*/ */
public $notEqual; public $notEqual;
/** /**
* @var boolean whether the attribute value can be null or empty. Defaults to true, * @var string the encoding of the string value to be validated (e.g. 'UTF-8').
* meaning that if the attribute is empty, it is considered valid. * If this property is not set, [[\yii\base\Application::charset]] will be used.
*/ */
public $allowEmpty = true; public $encoding;
/** /**
* @var mixed the encoding of the string value to be validated (e.g. 'UTF-8'). * Initializes the validator.
* This property is used only when mbstring PHP extension is enabled.
* The value of this property will be used as the 2nd parameter of the
* mb_strlen() function. If this property is not set, the application charset
* will be used. If this property is set false, then strlen() will be used even
* if mbstring is enabled.
*/ */
public $encoding; public function init()
{
parent::init();
if ($this->encoding === null) {
$this->encoding = Yii::$app->charset;
}
}
/** /**
* Validates the attribute of the object. * Validates the attribute of the object.
...@@ -69,37 +74,46 @@ class StringValidator extends Validator ...@@ -69,37 +74,46 @@ class StringValidator extends Validator
public function validateAttribute($object, $attribute) public function validateAttribute($object, $attribute)
{ {
$value = $object->$attribute; $value = $object->$attribute;
if ($this->allowEmpty && $this->isEmpty($value)) {
return;
}
if (!is_string($value)) { if (!is_string($value)) {
$message = ($this->message !== null) ? $this->message : \Yii::t('yii|{attribute} must be a string.'); $message = ($this->message !== null) ? $this->message : Yii::t('yii|{attribute} must be a string.');
$this->addError($object, $attribute, $message); $this->addError($object, $attribute, $message);
return; return;
} }
if (function_exists('mb_strlen') && $this->encoding !== false) { $length = mb_strlen($value, $this->encoding);
$length = mb_strlen($value, $this->encoding ? $this->encoding : \Yii::$app->charset);
} else {
$length = strlen($value);
}
if ($this->min !== null && $length < $this->min) { if ($this->min !== null && $length < $this->min) {
$message = ($this->tooShort !== null) ? $this->tooShort : \Yii::t('yii|{attribute} is too short (minimum is {min} characters).'); $message = ($this->tooShort !== null) ? $this->tooShort : Yii::t('yii|{attribute} should contain at least {min} characters.');
$this->addError($object, $attribute, $message, array('{min}' => $this->min)); $this->addError($object, $attribute, $message, array('{min}' => $this->min));
} }
if ($this->max !== null && $length > $this->max) { if ($this->max !== null && $length > $this->max) {
$message = ($this->tooLong !== null) ? $this->tooLong : \Yii::t('yii|{attribute} is too long (maximum is {max} characters).'); $message = ($this->tooLong !== null) ? $this->tooLong : Yii::t('yii|{attribute} should contain at most {max} characters.');
$this->addError($object, $attribute, $message, array('{max}' => $this->max)); $this->addError($object, $attribute, $message, array('{max}' => $this->max));
} }
if ($this->is !== null && $length !== $this->is) { if ($this->is !== null && $length !== $this->is) {
$message = ($this->notEqual !== null) ? $this->notEqual : \Yii::t('yii|{attribute} is of the wrong length (should be {length} characters).'); $message = ($this->notEqual !== null) ? $this->notEqual : Yii::t('yii|{attribute} should contain {length} characters.');
$this->addError($object, $attribute, $message, array('{length}' => $this->is)); $this->addError($object, $attribute, $message, array('{length}' => $this->is));
} }
} }
/** /**
* Validates the given value.
* @param mixed $value the value to be validated.
* @return boolean whether the value is valid.
*/
public function validateValue($value)
{
if (!is_string($value)) {
return false;
}
$length = mb_strlen($value, $this->encoding);
return ($this->min === null || $length >= $this->min)
&& ($this->max === null || $length <= $this->max)
&& ($this->is === null || $length === $this->is);
}
/**
* Returns the JavaScript needed for performing client-side validation. * Returns the JavaScript needed for performing client-side validation.
* @param \yii\base\Model $object the data object being validated * @param \yii\base\Model $object the data object being validated
* @param string $attribute the name of the attribute to be validated. * @param string $attribute the name of the attribute to be validated.
...@@ -111,7 +125,7 @@ class StringValidator extends Validator ...@@ -111,7 +125,7 @@ class StringValidator extends Validator
$value = $object->$attribute; $value = $object->$attribute;
if (($notEqual = $this->notEqual) === null) { if (($notEqual = $this->notEqual) === null) {
$notEqual = \Yii::t('yii|{attribute} is of the wrong length (should be {length} characters).'); $notEqual = Yii::t('yii|{attribute} should contain {length} characters.');
} }
$notEqual = strtr($notEqual, array( $notEqual = strtr($notEqual, array(
'{attribute}' => $label, '{attribute}' => $label,
...@@ -120,7 +134,7 @@ class StringValidator extends Validator ...@@ -120,7 +134,7 @@ class StringValidator extends Validator
)); ));
if (($tooShort = $this->tooShort) === null) { if (($tooShort = $this->tooShort) === null) {
$tooShort = \Yii::t('yii|{attribute} is too short (minimum is {min} characters).'); $tooShort = Yii::t('yii|{attribute} should contain at least {min} characters.');
} }
$tooShort = strtr($tooShort, array( $tooShort = strtr($tooShort, array(
'{attribute}' => $label, '{attribute}' => $label,
...@@ -129,7 +143,7 @@ class StringValidator extends Validator ...@@ -129,7 +143,7 @@ class StringValidator extends Validator
)); ));
if (($tooLong = $this->tooLong) === null) { if (($tooLong = $this->tooLong) === null) {
$tooLong = \Yii::t('yii|{attribute} is too long (maximum is {max} characters).'); $tooLong = Yii::t('yii|{attribute} should contain at most {max} characters.');
} }
$tooLong = strtr($tooLong, array( $tooLong = strtr($tooLong, array(
'{attribute}' => $label, '{attribute}' => $label,
......
...@@ -17,11 +17,6 @@ use yii\base\InvalidConfigException; ...@@ -17,11 +17,6 @@ use yii\base\InvalidConfigException;
class UniqueValidator extends Validator class UniqueValidator extends Validator
{ {
/** /**
* @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.
*/
public $allowEmpty = true;
/**
* @var string the ActiveRecord class name or alias of the class * @var string the ActiveRecord class name or alias of the class
* that should be used to look for the attribute value being validated. * that should be used to look for the attribute value being validated.
* Defaults to null, meaning using the ActiveRecord class of the attribute being validated. * Defaults to null, meaning using the ActiveRecord class of the attribute being validated.
...@@ -45,10 +40,6 @@ class UniqueValidator extends Validator ...@@ -45,10 +40,6 @@ class UniqueValidator extends Validator
public function validateAttribute($object, $attribute) public function validateAttribute($object, $attribute)
{ {
$value = $object->$attribute; $value = $object->$attribute;
if ($this->allowEmpty && $this->isEmpty($value)) {
return;
}
/** @var $className \yii\db\ActiveRecord */ /** @var $className \yii\db\ActiveRecord */
$className = $this->className === null ? get_class($object) : \Yii::import($this->className); $className = $this->className === null ? get_class($object) : \Yii::import($this->className);
$attributeName = $this->attributeName === null ? $attribute : $this->attributeName; $attributeName = $this->attributeName === null ? $attribute : $this->attributeName;
......
...@@ -32,11 +32,6 @@ class UrlValidator extends Validator ...@@ -32,11 +32,6 @@ class UrlValidator extends Validator
* contain the scheme part. * contain the scheme part.
**/ **/
public $defaultScheme; public $defaultScheme;
/**
* @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.
*/
public $allowEmpty = true;
/** /**
* Validates the attribute of the object. * Validates the attribute of the object.
...@@ -47,11 +42,10 @@ class UrlValidator extends Validator ...@@ -47,11 +42,10 @@ class UrlValidator extends Validator
public function validateAttribute($object, $attribute) public function validateAttribute($object, $attribute)
{ {
$value = $object->$attribute; $value = $object->$attribute;
if ($this->allowEmpty && $this->isEmpty($value)) { if ($this->validateValue($value)) {
return; if ($this->defaultScheme !== null && strpos($value, '://') === false) {
} $object->$attribute = $this->defaultScheme . '://' . $value;
if (($value = $this->validateValue($value)) !== false) { }
$object->$attribute = $value;
} else { } else {
$message = ($this->message !== null) ? $this->message : \Yii::t('yii|{attribute} is not a valid URL.'); $message = ($this->message !== null) ? $this->message : \Yii::t('yii|{attribute} is not a valid URL.');
$this->addError($object, $attribute, $message); $this->addError($object, $attribute, $message);
...@@ -59,11 +53,9 @@ class UrlValidator extends Validator ...@@ -59,11 +53,9 @@ class UrlValidator extends Validator
} }
/** /**
* Validates a static value to see if it is a valid URL. * Validates the given value.
* Note that this method does not respect [[allowEmpty]] property. * @param mixed $value the value to be validated.
* This method is provided so that you can call it directly without going through the model validation rule mechanism. * @return boolean whether the value is valid.
* @param mixed $value the value to be validated
* @return mixed false if the the value is not a valid URL, otherwise the possibly modified value ({@see defaultScheme})
*/ */
public function validateValue($value) public function validateValue($value)
{ {
...@@ -80,7 +72,7 @@ class UrlValidator extends Validator ...@@ -80,7 +72,7 @@ class UrlValidator extends Validator
} }
if (preg_match($pattern, $value)) { if (preg_match($pattern, $value)) {
return $value; return true;
} }
} }
return false; return false;
......
...@@ -7,6 +7,7 @@ ...@@ -7,6 +7,7 @@
namespace yii\validators; namespace yii\validators;
use Yii;
use yii\base\Component; use yii\base\Component;
use yii\base\NotSupportedException; use yii\base\NotSupportedException;
...@@ -95,6 +96,12 @@ abstract class Validator extends Component ...@@ -95,6 +96,12 @@ abstract class Validator extends Component
*/ */
public $skipOnError = true; public $skipOnError = true;
/** /**
* @var boolean whether this validation rule should be skipped if the attribute value
* is null or an empty string.
*/
public $skipOnEmpty = true;
/**
* @var boolean whether to enable client-side validation. Defaults to null, meaning * @var boolean whether to enable client-side validation. Defaults to null, meaning
* its actual value inherits from that of [[\yii\web\ActiveForm::enableClientValidation]]. * its actual value inherits from that of [[\yii\web\ActiveForm::enableClientValidation]].
*/ */
...@@ -150,7 +157,7 @@ abstract class Validator extends Component ...@@ -150,7 +157,7 @@ abstract class Validator extends Component
} }
} }
return \Yii::createObject($params); return Yii::createObject($params);
} }
/** /**
...@@ -169,12 +176,20 @@ abstract class Validator extends Component ...@@ -169,12 +176,20 @@ abstract class Validator extends Component
$attributes = $this->attributes; $attributes = $this->attributes;
} }
foreach ($attributes as $attribute) { foreach ($attributes as $attribute) {
if (!($this->skipOnError && $object->hasErrors($attribute))) { $skip = $this->skipOnError && $object->hasErrors($attribute)
|| $this->skipOnEmpty && $this->isEmpty($object->$attribute);
if (!$skip) {
$this->validateAttribute($object, $attribute); $this->validateAttribute($object, $attribute);
} }
} }
} }
/**
* Validates a value.
* A validator class can implement this method to support data validation out of the context of a data model.
* @param mixed $value the data value to be validated.
* @throws NotSupportedException if data validation without a model is not supported
*/
public function validateValue($value) public function validateValue($value)
{ {
throw new NotSupportedException(__CLASS__ . ' does not support validateValue().'); throw new NotSupportedException(__CLASS__ . ' does not support validateValue().');
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment