概要
画像ファイルを含むフォームの作り方、画像ファイルに対するバリデーションについて整理する。
アップロード画像処理~準備で枠組みを作った商品データのアプリケーションを加工していく。
一般的なアップロードファイルの入力・取得についてはこちらを参照。
入力・登録後のアップロード画像の登録・保存についてはこちらを参照。
ルーティング
通常のリソースベースでは、新規データの入力はcreate
ルートが想定されているが、ここではindex
ページに商品入力フォームを配置し、そこで商品データの内容や商品画像を入力する。
1 2 3 4 5 6 7 |
+--------+----------+-------+-------------+-------------------------------------------+------------+ | Domain | Method | URI | Name | Action | Middleware | +--------+----------+-------+-------------+-------------------------------------------+------------+ ........ | | GET|HEAD | items | items.index | App\Http\Controllers\ItemController@index | web | ........ +--------+----------+-------+-------------+-------------------------------------------+------------+ |
商品入力ページ~index.blade.php
index
ページに商品入力フォームを配置し、そこに商品画像ファイルの選択要素を含める。画像選択を含むフォームに関する要点は以下のとおり。
form
要素に以下のオプションを加えるenctype="multipart/form-data"
- input要素で
type="file"
を指定する
なおリソースベースによるデータ登録の場合、create
アクションでルーティングされるページに入力フォームを置くことが想定されているが、ここでは商品一覧を表示するindex
ページで商品入力も行い、その入力フォームからstore
アクションを呼び出す。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
<!DOCTYPE html> <html lang="ja" dir="ltr"> <head> <meta charset="utf-8"> <title>商品一覧・入力</title> </head> <body> <h1>商品一覧・入力</h1> <form method="post" action="{{ route('items.store') }}" enctype="multipart/form-data"> @csrf <div> <input type="text" name="name" placeholder="商品名を入力"> </div> <div> <input type="number" name="price" placeholder="価格を入力"> </div> <div> <input type="file" name="image"> </div> <input type="submit" value="商品登録"> </form> </body> </html> |
フォームリクエスト
フォームリクエストでバリデーションを行う。フォームリクエストItemRequest
は以下のコマンドで作成。
1 2 |
$ php artisan make:request ItemRequest Request created successfully. |
生成されたフォームリクエストの雛形で、以下を編集。
authorize()
の戻り値をtrue
に変更rules()
の戻り値の配列にバリデーションルールを記述
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
<?php namespace App\Http\Requests; use Illuminate\Foundation\Http\FormRequest; class ItemRequest extends FormRequest { public function authorize() { return true; } public function rules() { return [ 'name' => ['required'], 'price' => ['required', 'integer', 'min:0'], 'image' => ['file', 'mimes:jpeg,jpg,png', 'dimensions:min_width=100,min_height=100,max_width=2000,max_height=2000'], ]; } } |
コントローラー~index/store
コントローラーでは2つのアクションメソッドを定義している。
index
アクションではindex
ページを表示するのみstore
アクションでは、フォームデータに基づいてItem
インスタンスをデータベースに登録- ただし現段階では、画像ファイルパスを格納する
image
に、仮置きで空文字列''
をセットしている。 - この変数へのファイルパスの設定は、別項のアップロード画像ファイルの保存・登録で実装する。
- ただし現段階では、画像ファイルパスを格納する
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 |
<?php namespace App\Http\Controllers; use App\Item; use Illuminate\Http\Request; use App\Http\Requests\ItemRequest; class ItemController extends Controller { public function index() { return view('items.index'); } public function store(ItemRequest $request) { // 商品をデータベースに登録 Item::create([ 'name' => $request->name, 'price' => $request->price, 'image' => '', ]); } } |
ここでの留意点は以下のとおり。
- 作成したフォームリクエスト
ItemRequest
をuse
でインポートし、メソッドインジェクションをRequest
からItemRequest
に変更している create()
メソッドがマスアサインメントのため、Item
モデルで$fillable
の定義が必要
Item
モデルでの$fillable
定義は以下の部分を追記。
1 2 3 4 5 6 7 8 9 10 |
<?php namespace App; use Illuminate\Database\Eloquent\Model; class Item extends Model { protected $fillable = ['name', 'price', 'image']; } |
データ登録確認
この状況でアプリケーションを実行し、フォームでデータを登録したのが以下の例。
画像ファイルのパスは、まだ未登録の状態。
1 2 3 4 5 6 7 |
mysql> select * from items; +----+-------+-------+-------+---------------------+---------------------+ | id | name | price | image | created_at | updated_at | +----+-------+-------+-------+---------------------+---------------------+ | 1 | item1 | 100 | | 2021-10-25 21:25:52 | 2021-10-25 21:25:52 | +----+-------+-------+-------+---------------------+---------------------+ 1 row in set (0.00 sec) |