58
58

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

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

Last updated at Posted at 2017-12-09

背景

画像アップロードは、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

最後

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

58
58
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
58
58

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?