【Laravel/Vue】画像アップロード&DBへ保存

画像のアップロードにかなり手こずってしまいました。
Laravel×Vueの記事が少なかったため、記事にしました。

### 開発環境
Laravel9
Vue3
Inertia

※コントローラのルートは既に通してあることとします。
※今回の画像のアップロード先はpublic/imagesにします。

今回はプロフィールのEdit(編集画面)を想定しています。
これはLaravelインストール時に予め用意されているUserテーブルと紐づいています。
(カラムは最低限に絞りました。)



# テーブル

Profiles

|カラム名|型|
| --- | --- |
|nick_name|string|
|filename|string|

# Vue

先にフォームの準備をします。

```vuejs:Edit.vue

<template>
    <!-- 画像の表示(プレビューは別に作成してください) -->
    <div>
        <img :src="'/images/' + props.profile.filename">
        <input type="hidden" v-model="form.filename">
    </div>

    <form @submit.prevent="updateTest(form.id)"  enctype="multipart/form-data">
        <div>
            <label for="nick_name">ニックネーム</label>
            <input type="text" id="nick_name" name="nick_name" v-model="form.nick_name">
        </div>
        <div>
            <label for="filename">画像</label>
            <input id="file" name="file"  type="file" @input="form.file = $event.target.files[0]" >
        </div>
        <button type="submit">更新する</button>
    </form>
</template>
```

画像を扱う際は、enctype="multipart/form-data"が必須です。
inputタグ内で本来ならv-modelを使えますが、画像を扱う際は使えません。

画像で下記のinputタグ用意にしていますが、選択されたファイル名を疑似的に入れて、ユーザーからは見えないようにしています。これでupdate()が行えます。

```vuejs:
<input type="hidden" v-model="form.filename">
```

またコントローラで任意のファイル名を付けたいため、DBのカラム名はfilenameですが、idとnameにはfileとしておきます。


```vuejs:Edit.vue
<script setup>
import {router, useForm} from '@inertiajs/vue3';

 <!-- DVの値を取得 -->
const props = defineProps({
    Profile: Object
})

const form = useForm({
    id: props.profile.id,
    nick_name: props.profile.nick_name,
    filename: props.profile.filename,
    file: null
})


 <!-- コントローラにフォームの情報を送る -->
const updatePaidMemberDetail = id => {
    router.post(route('profile.update', {profile: id}), {
        _method: 'put',
        nick_name: form.nick_name,
        file: form.file,
    })
}


</script>
```

# コントローラー

```php:ProfileController.php
public function update(ProfileRequest $request, $id)
{
    $profile = profile::findOrFail($id);

    $fname = $request->file('file')->getClientOriginalExtension();
    $disk = Storage::build([
            'driver' => 'local',
            'root' => public_path('images'),
        ]);

    $random_name = Str::random(15);
    $hoge = date('Y-m-d') . $random_name . '.' . $fname;
    $disk->putFileAs('', $request->file('file'), $hoge);

    $profilel->nick_name = $request->nick_name;
    $profile->filename = $hoge;

    $profile->save();

    return redirect()->route('dashboard');

}
```

以下、詳細です。
```php:
 $fname = $request->file('file')->getClientOriginalExtension();
```
ファイルを取得し、拡張子を取得しています。

```php:
    $disk = Storage::build([
            'driver' => 'local',
            'root' => public_path('images'),
        ]);
```
 オンデマンドディスクです。アプリケーションのfilesystems設定ファイルに実際にその構成が存在しなくても、指定する構成を使用して実行時にディスクを作成します。

```php:
 $random_name = Str::random(15);
$hoge = date('Y-m-d') . $random_name . '.' . $fname;
```
ランダムで15文字の名前を生成しました。
今回は、今日の日付 + ランダムの名前 + 拡張子　としてファイル名を付けます。

```php:
$disk->putFileAs('', $request->file('file'), $hoge);
```
putFileAs()で任意の名前をつけます。

```php:
$profilel->nick_name = $request->nick_name;
$profile->filename = $hoge;

$profile->save();
```

ここでDBに格納して終わりです。


他に参考になる記事を貼っておきます。

https://qiita.com/t1k2a/items/50081988363cf2fa1bca#storageputfileas

https://qiita.com/nogizaka46/items/01b836f3d123f72a034d

https://www.tairaengineer-note.com/laravel-str-random/


https://reffect.co.jp/laravel/how_to_upload_file_in_laravel#Storage