gurelog

エンジニアになるため、日々学んだことをまとめています

【Laravel】画像をアップロードするには?

こんにちは。gureです。

今回はLaravelで画像投稿機能を実装してみました。

 

完成品

完成品はこんな感じです。

入力フォーム↓

f:id:gure-y:20201017222111p:plain

表示↓

f:id:gure-y:20201017222301p:plain

 

ルーティングの設定

 web.php

<?php

use App\Http\Controllers\ItemsController;


Route::get('/',[ItemsController::class, 'index'])->name('index');

Route::get('/create',[ItemsController::class, 'create'])->name('create');
Route::post('/store',[ItemsController::class, 'store'])->name('store');

 indexに投稿したitemが表示されるようになっています。

createではitemの情報を入力フォームに、storeでは入力フォームで入力した内容を実際にDBに保存します。

 

コントローラーの設定

ItemsController.php

<?php

namespace App\Http\Controllers;
use Illuminate\Http\Request;
use App\Http\Requests\ItemValid;
use App\Models\Item;

class ItemsController extends Controller
{
 public function index(){
 $items = Item::latest()->get();
 return view('index', ['items' => $items]);
}

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

public function store(ItemValid $request){
 if ($file = $request->image) {
 $fileName = time() . $file->getClientOriginalName();
 $target_path = public_path('uploads/');
 $file->move($target_path, $fileName);
} else {
 $fileName = "";
}
 $item = new Item;
 $item->name = $request->name;
 $item->bland = $request->bland;
 $item->price = $request->price;
 $item->image = $fileName;
 $item->save();
 return redirect()->route('index');
}
}

長いコントローラーは本当にこれでいいのか、、?という気持ちになりますね。 

 

if ($file = $request->image) {
 $fileName = time() . $file->getClientOriginalName();
 $target_path = public_path('uploads/');
 $file->move($target_path, $fileName);
} else {
 $fileName = "";
}

↑の2行目で保存した時刻とファイルの拡張子を組み合わせて$fileNameに代入しています。

3行目では保存先をpublic/uploadsに指定しています。

4行目で$fileNameはpublic/uploadsへと移動させます。

imageが添付されていない場合には条件分岐によって$fileNameには""が代入されます。

 

$item = new Item;
$item->name = $request->name;
$item->bland = $request->bland;
$item->price = $request->price;
 
$item->image = $fileName;
$item->save();

$itemのカラムそれぞれに$requestでとってきた(=入力フォームに入力された)各々の内容を代入します。

$item->imageには先ほど作成した$fileNameを代入して、保存します。

 

シンボリックリンクの作成

ターミナルで以下のコマンドを実行します。

$ php artisan storage:link

特定のファイルやディレクトリを指し示す別のファイルを作成し、それを通じて本体を参照できるようにする仕組みです。

 

入力フォームの作成

create.blade.php

@extends('layout')
@section('title', '商品投稿')
@section('content')

<form method="POST" action="{{ route('store') }}" enctype="multipart/form-data">
<p>商品名</p>
<textarea name="name"></textarea>
<p>ブランド</p>
<textarea name="bland"></textarea>
<p>画像</p>
<input type="file" name="image">
<p>値段</p>
<input name="price">
<button type="submit">作成</button>
<a href="{{ route('index') }}">キャンセル</a>
</form>

@endsection

 

 画像はtype="file"にします。

 

表示画面の作成

index.blade.php

<div class="container py-4">
@if(!isset($items[0]))
<span>登録なし</span>
@else
@foreach ($items as $item)
<div class="col-md-4 text-left mt-4">
 <div class="card-deck">
  <div class="img-flex-4">
   <div class="card">
    <p class="card-text"><small class="text-muted"> {{ $item->bland }}</small></p>
    <img src="../../uploads/{{ $item->image }}" class="card-img-top">
    <div class="card-body">
     <h5 class="card-title">{{ $item->name }}</h5>
     <p class="card-text">¥{{ $item->price }}</p>
     <a href="{{ route('edit', ['id'=>$item->id]) }}">編集</a>
     <a href="{{ route('delete', ['id'=>$item->id]) }}" id="btn-bell">削除</a>
    </div>
   </div>
  </div>
 </div>
</div>
@endforeach
@endif
</div>

 

画像の表示の部分ではpublic/uploadsに入っている画像を参照しています。

<img src="../../uploads/{{ $item->image }}" class="card-img-top">

 

 

Laravelでアプリケーションを作ってみているのですが、MVCの流れなどなどは記述が違うだけで、やっていることはRailsと同じですね。

ただ画像のアップロードの方法は全く別物で難しかったです。

 

おしまい。

 

 

参考資料

http://e-words.jp/w/%E3%82%B7%E3%83%B3%E3%83%9C%E3%83%AA%E3%83%83%E3%82%AF%E3%83%AA%E3%83%B3%E3%82%AF.html

https://qiita.com/ryo-program/items/35bbe8fc3c5da1993366