プログラミング学習284日目〜Laravel 自動車整備履歴アプリ作成 36日目〜

画像アップロードの覚え書き。

Route

 //web.php
 
 Route::get('/carinfo/create',[CarinfoController::class, 'create']);
 Route::post('/carinfo/store',[CarinfoController::class, 'store']);

Laravel8ではRouteの書き方が少し変わっています。

フォーム

//create.blade.php

<form method="POST" enctype="multipart/form-data" 
action="/carinfo/store" onSubmit="return checkSubmit()">
   @csrf
   <h3>メーカー(例)ホンダ</h3>
   <p><input type="text" name="maker" value="{{ old('maker') }}"></p>
   <h3> 車種(例)フィット</h3>
   <p><input type="text" name="model"value="{{ old('model') }}"></p>
   <h3>走行距離(例)12345</h3>
   <p><input type="number" name="mileage"value="{{ old('mileage') }}"></p>
   <h3>陸運事務局 (例)多摩</h3>
   <p><input type="text" name="rikuun" value="{{ old('rikuun') }}"></p>
   <h3>識別No(例)500</h3>
   <p><input type="number" name="class_no" value="{{ old('class_no') }}
   "></p>
   <h3>かな(例)お</h3>
   <p><input type="text" name="kana" value="{{ old('kana') }}"></p>
   <h3>車番(例)4649</h3>
   <p><input type="number" name="serial_no" value="{{ old('serial_no') }}"></p>
   <h3>車輌画像</h3>
   <p><input type="file" name="image" value=""></p>

   <button type="submit" href=""  class="btn btn-secondary">登録する</button>
</form>


<script>
   function checkSubmit(){
       if(window.confirm('登録してよろしいですか?')){
           return true;
       } else {
           return false;
       }
   }
</script>

フォームタグの中にはenctype="multipart/form-data"を入れないとうまく作動しません。複数の種類のデータを一度に扱うためには必要です。
登録前に確認を入れるためJavaScriptを少し書いていますが、確認がいらなければ必要ありません。

Controller

ここが一番厄介でした。
今回の決め事としてはデータベースには ”登録日時_ファイル名” を登録。
画像データの保存先はstorage¥car_image¥ログインユーザーid。ファイル名は同じく”登録日時_ファイル名”。

保存のファイル名に登録日時を使ったり、保存先のフォルダにログインしているユーザーのidを使っているのはデータが上書きされないようにするため。仮に登録日時を使わないでファイル名だけで登録すると、同じファイル名で登録した際、普通に上書きされてしまします。今回画像は一つしか扱わないので、登録日時を頭につけておけば、まず同じファイル名になることはないと思い、登録日時を使いました。

登録日時(現在の日時)の取得。
$date = now();
これは恐らくCarbonという日時を扱うPHPのフレームワークを使っています。恐らくというのはCarbonをインストールした覚えがないけど使えているから。覚えはないけどインストールしたのでしょう。

データベース、サーバーに登録する画像ファイル名。
if($request->file('image'))
{
$file_name = $date . "_" . $request->file('image')->getClientOriginalName();
}
getClientOriginalName()はファイルそのもののファイル名。これを使わないでデータベース、サーバーにアップロードすると暗号のような名前で登録されます。以前やった時はこれを使わなくても普通にファイル名で登録されていた気がするのですが、記憶違いでしょうか。

画像データの保存。
if($request->file('image'))
{
$users = \Auth::user();
$id = $users->id;
$request->file('image')->storeAs("public/car_image/$id",$file_name);
}


画像データがある時のみ保存の処理を行います。ない時も行うと$request->file('image')がないということで変なエラーが出ます。
$users = \Auth::user();
$id = $users->id;
これでログインユーザーのidを取得。
storeAsメソッドを使って第1引数で保存先、第2引数でファイル名を指定して画像データを保存。

//CarinfoController.php

class CarinfoController extends Controller
{
   public function create()
   {
       return view('/carinfo/create');
   }

   public function store(CarinfoRequest $request)
   {
       $carinfo = $request->input();
       
       //現在日時の取得
       $date = now();
       
       if($request->file('image'))
       {
           $file_name = $date . "_" . $request->file('image')->getClientOriginalName();
       }
       $carinfos = new Carinfo;
       unset($carinfo['_token']);
     
       //車輌情報を登録
       \DB::beginTransaction();
       try{
       $carinfos->fill($carinfo);
       //画像が存在すればファイル名をDBに登録
       if($request->file('image'))
       {
           $carinfos->image = basename($file_name);
       }
       $carinfos->save();
       //画像をサーバーに登録する時のみ以下の処理
       if($request->file('image'))
       {
           $users = \Auth::user();
           $id = $users->id;
           $request->file('image')->storeAs("public/car_image/$id",$file_name);
       }
       \DB::commit();
   } catch(\Throwable $e) {
       \DB::rollback();
       abort(500);
   }

       \Session::flash('err_msg','車輌を登録しました');
       return redirect('/carinfo/index');
   }
}

シンボリックリンクを貼る
ターミナルで以下を実行。

php artisan storage:link

シンボリックリンクというものが最初よくわかりませんでした。多少語弊はあるかもしれませんがショートカットのようなものと考えるとわかりやすいかもしれません。Laravelではpublicフォルダの中でないと画像データ(cssやスクリプトもそうだった気がします)にはアクセスできないらしく、これを実行することによって、publicフォルダ内にstorageフォルダへのショートカットらしきものが作成され、viewから画像データが扱えるようになります。











この記事が気に入ったらサポートをしてみませんか?