Yii2 Update Profile Photo

2019-06-08 16:42发布

问题:

I have here an Edit Profile page where user can change his/her profile photo/avatar.

The avatar displayed is the photo of the current user (of course) and when I click the Update Avatar button, the user can select an image, and then the selected image will preview replacing the current user avatar.

Here's the code in my view:

<div class="fileUpload btn btn-warning">
    <span>Update Avatar</span>
    <input type="file" accept="image/*" onchange="loadFile(event)" class="upload"/>
</div>
<script>
    var loadFile = function(event) {
    var output = document.getElementById('output');
    output.src = URL.createObjectURL(event.target.files[0]);
  };
</script>

The problem is that, whenever I click the Update button at the end of the form, the avatar does not change. I know that this is because it's all in the front end. How do I get the newly selected image and save it to the database? Or are there other implementation aside from this one?

BTW, I chose this method because I want to preview the image before and after selection. I tried Kartik's FileInput widget but I don't know where to put the onchange="loadFile(event)" event in the plugin.

If you need more code, like my action controller or the model, just let me know.

I really need help in this one.

回答1:

I don't know if you have found the solution or not.

You can save the picture in directory and filename in DB table as soon as the user selects the picture.

Use this widget 2amigon File Upload Widget to start uploading picture as soon as user selects the picture. This widget renders jQuery File Upload.

Usage:

view

use dosamigos\fileupload\FileUploadUI;

<?= FileUploadUI::widget([
        'model' => $model,
        'attribute' => 'profile_pic',
        'url' => ['user-profile/upload-profile-picture', 'id' => $model->id],
         'gallery' => false,
         'fieldOptions' => [
             'accept' => 'image/*',
         ],
         'clientOptions' => [  
             'maxFileSize' => 2000000,
             'autoUpload' => true,
          ],
          'clientEvents' => [
              'fileuploaddone' => 'function(e, data) {
                                      jQuery(".fb-image-profile").attr("src",data.result);
                                  }',
              'fileuploadfail' => 'function(e, data) {
                                      alert("Image Upload Failed, please try again.");
                                  }',
          ],
]);
?>

Controller :This will call UserProfileController/actionUploadProfilePicture method.

public function actionUploadProfilePicture($id)
{
    $model = $this->findModel($id);
    $oldFile = $model->getProfilePictureFile();
    $oldProfilePic = $model->profile_pic;

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

        // process uploaded image file instance
        $image = $model->uploadProfilePicture();

        if($image === false && !empty($oldProfilePic)) {
            $model->profile_pic = $oldProfilePic;
        }

        if ($model->save()) {
            // upload only if valid uploaded file instance found
            if ($image !== false) { // delete old and overwrite
                if(!empty($oldFile) && file_exists($oldFile)) {
                    unlink($oldFile);
                }
                $path = $model->getProfilePictureFile();
                $image->saveAs($path);
            }
            \Yii::$app->response->format = \yii\web\Response::FORMAT_JSON;
            return $model->getProfilePictureUrl();
        }
    }
}

Model

public function getProfilePictureFile()
{
    return isset($this->profile_pic) ? Yii::$app->params['uploadPath'] . 'user/profile/' . $this->profile_pic : null;
}

public function getProfilePictureUrl()
{
    // return a default image placeholder if your source profile_pic is not found
    $profile_pic = isset($this->profile_pic) ? $this->profile_pic : 'default_user.jpg';
    return Yii::$app->params['uploadUrl'] . 'user/profile/' . $profile_pic;
}

/**
* Process upload of profile picture
*
* @return mixed the uploaded profile picture instance
*/
public function uploadProfilePicture() {
    // get the uploaded file instance. for multiple file uploads
    // the following data will return an array (you may need to use
    // getInstances method)
    $image = UploadedFile::getInstance($this, 'profile_pic');

    // if no image was uploaded abort the upload
    if (empty($image)) {
        return false;
    }

    // store the source file name
    //$this->filename = $image->name;
    $ext = end((explode(".", $image->name)));

    // generate a unique file name
    $this->profile_pic = Yii::$app->security->generateRandomString().".{$ext}";

    // the uploaded profile picture instance
    return $image;
}

Apart from this, you can use Advanced upload using Yii2 FileInput widget tutorial for more details in picture uploading.

I hope this helps and clear your issues regarding file upload.