😺

FormRequestとサービスコンテナを使って画像アップロード

2023/08/26に公開

ファイルに関係するやつ

config/filesystems.phpにファイルシステム設定ファイルがある。
ここで、全てのファイルシステム(=ディスク)を設定できる

このうちの一つに、webに公開してアクセスできるようにするpublicディスクがある。

  1. ファイルシステムでは、ファイルをstorage/app/public/ディレクトリに保存する。
  2. ブラウザでは、ファイルを探すときはpublic/strageを見る (storage/app~は探さない見れない)
  3. ブラウザからはstorage/app/public/にアクセスできないので、シンボリックリンクを作成する
  4. public/strageにも同じ画像を保存できるようになる
  5. ブラウザからファイルの読み取りができる
シンボリックリンク作成コマンド
./vendor/bin/sail artisan storage:link

         出る→ INFO  The [public/storage] link has been connected to [storage/app/public].  

echo asset('storage/file_name');で見ると画像が見れる

ファイルのアップロード

name属性で、ファイルのデータをコントローラーに投げることができる。
(inputタグにname属性値を指定すると、ファイルのインスタンスオブジェクトが得られる)


name="icon" を追っていく

view

View/ account.index.php
// route関数は指定した名前付きルートのURLを作成する
    <form action="{{ route('account.icon') }}" method="post" enctype="multipart/form-data">
      <div class="position-relative">
      @csrf
    <label for="formFile" class="form-label col-sm-2 "></label>
      <div class="position-absolute top-100 start-50 translate-middle col-sm-5">
        <input class="form-control" type="file" id="formFile" name="icon">
        <button type="submit" class="btn btn-primary col-sm-12">Upload</button>
      </div>
      </div>
    </form>

Controller

AccountIconController.php
namespace App\Http\Controllers\Account;

use App\Http\Controllers\Controller;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use App\Http\Requests\Account\IconRequest;
use App\Services\AccountService;

class IconController extends Controller
{
    public function __invoke(IconRequest $request, AccountService $accountService)
    {
        $accountService->saveIcon(Auth::User()->id, $request->icon());

        return redirect()
            ->route('account');
    }
}

Account/Iconコントローラーには、IconRequestから分かるようにRequestFormを設定している。
あと、AccountService $accountServiceでサービスコンテナも使ってる

routeからコントローラーにパスされる
→ コントローラーのRequestクラスにパス
→ FormRequestでバリデーション確認
→ コントローラーの処理
→ 処理中にサービスコンテナの関数使用

FormRequest

Requests/Account/IconRequest.php
namespace App\Http\Requests\Account;

use Illuminate\Foundation\Http\FormRequest;

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

  public function rules()
  {
  // ↓以外のタイプのファイルが来たらバリデーションされる
    return [
      'icon' => 'required|image|mimes:jpeg,jpg,png|max:2048',
    ];
  }

  //画像を取得
  public function icon()
  {
    return $this->file('icon');
  }
}

icon()関数のfile('icon')← name属性のファイルデータが入る!

Service

Dervices/AccountService.php
namespace App\Services;

use Illuminate\Support\Facades\Storage;
use App\Models\User;

class AccountService
{
  public function saveIcon(int $userId, $icon)
  {
    Storage::putFile('public/images', $icon);
    $user = User::find($userId);
    $user->icon_file_name = $icon->hashName();
    $user->save();
  }
}

putFileメソッドでは、ファイル名ではなくディレクトリ名のみを指定する。
このメソッドは、Illuminate\Http\Fileか、Illuminate\Http\UploadedFileインスタンスのどっちかを引数に取って、ファイルを自動で保存&渡してくれる

引数の$iconには、name属性で渡したiconが入る!

AccountIconController
    public function __invoke(IconRequest $request, AccountService $accountService)
    {
        $accountService->saveIcon(Auth::User()->id, $request->icon());
	

$request->icon()には、サイズや登録時間などたくさんの情報が入っている。 $icon->hashName()で、その情報中の#hashName: "onI1NthUwkj5b9ctl9oTYEgDSxjS0a6RKi8CcNO3"をとることができる
->DBに保存される名前として利用

違うのだけど別の書き方

  • file&storeメソッド = Storage::putFileメソッド
 public function saveFile($file, $tweet)
 {
   $file_name = $file->getClientOriginalName();
   $file->storeAs('public/images', $file_name);
   $tweet->filename = $file_name;
 }

Discussion