1

I am using bootstrap ActiveForm. Here is my form:

use yii\helpers\Html;
use yii\bootstrap\ActiveForm;
use kartik\file\FileInput;

/* @var $this yii\web\View */
/* @var $model common\models\Customer */
/* @var $form yii\widgets\ActiveForm */
?>
<?php $form = ActiveForm::begin(['options' => ['enctype' => 'multipart/form-data'],
    'id' => 'customer-form',
    'enableClientValidation' => true,
    'options' => [
        'validateOnSubmit' => true,
        'class' => 'form'
    ],
    'layout' => 'horizontal',
    'fieldConfig' => [
      'horizontalCssClasses' => [
          'label' => 'col-sm-4',
         // 'offset' => 'col-sm-offset-2',
          'wrapper' => 'col-sm-8',
      ],
    ],
]); ?>
<?= $form->field($model, 'email')->textInput(['maxlength' => true]) ?>
<?php ActiveForm::end(); ?>

Here is my model:

class Customer extends \yii\db\ActiveRecord
{
    public $username;
    public $password;
    public $status;
    public $email;
    public $uploads;


    public function rules()
    {
        return [
            [['user_id', 'created_by', 'updated_by'], 'integer'],
            [['created_at','uploads', 'updated_at','legacy_customer_id','fax','phone_two','trn'], 'safe'],
            [['company_name','customer_name','username','password', 'tax_id'], 'string', 'max' => 200],
            [['customer_name','email','legacy_customer_id','company_name','city'], 'required'],
            [['is_deleted','status'], 'boolean'],
            [['address_line_1', 'state','phone', 'country'], 'string', 'max' => 450],
            [['address_line_2', 'city', 'zip_code'], 'string', 'max' => 45],
            [['user_id','legacy_customer_id'], 'unique'],
            ['email', 'email'],
            [['uploads'], 'file',  'maxFiles' => 10],
            [['email'], 'unique', 'skipOnError' => true, 'targetClass' => User::className(), 'targetAttribute' => ['email' => 'email'], 'message' => 'This email address has already been taken.'],
            [['user_id'], 'exist', 'skipOnError' => true, 'targetClass' => User::className(), 'targetAttribute' => ['user_id' => 'id']],
        ];
    }
}

Here is Controller

 public function actionCreate() {
        $model = new Customer();
        if ($model->load(Yii::$app->request->post())) {
            $transaction = Yii::$app->db->beginTransaction();
            try 
            {
            $user_create = \common\models\User::customeruser($model);
            if ($user_create) {
                $model->user_id = $user_create->id;
                $auth = \Yii::$app->authManager;
                $role = $auth->getRole('customer');
                $auth->assign($role, $model->user_id);
            }
            if ($user_create && $model->save()) {

                $photo = UploadedFile::getInstances($model, 'uploads');
                if ($photo !== null) {
                    $save_images = \common\models\CustomerDocuments::save_document($model->user_id, $photo);
                }
                $transaction->commit();  
                return $this->redirect(['view', 'id' => $model->user_id]);
            }
        }catch (Exception $e) 
        {
          $transaction->rollBack();
        }
    }

        if (Yii::$app->request->isAjax) {
            return $this->renderAjax('create', [
                        'model' => $model,
            ]);
        } else {
            return $this->render('create', [
                        'model' => $model,
            ]);
        }
    }

Now the required attribute working used in the rules. It does not allow the form to submit until the required field filled with some value, but at the same time the unique attribute using with target class not working and allow the form to submit. After click the submit form the form will not submit but it does not show the error of unique validation. Regard I am using the form in bootstrap modal and I want the form will show the unique submit error before submission like the same as required working. I can do it using jQuery on blur function and send custom AJAX request but I want the default solution of Yii 2.

EDIT

This is where the error is throw due to user not being saved

public static function customeruser( $model ) {
    $user = new User();
    $user->username = $model->email;
    $user->email = $model->email;
    $user->setPassword ( $model->legacy_customer_id );
    $user->generateAuthKey ();
    if ( !$user->save () ) {
        var_dump ( $user->getErrors () );
        exit ();
    } return $user->save () ? $user : null;
}

var_dump() shows the following

'username' => array (size = 1) 0 => string 'This username has already been taken.' (length = 37) 'email' => array (size = 1) 0 => string 'This email address has already been taken.' (length = 42).

Muhammad Omer Aslam
  • 22,976
  • 9
  • 42
  • 68
