56
Help us understand the problem. What are the problem?

More than 3 years have passed since last update.

posted at

updated at

Laravel 5.5で複数の画像をアップロードする方法

背景

画像アップロードは、Webプロジェクトで最も一般的に使用される機能の1つです。 例えば、ネットショップの商品画像をアップロードすることです。それは簡単だと思います。 しかし、1つの商品に対して複数の画像ファイルをアップロードできるようにしたい場合は、少し複雑になります。Laravel5.5でどのように行われたかを見てみましょう。

1.データベースを準備する

シンプルな例を作りたいので、商品にはJANコードと商品目と複数枚の画像があるとしたら、以下のコマンドを実行します。

php artisan make:model Item -mc
php artisan make:model ItemPhoto -m

-mパラメータを使うと、マイグレーションを自動的に作成されます。
-cパラメータを使うと、コントローラーを自動的に作成されます。
便利でしょう.

create_items_table.php
Schema::create('items', function (Blueprint $table) {
    $table->increments('id');
    $table->string('jan')->uniqid();
    $table->string('name');
    $table->timestamps();
});
create_item_photo_table.php
Schema::create('item_photos', function (Blueprint $table) {
    $table->increments('id');
    $table->integer('item_id')->unsigned();
    $table->foreign('item_id')->references('id')->on('items');
    $table->string('path');
    $table->timestamps();
});

一つの商品には複数枚の画像を持つため、1対多リレーションはEloquentモデルの関数として定義します。

App\Item.php

class Item extends Model
{
    protected $fillable = ['jan', 'name'];

    public function photos()
    {
        return $this->hasMany('App\ItemPhoto');
    }
}
App\ItemPhoto.php

class ItemPhoto extends Model
{
    protected $fillable = ['item_id', 'path'];

    public function item()
    {
        return $this->belongsTo('App\Item');
    }
}

2.Route,Controller,Viewを作成する

商品登録フォームと結果ページを作成します。

Routes\web.php
Route::get('/items', 'ItemController@index');
Route::match(['GET', 'POST'], '/create', 'ItemController@create');

次、コントローラーを作成します。

App\Http\Controllers\ItemController.php

class ItemController extends Controller
{

    public function index()
    {
        $items = Item::all();
        return view('item.index', compact('items'));
    }

    public function create(Request $request)
    {
        // POST
        if ($request->isMethod('POST')) {
            dd($request->all());
        }

        // GET
        return view('item.create');
    }

}

商品登録フォームを作成します。

resources\view\item\create.php
<!-- メッセージ -->
@if (count($errors) > 0)
<ul>
    @foreach($errors->all() as $error)
    <li>{{ $error }}</li>
    @endforeach
</ul>
@endif
<!-- フォーム -->
<form action="{{ url('upload') }}" method="POST" enctype="multipart/form-data">
    <label for="jan">Janコード:</label>
    <input type="text" class="form-control" name="jan" value="">
    <br>
    <label for="name">商品名:</label>
    <input type="text" class="form-control" name="name" value="">
    <br>
    <label for="photo">画像ファイル複数可:</label>
    <input type="file" class="form-control" name="files[][photo]" multiple>
    <br>
    <hr>
    {{ csrf_field() }}
    <button class="btn btn-success"> Upload </button>
</form>

3.バリデーションを作成する

フォームの入力値をチェックしたほうがいいでしょう。リクエストファイルを作成します。

php artisan make:request ItemRequest
App\Http\Requests\ItemRequest

class ItemRequest extends FormRequest
{
    public function authorize()
    {
        return true;
    }

    public function rules()
    {
        if ($this->isMethod('get')) return [];

        return [
            'jan' => 'required',
            'name' => 'required',
            'files.*.photo' => 'image|mimes:jpeg,bmp,png',
        ];
    }
}

*を使えば、配列の各要素をバリデーションすることもできます。詳しく

4.ファイルの保存場所を指定する

基本的には、すべてのファイルが/storage/appフォルダに保存されます。 しかし、/publicではないので、ブラウザURLから直接にアクセスすることはできませんので、変更します。

config\filesystems.php

return [
    'default' => 'local',
    'disks' => [
        'local' => [
            'driver' => 'local',
            // 'root' => storage_path('app'), // 変更前
            'root' => public_path('item'),        // 変更後
        ],
    // ...

以上のように変更すれば、画像ファイルはすべて/public/item下にアップされます。

5.ItemControllerの全貌

ItemRequestクラスをControllerに use することを忘れないでください。
コントローラ全体のメソッドは次のようになります:

App\Http\Controllers\ItemController.php
<?php

namespace App\Http\Controllers;

use App\Item;
use App\Http\Requests\ItemRequest;

class ItemController extends Controller
{

    public function index()
    {
        $items = Item::all();
        return view('item.index', compact('items'));
    }

    public function create(ItemRequest $request)
    {
        // POST
        if ($request->isMethod('POST')) {

            // 商品情報の保存
            $item = Item::create(['jan'=> $request->jan, 'name'=> $request->name]);

            // 商品画像の保存
            foreach ($request->file('files') as $index=> $e) {
                $ext = $e['photo']->guessExtension();
                $filename = "{$request->jan}_{$index}.{$ext}";
                $path = $e['photo']->storeAs('photos', $filename);
                // photosメソッドにより、商品に紐付けられた画像を保存する
                $item->photos()->create(['path'=> $path]);
            }

            return redirect('/items')->with(['success'=> '保存しました!']);
        }

        // GET
        return view('item.create');
    }
}

ご覧のように、ファイルをアップロードする方法は ->storeAs('photos', $filename) です。 第1引数はストレージに使用するサブフォルダの意味です。この場合は /public/item/photos になります。 第2引数は画像ファイルの名前です。

6.結果

Itemsテーブルのデータは
スクリーンショット 2017-12-09 21.25.10.png

Item_Photosテーブルのデータは
スクリーンショット 2017-12-09 21.18.38.png

最後

間違いなどがございましたら、ご指摘いただけると幸いです。

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Sign upLogin
56
Help us understand the problem. What are the problem?