【Laravel】画像の保存

# 1. マイグレーションの作成
まず items テーブルを作成・更新します。

## マイグレーションとモデルを同時作成
```
% php artisan make:model Item -m
```

## マイグレーションファイルを編集
```database/migrations/YYYY_MM_DD_create_items_table.php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;

return new class extends Migration {
    public function up()
    {
        Schema::create('items', function (Blueprint $table) {
            $table->id();
            $table->string('image_path')->nullable(); // 画像
            $table->timestamps();
        });
    }

    public function down()
    {
        Schema::dropIfExists('items');
    }
};

```

## マイグレーション実行
```
% php artisan migrate
```


---
# 2. モデルの編集
モデルは１で作成済み。

## モデルファイルを編集
```app/Models/Item.php
namespace App\Models;

use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;

class Item extends Model
{
    use HasFactory;

    protected $fillable = [
        'name', 'image_path'
    ];
}
```


---
# 3. コントローラーの編集
```app/Http/Controllers/ItemController.php
namespace App\Http\Controllers;

use App\Models\Item;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Storage;

class ItemController extends Controller
{
    public function index()
    {
        $items = Auth::user()->items()->get();
        return view('items.index', compact('items'));
    }

    public function create()
    {
        return view('items.create');
    }

    public function store(Request $request)
    {
        $request->validate([
            'name' => 'required|string|max:255',
            'image' => 'nullable|image|mimes:jpg,jpeg,png,gif|max:2048',
        ]);

        // 画像を保存
        $imagePath = null;
        if ($request->hasFile('image_path')) {
            $imagePath = $request->file('image_path')->store('items', 'public');
        }

        Item::create([
            'name' => $request->name,
            'image_path' => $imagePath,
        ]);

        return route('items.index');
    }

    public function show($id)
    {
        $item = Auth::user()->items()->findOrFail($id);
        return view('items.show', compact('item'));
    }
}

```


---
# 4. ルーティングの編集
```routes/web.php
use App\Http\Controllers\ItemController;

Route::middleware(['auth'])->group(function () {
    Route::resource('items', ItemController::class);
});
```


---
# 5. ビューの作成
```resources/views/items/create.blade.php
<x-app-layout>
    <x-slot name="header">
        <h2 class="font-semibold text-xl text-gray-800 leading-tight">アイテム追加</h2>
    </x-slot>

    <div class="py-12">
        <div class="max-w-7xl mx-auto sm:px-6 lg:px-8">
            <div class="bg-white overflow-hidden shadow-sm sm:rounded-lg">
                <div class="p-6 text-gray-900">
                    ⭐️<form action="{{ route('items.store') }}" method="POST" enctype="multipart/form-data">
                        @csrf

                        <label for="name">アイテム名</label>
                        <input type="text" name="name" required>

                        <label for="image">画像</label>
                        <input type="file" name="image">

                        <button type="submit">登録</button>
                    </form>
                </div>
            </div>
        </div>
    </div>
</x-app-layout>

```
---
```resources/views/items/index.blade.php
<x-app-layout>
    <x-slot name="header">
        <h2 class="font-semibold text-xl text-gray-800 leading-tight">アイテム一覧</h2>
    </x-slot>

    <div class="py-12">
        <div class="max-w-7xl mx-auto sm:px-6 lg:px-8">
            <div class="bg-white overflow-hidden shadow-sm sm:rounded-lg">
                <div class="p-6 text-gray-900">
                    <table>
                        <thead>
                            <tr>
                                <th>アイテム名</th>
                                <th>画像</th>
                            </tr>
                        </thead>
                        <tbody>
                            @foreach($items as $item)
                                <tr>
                                    <td>{{ $item->name }}</td>
                                    <td>
                                        @if($item->image_path)
                                            <img src="{{ asset('storage/' . $item->image_path) }}" alt="アイテム画像" width="100">
                                        @else
                                            画像なし
                                        @endif
                                    </td>
                                </tr>
                            @endforeach
                        </tbody>
                    </table>

                    {{ $items->links() }}
                </div>
            </div>
        </div>
    </div>
</x-app-layout>

```

---
# 6. storage:link の実行
```
% php artisan storage:link
```
これを実行しないと、画像が public/storage にリンクされず、表示されない。


---
# 7. まとめ
✅ 画像を storage/app/public/items/ に保存
✅ storage:link を実行し、公開ディレクトリと連携
✅ asset('storage/' . $item->image_path) で画像を表示