Commit da48b378 by Qiang Xue

Fixes #2756: Added support for injecting custom `isEmpty` check for all validators

parent cc08492b
......@@ -145,6 +145,7 @@ Yii Framework 2 Change Log
- Enh #2670: Changed `console\Controller::globalOptions()` to `options($actionId)` to (make it possible to) differentiate options per action (hqx)
- Enh #2729: Added `FilterValidator::skipOnArray` so that filters like `trim` will not fail for array inputs (qiangxue)
- Enh #2735: Added support for `DateTimeInterface` in `Formatter` (ivokund)
- Enh #2756: Added support for injecting custom `isEmpty` check for all validators (qiangxue)
- Enh: Added support for using arrays as option values for console commands (qiangxue)
- Enh: Added `favicon.ico` and `robots.txt` to default application templates (samdark)
- Enh: Added `Widget::autoIdPrefix` to support prefixing automatically generated widget IDs (qiangxue)
......
......@@ -11,20 +11,20 @@
*/
yii.validation = (function ($) {
var isEmpty = function (value, trim) {
return value === null || value === undefined || value == []
|| value === '' || trim && $.trim(value) === '';
};
var addMessage = function (messages, message, value) {
messages.push(message.replace(/\{value\}/g, value));
};
var pub = {
isEmpty: function (value) {
return value === null || value === undefined || value == [] || value === '';
},
return {
addMessage: function (messages, message, value) {
messages.push(message.replace(/\{value\}/g, value));
},
required: function (value, messages, options) {
var valid = false;
if (options.requiredValue === undefined) {
if (options.strict && value !== undefined || !options.strict && !isEmpty(value, true)) {
var isString = typeof value == 'string' || value instanceof String;
if (options.strict && value !== undefined || !options.strict && !pub.isEmpty(isString ? $.trim(value) : value)) {
valid = true;
}
} else if (!options.strict && value == options.requiredValue || options.strict && value === options.requiredValue) {
......@@ -32,85 +32,85 @@ yii.validation = (function ($) {
}
if (!valid) {
addMessage(messages, options.message, value);
pub.addMessage(messages, options.message, value);
}
},
boolean: function (value, messages, options) {
if (options.skipOnEmpty && isEmpty(value)) {
if (options.skipOnEmpty && pub.isEmpty(value)) {
return;
}
var valid = !options.strict && (value == options.trueValue || value == options.falseValue)
|| options.strict && (value === options.trueValue || value === options.falseValue);
if (!valid) {
addMessage(messages, options.message, value);
pub.addMessage(messages, options.message, value);
}
},
string: function (value, messages, options) {
if (options.skipOnEmpty && isEmpty(value)) {
if (options.skipOnEmpty && pub.isEmpty(value)) {
return;
}
if (typeof value !== 'string') {
addMessage(messages, options.message, value);
pub.addMessage(messages, options.message, value);
return;
}
if (options.min !== undefined && value.length < options.min) {
addMessage(messages, options.tooShort, value);
pub.addMessage(messages, options.tooShort, value);
}
if (options.max !== undefined && value.length > options.max) {
addMessage(messages, options.tooLong, value);
pub.addMessage(messages, options.tooLong, value);
}
if (options.is !== undefined && value.length != options.is) {
addMessage(messages, options.is, value);
pub.addMessage(messages, options.is, value);
}
},
number: function (value, messages, options) {
if (options.skipOnEmpty && isEmpty(value)) {
if (options.skipOnEmpty && pub.isEmpty(value)) {
return;
}
if (typeof value === 'string' && !value.match(options.pattern)) {
addMessage(messages, options.message, value);
pub.addMessage(messages, options.message, value);
return;
}
if (options.min !== undefined && value < options.min) {
addMessage(messages, options.tooSmall, value);
pub.addMessage(messages, options.tooSmall, value);
}
if (options.max !== undefined && value > options.max) {
addMessage(messages, options.tooBig, value);
pub.addMessage(messages, options.tooBig, value);
}
},
range: function (value, messages, options) {
if (options.skipOnEmpty && isEmpty(value)) {
if (options.skipOnEmpty && pub.isEmpty(value)) {
return;
}
var valid = !options.not && $.inArray(value, options.range) > -1
|| options.not && $.inArray(value, options.range) == -1;
if (!valid) {
addMessage(messages, options.message, value);
pub.addMessage(messages, options.message, value);
}
},
regularExpression: function (value, messages, options) {
if (options.skipOnEmpty && isEmpty(value)) {
if (options.skipOnEmpty && pub.isEmpty(value)) {
return;
}
if (!options.not && !value.match(options.pattern) || options.not && value.match(options.pattern)) {
addMessage(messages, options.message, value);
pub.addMessage(messages, options.message, value);
}
},
email: function (value, messages, options) {
if (options.skipOnEmpty && isEmpty(value)) {
if (options.skipOnEmpty && pub.isEmpty(value)) {
return;
}
......@@ -127,12 +127,12 @@ yii.validation = (function ($) {
}
if (!valid || !(value.match(options.pattern) || (options.allowName && value.match(options.fullPattern)))) {
addMessage(messages, options.message, value);
pub.addMessage(messages, options.message, value);
}
},
url: function (value, messages, options) {
if (options.skipOnEmpty && isEmpty(value)) {
if (options.skipOnEmpty && pub.isEmpty(value)) {
return;
}
......@@ -153,12 +153,12 @@ yii.validation = (function ($) {
}
if (!valid || !value.match(options.pattern)) {
addMessage(messages, options.message, value);
pub.addMessage(messages, options.message, value);
}
},
captcha: function (value, messages, options) {
if (options.skipOnEmpty && isEmpty(value)) {
if (options.skipOnEmpty && pub.isEmpty(value)) {
return;
}
......@@ -174,12 +174,12 @@ yii.validation = (function ($) {
h += v.charCodeAt(i);
}
if (h != hash) {
addMessage(messages, options.message, value);
pub.addMessage(messages, options.message, value);
}
},
compare: function (value, messages, options) {
if (options.skipOnEmpty && isEmpty(value)) {
if (options.skipOnEmpty && pub.isEmpty(value)) {
return;
}
......@@ -220,8 +220,9 @@ yii.validation = (function ($) {
}
if (!valid) {
addMessage(messages, options.message, value);
pub.addMessage(messages, options.message, value);
}
}
};
return pub;
})(jQuery);
......@@ -67,7 +67,7 @@ class RequiredValidator extends Validator
protected function validateValue($value)
{
if ($this->requiredValue === null) {
if ($this->strict && $value !== null || !$this->strict && !$this->isEmpty($value, true)) {
if ($this->strict && $value !== null || !$this->strict && !$this->isEmpty(is_string($value) ? trim($value) : $value)) {
return null;
}
} elseif (!$this->strict && $value == $this->requiredValue || $this->strict && $value === $this->requiredValue) {
......
......@@ -120,6 +120,13 @@ class Validator extends Component
* is true, no client-side validation will be done by this validator.
*/
public $enableClientValidation = true;
/**
* @var callable a PHP callable that replaces the default implementation of [[isEmpty()]].
* If not set, [[isEmpty()]] will be used to check if a value is empty. The signature
* of the callable should be `function ($value)` which returns a boolean indicating
* whether the value is empty.
*/
public $isEmpty;
/**
......@@ -301,12 +308,14 @@ class Validator extends Component
* 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
*/
public function isEmpty($value, $trim = false)
public function isEmpty($value)
{
return $value === null || $value === [] || $value === ''
|| $trim && is_scalar($value) && trim($value) === '';
if ($this->isEmpty !== null) {
return call_user_func($this->isEmpty, $value);
} else {
return $value === null || $value === [] || $value === '';
}
}
}
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