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 ...@@ -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 #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 #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 #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 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 `favicon.ico` and `robots.txt` to default application templates (samdark)
- Enh: Added `Widget::autoIdPrefix` to support prefixing automatically generated widget IDs (qiangxue) - Enh: Added `Widget::autoIdPrefix` to support prefixing automatically generated widget IDs (qiangxue)
......
...@@ -11,20 +11,20 @@ ...@@ -11,20 +11,20 @@
*/ */
yii.validation = (function ($) { yii.validation = (function ($) {
var isEmpty = function (value, trim) { var pub = {
return value === null || value === undefined || value == [] isEmpty: function (value) {
|| value === '' || trim && $.trim(value) === ''; return value === null || value === undefined || value == [] || value === '';
}; },
var addMessage = function (messages, message, value) { addMessage: function (messages, message, value) {
messages.push(message.replace(/\{value\}/g, value)); messages.push(message.replace(/\{value\}/g, value));
}; },
return {
required: function (value, messages, options) { required: function (value, messages, options) {
var valid = false; var valid = false;
if (options.requiredValue === undefined) { 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; valid = true;
} }
} else if (!options.strict && value == options.requiredValue || options.strict && value === options.requiredValue) { } else if (!options.strict && value == options.requiredValue || options.strict && value === options.requiredValue) {
...@@ -32,85 +32,85 @@ yii.validation = (function ($) { ...@@ -32,85 +32,85 @@ yii.validation = (function ($) {
} }
if (!valid) { if (!valid) {
addMessage(messages, options.message, value); pub.addMessage(messages, options.message, value);
} }
}, },
boolean: function (value, messages, options) { boolean: function (value, messages, options) {
if (options.skipOnEmpty && isEmpty(value)) { if (options.skipOnEmpty && pub.isEmpty(value)) {
return; return;
} }
var valid = !options.strict && (value == options.trueValue || value == options.falseValue) var valid = !options.strict && (value == options.trueValue || value == options.falseValue)
|| options.strict && (value === options.trueValue || value === options.falseValue); || options.strict && (value === options.trueValue || value === options.falseValue);
if (!valid) { if (!valid) {
addMessage(messages, options.message, value); pub.addMessage(messages, options.message, value);
} }
}, },
string: function (value, messages, options) { string: function (value, messages, options) {
if (options.skipOnEmpty && isEmpty(value)) { if (options.skipOnEmpty && pub.isEmpty(value)) {
return; return;
} }
if (typeof value !== 'string') { if (typeof value !== 'string') {
addMessage(messages, options.message, value); pub.addMessage(messages, options.message, value);
return; return;
} }
if (options.min !== undefined && value.length < options.min) { 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) { 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) { if (options.is !== undefined && value.length != options.is) {
addMessage(messages, options.is, value); pub.addMessage(messages, options.is, value);
} }
}, },
number: function (value, messages, options) { number: function (value, messages, options) {
if (options.skipOnEmpty && isEmpty(value)) { if (options.skipOnEmpty && pub.isEmpty(value)) {
return; return;
} }
if (typeof value === 'string' && !value.match(options.pattern)) { if (typeof value === 'string' && !value.match(options.pattern)) {
addMessage(messages, options.message, value); pub.addMessage(messages, options.message, value);
return; return;
} }
if (options.min !== undefined && value < options.min) { 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) { if (options.max !== undefined && value > options.max) {
addMessage(messages, options.tooBig, value); pub.addMessage(messages, options.tooBig, value);
} }
}, },
range: function (value, messages, options) { range: function (value, messages, options) {
if (options.skipOnEmpty && isEmpty(value)) { if (options.skipOnEmpty && pub.isEmpty(value)) {
return; return;
} }
var valid = !options.not && $.inArray(value, options.range) > -1 var valid = !options.not && $.inArray(value, options.range) > -1
|| options.not && $.inArray(value, options.range) == -1; || options.not && $.inArray(value, options.range) == -1;
if (!valid) { if (!valid) {
addMessage(messages, options.message, value); pub.addMessage(messages, options.message, value);
} }
}, },
regularExpression: function (value, messages, options) { regularExpression: function (value, messages, options) {
if (options.skipOnEmpty && isEmpty(value)) { if (options.skipOnEmpty && pub.isEmpty(value)) {
return; return;
} }
if (!options.not && !value.match(options.pattern) || options.not && value.match(options.pattern)) { 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) { email: function (value, messages, options) {
if (options.skipOnEmpty && isEmpty(value)) { if (options.skipOnEmpty && pub.isEmpty(value)) {
return; return;
} }
...@@ -127,12 +127,12 @@ yii.validation = (function ($) { ...@@ -127,12 +127,12 @@ yii.validation = (function ($) {
} }
if (!valid || !(value.match(options.pattern) || (options.allowName && value.match(options.fullPattern)))) { 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) { url: function (value, messages, options) {
if (options.skipOnEmpty && isEmpty(value)) { if (options.skipOnEmpty && pub.isEmpty(value)) {
return; return;
} }
...@@ -153,12 +153,12 @@ yii.validation = (function ($) { ...@@ -153,12 +153,12 @@ yii.validation = (function ($) {
} }
if (!valid || !value.match(options.pattern)) { if (!valid || !value.match(options.pattern)) {
addMessage(messages, options.message, value); pub.addMessage(messages, options.message, value);
} }
}, },
captcha: function (value, messages, options) { captcha: function (value, messages, options) {
if (options.skipOnEmpty && isEmpty(value)) { if (options.skipOnEmpty && pub.isEmpty(value)) {
return; return;
} }
...@@ -174,12 +174,12 @@ yii.validation = (function ($) { ...@@ -174,12 +174,12 @@ yii.validation = (function ($) {
h += v.charCodeAt(i); h += v.charCodeAt(i);
} }
if (h != hash) { if (h != hash) {
addMessage(messages, options.message, value); pub.addMessage(messages, options.message, value);
} }
}, },
compare: function (value, messages, options) { compare: function (value, messages, options) {
if (options.skipOnEmpty && isEmpty(value)) { if (options.skipOnEmpty && pub.isEmpty(value)) {
return; return;
} }
...@@ -220,8 +220,9 @@ yii.validation = (function ($) { ...@@ -220,8 +220,9 @@ yii.validation = (function ($) {
} }
if (!valid) { if (!valid) {
addMessage(messages, options.message, value); pub.addMessage(messages, options.message, value);
} }
} }
}; };
return pub;
})(jQuery); })(jQuery);
...@@ -67,7 +67,7 @@ class RequiredValidator extends Validator ...@@ -67,7 +67,7 @@ class RequiredValidator extends Validator
protected function validateValue($value) protected function validateValue($value)
{ {
if ($this->requiredValue === null) { 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; return null;
} }
} elseif (!$this->strict && $value == $this->requiredValue || $this->strict && $value === $this->requiredValue) { } elseif (!$this->strict && $value == $this->requiredValue || $this->strict && $value === $this->requiredValue) {
......
...@@ -120,6 +120,13 @@ class Validator extends Component ...@@ -120,6 +120,13 @@ class Validator extends Component
* is true, no client-side validation will be done by this validator. * is true, no client-side validation will be done by this validator.
*/ */
public $enableClientValidation = true; 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 ...@@ -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. * 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. * 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 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 * @return boolean whether the value is empty
*/ */
public function isEmpty($value, $trim = false) public function isEmpty($value)
{ {
return $value === null || $value === [] || $value === '' if ($this->isEmpty !== null) {
|| $trim && is_scalar($value) && trim($value) === ''; 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