ajax 验证时 Yii2 上传字段始终为空

Yii2 upload field always empty when ajax validation

我上传文件有问题。我使用 kartik-v/yii2-widget-fileinput 扩展名。这是我的代码:

表单模型规则

/**
 * @inheritdoc
 */
public function rules()
{
    return [
        [['image'], 'required', 'on' => static::SCENARIO_CREATE],
        [['image'], 'file', 'extensions' => 'png, jpg, jpeg', 'maxSize' => 1024 * 1024],
    ];
}

表单视图

<?php $form = ActiveForm::begin([     
    'enableAjaxValidation' => true,
    'options' => ['enctype' => 'multipart/form-data']
]); ?>

 <?= $form->field($model, 'image')->widget(FileInput::classname(), [
            'options' => ['accept' => 'image/*'],
            'pluginOptions' => [
                'showPreview' => false,
                'showCaption' => true,
                'showRemove' => true,
                'showUpload' => false,
                'showCancel' => false
            ],            
        ]); ?>

控制器动作

 public function actionCreate()
{
    $model = new ItemForm();
    $model->scenario = ItemForm::SCENARIO_CREATE;

    if (Yii::$app->request->isAjax && $model->load(Yii::$app->request->post())) {
        Yii::$app->response->format = Response::FORMAT_JSON;
        return ActiveForm::validate($model);
    }

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

        $image = UploadedFile::getInstance($model, 'image');

        $randomString = Yii::$app->getSecurity()->generateRandomString(10);
        $name = Inflector::slug($model->title) . '_' . $randomString . '.' . $image->extension;

        $url = Image::URL . $name;

        $model->image = $name;          

        if ($model->save()) {
            $image->saveAs($url);
            return $this->redirect(['view', 'id' => $model->id]);
        }       
    } else {         
        return $this->render('create', [
            'model' => $model,             
        ]);
    }
}

提交表单时总是出现错误 "image field is required"。我已经阅读了很多教程,但在使用 ajax 验证时仍然遇到同样的问题。谁能看看它并告诉我我做错了什么?

编辑

最重要的是,如果您的表单中有文件类型字段,则不应使用 enableAjaxValidation 选项。看到这个 ISSUE 使用 enableClientValidation 代替

除了查看您的完整模型之外,您似乎正在尝试使用数据库 table 字段 image 作为同一字段来上传图像,而您不应该这样做,您应该这样做在您的模型中声明一个自定义字段并使用它来上传文件并将新文件名分配给数据库字段 image 目前您必须在您的模型中添加一些内容并更改代码

1.public $tags 之后的模型顶部声明一个名为 $file 的自定义字段,如下所示,public $myFile;

2. 更改验证规则

[['image'], 'file', 'extensions' => 'png, jpg, jpeg', 'maxSize' => 1024 * 1024],

以下

[['myFile'], 'file', 'extensions' => 'png, jpg, jpeg', 'maxSize' => 1024 * 1024],

[['image'], 'required', 'on' => static::SCENARIO_CREATE],

到这个

[['myFile','image'], 'required', 'on' => static::SCENARIO_CREATE],

3. 更改 html 表单中的字段名称,从 imagemyFile$form->field($model, 'image')$form->field($model, 'myFile').

4. 对于 actionuploadItemImage() 函数内部的更改,请参见下文,我已经更新了它们。


您正在将 $name 变量分配给 $model->image 字段

 $model->image = $name; 

$name中它是一个字符串,而在模型中它应该是一个文件

 $name = Inflector::slug($model->title) . '_' . $randomString . '.' . $image->extension;

您应该做的是将上传文件的实例分配给模型字段 image,然后调用 $model->save() 并使用自定义文件名 saveAs(),更改您的action代码如下

public function actionCreate()
{
    $model = new ItemForm();
    $model->scenario = ItemForm::SCENARIO_CREATE;

    if (Yii::$app->request->isAjax && $model->load(Yii::$app->request->post())) {
        Yii::$app->response->format = Response::FORMAT_JSON;
        return ActiveForm::validate($model);
    }

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

        $model->myFile = UploadedFile::getInstance($model, 'myFile');
        $randomString = Yii::$app->getSecurity()->generateRandomString(10);
        $model->image = Inflector::slug($model->title) . '_' . $randomString . '.' . $model->myFile->extension;

        $model->uploadItemImage();
        if ($model->save()) {
            return $this->redirect(['view', 'id' => $model->id]);
        }       
    } else {         
        return $this->render('create', [
            'model' => $model,             
        ]);
    }
}

然后在模型中创建以下方法

public function uploadItemImage(){
    $url = Image::URL . $this->image;
    if(!$this->myFile->saveAs($url)){
       $this->addError('myFile','Unable to save the uploaded file');
    }
}