yii2 - Kartik文件输入 - 更新

时间:2015-03-27 02:37:35

标签: php file-upload yii2

情况就是这样:我是Yii2的新手,想在ActiveForm中使用一些文件上传器小部件..到目前为止,我发现这个非常优秀:\kartik\widget\FileInput

使用此小部件,我可以管理文件上传,然后在进入编辑模式时,使用oportunite显示上一个上传的图像以替换它。

问题在于,如果我按下表格的“更新”按钮而不修改图像,则说明图像“不能为空”,因为我在模型中设置了“必需”规则。

4 个答案:

答案 0 :(得分:7)

在一个糟糕的下午和一个更有成效的夜晚之后,我遇到了一个对我有用的解决方案..

主要问题是文件输入在更新时不发送其值(存储在数据库中的文件的名称)。它仅在浏览并通过文件输入选择时发送图像信息..

所以,我的解决方法是创建另一个"虚拟"用于管理文件上传的字段,名为" upload_image"。为实现这一点,我简单地将一个带有此名称的公共属性添加到我的模型类中:public $upload_image;

我还将以下验证添加到Model类的规则方法:

 public function rules()
{
    return [
        [['upload_image'], 'file', 'extensions' => 'png, jpg', 'skipOnEmpty' => true],
        [['image'], 'required'],
    ];
}

此处,' upload_image'是我的虚拟专栏。我添加了' file'使用' skipOnEmpty'验证= true,' image'是我的数据库中的字段,在我的情况下必须是必需的。

然后,在我看来,我配置了'upload_image'小部件如下:

    echo FileInput::widget([
        'model' => $model,
        'attribute' => 'upload_image',
        'pluginOptions' => [
            'initialPreview'=>[
                Html::img("/uploads/" . $model->image)
            ],
            'overwriteInitial'=>true
        ]
    ]);

在" initialPreview'选项I我的图像名称,存储在' $ model-> image'从数据库返回的属性。

最后,我的控制器如下:

public function actionUpdate($id)
{
    $model = $this->findModel($id);
    $model->load(Yii::$app->request->post());

    if(Yii::$app->request->isPost){
        //Try to get file info
        $upload_image = \yii\web\UploadedFile::getInstance($model, 'upload_image');

        //If received, then I get the file name and asign it to $model->image in order to store it in db
        if(!empty($upload_image)){
            $image_name = $upload_image->name;
            $model->image = $image_name;
        }

        //I proceed to validate model. Notice that will validate that 'image' is required and also 'image_upload' as file, but this last is optional
        if ($model->validate() && $model->save()) {

            //If all went OK, then I proceed to save the image in filesystem
            if(!empty($upload_image)){
                $upload_image->saveAs('uploads/' . $image_name);
            }

            return $this->redirect(['view', 'id' => $model->id]);
        }
    }
    return $this->render('update', [
        'model' => $model,
    ]);
}

答案 1 :(得分:4)

我通过创建方案遇到了另一种解决方案。在你的情况下,我会修改这样的规则:

public funtion rules() {
    [['image'], 'file'],
    [['image'], 'required', 'on'=> 'create']
}

因此仅在create action中需要fileupload字段。在更新操作中,我有以下代码:

public function actionUpdate($id)
    {
      $model = $this->findModel($id);

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

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

          if (!empty($newCover)) {
            $newCoverName = Yii::$app->security->generateRandomString();
            unlink($model->cover);
            $model->cover = 'uploads/covers/' . $newCoverName . '.' . $newCover->extension;
            $newCover->saveAs('uploads/covers/' . $newCoverName . '.' . $newCover->extension);
          }

          if ($model->validate() && $model->save()) {
            return $this->redirect(['view', 'id' => $model->post_id]);
          } else {
            // error saving model
          }

        } else {
          return $this->render('update', [
          'model' => $model,
          ]);
        }

    }

在更新方案中,图像文件不是必需的,但代码会检查是否上传了任何内容并且不会更改以前的值。

我的表单文件:

<?= $form->field($model, 'image')->widget(FileInput::classname(), [
    'options' => ['accept'=>'image/*'],
    'pluginOptions'=>[
        'allowedFileExtensions'=>['jpg', 'gif', 'png', 'bmp'],
        'showUpload' => true,
        'initialPreview' => [
            $model->cover ? Html::img($model->cover) : null, // checks the models to display the preview
        ],
        'overwriteInitial' => false,
    ],
]); ?>

我认为比虚拟领域更容易一些。希望它有所帮助!

答案 2 :(得分:3)

尝试使用该字段的内容预加载文件输入字段。这样,您在提交表单后就不会丢失数据。

我查看了kartik file-input widget(很好的发现,顺便说一句),我遇到了一种方法来做到这一点

// Display an initial preview of files with caption
// (useful in UPDATE scenarios). Set overwrite `initialPreview`
// to `false` to append uploaded images to the initial preview.
echo FileInput::widget([
    'name' => 'attachment_49[]',
    'options' => [
        'multiple' => true
    ],
    'pluginOptions' => [
        'initialPreview' => [
            Html::img("/images/moon.jpg", ['class'=>'file-preview-image', 'alt'=>'The Moon', 'title'=>'The Moon']),
            Html::img("/images/earth.jpg", ['class'=>'file-preview-image', 'alt'=>'The Earth', 'title'=>'The Earth']),
        ],
        'initialCaption'=>"The Moon and the Earth",
        'overwriteInitial'=>false
    ]
]);

您可能还想放宽模型中针对该字段的required规则,因此它不会在验证时抱怨。您可以选择通过更微妙的方式提示用户。

答案 3 :(得分:-4)

来自Krajee:

http://webtips.krajee.com/advanced-upload-using-yii2-fileinput-widget

创建,删除,更新:非常简单,不用再看了。

(1)我已经设定了所需的&#39;也在我的模型中统治。

(2)在Wampserver上工作:

Yii::$app->params['uploadPath'] = Yii::$app->basePath . '/web/uploads/';

Yii::$app->params['uploadUrl'] = Yii::$app->urlManager->baseUrl . '/uploads/';