rajwa766
  • 604
  • 13
  • 31
  • my be this will helps you https://stackoverflow.com/questions/35487411/yii2-unique-validation-not-working – Venki WAR May 11 '18 at 07:17
  • @Muhammad Aslam Omer Bro i need your help..I have trying many technique but could not find solution – rajwa766 May 11 '18 at 07:20
  • can you please show your code of controller. – Amitesh Kumar May 11 '18 at 07:26
  • @AmiteshKumar have updated the code – rajwa766 May 11 '18 at 09:50
  • The problem could have to do with your data, so the problem may have nothing to do with the code; we would need to see the data to actually help troubleshoot. Also, which unique validation rule do you think is broken? – dataskills May 11 '18 at 14:29
  • You're checking the uniqueness of the email to the user table, shouldn't it be checked against the customer table? – Maarten van Middelaar May 11 '18 at 14:30
  • can you confirm with a `print_r($model->getErrors())` in the `else` part of `if ($user_create && $model->save()) {` does it show you the unique error against the email attribute if it already exists in the target table – Muhammad Omer Aslam May 11 '18 at 14:40
  • @MuhammadOmerAslam here the error is in user table, – rajwa766 May 14 '18 at 07:07
  • @MuhammadOmerAslam public static function customeruser($model){ $user = new User(); $user->username = $model->email; $user->email = $model->email; $user->setPassword($model->legacy_customer_id); $user->generateAuthKey(); if(!$user->save()){ var_dump($user->getErrors()); exit(); } return $user->save() ? $user : null; } – rajwa766 May 14 '18 at 07:07
  • The current model is customer model,The creation process is like that first the user will create after that the id of user will the primary key of customer id user_id and the email and username are save in user table after that customer will create no email and username filed in customer table so the error is when i vardump the usertable 'username' => array (size=1) 0 => string 'This username has already been taken.' (length=37) 'email' => array (size=1) 0 => string 'This email address has already been taken.' (length=42)..How i can pass the error to customer – rajwa766 May 14 '18 at 07:12
  • do mark the answer as correct if it worked for you – Muhammad Omer Aslam May 16 '18 at 22:32
  • @MuhammadOmerAslam sure bro i need to implement spme part of it...tommarow i will accept it after complete implentation ..thank you – rajwa766 May 28 '18 at 17:05
  • no that's ok, if you havent yet implemented it yet, no problem take your time, i thought you have forgotten about it ;) – Muhammad Omer Aslam May 28 '18 at 18:38
  • switch to next project thats why is pending back to my project now so i will do by tommarow inshallah – rajwa766 May 28 '18 at 22:28
  • @MuhammadOmerAslam have a look to this question please – rajwa766 May 31 '18 at 07:28
  • https://stackoverflow.com/questions/50561347/how-to-update-multiple-images-in-kartik-upload-widget – rajwa766 May 31 '18 at 07:28
  • i am not feeling well from the last 2 days thats why not posting anything – Muhammad Omer Aslam May 31 '18 at 12:27
  • @MuhammadOmerAslam get well soon bro – rajwa766 May 31 '18 at 12:37

2 Answers2

4

As you are using the try catch block along with the transaction you should throw and catch such errors as the exception so that the transaction is rolled back, and the message is displayed to the user too.

You are not consuming or using the beauty of try{}catch(){} block with transactions. You should always throw an Exception in case any of the models are not saved and the catch block will rollback the transaction.

For example, you are saving the user in the function customeruser() by calling

$user_create = \common\models\User::customeruser($model);

and returning the user object or null otherwise and then in the very next line, you are verifying the user was created or not.

if ($user_create) {

You should simply throw an exception from the function customeruser() in case the model was not saved and return the $user object otherwise, you don't have to check $user_create again to verify if user was not saved the exception will be thrown and control will be transferred to the catch block and the lines after $user_create = \common\models\User::customeruser($model); will never be called.

I mostly use the following way when i have multiple models to save and i am using the transaction block.

$transaction = Yii::$app->db->beginTransaction ();
try {
    if ( !$modelUser->save () ) {
        throw new \Exception ( implode ( "<br />" , \yii\helpers\ArrayHelper::getColumn ( $modelUser->errors , 0 , false ) ) );
    }
    if ( !$modelProfile->save () ) {
        throw new \Exception ( implode ( "<br />" , \yii\helpers\ArrayHelper::getColumn ( $modelProfile->errors , 0 , false ) ) );
    }
    $transaction->commit();
} catch ( \Exception $ex ) {
    $transaction->rollBack();
    Yii::$app->session->setFlash ( 'error' , $ex->getMessage () );
}

So you can do the same for your code

public static function customeruser( $model ) {
    $user = new User();
    $user->username = $model->email;
    $user->email = $model->email;
    $user->setPassword ( $model->legacy_customer_id );
    $user->generateAuthKey ();
    if(!$user->save()){
        throw new \Exception ( implode ( "<br />" , \yii\helpers\ArrayHelper::getColumn ( $user->errors , 0 , false ) ) );
    }
    return $user;
}

change your actionCreate to the following

public function actionCreate() {
    $model = new Customer();
    if ( $model->load ( Yii::$app->request->post () ) ) {
        $transaction = Yii::$app->db->beginTransaction ();
        try {
            $user_create = \common\models\User::customeruser ( $model );
            $model->user_id = $user_create->id;
            $auth = \Yii::$app->authManager;
            $role = $auth->getRole ( 'customer' );
            $auth->assign ( $role , $model->user_id );

            if ( !$model->save () ) {
                throw new \Exception ( implode ( "<br />" , \yii\helpers\ArrayHelper::getColumn ( $model->errors , 0 , false ) ) );
            }

            $photo = UploadedFile::getInstances ( $model , 'uploads' );
            if ( $photo !== null ) {
                $save_images = \common\models\CustomerDocuments::save_document ( $model->user_id , $photo );
            }

            $transaction->commit ();
            return $this->redirect ( [ 'view' , 'id' => $model->user_id ] );
        } catch ( \Exception $ex ) {
            Yii::$app->session->setFlash ( 'error' , $ex->getMessage () );
            $transaction->rollBack ();
        }
    }

    if ( Yii::$app->request->isAjax ) {
        return $this->renderAjax ( 'create' , [
                    'model' => $model ,
                ] );
    }

    return $this->render ( 'create' , [
                'model' => $model ,
            ] );
}
Muhammad Omer Aslam
  • 22,976
  • 9
  • 42
  • 68
-1

There are two three thing :

1. You are not accepting email address by user input .

2. It will insert a blank entry if in database your field is taken as NULL

3. In second insertion it will show you the error message if db field is not NUll.

Solution: 1. Make db field Not NUll .

2. Take email as user input .

3. Try to print error

if ($model->validate()) {
    // all inputs are valid
} else {
    // validation failed: $errors is an array containing error messages
    $errors = $model->errors;
}

4. remove 'skipOnError' => true,

Try Above I am sure you will get the solution

Help Full LINK For validation

Amitesh Kumar
  • 3,051
  • 1
  • 26
  • 42