Closes #6242: Access to validator in inline validation (#13027)

* Closes #6242: Access to validator in inline validation

* Updated PHPDoc according to PR review [skip ci]

* Imrpoved PHPDoc, updated guide info [skip ci]

* Fixes related with PR review

* Corrected CHANGELOG [skip ci]

* Update input-validation.md

added version info
This commit is contained in:
Alexey Rogachev
2016-12-09 04:29:53 +06:00
committed by Carsten Brandt
parent 3611aa409b
commit bd85b7ced2
5 changed files with 72 additions and 14 deletions

View File

@ -331,8 +331,9 @@ the method/function is:
/**
* @param string $attribute the attribute currently being validated
* @param mixed $params the value of the "params" given in the rule
* @param \yii\validators\InlineValidator related InlineValidator instance
*/
function ($attribute, $params)
function ($attribute, $params, $validator)
```
If an attribute fails the validation, the method/function should call [[yii\base\Model::addError()]] to save
@ -355,7 +356,7 @@ class MyForm extends Model
['country', 'validateCountry'],
// an inline validator defined as an anonymous function
['token', function ($attribute, $params) {
['token', function ($attribute, $params, $validator) {
if (!ctype_alnum($this->$attribute)) {
$this->addError($attribute, 'The token must contain letters or digits.');
}
@ -363,7 +364,7 @@ class MyForm extends Model
];
}
public function validateCountry($attribute, $params)
public function validateCountry($attribute, $params, $validator)
{
if (!in_array($this->$attribute, ['USA', 'Web'])) {
$this->addError($attribute, 'The country must be either "USA" or "Web".');
@ -372,6 +373,14 @@ class MyForm extends Model
}
```
> Note: Since version 2.0.11 you can use [[yii\validators\InlineValidator::addError()]] for adding errors instead. That way the error
> message can be formatted using [[yii\i18n\I18N::format()]] right away. Use `{attribute}` and `{value}` in the error
> message to refer to an attribute label (no need to get it manually) and attribute value accordingly:
>
> ```php
> $validator->addError($this, $attribute, 'The value "{value}" is not acceptable for {attribute}.');
> ```
> Note: By default, inline validators will not be applied if their associated attributes receive empty inputs
or if they have already failed some validation rules. If you want to make sure a rule is always applied,
you may configure the [[yii\validators\Validator::skipOnEmpty|skipOnEmpty]] and/or [[yii\validators\Validator::skipOnError|skipOnError]]

View File

@ -30,6 +30,7 @@ Yii Framework 2 Change Log
- Bug #7727: Fixed truncateHtml leaving extra tags (developeruz)
- Bug #13118: Fixed `handleAction()` function in `yii.js` to handle attribute `data-pjax=0` as disabled PJAX (silverfire)
- Enh #475: Added Bash and Zsh completion support for the `./yii` command (cebe, silverfire)
- Enh #6242: Access to validator in inline validation (arogachev)
- Enh #6373: Introduce `yii\db\Query::emulateExecution()` to force returning an empty result for a query (klimov-paul)
- Enh #6809: Added `yii\caching\Cache::$defaultDuration` property, allowing to set custom default cache duration (sdkiller)
- Enh #7333: Improved error message for `yii\di\Instance::ensure()` when a component does not exist (cebe)

View File

