diff --git a/framework/validators/BooleanValidator.php b/framework/validators/BooleanValidator.php new file mode 100644 index 0000000..e4e7119 --- /dev/null +++ b/framework/validators/BooleanValidator.php @@ -0,0 +1,85 @@ + + * @link http://www.yiiframework.com/ + * @copyright Copyright © 2008-2011 Yii Software LLC + * @license http://www.yiiframework.com/license/ + */ + +/** + * CBooleanValidator validates that the attribute value is either {@link trueValue} or {@link falseValue}. + * + * @author Qiang Xue + * @version $Id: CBooleanValidator.php 3120 2011-03-25 01:50:48Z qiang.xue $ + * @package system.validators + * @since 1.0.10 + */ +class CBooleanValidator extends CValidator +{ + /** + * @var mixed the value representing true status. Defaults to '1'. + */ + public $trueValue = '1'; + /** + * @var mixed the value representing false status. Defaults to '0'. + */ + public $falseValue = '0'; + /** + * @var boolean whether the comparison to {@link trueValue} and {@link falseValue} is strict. + * When this is true, the attribute value and type must both match those of {@link trueValue} or {@link falseValue}. + * Defaults to false, meaning only the value needs to be matched. + */ + 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. + * If there is any error, the error message is added to the object. + * @param CModel $object the object being validated + * @param string $attribute the attribute being validated + */ + protected function validateAttribute($object, $attribute) + { + $value = $object->$attribute; + if ($this->allowEmpty && $this->isEmpty($value)) + return; + 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( + '{true}' => $this->trueValue, + '{false}' => $this->falseValue, + )); + } + } + + /** + * Returns the JavaScript needed for performing client-side validation. + * @param CModel $object the data object being validated + * @param string $attribute the name of the attribute to be validated. + * @return string the client-side validation script. + * @see CActiveForm::enableClientValidation + * @since 1.1.7 + */ + public function clientValidateAttribute($object, $attribute) + { + $message = $this->message !== null ? $this->message : Yii::t('yii', '{attribute} must be either {true} or {false}.'); + $message = strtr($message, array( + '{attribute}' => $object->getAttributeLabel($attribute), + '{true}' => $this->trueValue, + '{false}' => $this->falseValue, + )); + return " +if(" . ($this->allowEmpty ? "$.trim(value)!='' && " : '') . "value!=" . CJSON::encode($this->trueValue) . " && value!=" . CJSON::encode($this->falseValue) . ") { + messages.push(" . CJSON::encode($message) . "); +} +"; + } +} diff --git a/framework/validators/CaptchaValidator.php b/framework/validators/CaptchaValidator.php new file mode 100644 index 0000000..b7331f6 --- /dev/null +++ b/framework/validators/CaptchaValidator.php @@ -0,0 +1,123 @@ + + * @link http://www.yiiframework.com/ + * @copyright Copyright © 2008-2011 Yii Software LLC + * @license http://www.yiiframework.com/license/ + */ + +/** + * CCaptchaValidator validates that the attribute value is the same as the verification code displayed in the CAPTCHA. + * + * CCaptchaValidator should be used together with {@link CCaptchaAction}. + * + * @author Qiang Xue + * @version $Id: CCaptchaValidator.php 3124 2011-03-25 15:48:05Z qiang.xue $ + * @package system.validators + * @since 1.0 + */ +class CCaptchaValidator extends CValidator +{ + /** + * @var boolean whether the comparison is case sensitive. Defaults to false. + */ + public $caseSensitive = false; + /** + * @var string ID of the action that renders the CAPTCHA image. Defaults to 'captcha', + * meaning the 'captcha' action declared in the current controller. + * This can also be a route consisting of controller ID and action ID. + */ + 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; + + /** + * Validates the attribute of the object. + * If there is any error, the error message is added to the object. + * @param CModel $object the object being validated + * @param string $attribute the attribute being validated + */ + protected function validateAttribute($object, $attribute) + { + $value = $object->$attribute; + if ($this->allowEmpty && $this->isEmpty($value)) + return; + $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); + } + } + + /** + * Returns the CAPTCHA action object. + * @return CCaptchaAction the action object + * @since 1.1.7 + */ + protected function getCaptchaAction() + { + if (($captcha = Yii::app()->getController()->createAction($this->captchaAction)) === null) + { + if (strpos($this->captchaAction, '/') !== false) // contains controller or module + { + if (($ca = Yii::app()->createController($this->captchaAction)) !== null) + { + list($controller, $actionID) = $ca; + $captcha = $controller->createAction($actionID); + } + } + if ($captcha === null) + throw new CException(Yii::t('yii', 'CCaptchaValidator.action "{id}" is invalid. Unable to find such an action in the current controller.', + array('{id}' => $this->captchaAction))); + } + return $captcha; + } + + /** + * Returns the JavaScript needed for performing client-side validation. + * @param CModel $object the data object being validated + * @param string $attribute the name of the attribute to be validated. + * @return string the client-side validation script. + * @see CActiveForm::enableClientValidation + * @since 1.1.7 + */ + public function clientValidateAttribute($object, $attribute) + { + $captcha = $this->getCaptchaAction(); + $message = $this->message !== null ? $this->message : Yii::t('yii', 'The verification code is incorrect.'); + $message = strtr($message, array( + '{attribute}' => $object->getAttributeLabel($attribute), + )); + $code = $captcha->getVerifyCode(false); + $hash = $captcha->generateValidationHash($this->caseSensitive ? $code : strtolower($code)); + $js = " +var hash = $('body').data(' {$this->captchaAction}.hash'); +if (hash == null) + hash = $hash; +else + hash = hash[" . ($this->caseSensitive ? 0 : 1) . "]; +for(var i=value.length-1, h=0; i >= 0; --i) h+=value." . ($this->caseSensitive ? '' : 'toLowerCase().') . "charCodeAt(i); +if(h != hash) { + messages.push(" . CJSON::encode($message) . "); +} +"; + + if ($this->allowEmpty) + { + $js = " +if($.trim(value)!='') { + $js +} +"; + } + + return $js; + } +} + diff --git a/framework/validators/CompareValidator.php b/framework/validators/CompareValidator.php new file mode 100644 index 0000000..6b4dd4d --- /dev/null +++ b/framework/validators/CompareValidator.php @@ -0,0 +1,209 @@ + + * @link http://www.yiiframework.com/ + * @copyright Copyright © 2008-2011 Yii Software LLC + * @license http://www.yiiframework.com/license/ + */ + +/** + * CCompareValidator compares the specified attribute value with another value and validates if they are equal. + * + * The value being compared with can be another attribute value + * (specified via {@link compareAttribute}) or a constant (specified via + * {@link compareValue}. When both are specified, the latter takes + * precedence. If neither is specified, the attribute will be compared + * with another attribute whose name is by appending "_repeat" to the source + * attribute name. + * + * The comparison can be either {@link strict} or not. + * + * Starting from version 1.0.8, CCompareValidator supports different comparison operators. + * Previously, it only compares to see if two values are equal or not. + * + * @author Qiang Xue + * @version $Id: CCompareValidator.php 3120 2011-03-25 01:50:48Z qiang.xue $ + * @package system.validators + * @since 1.0 + */ +class CCompareValidator extends CValidator +{ + /** + * @var string the name of the attribute to be compared with + */ + public $compareAttribute; + /** + * @var string the constant value to be compared with + */ + public $compareValue; + /** + * @var boolean whether the comparison is strict (both value and type must be the same.) + * Defaults to false. + */ + public $strict = false; + /** + * @var boolean whether the attribute value can be null or empty. Defaults to false. + * 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 {@link 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 {@link 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.
  • + *
