【问题标题】:Yii2: show user friendly validation errors when using try catch with transactionsYii2:在对事务使用 try catch 时显示用户友好的验证错误
【发布时间】:2018-05-11 07:15:49
【问题描述】:

我正在使用引导程序ActiveForm。这是我的表格:

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(); ?>

这是我的模型:

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']],
        ];
    }
}

这里是控制器

 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,
            ]);
        }
    }

现在在规则中使用所需的属性。它不允许表单提交,直到必填字段填充了一些值,但同时使用目标类的唯一属性不起作用并允许表单提交。点击提交表单后,表单不会提交,但不会显示唯一验证错误。关于我在引导模式中使用表单,我希望表单在提交之前显示唯一的提交错误,就像所需的工作一样。我可以在模糊功能上使用 jQuery 并发送自定义 AJAX 请求,但我想要 Yii 2 的默认解决方案。

EDIT

这是由于未保存用户而引发错误的地方

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() 显示如下

'用户名' => 数组(大小 = 1) 0 => string '此用户名已被占用。' (长度 = 37) 'email' => array (size = 1) 0 => string '此电子邮件地址已被占用。' (长度 = 42)。

【问题讨论】:

  • @Muhammad Aslam Omer Bro 我需要你的帮助..我尝试了很多技术但找不到解决方案
  • 能否请您出示您的控制器代码。
  • @AmiteshKumar 已更新代码
  • 问题可能与您的数据有关,因此问题可能与代码无关;我们需要查看数据才能真正帮助解决问题。另外,您认为哪个独特的验证规则被破坏了?

标签: yii yii2 yii2-advanced-app yii-extensions


【解决方案1】:

当您将 try catch 块与事务一起使用时,您应该抛出并捕获异常等错误,以便回滚事务,并将消息也显示给用户。

您没有在交易中消费或使用try{}catch(){} 块的美丽。您应该始终抛出Exception,以防任何模型未保存并且catch 块将回滚事务。

例如,您通过调用将用户保存在函数customeruser()

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

并返回 user 对象或 null 否则,然后在下一行,您正在验证用户是否已创建。

if ($user_create) {

您应该简单地从函数customeruser() 中抛出一个异常以防模型未保存并返回$user 对象,否则您不必再次检查$user_create 来验证用户是否未保存将抛出异常并将控制转移到catch 块,并且永远不会调用$user_create = \common\models\User::customeruser($model); 之后的行。

当我有多个模型要保存并且我正在使用事务块时,我主要使用以下方式。

$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 () );
}

所以你可以对你的代码做同样的事情

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;
}

将您的 actionCreate 更改为以下内容

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 ,
            ] );
}

【讨论】:

    【解决方案2】:

    有两三件事:

    1.您不接受用户输入的电子邮件地址。

    2.如果在数据库中您的字段被视为NULL

    ,它将插入一个空白条目

    3.在第二次插入时,如果 db 字段不是 NUll,它将显示错误消息。

    解决方案: 1. 使数据库字段不为空。

    2. 将电子邮件作为用户输入。

    3.尝试打印错误

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

    4.删除'skipOnError' =&gt; true,

    试试上面我相信你会得到解决方案

    Help Full LINK For validation

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-12-23
      • 1970-01-01
      • 2021-10-08
      • 1970-01-01
      相关资源
      最近更新 更多