ajaxで画像アップロードサーバー側編

Laravel

この記事でブラウザから画像をajaxでサーバー側へ届けることができたので、
今後はサーバー側の処理を実装します。

全部のコードを載せると長くなるので大事だと思うところだけにしています。
そのため以下のコードだけでは動きません💦

流れ

とても簡単な図ですが、青色枠がサーバー側の処理になります。

  • 受け取った画像をstorageに保存
  • 画像のパスを一時保存データ用テーブルへ保存
  • そのレコードidをブラウザへ返却
  • ブラウザで登録ボタンをクリック
  • 本登録処理

②③画像をstorageへ、パスを一時テーブルへ

図の②、③の部分を実装します。

    public function ajaxStoreImage(Request $request)
    {
        $img = $request->file('image');

        // storage/app/img に画像本体を保存
        $path = $img->store('img');
        
        // tpmImgテーブルに画像パスを入れ,IDを取得
        $tmpImg = $this->tmpImg->create([
            'path' => $path,
        ]);

        return response()->json(
            [
                'id' => $tmpImg->id,
            ]
        );
    }

storageとTmpImgテーブルへデータを保存し、最後にjsonをreturnしています。

要件次第なので画像はpublic配下に保存してもいいのですが、
今回はまだ本登録していない画像は storage/app/img へ保存することにしました。
(publicでないのでブラウザからアクセスできない)

$path = $img->store('img');

laravelのstoreメソッドを使うことで、画像にオリジナルの名前をつけて保存し、最後にパスを返却してくれます!

参考:readoubleファイルのアップロードの項

返却されたパスは 

/img/ljrk3fEH2VdNmUabOFlkh7FtyzHSxOjwpjHncfyH.png

こんな感じになっているので、それをTmpImgテーブルに保存。id(ここでは1)を返却します。

ここまでの段階で、画像自体はStorage/img配下に、パスはDBに保存されました。

④IDを元に画像を表示

phpからjsへidが返ってきたので、これをattrなどで imgタグに組み込みます(jsは省略)。

<img src="'/get-tmp-img/1"> // idが組み込まれた

/get-tmp-img の部分は任意なので何でも良いです。

そして、このurlがsrcに組み込まれると、今度は定義していたルーティングが動きます。

   Route::get('/get-tmp-img/{tmpImg}',function(TmpImg $tmpImg) {
         return response()->file(Storage::path($tmpImg->path));
    });

web.phpに、/get-tmp-img/{tmpImg} でアクセスがあった場合の処理をこんな風に定義していました。

function(TmpImg $tmpImg)

ここでは、imgタグのsrcに書かれていたidを$tmpImgとしてRouteの第二引数で使用。TmpImgのインスタンスを受け取っています。

return response()->file(Storage::path($tmpImg->path));

そして、最後はファイルレスポンス機能でパスを元にファイルを返却し、ブラウザで画像を表示しています。

たった3行ですが、なんだかすごいですね。。

⑤本登録処理

ブラウザでぽちっと登録ボタンを押せば、あとは普通の登録処理となります。

必要データを本登録用テーブルに保存

本登録データは実際には他にもあるのですが、画像の部分だけにして後はできるだけはしょっています。

  // コントローラー内
 public function store(Request $request)
    {
       //略

        DB::transaction(function () {

            $imgPaths = $this->tmpImg->find([   //画像を三つまでアップロードできる仕様
                Session::get('form-input.hidden-image.0'),
                Session::get('form-input.hidden-image.1'),
                Session::get('form-input.hidden-image.2'),
            ])->pluck('path');

            $sessions = Session::get('form-input');  // その他の必要データ

            $review = $this->review->createReview($imgPaths, $sessions); //保存処理はModelで
   });

    // 画像をpublicへ移動
    // 不要なデータは削除
       }
            
   //Model内
   public function createReview(\Illuminate\Support\Collection $imgPaths, $sessions)
    {
        return self::create([
                //略
                'image_path_01' => $imgPaths[0] ?? null,  //nullを許容しているのでデータなければnull
                'image_path_02' => $imgPaths[1] ?? null,
                'image_path_03' => $imgPaths[2] ?? null,
            ]);
    }

説明なくsessionとか出てきてすみません、、

確認画面を経る仕様なので、入力データはセッションで管理しています。

単純に画像パスをセッションから取得して、本登録テーブルに保存しています。

画像データをpublic配下に

本登録した画像はブラウザからアクセスできるよう、storage/public/配下に移動します。

    public function moveImageToPublic(int $id = null)
    {
        if ($id === null) {
            return null;
        }

        $path = $this->tmpImg->find($id)->path;

        Storage::move($path, 'public/' . $path);

        return  $path;
    }

現在のパスにpublic/をプラスして、同じstorageディレクトリ内で引越しします。
そして新しいパスを返却。

不要なDB、storageデータを削除

こちらはTmpImgModelに記述しています。

    public function deleteImage(int $id)
    {
        $tmpImg = self::find($id);

        if (Storage::exists($tmpImg->path)) {
            Storage::delete($tmpImg->path);
        }

        $tmpImg->delete();
    }

最初に保存したstorage(publicでない)に画像が残っていれば削除、
続いて一時保存テーブルのレコードを削除。

タイトルとURLをコピーしました