【问题标题】:yii2 - Kartik file input - updateyii2 - Kartik 文件输入 - 更新
【发布时间】:2015-05-31 06:58:51
【问题描述】:

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

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

问题是,如果我在不修改图像的情况下按下表单的“更新”按钮,yii 会说图像“不能为空”,因为我在模型中设置了“必需”规则。

【问题讨论】:

    标签: php file-upload yii2


    【解决方案1】:

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

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

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

    我还在 Model 类的规则方法中添加了以下验证:

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

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

    然后,在我看来,我配置了“upload_image”小部件,如下所示:

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

    在“initialPreview”选项中,我指定了我的图像名称,存储在从数据库返回的“$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,
        ]);
    }
    

    【讨论】:

      【解决方案2】:

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

      我浏览了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】:

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

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

      因此文件上传字段仅在创建操作中是必需的。在更新操作中,我有以下代码:

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

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

      【讨论】:

      • 你的代码不行,更新的时候还是空的???
      【解决方案4】:

      来自克拉吉:

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

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

      (1) 我也在我的模型中设置了“必需”规则。

      (2) 在 Wampserver 上工作:

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

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2017-01-13
        • 1970-01-01
        • 1970-01-01
        • 2021-12-19
        • 2017-06-07
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多