Getting 'cannot be blank' error on save() because of 'file' validation rule

I got this error when an image file is required: "Preview cannot be blank". Although I filled this field.

My rules:

public function rules()
{
    return [
        [['name', 'preview', 'date', 'author_id'], 'required', 'on' => 'update'],
        [['name', 'preview', 'date', 'author_id'], 'required', 'on' => 'create'],
        [['date_create', 'date_update', 'author_id'], 'integer'],
        [['preview'], 'file', 'skipOnEmpty' => 'false', 'extensions' => 'png, jpg, jpeg'],
        [['date'], 'safe'],
        [['name'], 'string', 'max' => 255]
    ];
}

Controller:

public function actionCreate()
{
    $model = new Book();
    $model->scenario = 'create';
    if ($model->load(Yii::$app->request->post()) && $model->validate()) {
        $model->preview = UploadedFile::getInstance($model, 'preview');
        if ($model->save() && $model->preview->saveAs('uploads/' . $model->preview->baseName . '.' . $model->preview->extension))
        {
            return $this->redirect(['view', 'id' => $model->id]);
        }
    } else {
        return $this->render('create', [
            'model' => $model,
        ]);
    }
}

If preview file is not required there is no error and the file is being loaded into the uploads folder.

Upvotes: 4

Views: 1194

Answers (2)

LihO
LihO

Reputation: 42133

Best thing to do here is to avoid using the same field for different purposes.

In your case you are overwriting preview with UploadedFile instance, you could create another field for this and then:

$model->previewFile = UploadedFile::getInstance($model, 'preview');

Then the validation invoked by save() won't hit any new issues about preview field as the file is held in previewFile and original value of preview passed through the $model->validate() check already.

Upvotes: 2

stefandoorn
stefandoorn

Reputation: 1032

I think you can't make this field required, as it only validates $_POST variables inserted. The file upload is entered in the $_FILES superglobal and not in the $_POST superglobal. Requiring this would mean you want it in your $_POST variables.

You run the validation before handling the file upload. So I would recommend handling the file upload before you handle the model validation, so you can set the value to the model and then run validate afterwards:

public function actionCreate()
{
    $model = new Book();
    $model->load(Yii::$app->request->post());
    $model->scenario = 'create';
    $model->preview = UploadedFile::getInstance($model, 'preview');
    if ($model->validate()) {
        if ($model->save() && $model->preview->saveAs('uploads/' . $model->preview->baseName . '.' . $model->preview->extension))
        {
            return $this->redirect(['view', 'id' => $model->id]);
        }
    } else {
        return $this->render('create', [
            'model' => $model,
        ]);
    }
}

I didn't test it locally, but making the 'preview' field required without any info in it is not going to work for sure.

P.S. I think it should be 'skipOnEmpty' => false, not with '' around the false.

Upvotes: 2

Related Questions