こんにちは。webアプリケーションを作る際にファイルアップロードはごく当然の機能で、Laravelでももちろん標準でサポートされています。が、今回は要件次第では実装がほとんど不要になるライブラリlaravel-imageup
を紹介します。
(要件次第で、と前置きをつけた理由は後述します)
公式のREADMEに従って、composerでサクッとインストールします。
なお、依存先のライブラリであるIntervention Image
がPHPのGD拡張もしくはImagick拡張に依存するので、あらかじめ入れておきましょう。
# インストール $ composer require qcod/laravel-imageup Installing qcod/laravel-imageup (1.0.6): Downloading (100%) ... ... Writing lock file Generating optimized autoload files ... ... Discovered Package: qcod/laravel-imageup Package manifest generated successfully. # 設定ファイル生成 $ php artisan vendor:publish --provider="QCod\ImageUp\ImageUpServiceProvider" --tag="config" Copied File [/vendor/qcod/laravel-imageup/config/imageup.php] To [/config/imageup.php] Publishing complete. # /storageを公開するためのシンボリックリンク作成(laravel-imageupはデフォルトでstorageを使う) $ php artisan storage:link The [public/storage] directory has been linked.
あとはライブラリを/config/app.php
に登録して導入完了です。
'providers' => [ /* * Laravel Framework Service Providers... */ ... ... /* * Package Service Providers... */ Illuminate\View\ViewServiceProvider::class, ]
チュートリアルでお馴染みのmake:auth
でログイン機能を生成し、登録画面に画像アップロードのフォームを追加します。
なおマイグレーション処理は省略しますがUser
テーブルにファイル名を保存するためのavatar
カラムを追加済みとします。
$ php artisan make:auth Authentication scaffolding generated successfully.
次に
register.blade.php
を編集します。form要素にenctype="multipart/form-data"
を追加するのをお忘れなく。@if ($errors->has('name')) {{ $errors->first('avatar') }} @endif
モデルクラス/app/User.php
にプロパティを追記します。
namespace App; use QCod\ImageUp\HasImageUploads; class User extends Authenticatable { use HasImageUploads; protected $fillable = [ 'name', 'email', 'password', 'avatar', ]; // ライブラリ用に追記するプロパティ protected static $imageFields = [ 'avatar' ]; }
User
テーブルにレコードを作成する処理ところで、avatar
カラムに値を入れるためのコードを追記します。
protected function create(array $data) { return User::create([ 'name' => $data['name'], 'email' => $data['email'], 'password' => Hash::make($data['password']), 'avatar' => sprintf('%s/%s', config('imageup.upload_directory'), $data['avatar']->hashName()), // 追記 ]); }
実際にはRequestクラスでのバリデーションなどありますが、これで最低限の実装完了です。フォームを送信してみましょう。
アップロードした画像が/app/storage/app/public/uploads
に保存されていれば成功です。
私がこのライブラリを使った時、実装の要件として「複数のファイルを一度にアップロードできる」というのがありました。当初は特に深く考えず以下のようなhtmlを書いてましたが、ここで軽くハマりました。
この状態のままだと、前述の$data['avatar']
に配列で格納され、ライブラリの自動アップロードが効かなくなるばかりかエラーを吐いてしまいます。
そもそもライブラリ側がIlluminate\Http\UploadedFile
を受け取ることが前提なので、この場合は以下2つの解決策があります。
name="avatar_1"
name="avatar_2"
というようにユニークな値で記述する私は後者で解決しました。
自動アップロードを無効化する場合は設定ファイルで'auto_upload_images' => false
としてもよいのですが、アプリケーション全体に影響してしまうので、モデルクラスで以下のようにプロパティを設定します。
protected static $imageFields = [ 'avatar' => [ // override global auto upload setting coming from config('imageup.auto_upload_images') 'auto_upload' => false, ], ];
あとは$model->uploadImage($uploadedFile, 'avatar');
で、配列に格納されているUploadedFile
オブジェクトをひとつずつ渡せばOKです。
uploadImage
メソッドが、PHPコードを静的解析するツールであるPHPStanでエラーを吐きます。
ライブラリのPHPDocが以下のようになっているため「第二引数$field
がNULLのみ受け付ける」という意味になってしまっています。
/** * Upload and resize image * * @param $imageFile * @param null $field * @throws InvalidUploadFieldException|\Exception */public function uploadImage($imageFile, $field = null) { ... ...
これはuploadImage
をオーバーライドするか、モデルクラスに適当なメソッドを作って、その中でuploadImage
を呼ぶようにしましょう。
少々面倒なファイルアップロード処理を少ないコードで実装できるlaravel-imageup
を紹介しました。中身とその挙動を把握した上で使えばかなり便利だと思います。また、Laravel本体のバージョンに追随している点も地味に長所だと思います。