実装したいこと
- usersテーブルにプロフィール画像を追加
- デフォルト画像を用意
- プロフィール画像変更
- 変更時、選択した画像を表示
- アップロード時、画像をリサイズ
前提
- Laravel7
- マイグレーション済み
- routes/web.phpにRoute::resource('user', 'UserController');を記述済み
実装
データベースに画像のファイル名を保存しておいて、そのファイル名をもとに画像の読み出しを行う、という戦略をとることとします。
シンボリックリンクを張る
画像の保存場所はstorage/app/public/とします。webからのアクセスを許すために、public/storageからstorage/app/public/へシンボリックリンクを張る必要があります。
以下のコマンドを実行します。
% php artisan storage:link
public/storage/以下にprofilesディレクトリを作り、その中にデフォルト画像を配置しておいてください。
profile_imageカラムの追加
マイグレーションファイルを作成します。
% php artisan make:migration add_column_to_users_table --table=users
カラムを追加する処理を書きます。
class AddColumnToUsersTable extends Migration
{
public function up()
{
Schema::table('users', function (Blueprint $table) {
$table->string('profile_image')->default('default.png');
});
}
public function down()
{
Schema::table('users', function (Blueprint $table) {
$table->dropColumn('profile_image');
});
}
}
マイグレーション
% php artisan migrate
User.phpの$fillableにカラムを追加
protected $fillable = [
'name', 'email', 'password', 'profile_image'
];
画像の表示
画像の表示の一例を以下に示します
コントローラー
public function profile() {
$user = Auth::user();
return view('profile', ['user' => $user]);
}
ビュー
<img src="{{ asset('storage/profiles/'.$user->profile_image) }}" alt="プロフィール画像">
プロフィール画像編集(アップロード)
ここで、Intervention Imageを用います。
Intervention Imageを使用するには、以下のコマンドを実行するだけでいいです。
% composer require intervention/image
Intervention Imageの使い方は以下のブログを参考にしました。
「完全網羅!Intervention Image(PHP)で画像を編集する全実例」
公式はこちら。
コントローラー
Intervention Imageでの処理は、saveProfileImage()内で行っています。
バリデーションはフォームリクエストUserRequestで行います。(省略)
public function edit($id) {
$user = Auth::user();
return view('user.edit', ['user' => $user]);
}
public function update($id, UserRequest $request) {
$user = Auth::user();
$form = $request->all();
$profileImage = $request->file('profile_image');
if ($profileImage != null) {
$form['profile_image'] = $this->saveProfileImage($profileImage, $id); // return file name
}
unset($form['_token']);
unset($form['_method']);
$user->fill($form)->save();
return redirect('/home');
}
private function saveProfileImage($image, $id) {
// get instance
$img = \Image::make($image);
// resize
$img->fit(100, 100, function($constraint){
$constraint->upsize();
});
// save
$file_name = 'profile_'.$id.'.'.$image->getClientOriginalExtension();
$save_path = 'public/profiles/'.$file_name;
Storage::put($save_path, (string) $img->encode());
// return file name
return $file_name;
}
ビュー
- 現在のプロフィール画像を最初に表示
- プロフィール画像をクリックしたら、画像ファイルを選択できる
- 選択した画像ファイルが表示される
以上を満たすように実装します。
「選択画像が変化したらアップロードしようとしている画像を表示する」といった処理をJavaScriptで実装しています。
ファイルをアップロードするためには、enctype="multipart/form-data"をformタグに追加する必要があります。
<form method="post" action="{{ route('user.update', ['user' => $user->id]) }}" enctype="multipart/form-data">
@csrf
@method('PATCH')
<label for="profile_image">プロフィール画像</label>
<label for="profile_image" class="btn">
<img src="{{ asset('storage/profiles/'.$user->profile_image) }}" id="img">
<input id="profile_image" type="file" name="profile_image" onchange="previewImage(this);">
</label>
<button type="submit" class="btn btn-primary">
変更
</button>
</form>
<script>
function previewImage(obj)
{
var fileReader = new FileReader();
fileReader.onload = (function() {
document.getElementById('img').src = fileReader.result;
});
fileReader.readAsDataURL(obj.files[0]);
}
</script>
SASS(CSS)
input#profile_image {
display: none;
}
おわり
画像のリサイズやJavaScriptの部分は一例に過ぎないので、他のサイトで別の方法をとてもいいかも
Intervention Imageは便利なので上で紹介したサイトで勉強してみては?