4

我在 Yii2 中有两个模型(masterTransaction 和 splitTransaction),其中每个 masterTransactions 可以有多个 splitTransactions。每个 splitTransaction 都有一个属性“金额”。我的问题是我需要验证所有“金额”属性的总和是否为 0。

我的第一个解决方案是创建另一个名为 Transaction 的模型,其中我有一个属性,我保存了 masterTransaction 模型的一个实例,另一个属性包含一个 splitTransaction 实例数组。我使用自定义内联验证器进行了验证,效果很好。

交易模式

class Transaction extends Model
{
    public $masterTransaction;
    public $splitTransactions;

    public function init()
    {
        $this->masterTransaction = new MasterTransaction();
        $this->splitTransactions[] = new SplitTransaction();
    }

    public function rules()
    {
        return [
            ['splitTransactions', 'validateSplitTransactions'],
        ];
    }

    public function validateSplitTransactions($attribute, $params)
    {
        $sum = 0;
        foreach ($this->$attribute as $transaction) {
            $sum = bcadd($sum, $transaction->amount, 3);
        }
        if ($sum != 0) {
            $this->addError($attribute, 'The sum of the entries has to be 0');
        }
    }

    public function save()
    {
        $this->masterTransaction->save();
        foreach ($this->splitTransactions as $splitTransaction) {
            $splitTransaction->master_transaction_id = $this->masterTransaction->id;
            $splitTransaction->save();
        }
    }
}

创建模型的控制器函数

public function actionCreate()
{
    $transaction = new Transaction();
    $count = count(Yii::$app->request->post('SplitTransaction', []));
    for ($i = 1; $i < $count; $i++) {
        $transaction->splitTransactions[] = new SplitTransaction();
    }

    if ($transaction->masterTransaction->load(Yii::$app->request->post()) && Model::loadMultiple($transaction->splitTransactions, Yii::$app->request->post())) {
        $transaction->masterTransaction->user_id = Yii::$app->user->id;
        foreach ($transaction->splitTransactions as $splitTransaction) {
            $splitTransaction->user_id = Yii::$app->user->id;
        }
        if ($transaction->validate()) {
            $transaction->save();
        }
    }

    return $this->render('create', [
        'transaction' => $transaction,
    ]);
}

但是当我尝试构建一个表单来输入数据时,我遇到了 Ajax 验证的问题。验证会起作用,但 Yii 不知道将错误消息放在哪里,所以它只是将其删除。

我怀疑这不是 Yii2 对我的数据建模的首选方式,但我真的没有其他想法。也许有人对我有一些想法。

4

1 回答 1

1

选项 1。 这取决于您的视图文件代码。您的表单是否包含“splitTransactions”变量?如果没有,你可以这样写

<?= $form->field($model, 'splitTransactions')->hiddenInput(['maxlength' => true])->label(false); ?>

该变量将被隐藏,但仍会显示错误。在某些情况下,由于“splitTransactions”变量的值为空,验证不会被触发。“splitTransactions”应该包含一些触发验证的值。在像这样粘贴表单之前,您可以为 if 赋予一些价值

$model->splitTransactions=1;

选项2。 您可以像这样将错误添加到其他变量(表单包含)

public function validateSplitTransactions($attribute, $params)
{
    $sum = 0;
    foreach ($this->$attribute as $transaction) {
        $sum = bcadd($sum, $transaction->amount, 3);
    }
    if ($sum != 0) {
        $this->addError('transaction_number', 'The sum of the entries has to be 0');
    }
}

看,表单应该包含“transaction_number”变量。错误将添加到“transaction_number”输入。


选项 3。根据我的经验。最好将 ajax 验证与表单操作 url ag 分开创建另一个用于 ajax 验证的控制器操作并使用它。

例子

创建模型FeedbackForm

class FeedbackForm extends Model
{
    public $name;
    public $email;
    public $text;


    /**
     * @inheritdoc
     */
    public function rules()
    {
        return [
            [['name', 'email', 'text'], 'required'],
            [['name', 'email'], 'string', 'max' => 128],
            [['email'], 'email'],
            [['text'], 'string', 'max' => 512],
        ];
    }

    public function attributeLabels()
    {
        return [
            'name' => \Yii::t('front', 'Name'),
            'email' => \Yii::t('front', 'Email'),
            'text' => \Yii::t('front', 'Message text'),
        ];
    }
}

对 SiteSontroller 采取行动

public function actionFeedback()
{
    $model=  new \frontend\models\FeedbackForm;
    $model->load(Yii::$app->request->post());
    if($model->validate()) {
        $newFeed=new  \frontend\models\Feedback;
        $newFeed->create_time=new \yii\db\Expression('NOW()');
        $newFeed->name=$model->name;
        $newFeed->email=$model->email;
        $newFeed->is_new=1;
        $newFeed->text=$model->text;
        if($newFeed->save()) {
            \Yii::$app->session->setFlash('success', \Yii::t('front', 'Your message has accepted'));
        } else {
            \Yii::$app->session->setFlash('error', \Yii::t('front', 'Error on save'));
        }
    } else {
        \Yii::$app->session->setFlash('error', \Yii::t('front', 'Data error'));
    }
    return $this->redirect(['/site/index']);
}


public function actionFeedbackvalidate()
{   
     Yii::$app->response->format = \yii\web\Response::FORMAT_JSON;

    $model=  new \frontend\models\FeedbackForm;

    $model->load(Yii::$app->request->post());


    return ActiveForm::validate($model);
}

并在视图内创建表单

                <?php $model=new \frontend\models\FeedbackForm; ?>
                <?php $form = ActiveForm::begin([
                        'enableClientValidation' => true,
                        'enableAjaxValidation' => true,
                        'validationUrl'=>['/site/feedbackvalidate'],
                        'validateOnSubmit' => true,
                        'id' => 'form-feedback',
                        'action'=>['/site/feedback'],
                        'options'=>['class'=>'some class', 'autocomplete'=>'off']
                    ]); ?>
                        <?= $form->field($model, 'name')->textInput(['maxlength' => true, 'placeholder'=>$model->getAttributeLabel('name'), 'autocomplete'=>'off'])->label(false); ?>
                        <?= $form->field($model, 'email')->textInput(['maxlength' => true, 'placeholder'=>$model->getAttributeLabel('email'), 'autocomplete'=>'off'])->label(false); ?>
                        <?= $form->field($model, 'text')->textarea(['maxlength' => true, 'placeholder'=>$model->getAttributeLabel('text'), 'autocomplete'=>'off'])->label(false); ?>


                    <div class="form-group">
                        <input type="submit" class="btn btn-default" value="<?php echo Yii::t('front', 'Send') ?>">
                    </div>
                <?php ActiveForm::end(); ?>

这就对了

于 2018-01-30T05:05:53.273 回答