@ -13,11 +13,12 @@ namespace yii\validators;
* The validation method must have the following signature:
*
* ```php
* function foo($attribute, $params)
* function foo($attribute, $params, $validator)
* ```
*
* where `$attribute` refers to the name of the attribute being validated, while `$params`
* is an array representing the additional parameters supplied in the validation rule.
* where `$attribute` refers to the name of the attribute being validated, while `$params` is an array representing the
* additional parameters supplied in the validation rule. Parameter `$validator` refers to the related
* [[InlineValidator]] object and is available since version 2.0.11.
*
* @author Qiang Xue <qiang.xue@gmail.com>
* @since 2.0
@ -26,13 +27,15 @@ class InlineValidator extends Validator
{
/**
* @var string|\Closure an anonymous function or the name of a model class method that will be
* called to perform the actual validation. The signature of the method should be like the following,
* where `$attribute` is the name of the attribute to be validated, and `$params` contains the value
* of [[params]] that you specify when declaring the inline validation rule:
* called to perform the actual validation. The signature of the method should be like the following:
*
* ```php
* function foo($attribute, $params)
* function foo($attribute, $params, $validator)
* ```
*
* - `$attribute` is the name of the attribute to be validated;
* - `$params` contains the value of [[params]] that you specify when declaring the inline validation rule;
* - `$validator` is a reference to related [[InlineValidator]] object.
*/
public $method;
/**
@ -44,7 +47,7 @@ class InlineValidator extends Validator
* The signature of the method should be like the following:
*
* ```php
* function foo($attribute, $params)
* function foo($attribute, $params, $validator)
* {
* return "javascript";
* }
@ -66,7 +69,7 @@ class InlineValidator extends Validator
if (is_string($method)) {
$method = [$model, $method];
}
call_user_func($method, $attribute, $this->params);
call_user_func($method, $attribute, $this->params, $this);
}
/**
@ -80,7 +83,7 @@ class InlineValidator extends Validator
$method = [$model, $method];
}
return call_user_func($method, $attribute, $this->params);
return call_user_func($method, $attribute, $this->params, $this);
} else {
return null;
}

View File

@ -11,6 +11,7 @@ class FakedValidationModel extends Model
public $val_attr_c;
public $val_attr_d;
private $attr = [];
private $inlineValArgs;
/**
* @param array $attributes
@ -36,11 +37,18 @@ class FakedValidationModel extends Model
];
}
public function inlineVal($attribute, $params = [])
public function inlineVal($attribute, $params = [], $validator)
{
$this->inlineValArgs = func_get_args();
return true;
}
public function clientInlineVal($attribute, $params = [], $validator)
{
return func_get_args();
}
public function __get($name)
{
if (stripos($name, 'attr') === 0) {
@ -63,4 +71,14 @@ class FakedValidationModel extends Model
{
return $attr;
}
/**
* Returns the arguments of the inlineVal method in the last call.
* @return array|null an array of arguments in the last call or null if method never been called.
* @see inlineVal
*/
public function getInlineValArgs()
{
return $this->inlineValArgs;
}
}

View File

@ -176,12 +176,39 @@ class ValidatorTest extends TestCase
$val->validate('abc');
}
public function testValidateAttribute()
{
// Access to validator in inline validation (https://github.com/yiisoft/yii2/issues/6242)
$model = new FakedValidationModel();
$val = TestValidator::createValidator('inlineVal', $model, ['val_attr_a'], ['params' => ['foo' => 'bar']]);
$val->validateAttribute($model, 'val_attr_a');
$args = $model->getInlineValArgs();
$this->assertCount(3, $args);
$this->assertEquals('val_attr_a', $args[0]);
$this->assertEquals(['foo' => 'bar'], $args[1]);
$this->assertInstanceOf(InlineValidator::className(), $args[2]);
}
public function testClientValidateAttribute()
{
$val = new TestValidator();
$this->assertNull(
$val->clientValidateAttribute($this->getTestModel(), 'attr_runMe1', [])
); //todo pass a view instead of array
// Access to validator in inline validation (https://github.com/yiisoft/yii2/issues/6242)
$model = new FakedValidationModel();
$val = TestValidator::createValidator('inlineVal', $model, ['val_attr_a'], ['params' => ['foo' => 'bar']]);
$val->clientValidate = 'clientInlineVal';
$args = $val->clientValidateAttribute($model, 'val_attr_a', null);
$this->assertCount(3, $args);
$this->assertEquals('val_attr_a', $args[0]);
$this->assertEquals(['foo' => 'bar'], $args[1]);
$this->assertInstanceOf(InlineValidator::className(), $args[2]);
}
public function testIsActive()