概要
公開領域のディスクに保存された画像ファイルを変更・削除する手順を整理する。
- アップロード画像処理~準備
- 画像ファイルの入力
- アップロード画像ファイルの保存・登録
- アップロード画像の表示
- アップロード画像の変更・削除
変更は現在のファイルを削除して新しいファイルを保存するので、画像ファイルの削除手順がキーになる。
一般的なアップロードファイルの削除はこちらを参照。
ファイルの削除手順
storageディレクトリーのディスクに保存された画像ファイルの削除は、以下で行う。
|
1 |
\Storage::disk('ディスク')->delete('ファイルパス'); |
ここで'ディスク'と'ファイルパス'は、保存・登録でstore()メソッドの引数に指定したものと同じ。
データの変更
例題のアプリケーションを、画像ファイルのほか、商品名や価格も併せて変更できるように修正する。
ルーティング
- 画像データの編集は、
GETメソッドでeditアクションにルーティングされる。 - 編集されたデータの更新登録は、
PATCHメソッドでupdateアクションにルーティングされる。
|
1 2 3 4 5 6 7 8 9 |
$ php artisan route:list +--------+-----------+-------------------+----------------+--------------------------------------------+------------+ | Domain | Method | URI | Name | Action | Middleware | +--------+-----------+-------------------+----------------+--------------------------------------------+------------+ ........ | | PUT|PATCH | items/{item} | items.update | App\Http\Controllers\ItemController@update | web | | | GET|HEAD | items/{item}/edit | items.edit | App\Http\Controllers\ItemController@edit | web | ........ +--------+-----------+-------------------+----------------+--------------------------------------------+------------+ |
ビューからのリンク~index.blade.php
indexページで一覧された各商品に、編集のリンクを配置する。要点としては、
- a要素の
hrefの遷移先でroute('items.edit', $item)をしている - 第1引数はeditのルート名、第2引数は編集対象のデータインスタンス
GETのURLは以下の様に展開されるアプリケーションルート/{$id}/edit
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
<!DOCTYPE html> <html lang="ja" dir="ltr"> <head> <meta charset="utf-8"> <title>商品一覧・入力</title> </head> <body> <h1>商品一覧・入力</h1> ........ {{-- 商品データ・画像表示 --}} @foreach ($items as $item) <p>{{ $item->name }} : {{ $item->price }}円</p> <div> @if ($item->image !=='') <img src="{{ \Storage::url($item->image) }}" width="25%"> @else <img src="{{ \Storage::url('items/no_image.png') }}"> @endif </div> <a href="{{ route('items.edit', $item) }}">内容編集</a> @endforeach </body> </html> |
コントローラー~edit
GETメソッドでルーティングされたeditアクションでは、URLに含まれる$idに対応するインスタンス$itemがデータベースから引数として渡され、このインスタンスをそのままeditビューに渡している。
|
1 2 3 4 5 6 7 8 9 |
class ItemController extends Controller { ........ public function edit(Item $item) { return view('items.edit', ['item' => $item]); } ........ } |
ビュー~edit.blade.php
editビューでは渡された$itemインスタンスの内容を各input要素に表示し、画像ファイルのパスから画像を表示している。
- 画像を扱うため、
formのenctypeオプションを指定している form要素で指定できるメソッドはGETかPOSTだけだが、updateルートはPATCHメソッドを期待しているので、@methodディレクティブで'patch'を指定している- 新規入力時と同じく、フォームリクエストで編集時の入力バリデーションを行っている
|
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 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 |
<!DOCTYPE html> <html lang="ja" dir="ltr"> <head> <meta charset="utf-8"> <title>商品データ編集</title> </head> <body> <h1>商品データ編集</h1> <p>商品ID: {{ $item->id }}</p> <form method="post" action="{{ route('items.update', $item) }}" enctype="multipart/form-data"> @csrf @method('patch') <div> <label>商品名: <input type="text" name="name" value="{{ $item->name }}"> </label> </div> <div> <label>価 格: <input type="text" name="price" value="{{ $item->price }}">円 </label> </div> <div> @if ($item->image !=='') <img src="{{ \Storage::url($item->image) }}" width="25%"> @else <img src="{{ \Storage::url('items/no_image.png') }}"> @endif </div> <div> <input type="file" name="image"> </div> <input type="submit" value="更新"> </form> <a href="{{ route('items.index') }}">一覧に戻る</a> {{-- バリデーションエラー表示 --}} @foreach ($errors->all() as $error) <p>{{ $error }}</p> @endforeach </body> </html> |
コントローラー~update
PATCHメソッドでルーティングされたupdateアクションでは、編集入力内容によって、商品データの内容と画像ファイルを更新している。
- 編集時に画像が選択されていれば、現在のファイルを削除して、選択されたファイルを保存
- このときにファイルのパスも取得
- 商品内容、画像ファイルへのパスでデータの内容を更新
|
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 |
class ItemController extends Controller { ........ public function update(ItemRequest $request, Item $item) { // 画像ファイルインスタンス取得 $image = $request->file('image'); // 現在の画像へのパスをセット $path = $item->image; if (isset($image)) { // 現在の画像ファイルの削除 \Storage::disk('public')->delete($path); // 選択された画像ファイルを保存してパスをセット $path = $image->store('items', 'public'); } // データベースを更新 $item->update([ 'name' => $request->name, 'price' => $request->price, 'image' => $path, ]); return redirect()->route('items.edit', $item); } ........ } |
データの削除
ルーティング
indexページで一覧表示された商品の削除ボタンを押すと、DELETEメソッドでdestroyにルーティングされる。
|
1 2 3 4 5 6 7 8 |
$ php artisan route:list +--------+--------+--------------+---------------+---------------------------------------------+------------+ | Domain | Method | URI | Name | Action | Middleware | +--------+--------+--------------+---------------+---------------------------------------------+------------+ ........ | | DELETE | items/{item} | items.destroy | App\Http\Controllers\ItemController@destroy | web | ........ +--------+--------+--------------+---------------+---------------------------------------------+------------+ |
ビューへの削除ボタン配置~index.blade.php
indexページの各商品表示にフォームと削除ボタンを加える。
form要素ではmethod="post"を指定し、@methodディレクティブで'delete'メソッドを指定している- 削除する商品を指定して
destroyにルーティングするだけなので、フォームにはsubmitボタンだけが配置されている
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
{{-- 商品データ・画像表示 --}} @foreach ($items as $item) <p>{{ $item->name }} : {{ $item->price }}円</p> <div> @if ($item->image !=='') <img src="{{ \Storage::url($item->image) }}" width="25%"> @else <img src="{{ \Storage::url('items/no_image.png') }}"> @endif </div> <a href="{{ route('items.edit', $item) }}">内容編集</a> <form method="post" action="{{ route('items.destroy', $item) }}"> @csrf @method('delete') <input type="submit" value="データ削除"> </form> @endforeach |
コントローラー~destroy
destroyアクションでは、ファイルが登録されていればpublicディスクから削除し、商品データをデータベースから削除している。
|
1 2 3 4 5 6 7 8 9 10 11 12 13 |
public function destroy(Item $item) { // 商品画像ファイルへのパスを取得 $path = $item->image; // ファイルが登録されていれば削除 if ($path !== '') { \Storage::disk('public')->delete($path); } // データベースからデータを削除 $item->delete(); return redirect()->route('items.index'); } |