input-validation.md 8.21 KB
Newer Older
Qiang Xue committed
1 2
Validating Input
================
Alexander Makarov committed
3

Qiang Xue committed
4 5 6
As a rule of thumb, you should never trust the data coming from end users and should always validate them
before putting them to good use. In the [Models](structure-models.md#validation) section, we have described
how validation works in general. In this section, we will give more details about validation.
Qiang Xue committed
7

Qiang Xue committed
8

Qiang Xue committed
9
## Validating Input
Larry Ullman committed
10

Qiang Xue committed
11 12
Assume you have a model that takes user input. In order to validate the input, you should define a set
of validation rules by overriding the [[yii\base\Model::rules()]] method, like the following,
13

Qiang Xue committed
14 15 16 17 18 19
```php
public function rules()
{
    return [
        // the name, email, subject and body attributes are required
        [['name', 'email', 'subject', 'body'], 'required'],
20

Qiang Xue committed
21 22 23 24 25
        // the email attribute should be a valid email address
        ['email', 'email'],
    ];
}
```
26

Qiang Xue committed
27
The `rules()` method returns an array of rules, each of which is an array in the following format:
28

Qiang Xue committed
29 30 31 32 33 34
```php
[
    // required, specifies which attributes should be validated by this rule.
    // For single attribute, you can use the attribute name directly
    // without having it in an array instead of an array
    ['attribute1', 'attribute2', ...],
35

Qiang Xue committed
36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90
    // required, specifies the type of this rule.
    // It can be a class name, validator alias, or a validation method name
    'validator',

    // optional, specifies in which scenario(s) this rule should be applied
    // if not given, it means the rule applies to all scenarios
    'on' => ['scenario1', 'scenario2', ...],

    // optional, specifies additional configurations for the validator object
    'property1' => 'value1', 'property2' => 'value2', ...
]
```



When the `validate()` method is called, it does the following steps to perform validation:

1. Determine which attributes should be validated by checking the current [[yii\base\Model::scenario|scenario]]
   against the scenarios declared in [[yii\base\Model::scenarios()]]. These attributes are the active attributes.
2. Determine which rules should be applied by checking the current [[yii\base\Model::scenario|scenario]]
   against the rules declared in [[yii\base\Model::rules()]]. These rules are the active rules.
3. Use each active rule to validate each active attribute which is associated with the rule.

According to the above validation steps, an attribute will be validated if and only if it is
an active attribute declared in `scenarios()` and it is associated with one or multiple active rules
declared in `rules()`.

Yii provides a set of [built-in validators](tutorial-core-validators.md) to support commonly needed data
validation tasks. You may also create your own validators by extending [[yii\validators\Validator]] or
writing an inline validation method within model classes. For more details about the built-in validators
and how to create your own validators, please refer to the [Input Validation](input-validation.md) section.

### Declaring Validation Rules

### Error Messages

### Core Validators

### Conditional Validation

### Ad Hoc Validation

### Data Filtering



## Creating Validators

### Inline Validators

### Standalone Validators

### Empty Inputs and Array Inputs

### Client-Side Validation
91 92


Qiang Xue committed
93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184

## Creating Validators

If none of the built in validators fit your needs, you can create your own validator by creating a method in you model class.
This method will be wrapped by an [[yii\validators\InlineValidator|InlineValidator]] an be called upon validation.
You will do the validation of the attribute and [[yii\base\Model::addError()|add errors]] to the model when validation fails.

The method has the following signature `public function myValidator($attribute, $params)` while you are free to choose the name.

Here is an example implementation of a validator validating the age of a user:

```php
public function validateAge($attribute, $params)
{
    $value = $this->$attribute;
    if (strtotime($value) > strtotime('now - ' . $params['min'] . ' years')) {
        $this->addError($attribute, 'You must be at least ' . $params['min'] . ' years old to register for this service.');
    }
}

public function rules()
{
    return [
        // ...
        [['birthdate'], 'validateAge', 'params' => ['min' => '12']],
    ];
}
```

You may also set other properties of the [[yii\validators\InlineValidator|InlineValidator]] in the rules definition,
for example the [[yii\validators\InlineValidator::$skipOnEmpty|skipOnEmpty]] property:

```php
[['birthdate'], 'validateAge', 'params' => ['min' => '12'], 'skipOnEmpty' => false],
```


### Inline Validators

### Standalone Validators

## Client-Side Validation

## Conditional Validation


To validate attributes only when certain conditions apply, e.g. the validation of
one field depends on the value of another field you can use [[yii\validators\Validator::when|the `when` property]]
to define such conditions:

```php
['state', 'required', 'when' => function($model) { return $model->country == Country::USA; }],
['stateOthers', 'required', 'when' => function($model) { return $model->country != Country::USA; }],
['mother', 'required', 'when' => function($model) { return $model->age < 18 && $model->married != true; }],
```

For better readability the conditions can also be written like this:

```php
public function rules()
{
    $usa = function($model) { return $model->country == Country::USA; };
    $notUsa = function($model) { return $model->country != Country::USA; };
    $child = function($model) { return $model->age < 18 && $model->married != true; };
    return [
        ['state', 'required', 'when' => $usa],
        ['stateOthers', 'required', 'when' => $notUsa], // note that it is not possible to write !$usa
        ['mother', 'required', 'when' => $child],
    ];
}
```

When you need conditional validation logic on client-side (`enableClientValidation` is true), don't forget
to add `whenClient`:

```php
public function rules()
{
    $usa = [
        'server-side' => function($model) { return $model->country == Country::USA; },
        'client-side' => "function (attribute, value) {return $('#country').value == 'USA';}"
    ];

    return [
        ['state', 'required', 'when' => $usa['server-side'], 'whenClient' => $usa['client-side']],
    ];
}
```

This guide describes all of Yii's validators and their parameters.


Qiang Xue committed
185

Qiang Xue committed
186 187 188

## Ad Hoc Validation

189

Larry Ullman committed
190 191
Sometimes you need to validate a value that is not bound to any model, such as a standalone email address. The `Validator` class has a
`validateValue` method that can help you in these scenarios. Not all validator classes have implemented this method, but the ones that have implemented `validateValue` can be used without a model. For example, to validate an email stored in a string, you can do the following:
192 193 194 195

```php
$email = 'test@example.com';
$validator = new yii\validators\EmailValidator();
Qiang Xue committed
196
if ($validator->validate($email, $error)) {
197
    echo 'Email is valid.';
198
} else {
199
    echo $error;
200 201
}
```
Alexander Makarov committed
202

Qiang Xue committed
203 204 205 206 207 208 209 210
DynamicModel is a model class primarily used to support ad hoc data validation.

The typical usage of DynamicModel is as follows,

```php
public function actionSearch($name, $email)
{
    $model = DynamicModel::validateData(compact('name', 'email'), [
Ryadnov Andrey committed
211
        [['name', 'email'], 'string', 'max' => 128],
Qiang Xue committed
212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241
        ['email', 'email'],
    ]);
    if ($model->hasErrors()) {
        // validation fails
    } else {
        // validation succeeds
    }
}
```

The above example shows how to validate `$name` and `$email` with the help of DynamicModel.
The [[validateData()]] method creates an instance of DynamicModel, defines the attributes
using the given data (`name` and `email` in this example), and then calls [[Model::validate()]].

You can check the validation result by [[hasErrors()]], like you do with a normal model.
You may also access the dynamic attributes defined through the model instance, e.g.,
`$model->name` and `$model->email`.

Alternatively, you may use the following more "classic" syntax to perform ad-hoc data validation:

```php
$model = new DynamicModel(compact('name', 'email'));
$model->addRule(['name', 'email'], 'string', ['max' => 128])
    ->addRule('email', 'email')
    ->validate();
```

DynamicModel implements the above ad-hoc data validation feature by supporting the so-called
"dynamic attributes". It basically allows an attribute to be defined dynamically through its constructor
or [[defineAttribute()]].