yii2Validation

Validate unique value from database in Yii2

Few people have issue regarding error message not displaying if existing value is being entered in textbox.

So, For Example I'm not allowing user to enter existing email.

signup.php

(Page where you wanted to sign up new user without existing email id)

  1. Remove use yii\bootstrap\ActiveForm; (if present)
  2. Add use yii\widgets\ActiveForm;
  3. Add 'enableAjaxValidation' => true (In that field Where you want to stop user for entering existing email id.)
<?php
use yii\bootstrap\ActiveForm;
use yii\widgets\ActiveForm;
?>

<?= $form->field($modelUser, 'email',['enableAjaxValidation' => true])
    ->textInput(['class'=>'form-control','placeholder'=>'Email']); ?>

Controller

Add these lines on top use yii\web\Response;use yii\widgets\ActiveForm;

<?php
use yii\web\Response;
use yii\widgets\ActiveForm;

  .
  .// Your code
  .

  public function actionSignup() {
    
    $modelUser = new User();

    //Add This For Ajax Email Exist Validation 
    if(Yii::$app->request->isAjax && $modelUser->load(Yii::$app->request->post())){
      Yii::$app->response->format = Response::FORMAT_JSON;
      return ActiveForm::validate($modelUser);
    } 
    else if ($model->load(Yii::$app->request->post())) {
      
    }
    
  }
?>

Model

[['email'],'unique','message'=>'Email already exist. Please try another one.'],

Validating Unique Value From Database : Unique Validation

Some people have issues regarding error messages not being displayed if an existing value is being entered. For example I'm not allowing a user signup with an existing email.

View

<?php
......................    
    
    <?= $form->field($modelUser, 'email')->textInput(['class'=>'form-control','placeholder'=>'Email']) ?>
......................    

Controller

<?php
use yii\web\Response; // important lines
use yii\widgets\ActiveForm; // important lines
        
.
.// Your code
.
        
public function actionSignup() 
{
            
    $modelUser = new User();
        
    //Add This For Ajax Validation 
    if(Yii::$app->request->isAjax && $modelUser->load(Yii::$app->request->post())){
        Yii::$app->response->format = Response::FORMAT_JSON;
        return ActiveForm::validate($modelUser);
    } 
    if ($modelUser->load(Yii::$app->request->post()) && $modelUser->save()) {
        return $this->redirect(['someplace nice']);
    }
    return $this->render('update', [
        'modelUser' => $modelUser,
    ]);            
}

Model

public function rules()
{
    return [
        ..............
        ['email', 'unique', 'message'=>'Email already exist. Please try another one.'],
        ...........
    ]
}

Disable Validation Error Message On Focus / Key Up

By default error message appears below textbox in <div class="help-block"></div> on keyUp or after pressing submit button if any validation constraints aren't met.

Sometimes we want a message on submit only i.e. no validation at onKeyup event.

Let's check yii2/widgets/ActiveForm.php file:

<?php

namespace yii\widgets;

use Yii;
use yii\base\InvalidCallException;
use yii\base\Widget;
use yii\base\Model;
use yii\helpers\ArrayHelper;
use yii\helpers\Url;
use yii\helpers\Html;
use yii\helpers\Json;

class ActiveForm extends Widget
{
  public $action = '';
  public $method = 'post';
  public $options = [];
  .
  .
  .
  public $validateOnSubmit = true;
  public $validateOnChange = true;
  public $validateOnBlur = true;
  public $validateOnType = false;
  
  .
  .
  .
  
}

There we see that $validateOnBlur is set to true by default. Changing framework files is a very bad thing to do so we need to override it when using the form:

<?php $form = ActiveForm::begin([ 'id' => 'register-form','validateOnBlur' => false]); ?>

Scenario in Validation

Using scenario you can perform validation on different situation

Define scenario in model class

    class User extends \yii\db\ActiveRecord 
    {
      public static function tableName()
      {
          return 'user_master';
      }

    // define validation in rule() function
  public function rules()
  {
    return [
      [['email_id'],'email'],
      [['first_name',],'required','on'=>['create','update']],  // create scenario
      [['email_id',],'required','on'=> ['admin','create','update','forgotpassword']],
      [['mobile',],'required','on'=>['admin','create','update']],
    ];
  }
}

Use Scenario in Controller

public function actionCreate()
{
  $model = new User();
  $model->scenario="create";  // use create scenario, create scenario validaion applied in this model
            
  
}
public function actionUpdate()
{
    $model = new User();
    $model->scenario="update";  // use update scenario, update scenario validaion applied in this model
}

Validate array

Since Yii2 version 2.0.4 there is the EachValidator used to validate each item in an array.

[
    // ... other rules
    ['userIDs', 'each', 'rule' => ['integer']],
]

The ['integer'] part can be every other validator object that Yii2 offers and can hold the specific arguments for the validator. Like: ['integer', 'min' => 1337]. If the userIDs doesn't contain an array the rule validation will fail.

If you just want to see if an attribute contains an array without validating the contents you can write your own validator.

[
    ['myAttr', function($attribute, $params) {
        if (!is_array($this->$attribute)) {
            $this->addError($attribute, "$attribute isn't an array!");
        }
    }]
]