+ * @since 1.0.8 + */ + public $operator = '='; + + /** + * Validates the attribute of the object. + * If there is any error, the error message is added to the object. + * @param CModel $object the object being validated + * @param string $attribute the attribute being validated + */ + protected function validateAttribute($object, $attribute) + { + $value = $object->$attribute; + if ($this->allowEmpty && $this->isEmpty($value)) + return; + if ($this->compareValue !== null) + $compareTo = $compareValue = $this->compareValue; + else + { + $compareAttribute = $this->compareAttribute === null ? $attribute . '_repeat' : $this->compareAttribute; + $compareValue = $object->$compareAttribute; + $compareTo = $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)); + } + 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)); + } + 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)); + } + 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)); + } + 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)); + } + 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)); + } + break; + default: + throw new CException(Yii::t('yii', 'Invalid operator "{operator}".', array('{operator}' => $this->operator))); + } + } + + /** + * Returns the JavaScript needed for performing client-side validation. + * @param CModel $object the data object being validated + * @param string $attribute the name of the attribute to be validated. + * @return string the client-side validation script. + * @see CActiveForm::enableClientValidation + * @since 1.1.7 + */ + public function clientValidateAttribute($object, $attribute) + { + if ($this->compareValue !== null) + { + $compareTo = $this->compareValue; + $compareValue = CJSON::encode($this->compareValue); + } + else + { + $compareAttribute = $this->compareAttribute === null ? $attribute . '_repeat' : $this->compareAttribute; + $compareValue = "\$('#" . (CHtml::activeId($object, $compareAttribute)) . "').val()"; + $compareTo = $object->getAttributeLabel($compareAttribute); + } + + $message = $this->message; + switch ($this->operator) + { + case '=': + case '==': + if ($message === null) + $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}".'); + $condition = 'value==' . $compareValue; + break; + case '>': + if ($message === null) + $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}".'); + $condition = 'value<' . $compareValue; + break; + case '<': + if ($message === null) + $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}".'); + $condition = 'value>' . $compareValue; + break; + default: + throw new CException(Yii::t('yii', 'Invalid operator "{operator}".', array('{operator}' => $this->operator))); + } + + $message = strtr($message, array( + '{attribute}' => $object->getAttributeLabel($attribute), + '{compareValue}' => $compareTo, + )); + + return " +if(" . ($this->allowEmpty ? "$.trim(value)!='' && " : '') . $condition . ") { + messages.push(" . CJSON::encode($message) . "); +} +"; + } +} diff --git a/framework/validators/DateValidator.php b/framework/validators/DateValidator.php new file mode 100644 index 0000000..c75e612 --- /dev/null +++ b/framework/validators/DateValidator.php @@ -0,0 +1,76 @@ + + * @link http://www.yiiframework.com/ + * @copyright Copyright © 2008-2011 Yii Software LLC + * @license http://www.yiiframework.com/license/ + */ + +/** + * CDateValidator verifies if the attribute represents a date, time or datetime. + * + * By setting the {@link format} property, one can specify what format the date value + * must be in. If the given date value doesn't follow the format, the attribute is considered as invalid. + * + * @author Qiang Xue + * @version $Id: CDateValidator.php 2799 2011-01-01 19:31:13Z qiang.xue $ + * @package system.validators + * @since 1.1.7 + */ +class CDateValidator extends CValidator +{ + /** + * @var mixed the format pattern that the date value should follow. + * This can be either a string or an array representing multiple formats. + * Defaults to 'MM/dd/yyyy'. Please see {@link CDateTimeParser} for details + * about how to specify a date format. + */ + public $format = 'MM/dd/yyyy'; + /** + * @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 name of the attribute to receive the parsing result. + * When this property is not null and the validation is successful, the named attribute will + * receive the parsing result. + */ + public $timestampAttribute; + + /** + * Validates the attribute of the object. + * If there is any error, the error message is added to the object. + * @param CModel $object the object being validated + * @param string $attribute the attribute being validated + */ + protected function validateAttribute($object, $attribute) + { + $value = $object->$attribute; + if ($this->allowEmpty && $this->isEmpty($value)) + return; + + $formats = is_string($this->format) ? array($this->format) : $this->format; + $valid = false; + foreach ($formats as $format) + { + $timestamp = CDateTimeParser::parse($value, $format, array('month' => 1, 'day' => 1, 'hour' => 0, 'minute' => 0, 'second' => 0)); + if ($timestamp !== false) + { + $valid = true; + if ($this->timestampAttribute !== null) + $object-> {$this->timestampAttribute} = $timestamp; + break; + } + } + + if (!$valid) + { + $message = $this->message !== null ? $this->message : Yii::t('yii', 'The format of {attribute} is invalid.'); + $this->addError($object, $attribute, $message); + } + } +} + diff --git a/framework/validators/DefaultValueValidator.php b/framework/validators/DefaultValueValidator.php new file mode 100644 index 0000000..8811907 --- /dev/null +++ b/framework/validators/DefaultValueValidator.php @@ -0,0 +1,51 @@ + + * @link http://www.yiiframework.com/ + * @copyright Copyright © 2008-2011 Yii Software LLC + * @license http://www.yiiframework.com/license/ + */ + +/** + * CDefaultValueValidator sets the attributes with the specified value. + * It does not do validation. Its existence is mainly to allow + * specifying attribute default values in a dynamic way. + * + * @author Qiang Xue + * @version $Id: CDefaultValueValidator.php 2799 2011-01-01 19:31:13Z qiang.xue $ + * @package system.validators + * @since 1.0.2 + */ +class CDefaultValueValidator extends CValidator +{ + /** + * @var mixed the default value to be set to the specified attributes. + */ + public $value; + /** + * @var boolean whether to set the default value only when the attribute value is null or empty string. + * Defaults to true. If false, the attribute will always be assigned with the default value, + * even if it is already explicitly assigned a value. + */ + public $setOnEmpty = true; + + /** + * Validates the attribute of the object. + * @param CModel $object the object being validated + * @param string $attribute the attribute being validated + */ + protected function validateAttribute($object, $attribute) + { + if (!$this->setOnEmpty) + $object->$attribute = $this->value; + else + { + $value = $object->$attribute; + if ($value === null || $value === '') + $object->$attribute = $this->value; + } + } +} + diff --git a/framework/validators/EmailValidator.php b/framework/validators/EmailValidator.php new file mode 100644 index 0000000..02ff5bb --- /dev/null +++ b/framework/validators/EmailValidator.php @@ -0,0 +1,121 @@ + + * @link http://www.yiiframework.com/ + * @copyright Copyright © 2008-2011 Yii Software LLC + * @license http://www.yiiframework.com/license/ + */ + +/** + * CEmailValidator validates that the attribute value is a valid email address. + * + * @author Qiang Xue + * @version $Id: CEmailValidator.php 3242 2011-05-28 14:31:04Z qiang.xue $ + * @package system.validators + * @since 1.0 + */ +class CEmailValidator extends CValidator +{ + /** + * @var string the regular expression used to validate the attribute value. + * @see http://www.regular-expressions.info/email.html + */ + public $pattern = '/^[a-zA-Z0-9!#$%&\'*+\\/=?^_`{|}~-]+(?:\.[a-zA-Z0-9!#$%&\'*+\\/=?^_`{|}~-]+)*@(?:[a-zA-Z0-9](?:[a-zA-Z0-9-]*[a-zA-Z0-9])?\.)+[a-zA-Z0-9](?:[a-zA-Z0-9-]*[a-zA-Z0-9])?$/'; + /** + * @var string the regular expression used to validate email addresses with the name part. + * This property is used only when {@link allowName} is true. + * @since 1.0.5 + * @see allowName + */ + public $fullPattern = '/^[^@]*<[a-zA-Z0-9!#$%&\'*+\\/=?^_`{|}~-]+(?:\.[a-zA-Z0-9!#$%&\'*+\\/=?^_`{|}~-]+)*@(?:[a-zA-Z0-9](?:[a-zA-Z0-9-]*[a-zA-Z0-9])?\.)+[a-zA-Z0-9](?:[a-zA-Z0-9-]*[a-zA-Z0-9])?>$/'; + /** + * @var boolean whether to allow name in the email address (e.g. "Qiang Xue "). Defaults to false. + * @since 1.0.5 + * @see fullPattern + */ + public $allowName = false; + /** + * @var boolean whether to check the MX record for the email address. + * Defaults to false. To enable it, you need to make sure the PHP function 'checkdnsrr' + * exists in your PHP installation. + */ + public $checkMX = false; + /** + * @var boolean whether to check port 25 for the email address. + * Defaults to false. + * @since 1.0.4 + */ + 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. + * If there is any error, the error message is added to the object. + * @param CModel $object the object being validated + * @param string $attribute the attribute being validated + */ + protected function validateAttribute($object, $attribute) + { + $value = $object->$attribute; + if ($this->allowEmpty && $this->isEmpty($value)) + return; + if (!$this->validateValue($value)) + { + $message = $this->message !== null ? $this->message : Yii::t('yii', '{attribute} is not a valid email address.'); + $this->addError($object, $attribute, $message); + } + } + + /** + * Validates a static value to see if it is a valid email. + * Note that this method does not respect {@link allowEmpty} property. + * This method is provided so that you can call it directly without going through the model validation rule mechanism. + * @param mixed $value the value to be validated + * @return boolean whether the value is a valid email + * @since 1.1.1 + */ + public function validateValue($value) + { + // make sure string length is limited to avoid DOS attacks + $valid = is_string($value) && strlen($value) <= 254 && (preg_match($this->pattern, $value) || $this->allowName && preg_match($this->fullPattern, $value)); + if ($valid) + $domain = rtrim(substr($value, strpos($value, '@') + 1), '>'); + if ($valid && $this->checkMX && function_exists('checkdnsrr')) + $valid = checkdnsrr($domain, 'MX'); + if ($valid && $this->checkPort && function_exists('fsockopen')) + $valid = fsockopen($domain, 25) !== false; + return $valid; + } + + /** + * Returns the JavaScript needed for performing client-side validation. + * @param CModel $object the data object being validated + * @param string $attribute the name of the attribute to be validated. + * @return string the client-side validation script. + * @see CActiveForm::enableClientValidation + * @since 1.1.7 + */ + public function clientValidateAttribute($object, $attribute) + { + $message = $this->message !== null ? $this->message : Yii::t('yii', '{attribute} is not a valid email address.'); + $message = strtr($message, array( + '{attribute}' => $object->getAttributeLabel($attribute), + )); + + $condition = "!value.match( {$this->pattern})"; + if ($this->allowName) + $condition .= " && !value.match( {$this->fullPattern})"; + + return " +if(" . ($this->allowEmpty ? "$.trim(value)!='' && " : '') . $condition . ") { + messages.push(" . CJSON::encode($message) . "); +} +"; + } +} diff --git a/framework/validators/ExistValidator.php b/framework/validators/ExistValidator.php new file mode 100644 index 0000000..707a4f1 --- /dev/null +++ b/framework/validators/ExistValidator.php @@ -0,0 +1,86 @@ + + * @link http://www.yiiframework.com/ + * @copyright Copyright © 2008-2011 Yii Software LLC + * @license http://www.yiiframework.com/license/ + */ + +/** + * CExistValidator validates that the attribute value exists in a table. + * + * This validator is often used to verify that a foreign key contains a value + * that can be found in the foreign table. + * + * @author Qiang Xue + * @version $Id: CExistValidator.php 2799 2011-01-01 19:31:13Z qiang.xue $ + * @package system.validators + * @since 1.0.4 + */ +class CExistValidator extends CValidator +{ + /** + * @var string the ActiveRecord class name 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. + * You may use path alias to reference a class name here. + * @see attributeName + */ + public $className; + /** + * @var string the ActiveRecord class attribute name that should be + * used to look for the attribute value being validated. Defaults to null, + * meaning using the name of the attribute being validated. + * @see className + */ + public $attributeName; + /** + * @var array additional query criteria. This will be combined with the condition + * that checks if the attribute value exists in the corresponding table column. + * This array will be used to instantiate a {@link CDbCriteria} object. + * @since 1.0.8 + */ + public $criteria = array(); + /** + * @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. + * If there is any error, the error message is added to the object. + * @param CModel $object the object being validated + * @param string $attribute the attribute being validated + */ + protected function validateAttribute($object, $attribute) + { + $value = $object->$attribute; + if ($this->allowEmpty && $this->isEmpty($value)) + return; + + $className = $this->className === null ? get_class($object) : Yii::import($this->className); + $attributeName = $this->attributeName === null ? $attribute : $this->attributeName; + $finder = CActiveRecord::model($className); + $table = $finder->getTableSchema(); + if (($column = $table->getColumn($attributeName)) === null) + throw new CException(Yii::t('yii', 'Table "{table}" does not have a column named "{column}".', + array('{column}' => $attributeName, '{table}' => $table->name))); + + $criteria = array('condition' => $column->rawName . '=:vp', 'params' => array(':vp' => $value)); + if ($this->criteria !== array()) + { + $criteria = new CDbCriteria($criteria); + $criteria->mergeWith($this->criteria); + } + + if (!$finder->exists($criteria)) + { + $message = $this->message !== null ? $this->message : Yii::t('yii', '{attribute} "{value}" is invalid.'); + $this->addError($object, $attribute, $message, array('{value}' => $value)); + } + } +} + diff --git a/framework/validators/FileValidator.php b/framework/validators/FileValidator.php new file mode 100644 index 0000000..9371fd0 --- /dev/null +++ b/framework/validators/FileValidator.php @@ -0,0 +1,235 @@ + + * @link http://www.yiiframework.com/ + * @copyright Copyright © 2008-2011 Yii Software LLC + * @license http://www.yiiframework.com/license/ + */ + +/** + * CFileValidator verifies if an attribute is receiving a valid uploaded file. + * + * It uses the model class and attribute name to retrieve the information + * about the uploaded file. It then checks if a file is uploaded successfully, + * if the file size is within the limit and if the file type is allowed. + * + * This validator will attempt to fetch uploaded data if attribute is not + * previously set. Please note that this cannot be done if input is tabular: + *
+ *  foreach($models as $i=>$model)
+ *     $model->attribute = CUploadedFile::getInstance($model, "[$i]attribute");
+ * 
+ * Please note that you must use {@link CUploadedFile::getInstances} for multiple + * file uploads. + * + * When using CFileValidator with an active record, the following code is often used: + *
+ *  if($model->save())
+ *  {
+ *     // single upload
+ *     $model->attribute->saveAs($path);
+ *     // multiple upload
+ *     foreach($model->attribute as $file)
+ *        $file->saveAs($path);
+ *  }
+ * 
+ * + * You can use {@link CFileValidator} to validate the file attribute. + * + * @author Qiang Xue + * @version $Id: CFileValidator.php 2799 2011-01-01 19:31:13Z qiang.xue $ + * @package system.validators + * @since 1.0 + */ +class CFileValidator extends CValidator +{ + /** + * @var boolean whether the attribute requires a file to be uploaded or not. + * Defaults to false, meaning a file is required to be uploaded. + */ + public $allowEmpty = false; + /** + * @var mixed a list of file name extensions that are allowed to be uploaded. + * This can be either an array or a string consisting of file extension names + * separated by space or comma (e.g. "gif, jpg"). + * Extension names are case-insensitive. Defaults to null, meaning all file name + * extensions are allowed. + */ + public $types; + /** + * @var integer the minimum number of bytes required for the uploaded file. + * Defaults to null, meaning no limit. + * @see tooSmall + */ + public $minSize; + /** + * @var integer the maximum number of bytes required for the uploaded file. + * Defaults to null, meaning no limit. + * Note, the size limit is also affected by 'upload_max_filesize' INI setting + * and the 'MAX_FILE_SIZE' hidden field value. + * @see tooLarge + */ + public $maxSize; + /** + * @var string the error message used when the uploaded file is too large. + * @see maxSize + */ + public $tooLarge; + /** + * @var string the error message used when the uploaded file is too small. + * @see minSize + */ + public $tooSmall; + /** + * @var string the error message used when the uploaded file has an extension name + * that is not listed among {@link extensions}. + */ + public $wrongType; + /** + * @var integer the maximum file count the given attribute can hold. + * It defaults to 1, meaning single file upload. By defining a higher number, + * multiple uploads become possible. + */ + public $maxFiles = 1; + /** + * @var string the error message used if the count of multiple uploads exceeds + * limit. + */ + public $tooMany; + + /** + * Set the attribute and then validates using {@link validateFile}. + * If there is any error, the error message is added to the object. + * @param CModel $object the object being validated + * @param string $attribute the attribute being validated + */ + protected function validateAttribute($object, $attribute) + { + if ($this->maxFiles > 1) + { + $files = $object->$attribute; + if (!is_array($files) || !isset($files[0]) || !$files[0] instanceof CUploadedFile) + $files = CUploadedFile::getInstances($object, $attribute); + if (array() === $files) + return $this->emptyAttribute($object, $attribute); + if (count($files) > $this->maxFiles) + { + $message = $this->tooMany !== null ? $this->tooMany : Yii::t('yii', '{attribute} cannot accept more than {limit} files.'); + $this->addError($object, $attribute, $message, array('{attribute}' => $attribute, '{limit}' => $this->maxFiles)); + } + else + foreach ($files as $file) + $this->validateFile($object, $attribute, $file); + } + else + { + $file = $object->$attribute; + if (!$file instanceof CUploadedFile) + { + $file = CUploadedFile::getInstance($object, $attribute); + if (null === $file) + return $this->emptyAttribute($object, $attribute); + } + $this->validateFile($object, $attribute, $file); + } + } + + /** + * Internally validates a file object. + * @param CModel $object the object being validated + * @param string $attribute the attribute being validated + * @param CUploadedFile $file uploaded file passed to check against a set of rules + */ + protected function validateFile($object, $attribute, $file) + { + if (null === $file || ($error = $file->getError()) == UPLOAD_ERR_NO_FILE) + return $this->emptyAttribute($object, $attribute); + elseif ($error == UPLOAD_ERR_INI_SIZE || $error == UPLOAD_ERR_FORM_SIZE || $this->maxSize !== null && $file->getSize() > $this->maxSize) + { + $message = $this->tooLarge !== null ? $this->tooLarge : Yii::t('yii', 'The file "{file}" is too large. Its size cannot exceed {limit} bytes.'); + $this->addError($object, $attribute, $message, array('{file}' => $file->getName(), '{limit}' => $this->getSizeLimit())); + } + elseif ($error == UPLOAD_ERR_PARTIAL) + throw new CException(Yii::t('yii', 'The file "{file}" was only partially uploaded.', array('{file}' => $file->getName()))); + elseif ($error == UPLOAD_ERR_NO_TMP_DIR) + throw new CException(Yii::t('yii', 'Missing the temporary folder to store the uploaded file "{file}".', array('{file}' => $file->getName()))); + elseif ($error == UPLOAD_ERR_CANT_WRITE) + throw new CException(Yii::t('yii', 'Failed to write the uploaded file "{file}" to disk.', array('{file}' => $file->getName()))); + elseif (defined('UPLOAD_ERR_EXTENSION') && $error == UPLOAD_ERR_EXTENSION) // available for PHP 5.2.0 or above + throw new CException(Yii::t('yii', 'File upload was stopped by extension.')); + + if ($this->minSize !== null && $file->getSize() < $this->minSize) + { + $message = $this->tooSmall !== null ? $this->tooSmall : Yii::t('yii', 'The file "{file}" is too small. Its size cannot be smaller than {limit} bytes.'); + $this->addError($object, $attribute, $message, array('{file}' => $file->getName(), '{limit}' => $this->minSize)); + } + + if ($this->types !== null) + { + if (is_string($this->types)) + $types = preg_split('/[\s,]+/', strtolower($this->types), -1, PREG_SPLIT_NO_EMPTY); + else + $types = $this->types; + if (!in_array(strtolower($file->getExtensionName()), $types)) + { + $message = $this->wrongType !== null ? $this->wrongType : Yii::t('yii', 'The file "{file}" cannot be uploaded. Only files with these extensions are allowed: {extensions}.'); + $this->addError($object, $attribute, $message, array('{file}' => $file->getName(), '{extensions}' => implode(', ', $types))); + } + } + } + + /** + * Raises an error to inform end user about blank attribute. + * @param CModel $object the object being validated + * @param string $attribute the attribute being validated + */ + protected function emptyAttribute($object, $attribute) + { + if (!$this->allowEmpty) + { + $message = $this->message !== null ? $this->message : Yii::t('yii', '{attribute} cannot be blank.'); + $this->addError($object, $attribute, $message); + } + } + + /** + * Returns the maximum size allowed for uploaded files. + * This is determined based on three factors: + *
    + *
  • 'upload_max_filesize' in php.ini
  • + *
  • 'MAX_FILE_SIZE' hidden field
  • + *
  • {@link maxSize}
  • + *
+ * + * @return integer the size limit for uploaded files. + */ + protected function getSizeLimit() + { + $limit = ini_get('upload_max_filesize'); + $limit = $this->sizeToBytes($limit); + if ($this->maxSize !== null && $limit > 0 && $this->maxSize < $limit) + $limit = $this->maxSize; + if (isset($_POST['MAX_FILE_SIZE']) && $_POST['MAX_FILE_SIZE'] > 0 && $_POST['MAX_FILE_SIZE'] < $limit) + $limit = $_POST['MAX_FILE_SIZE']; + return $limit; + } + + /** + * Converts php.ini style size to bytes + * + * @param string $sizeStr $sizeStr + * @return int + */ + private function sizeToBytes($sizeStr) + { + switch (substr($sizeStr, -1)) + { + case 'M': case 'm': return (int)$sizeStr * 1048576; + case 'K': case 'k': return (int)$sizeStr * 1024; + case 'G': case 'g': return (int)$sizeStr * 1073741824; + default: return (int)$sizeStr; + } + } +} \ No newline at end of file diff --git a/framework/validators/FilterValidator.php b/framework/validators/FilterValidator.php new file mode 100644 index 0000000..fe73e1f --- /dev/null +++ b/framework/validators/FilterValidator.php @@ -0,0 +1,49 @@ + + * @link http://www.yiiframework.com/ + * @copyright Copyright © 2008-2011 Yii Software LLC + * @license http://www.yiiframework.com/license/ + */ + +/** + * CFilterValidator transforms the data being validated based on a filter. + * + * CFilterValidator is actually not a validator but a data processor. + * It invokes the specified filter method to process the attribute value + * and save the processed value back to the attribute. The filter method + * must follow the following signature: + *
+ * function foo($value) {...return $newValue; }
+ * 
+ * Many PHP functions qualify this signature (e.g. trim). + * + * To specify the filter method, set {@link filter} property to be the function name. + * + * @author Qiang Xue + * @version $Id: CFilterValidator.php 2799 2011-01-01 19:31:13Z qiang.xue $ + * @package system.validators + * @since 1.0 + */ +class CFilterValidator extends CValidator +{ + /** + * @var callback the filter method + */ + public $filter; + + /** + * Validates the attribute of the object. + * If there is any error, the error message is added to the object. + * @param CModel $object the object being validated + * @param string $attribute the attribute being validated + */ + protected function validateAttribute($object, $attribute) + { + if ($this->filter === null || !is_callable($this->filter)) + throw new CException(Yii::t('yii', 'The "filter" property must be specified with a valid callback.')); + $object->$attribute = call_user_func_array($this->filter, array($object->$attribute)); + } +} diff --git a/framework/validators/InlineValidator.php b/framework/validators/InlineValidator.php new file mode 100644 index 0000000..f10cd1b --- /dev/null +++ b/framework/validators/InlineValidator.php @@ -0,0 +1,41 @@ + + * @link http://www.yiiframework.com/ + * @copyright Copyright © 2008-2011 Yii Software LLC + * @license http://www.yiiframework.com/license/ + */ + +/** + * CInlineValidator represents a validator which is defined as a method in the object being validated. + * + * @author Qiang Xue + * @version $Id: CInlineValidator.php 2799 2011-01-01 19:31:13Z qiang.xue $ + * @package system.validators + * @since 1.0 + */ +class CInlineValidator extends CValidator +{ + /** + * @var string the name of the validation method defined in the active record class + */ + public $method; + /** + * @var array additional parameters that are passed to the validation method + */ + public $params; + + /** + * Validates the attribute of the object. + * If there is any error, the error message is added to the object. + * @param CModel $object the object being validated + * @param string $attribute the attribute being validated + */ + protected function validateAttribute($object, $attribute) + { + $method = $this->method; + $object->$method($attribute, $this->params); + } +} diff --git a/framework/validators/NumberValidator.php b/framework/validators/NumberValidator.php new file mode 100644 index 0000000..afb0f12 --- /dev/null +++ b/framework/validators/NumberValidator.php @@ -0,0 +1,163 @@ + + * @link http://www.yiiframework.com/ + * @copyright Copyright © 2008-2011 Yii Software LLC + * @license http://www.yiiframework.com/license/ + */ + +/** + * CNumberValidator validates that the attribute value is a number. + * + * @author Qiang Xue + * @version $Id: CNumberValidator.php 3190 2011-04-16 23:40:21Z qiang.xue $ + * @package system.validators + * @since 1.0 + */ +class CNumberValidator extends CValidator +{ + /** + * @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. + */ + public $allowEmpty = true; + /** + * @var integer|float upper limit of the number. Defaults to null, meaning no upper limit. + */ + public $max; + /** + * @var integer|float lower limit of the number. Defaults to null, meaning no lower limit. + */ + public $min; + /** + * @var string user-defined error message used when the value is too big. + */ + public $tooBig; + /** + * @var string user-defined error message used when the value is too small. + */ + public $tooSmall; + /** + * @var string the regular expression for matching integers. + * @since 1.1.7 + */ + public $integerPattern = '/^\s*[+-]?\d+\s*$/'; + /** + * @var string the regular expression for matching numbers. + * @since 1.1.7 + */ + public $numberPattern = '/^\s*[-+]?[0-9]*\.?[0-9]+([eE][-+]?[0-9]+)?\s*$/'; + + + /** + * Validates the attribute of the object. + * If there is any error, the error message is added to the object. + * @param CModel $object the object being validated + * @param string $attribute the attribute being validated + */ + protected function validateAttribute($object, $attribute) + { + $value = $object->$attribute; + if ($this->allowEmpty && $this->isEmpty($value)) + return; + 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}).'); + $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}).'); + $this->addError($object, $attribute, $message, array('{max}' => $this->max)); + } + } + + /** + * Returns the JavaScript needed for performing client-side validation. + * @param CModel $object the data object being validated + * @param string $attribute the name of the attribute to be validated. + * @return string the client-side validation script. + * @see CActiveForm::enableClientValidation + * @since 1.1.7 + */ + public function clientValidateAttribute($object, $attribute) + { + $label = $object->getAttributeLabel($attribute); + + if (($message = $this->message) === null) + $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, + )); + + 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, + )); + + 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, + )); + + $pattern = $this->integerOnly ? $this->integerPattern : $this->numberPattern; + $js = " +if(!value.match($pattern)) { + messages.push(" . CJSON::encode($message) . "); +} +"; + if ($this->min !== null) + { + $js .= " +if(value< {$this->min}) { + messages.push(" . CJSON::encode($tooSmall) . "); +} +"; + } + if ($this->max !== null) + { + $js .= " +if(value> {$this->max}) { + messages.push(" . CJSON::encode($tooBig) . "); +} +"; + } + + if ($this->allowEmpty) + { + $js = " +if($.trim(value)!='') { + $js +} +"; + } + + return $js; + } +} diff --git a/framework/validators/RangeValidator.php b/framework/validators/RangeValidator.php new file mode 100644 index 0000000..b0fcbec --- /dev/null +++ b/framework/validators/RangeValidator.php @@ -0,0 +1,97 @@ + + * @link http://www.yiiframework.com/ + * @copyright Copyright © 2008-2011 Yii Software LLC + * @license http://www.yiiframework.com/license/ + */ + +/** + * CRangeValidator validates that the attribute value is among the list (specified via {@link range}). + * You may invert the validation logic with help of the {@link not} property (available since 1.1.5). + * + * @author Qiang Xue + * @version $Id: CRangeValidator.php 3120 2011-03-25 01:50:48Z qiang.xue $ + * @package system.validators + * @since 1.0 + */ +class CRangeValidator extends CValidator +{ + /** + * @var array list of valid values that the attribute value should be among + */ + public $range; + /** + * @var boolean whether the comparison is strict (both type and value must be the same) + */ + 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, + * the attribute value should NOT be among the list of values defined via {@link range}. + * @since 1.1.5 + **/ + public $not = false; + + /** + * Validates the attribute of the object. + * If there is any error, the error message is added to the object. + * @param CModel $object the object being validated + * @param string $attribute the attribute being validated + */ + protected function validateAttribute($object, $attribute) + { + $value = $object->$attribute; + if ($this->allowEmpty && $this->isEmpty($value)) + return; + if (!is_array($this->range)) + throw new CException(Yii::t('yii', 'The "range" property must be specified with a list of values.')); + if (!$this->not && !in_array($value, $this->range, $this->strict)) + { + $message = $this->message !== null ? $this->message : Yii::t('yii', '{attribute} is not in the list.'); + $this->addError($object, $attribute, $message); + } + elseif ($this->not && in_array($value, $this->range, $this->strict)) + { + $message = $this->message !== null ? $this->message : Yii::t('yii', '{attribute} is in the list.'); + $this->addError($object, $attribute, $message); + } + } + + /** + * Returns the JavaScript needed for performing client-side validation. + * @param CModel $object the data object being validated + * @param string $attribute the name of the attribute to be validated. + * @return string the client-side validation script. + * @see CActiveForm::enableClientValidation + * @since 1.1.7 + */ + public function clientValidateAttribute($object, $attribute) + { + if (!is_array($this->range)) + throw new CException(Yii::t('yii', 'The "range" property must be specified with a list of values.')); + + if (($message = $this->message) === null) + $message = $this->not ? Yii::t('yii', '{attribute} is in the list.') : Yii::t('yii', '{attribute} is not in the list.'); + $message = strtr($message, array( + '{attribute}' => $object->getAttributeLabel($attribute), + )); + + $range = array(); + foreach ($this->range as $value) + $range[] = (string)$value; + $range = CJSON::encode($range); + + return " +if(" . ($this->allowEmpty ? "$.trim(value)!='' && " : '') . ($this->not ? "$.inArray(value, $range)>=0" : "$.inArray(value, $range)<0") . ") { + messages.push(" . CJSON::encode($message) . "); +} +"; + } +} diff --git a/framework/validators/RegularExpressionValidator.php b/framework/validators/RegularExpressionValidator.php new file mode 100644 index 0000000..2595a3a --- /dev/null +++ b/framework/validators/RegularExpressionValidator.php @@ -0,0 +1,94 @@ + + * @link http://www.yiiframework.com/ + * @copyright Copyright © 2008-2011 Yii Software LLC + * @license http://www.yiiframework.com/license/ + */ + +/** + * CRegularExpressionValidator validates that the attribute value matches to the specified {@link pattern regular expression}. + * You may invert the validation logic with help of the {@link not} property (available since 1.1.5). + * + * @author Qiang Xue + * @version $Id: CRegularExpressionValidator.php 3120 2011-03-25 01:50:48Z qiang.xue $ + * @package system.validators + * @since 1.0 + */ +class CRegularExpressionValidator extends CValidator +{ + /** + * @var string the regular expression to be matched with + */ + 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, + * the regular expression defined via {@link pattern} should NOT match the attribute value. + * @since 1.1.5 + **/ + public $not = false; + + /** + * Validates the attribute of the object. + * If there is any error, the error message is added to the object. + * @param CModel $object the object being validated + * @param string $attribute the attribute being validated + */ + protected function validateAttribute($object, $attribute) + { + $value = $object->$attribute; + if ($this->allowEmpty && $this->isEmpty($value)) + return; + if ($this->pattern === null) + throw new CException(Yii::t('yii', '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))) + { + $message = $this->message !== null ? $this->message : Yii::t('yii', '{attribute} is invalid.'); + $this->addError($object, $attribute, $message); + } + } + + /** + * Returns the JavaScript needed for performing client-side validation. + * @param CModel $object the data object being validated + * @param string $attribute the name of the attribute to be validated. + * @return string the client-side validation script. + * @see CActiveForm::enableClientValidation + * @since 1.1.7 + */ + public function clientValidateAttribute($object, $attribute) + { + if ($this->pattern === null) + throw new CException(Yii::t('yii', 'The "pattern" property must be specified with a valid regular expression.')); + + $message = $this->message !== null ? $this->message : Yii::t('yii', '{attribute} is invalid.'); + $message = strtr($message, array( + '{attribute}' => $object->getAttributeLabel($attribute), + )); + + $pattern = $this->pattern; + $pattern = preg_replace('/\\\\x\{?([0-9a-fA-F]+)\}?/', '\u$1', $pattern); + $delim = substr($pattern, 0, 1); + $endpos = strrpos($pattern, $delim, 1); + $flag = substr($pattern, $endpos + 1); + if ($delim !== '/') + $pattern = '/' . str_replace('/', '\\/', substr($pattern, 1, $endpos - 1)) . '/'; + else + $pattern = substr($pattern, 0, $endpos + 1); + if (!empty($flag)) + $pattern .= preg_replace('/[^igm]/', '', $flag); + + return " +if(" . ($this->allowEmpty ? "$.trim(value)!='' && " : '') . ($this->not ? '' : '!') . "value.match($pattern)) { + messages.push(" . CJSON::encode($message) . "); +} +"; + } +} \ No newline at end of file diff --git a/framework/validators/RequiredValidator.php b/framework/validators/RequiredValidator.php new file mode 100644 index 0000000..830fd3c --- /dev/null +++ b/framework/validators/RequiredValidator.php @@ -0,0 +1,102 @@ + + * @link http://www.yiiframework.com/ + * @copyright Copyright © 2008-2011 Yii Software LLC + * @license http://www.yiiframework.com/license/ + */ + +/** + * CRequiredValidator validates that the specified attribute does not have null or empty value. + * + * @author Qiang Xue + * @version $Id: CRequiredValidator.php 3157 2011-04-02 19:21:06Z qiang.xue $ + * @package system.validators + * @since 1.0 + */ +class CRequiredValidator extends CValidator +{ + /** + * @var mixed the desired value that the attribute must have. + * If this is null, the validator will validate that the specified attribute does not have null or empty value. + * If this is set as a value that is not null, the validator will validate that + * the attribute has a value that is the same as this property value. + * Defaults to null. + * @since 1.0.10 + */ + public $requiredValue; + /** + * @var boolean whether the comparison to {@link requiredValue} is strict. + * When this is true, the attribute value and type must both match those of {@link requiredValue}. + * Defaults to false, meaning only the value needs to be matched. + * This property is only used when {@link requiredValue} is not null. + * @since 1.0.10 + */ + public $strict = false; + /** + * Validates the attribute of the object. + * If there is any error, the error message is added to the object. + * @param CModel $object the object being validated + * @param string $attribute the attribute being validated + */ + protected function validateAttribute($object, $attribute) + { + $value = $object->$attribute; + if ($this->requiredValue !== null) + { + if (!$this->strict && $value != $this->requiredValue || $this->strict && $value !== $this->requiredValue) + { + $message = $this->message !== null ? $this->message : Yii::t('yii', '{attribute} must be {value}.', + array('{value}' => $this->requiredValue)); + $this->addError($object, $attribute, $message); + } + } + elseif ($this->isEmpty($value, true)) + { + $message = $this->message !== null ? $this->message : Yii::t('yii', '{attribute} cannot be blank.'); + $this->addError($object, $attribute, $message); + } + } + + /** + * Returns the JavaScript needed for performing client-side validation. + * @param CModel $object the data object being validated + * @param string $attribute the name of the attribute to be validated. + * @return string the client-side validation script. + * @see CActiveForm::enableClientValidation + * @since 1.1.7 + */ + public function clientValidateAttribute($object, $attribute) + { + $message = $this->message; + if ($this->requiredValue !== null) + { + if ($message === null) + $message = Yii::t('yii', '{attribute} must be {value}.'); + $message = strtr($message, array( + '{value}' => $this->requiredValue, + '{attribute}' => $object->getAttributeLabel($attribute), + )); + return " +if(value!=" . CJSON::encode($this->requiredValue) . ") { + messages.push(" . CJSON::encode($message) . "); +} +"; + } + else + { + if ($message === null) + $message = Yii::t('yii', '{attribute} cannot be blank.'); + $message = strtr($message, array( + '{attribute}' => $object->getAttributeLabel($attribute), + )); + return " +if($.trim(value)=='') { + messages.push(" . CJSON::encode($message) . "); +} +"; + } + } +} diff --git a/framework/validators/SafeValidator.php b/framework/validators/SafeValidator.php new file mode 100644 index 0000000..13c9b5d --- /dev/null +++ b/framework/validators/SafeValidator.php @@ -0,0 +1,31 @@ + + * @link http://www.yiiframework.com/ + * @copyright Copyright © 2008-2011 Yii Software LLC + * @license http://www.yiiframework.com/license/ + */ + +/** + * CSafeValidator marks the associated attributes to be safe for massive assignments. + * + * @author Qiang Xue + * @version $Id: CSafeValidator.php 2799 2011-01-01 19:31:13Z qiang.xue $ + * @package system.validators + * @since 1.1 + */ +class CSafeValidator extends CValidator +{ + /** + * Validates the attribute of the object. + * If there is any error, the error message is added to the object. + * @param CModel $object the object being validated + * @param string $attribute the attribute being validated + */ + protected function validateAttribute($object, $attribute) + { + } +} + diff --git a/framework/validators/StringValidator.php b/framework/validators/StringValidator.php new file mode 100644 index 0000000..1bf6bb5 --- /dev/null +++ b/framework/validators/StringValidator.php @@ -0,0 +1,164 @@ + + * @link http://www.yiiframework.com/ + * @copyright Copyright © 2008-2011 Yii Software LLC + * @license http://www.yiiframework.com/license/ + */ + +/** + * CStringValidator validates that the attribute value is of certain length. + * + * Note, this validator should only be used with string-typed attributes. + * + * @author Qiang Xue + * @version $Id: CStringValidator.php 3148 2011-03-31 21:44:00Z alexander.makarow $ + * @package system.validators + * @since 1.0 + */ +class CStringValidator extends CValidator +{ + /** + * @var integer maximum length. Defaults to null, meaning no maximum limit. + */ + public $max; + /** + * @var integer minimum length. Defaults to null, meaning no minimum limit. + */ + public $min; + /** + * @var integer exact length. Defaults to null, meaning no exact length limit. + */ + public $is; + /** + * @var string user-defined error message used when the value is too short. + */ + public $tooShort; + /** + * @var string user-defined error message used when the value is too long. + */ + public $tooLong; + /** + * @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 encoding of the string value to be validated (e.g. 'UTF-8'). + * 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. + * @since 1.1.1 + */ + public $encoding; + + /** + * Validates the attribute of the object. + * If there is any error, the error message is added to the object. + * @param CModel $object the object being validated + * @param string $attribute the attribute being validated + */ + protected function validateAttribute($object, $attribute) + { + $value = $object->$attribute; + if ($this->allowEmpty && $this->isEmpty($value)) + return; + + if (function_exists('mb_strlen') && $this->encoding !== false) + $length = mb_strlen($value, $this->encoding ? $this->encoding : Yii::app()->charset); + else + $length = strlen($value); + + if ($this->min !== null && $length < $this->min) + { + $message = $this->tooShort !== null ? $this->tooShort : Yii::t('yii', '{attribute} is too short (minimum is {min} characters).'); + $this->addError($object, $attribute, $message, array('{min}' => $this->min)); + } + if ($this->max !== null && $length > $this->max) + { + $message = $this->tooLong !== null ? $this->tooLong : Yii::t('yii', '{attribute} is too long (maximum is {max} characters).'); + $this->addError($object, $attribute, $message, array('{max}' => $this->max)); + } + if ($this->is !== null && $length !== $this->is) + { + $message = $this->message !== null ? $this->message : Yii::t('yii', '{attribute} is of the wrong length (should be {length} characters).'); + $this->addError($object, $attribute, $message, array('{length}' => $this->is)); + } + } + + /** + * Returns the JavaScript needed for performing client-side validation. + * @param CModel $object the data object being validated + * @param string $attribute the name of the attribute to be validated. + * @return string the client-side validation script. + * @see CActiveForm::enableClientValidation + * @since 1.1.7 + */ + public function clientValidateAttribute($object, $attribute) + { + $label = $object->getAttributeLabel($attribute); + + if (($message = $this->message) === null) + $message = Yii::t('yii', '{attribute} is of the wrong length (should be {length} characters).'); + $message = strtr($message, array( + '{attribute}' => $label, + '{length}' => $this->is, + )); + + if (($tooShort = $this->tooShort) === null) + $tooShort = Yii::t('yii', '{attribute} is too short (minimum is {min} characters).'); + $tooShort = strtr($tooShort, array( + '{attribute}' => $label, + '{min}' => $this->min, + )); + + if (($tooLong = $this->tooLong) === null) + $tooLong = Yii::t('yii', '{attribute} is too long (maximum is {max} characters).'); + $tooLong = strtr($tooLong, array( + '{attribute}' => $label, + '{max}' => $this->max, + )); + + $js = ''; + if ($this->min !== null) + { + $js .= " +if(value.length< {$this->min}) { + messages.push(" . CJSON::encode($tooShort) . "); +} +"; + } + if ($this->max !== null) + { + $js .= " +if(value.length> {$this->max}) { + messages.push(" . CJSON::encode($tooLong) . "); +} +"; + } + if ($this->is !== null) + { + $js .= " +if(value.length!= {$this->is}) { + messages.push(" . CJSON::encode($message) . "); +} +"; + } + + if ($this->allowEmpty) + { + $js = " +if($.trim(value)!='') { + $js +} +"; + } + + return $js; + } +} + diff --git a/framework/validators/TypeValidator.php b/framework/validators/TypeValidator.php new file mode 100644 index 0000000..3526a0b --- /dev/null +++ b/framework/validators/TypeValidator.php @@ -0,0 +1,105 @@ + + * @link http://www.yiiframework.com/ + * @copyright Copyright © 2008-2011 Yii Software LLC + * @license http://www.yiiframework.com/license/ + */ + +/** + * CTypeValidator verifies if the attribute is of the type specified by {@link type}. + * + * The following data types are supported: + *
    + *
  • integer A 32-bit signed integer data type.
  • + *
  • float A double-precision floating point number data type.
  • + *
  • string A string data type.
  • + *
  • array An array value.
  • + *
  • date A date data type.
  • + *
  • time A time data type (available since version 1.0.5).
  • + *
  • datetime A date and time data type (available since version 1.0.5).
  • + *
+ * + * For date type, the property {@link dateFormat} + * will be used to determine how to parse the date string. If the given date + * value doesn't follow the format, the attribute is considered as invalid. + * + * Starting from version 1.1.7, we have a dedicated date validator {@link CDateValidator}. + * Please consider using this validator to validate a date-typed value. + * + * @author Qiang Xue + * @version $Id: CTypeValidator.php 3052 2011-03-12 14:27:07Z qiang.xue $ + * @package system.validators + * @since 1.0 + */ +class CTypeValidator extends CValidator +{ + /** + * @var string the data type that the attribute should be. Defaults to 'string'. + * Valid values include 'string', 'integer', 'float', 'array', 'date', 'time' and 'datetime'. + * Note that 'time' and 'datetime' have been available since version 1.0.5. + */ + public $type = 'string'; + /** + * @var string the format pattern that the date value should follow. Defaults to 'MM/dd/yyyy'. + * Please see {@link CDateTimeParser} for details about how to specify a date format. + * This property is effective only when {@link type} is 'date'. + */ + public $dateFormat = 'MM/dd/yyyy'; + /** + * @var string the format pattern that the time value should follow. Defaults to 'hh:mm'. + * Please see {@link CDateTimeParser} for details about how to specify a time format. + * This property is effective only when {@link type} is 'time'. + * @since 1.0.5 + */ + public $timeFormat = 'hh:mm'; + /** + * @var string the format pattern that the datetime value should follow. Defaults to 'MM/dd/yyyy hh:mm'. + * Please see {@link CDateTimeParser} for details about how to specify a datetime format. + * This property is effective only when {@link type} is 'datetime'. + * @since 1.0.5 + */ + public $datetimeFormat = 'MM/dd/yyyy hh:mm'; + /** + * @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. + * If there is any error, the error message is added to the object. + * @param CModel $object the object being validated + * @param string $attribute the attribute being validated + */ + protected function validateAttribute($object, $attribute) + { + $value = $object->$attribute; + if ($this->allowEmpty && $this->isEmpty($value)) + return; + + if ($this->type === 'integer') + $valid = preg_match('/^[-+]?[0-9]+$/', trim($value)); + elseif ($this->type === 'float') + $valid = preg_match('/^[-+]?([0-9]*\.)?[0-9]+([eE][-+]?[0-9]+)?$/', trim($value)); + elseif ($this->type === 'date') + $valid = CDateTimeParser::parse($value, $this->dateFormat, array('month' => 1, 'day' => 1, 'hour' => 0, 'minute' => 0, 'second' => 0)) !== false; + elseif ($this->type === 'time') + $valid = CDateTimeParser::parse($value, $this->timeFormat) !== false; + elseif ($this->type === 'datetime') + $valid = CDateTimeParser::parse($value, $this->datetimeFormat, array('month' => 1, 'day' => 1, 'hour' => 0, 'minute' => 0, 'second' => 0)) !== false; + elseif ($this->type === 'array') + $valid = is_array($value); + else + return; + + if (!$valid) + { + $message = $this->message !== null ? $this->message : Yii::t('yii', '{attribute} must be {type}.'); + $this->addError($object, $attribute, $message, array('{type}' => $this->type)); + } + } +} + diff --git a/framework/validators/UniqueValidator.php b/framework/validators/UniqueValidator.php new file mode 100644 index 0000000..1291393 --- /dev/null +++ b/framework/validators/UniqueValidator.php @@ -0,0 +1,124 @@ + + * @link http://www.yiiframework.com/ + * @copyright Copyright © 2008-2011 Yii Software LLC + * @license http://www.yiiframework.com/license/ + */ + +/** + * CUniqueValidator validates that the attribute value is unique in the corresponding database table. + * + * @author Qiang Xue + * @version $Id: CUniqueValidator.php 3260 2011-06-13 20:56:54Z alexander.makarow $ + * @package system.validators + * @since 1.0 + */ +class CUniqueValidator extends CValidator +{ + /** + * @var boolean whether the comparison is case sensitive. Defaults to true. + * Note, by setting it to false, you are assuming the attribute type is string. + */ + public $caseSensitive = true; + /** + * @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 that should be used to + * look for the attribute value being validated. Defaults to null, meaning using + * the class of the object currently being validated. + * You may use path alias to reference a class name here. + * @see attributeName + * @since 1.0.8 + */ + public $className; + /** + * @var string the ActiveRecord class attribute name that should be + * used to look for the attribute value being validated. Defaults to null, + * meaning using the name of the attribute being validated. + * @see className + * @since 1.0.8 + */ + public $attributeName; + /** + * @var array additional query criteria. This will be combined with the condition + * that checks if the attribute value exists in the corresponding table column. + * This array will be used to instantiate a {@link CDbCriteria} object. + * @since 1.0.8 + */ + public $criteria = array(); + /** + * @var string the user-defined error message. The placeholders "{attribute}" and "{value}" + * are recognized, which will be replaced with the actual attribute name and value, respectively. + */ + public $message; + /** + * @var boolean whether this validation rule should be skipped if when there is already a validation + * error for the current attribute. Defaults to true. + * @since 1.1.1 + */ + public $skipOnError = true; + + + /** + * Validates the attribute of the object. + * If there is any error, the error message is added to the object. + * @param CModel $object the object being validated + * @param string $attribute the attribute being validated + */ + protected function validateAttribute($object, $attribute) + { + $value = $object->$attribute; + if ($this->allowEmpty && $this->isEmpty($value)) + return; + + $className = $this->className === null ? get_class($object) : Yii::import($this->className); + $attributeName = $this->attributeName === null ? $attribute : $this->attributeName; + $finder = CActiveRecord::model($className); + $table = $finder->getTableSchema(); + if (($column = $table->getColumn($attributeName)) === null) + throw new CException(Yii::t('yii', 'Table "{table}" does not have a column named "{column}".', + array('{column}' => $attributeName, '{table}' => $table->name))); + + $columnName = $column->rawName; + $criteria = new CDbCriteria(array( + 'condition' => $this->caseSensitive ? "$columnName=:value" : "LOWER($columnName)=LOWER(:value)", + 'params' => array(':value' => $value), + )); + if ($this->criteria !== array()) + $criteria->mergeWith($this->criteria); + + if (!$object instanceof CActiveRecord || $object->isNewRecord || $object->tableName() !== $finder->tableName()) + $exists = $finder->exists($criteria); + else + { + $criteria->limit = 2; + $objects = $finder->findAll($criteria); + $n = count($objects); + if ($n === 1) + { + if ($column->isPrimaryKey) // primary key is modified and not unique + $exists = $object->getOldPrimaryKey() != $object->getPrimaryKey(); + else + { + // non-primary key, need to exclude the current record based on PK + $exists = array_shift($objects)->getPrimaryKey() != $object->getOldPrimaryKey(); + } + } + else + $exists = $n > 1; + } + + if ($exists) + { + $message = $this->message !== null ? $this->message : Yii::t('yii', '{attribute} "{value}" has already been taken.'); + $this->addError($object, $attribute, $message, array('{value}' => $value)); + } + } +} + diff --git a/framework/validators/UnsafeValidator.php b/framework/validators/UnsafeValidator.php new file mode 100644 index 0000000..9687898 --- /dev/null +++ b/framework/validators/UnsafeValidator.php @@ -0,0 +1,37 @@ + + * @link http://www.yiiframework.com/ + * @copyright Copyright © 2008-2011 Yii Software LLC + * @license http://www.yiiframework.com/license/ + */ + +/** + * CUnsafeValidator marks the associated attributes to be unsafe so that they cannot be massively assigned. + * + * @author Qiang Xue + * @version $Id: CUnsafeValidator.php 2799 2011-01-01 19:31:13Z qiang.xue $ + * @package system.validators + * @since 1.0 + */ +class CUnsafeValidator extends CValidator +{ + /** + * @var boolean whether attributes listed with this validator should be considered safe for massive assignment. + * Defaults to false. + * @since 1.1.4 + */ + public $safe = false; + /** + * Validates the attribute of the object. + * If there is any error, the error message is added to the object. + * @param CModel $object the object being validated + * @param string $attribute the attribute being validated + */ + protected function validateAttribute($object, $attribute) + { + } +} + diff --git a/framework/validators/UrlValidator.php b/framework/validators/UrlValidator.php new file mode 100644 index 0000000..cf7039a --- /dev/null +++ b/framework/validators/UrlValidator.php @@ -0,0 +1,139 @@ + + * @link http://www.yiiframework.com/ + * @copyright Copyright © 2008-2011 Yii Software LLC + * @license http://www.yiiframework.com/license/ + */ + +/** + * CUrlValidator validates that the attribute value is a valid http or https URL. + * + * @author Qiang Xue + * @version $Id: CUrlValidator.php 3242 2011-05-28 14:31:04Z qiang.xue $ + * @package system.validators + * @since 1.0 + */ +class CUrlValidator extends CValidator +{ + /** + * @var string the regular expression used to validate the attribute value. + * Since version 1.1.7 the pattern may contain a {schemes} token that will be replaced + * by a regular expression which represents the {@see validSchemes}. + */ + public $pattern = '/^{schemes}:\/\/(([A-Z0-9][A-Z0-9_-]*)(\.[A-Z0-9][A-Z0-9_-]*)+)/i'; + /** + * @var array list of URI schemes which should be considered valid. By default, http and https + * are considered to be valid schemes. + * @since 1.1.7 + **/ + public $validSchemes = array('http', 'https'); + /** + * @var string the default URI scheme. If the input doesn't contain the scheme part, the default + * scheme will be prepended to it (thus changing the input). Defaults to null, meaning a URL must + * contain the scheme part. + * @since 1.1.7 + **/ + 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. + * If there is any error, the error message is added to the object. + * @param CModel $object the object being validated + * @param string $attribute the attribute being validated + */ + protected function validateAttribute($object, $attribute) + { + $value = $object->$attribute; + if ($this->allowEmpty && $this->isEmpty($value)) + return; + if (($value = $this->validateValue($value)) !== false) + $object->$attribute = $value; + else + { + $message = $this->message !== null ? $this->message : Yii::t('yii', '{attribute} is not a valid URL.'); + $this->addError($object, $attribute, $message); + } + } + + /** + * Validates a static value to see if it is a valid URL. + * Note that this method does not respect {@link allowEmpty} property. + * This method is provided so that you can call it directly without going through the model validation rule mechanism. + * @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}) + * @since 1.1.1 + */ + public function validateValue($value) + { + if (is_string($value) && strlen($value) < 2000) // make sure the length is limited to avoid DOS attacks + { + if ($this->defaultScheme !== null && strpos($value, '://') === false) + $value = $this->defaultScheme . '://' . $value; + + if (strpos($this->pattern, '{schemes}') !== false) + $pattern = str_replace('{schemes}', '(' . implode('|', $this->validSchemes) . ')', $this->pattern); + else + $pattern = $this->pattern; + + if (preg_match($pattern, $value)) + return $value; + } + return false; + } + + /** + * Returns the JavaScript needed for performing client-side validation. + * @param CModel $object the data object being validated + * @param string $attribute the name of the attribute to be validated. + * @return string the client-side validation script. + * @see CActiveForm::enableClientValidation + * @since 1.1.7 + */ + public function clientValidateAttribute($object, $attribute) + { + $message = $this->message !== null ? $this->message : Yii::t('yii', '{attribute} is not a valid URL.'); + $message = strtr($message, array( + '{attribute}' => $object->getAttributeLabel($attribute), + )); + + if (strpos($this->pattern, '{schemes}') !== false) + $pattern = str_replace('{schemes}', '(' . implode('|', $this->validSchemes) . ')', $this->pattern); + else + $pattern = $this->pattern; + + $js = " +if(!value.match($pattern)) { + messages.push(" . CJSON::encode($message) . "); +} +"; + if ($this->defaultScheme !== null) + { + $js = " +if(!value.match(/:\\/\\//)) { + value=" . CJSON::encode($this->defaultScheme) . "+'://'+value; +} +$js +"; + } + + if ($this->allowEmpty) + { + $js = " +if($.trim(value)!='') { + $js +} +"; + } + + return $js; + } +} + diff --git a/framework/validators/Validator.php b/framework/validators/Validator.php new file mode 100644 index 0000000..d636c5c --- /dev/null +++ b/framework/validators/Validator.php @@ -0,0 +1,258 @@ + + * @link http://www.yiiframework.com/ + * @copyright Copyright © 2008-2011 Yii Software LLC + * @license http://www.yiiframework.com/license/ + */ + +/** + * CValidator is the base class for all validators. + * + * Child classes must implement the {@link validateAttribute} method. + * + * The following properties are defined in CValidator: + *
    + *
  • {@link attributes}: array, list of attributes to be validated;
  • + *
  • {@link message}: string, the customized error message. The message + * may contain placeholders that will be replaced with the actual content. + * For example, the "{attribute}" placeholder will be replaced with the label + * of the problematic attribute. Different validators may define additional + * placeholders.
  • + *
  • {@link on}: string, in which scenario should the validator be in effect. + * This is used to match the 'on' parameter supplied when calling {@link CModel::validate}.
  • + *
+ * + * When using {@link createValidator} to create a validator, the following aliases + * are recognized as the corresponding built-in validator classes: + *
    + *
  • required: {@link CRequiredValidator}
  • + *
  • filter: {@link CFilterValidator}
  • + *
  • match: {@link CRegularExpressionValidator}
  • + *
  • email: {@link CEmailValidator}
  • + *
  • url: {@link CUrlValidator}
  • + *
  • unique: {@link CUniqueValidator}
  • + *
  • compare: {@link CCompareValidator}
  • + *
  • length: {@link CStringValidator}
  • + *
  • in: {@link CRangeValidator}
  • + *
  • numerical: {@link CNumberValidator}
  • + *
  • captcha: {@link CCaptchaValidator}
  • + *
  • type: {@link CTypeValidator}
  • + *
  • file: {@link CFileValidator}
  • + *
  • default: {@link CDefaultValueValidator}
  • + *
  • exist: {@link CExistValidator}
  • + *
  • boolean: {@link CBooleanValidator}
  • + *
  • date: {@link CDateValidator}
  • + *
  • safe: {@link CSafeValidator}
  • + *
  • unsafe: {@link CUnsafeValidator}
  • + *
+ * + * @author Qiang Xue + * @version $Id: CValidator.php 3160 2011-04-03 01:08:23Z qiang.xue $ + * @package system.validators + * @since 1.0 + */ +abstract class CValidator extends CComponent +{ + /** + * @var array list of built-in validators (name=>class) + */ + public static $builtInValidators = array( + 'required' => 'CRequiredValidator', + 'filter' => 'CFilterValidator', + 'match' => 'CRegularExpressionValidator', + 'email' => 'CEmailValidator', + 'url' => 'CUrlValidator', + 'unique' => 'CUniqueValidator', + 'compare' => 'CCompareValidator', + 'length' => 'CStringValidator', + 'in' => 'CRangeValidator', + 'numerical' => 'CNumberValidator', + 'captcha' => 'CCaptchaValidator', + 'type' => 'CTypeValidator', + 'file' => 'CFileValidator', + 'default' => 'CDefaultValueValidator', + 'exist' => 'CExistValidator', + 'boolean' => 'CBooleanValidator', + 'safe' => 'CSafeValidator', + 'unsafe' => 'CUnsafeValidator', + 'date' => 'CDateValidator', + ); + + /** + * @var array list of attributes to be validated. + */ + public $attributes; + /** + * @var string the user-defined error message. Different validators may define various + * placeholders in the message that are to be replaced with actual values. All validators + * recognize "{attribute}" placeholder, which will be replaced with the label of the attribute. + */ + public $message; + /** + * @var boolean whether this validation rule should be skipped if when there is already a validation + * error for the current attribute. Defaults to false. + * @since 1.1.1 + */ + public $skipOnError = false; + /** + * @var array list of scenarios that the validator should be applied. + * Each array value refers to a scenario name with the same name as its array key. + */ + public $on; + /** + * @var boolean whether attributes listed with this validator should be considered safe for massive assignment. + * Defaults to true. + * @since 1.1.4 + */ + public $safe = true; + /** + * @var boolean whether to perform client-side validation. Defaults to true. + * Please refer to {@link CActiveForm::enableClientValidation} for more details about client-side validation. + * @since 1.1.7 + */ + public $enableClientValidation = true; + + /** + * Validates a single attribute. + * This method should be overridden by child classes. + * @param CModel $object the data object being validated + * @param string $attribute the name of the attribute to be validated. + */ + abstract protected function validateAttribute($object, $attribute); + + + /** + * Creates a validator object. + * @param string $name the name or class of the validator + * @param CModel $object the data object being validated that may contain the inline validation method + * @param mixed $attributes list of attributes to be validated. This can be either an array of + * the attribute names or a string of comma-separated attribute names. + * @param array $params initial values to be applied to the validator properties + * @return CValidator the validator + */ + public static function createValidator($name, $object, $attributes, $params = array()) + { + if (is_string($attributes)) + $attributes = preg_split('/[\s,]+/', $attributes, -1, PREG_SPLIT_NO_EMPTY); + + if (isset($params['on'])) + { + if (is_array($params['on'])) + $on = $params['on']; + else + $on = preg_split('/[\s,]+/', $params['on'], -1, PREG_SPLIT_NO_EMPTY); + } + else + $on = array(); + + if (method_exists($object, $name)) + { + $validator = new CInlineValidator; + $validator->attributes = $attributes; + $validator->method = $name; + $validator->params = $params; + if (isset($params['skipOnError'])) + $validator->skipOnError = $params['skipOnError']; + } + else + { + $params['attributes'] = $attributes; + if (isset(self::$builtInValidators[$name])) + $className = Yii::import(self::$builtInValidators[$name], true); + else + $className = Yii::import($name, true); + $validator = new $className; + foreach ($params as $name => $value) + $validator->$name = $value; + } + + $validator->on = empty($on) ? array() : array_combine($on, $on); + + return $validator; + } + + /** + * Validates the specified object. + * @param CModel $object the data object being validated + * @param array $attributes the list of attributes to be validated. Defaults to null, + * meaning every attribute listed in {@link attributes} will be validated. + */ + public function validate($object, $attributes = null) + { + if (is_array($attributes)) + $attributes = array_intersect($this->attributes, $attributes); + else + $attributes = $this->attributes; + foreach ($attributes as $attribute) + { + if (!$this->skipOnError || !$object->hasErrors($attribute)) + $this->validateAttribute($object, $attribute); + } + } + + /** + * Returns the JavaScript needed for performing client-side validation. + * Do not override this method if the validator does not support client-side validation. + * Two predefined JavaScript variables can be used: + *
    + *
  • value: the value to be validated
  • + *
  • messages: an array used to hold the validation error messages for the value
  • + *
+ * @param CModel $object the data object being validated + * @param string $attribute the name of the attribute to be validated. + * @return string the client-side validation script. Null if the validator does not support client-side validation. + * @see CActiveForm::enableClientValidation + * @since 1.1.7 + */ + public function clientValidateAttribute($object, $attribute) + { + } + + /** + * Returns a value indicating whether the validator applies to the specified scenario. + * A validator applies to a scenario as long as any of the following conditions is met: + *
    + *
  • the validator's "on" property is empty
  • + *
  • the validator's "on" property contains the specified scenario
  • + *
+ * @param string $scenario scenario name + * @return boolean whether the validator applies to the specified scenario. + * @since 1.0.2 + */ + public function applyTo($scenario) + { + return empty($this->on) || isset($this->on[$scenario]); + } + + /** + * Adds an error about the specified attribute to the active record. + * This is a helper method that performs message selection and internationalization. + * @param CModel $object the data object being validated + * @param string $attribute the attribute being validated + * @param string $message the error message + * @param array $params values for the placeholders in the error message + */ + protected function addError($object, $attribute, $message, $params = array()) + { + $params['{attribute}'] = $object->getAttributeLabel($attribute); + $object->addError($attribute, strtr($message, $params)); + } + + /** + * Checks if the given value is empty. + * A value is considered empty if it is null, an empty array, or the trimmed result is an empty string. + * Note that this method is different from PHP empty(). It will return false when the value is 0. + * @param mixed $value the value to be checked + * @param boolean $trim whether to perform trimming before checking if the string is empty. Defaults to false. + * @return boolean whether the value is empty + * @since 1.0.9 + */ + protected function isEmpty($value, $trim = false) + { + return $value === null || $value === array() || $value === '' || $trim && is_scalar($value) && trim($value) === ''; + } +} +