皆さんこんにちは、本格的な勉強会に参加したら???になった私です。
今までの開発記録はこちらへ
胡蝶蘭を捨てるくらいならワイが欲しいので、サービス開発する編
公式ドキュメントの言う通り、パッケージをインストールされたら、Inertia.jsが導入されて???になった編
マルチログインを作ってみた編
デザインをtailwindcssに丸投げする編
いよいよユーザー画面を作る
今回の目的はユーザーのプロフィール画面
そのために必要なものは
- ユーザー詳細表示機能
- ユーザー編集機能(Adminでやったひな型を使いまわす)
- 画像取り込み機能
- 退会機能
まずはユーザー詳細機能を作っていく
ルートはresourceを利用してもよかったが今回は普通に作成
Route::prefix('profiles')->middleware(['auth:users'])->group(function () {
Route::get('show/{profile}', [ProfileController::class, 'show'])->name('profiles.show');
Route::get('edit/{profile}', [ProfileController::class, 'edit'])->name('profiles.edit');
Route::post('update/{profile}', [ProfileController::class, 'update'])->name('profiles.update');
Route::get('destroy/{profile}', [ProfileController::class, 'destroy'])->name('profiles.destroy');
Route::post('destroy/{profile}', [ProfileController::class, 'destroy'])->name('profiles.destroy');
});
コントローラー側
namespace App\Http\Controllers\User;
use App\Http\Controllers\Controller;
use Illuminate\Http\Request;
use App\Models\User;
use App\Models\Review;
use App\Models\Product;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Hash;
use Illuminate\Support\Facades\Auth;
use App\Http\Requests\UploadImageRequest;
use App\Services\ImageService;
use Illuminate\Validation\Rules\Password;
class ProfileController extends Controller
{
public function show($id)
{
$userProfile=User::findOrFail($id);
return view('user.profiles.show', compact('userProfile'));
}
public function edit(Request $request, $id) //リクエスト入れる
{
$id=$request->route()->parameter('profile');
if (!is_null($id)) {
$userId=User::findOrFail($id)->id;
$currentUserId=(int)$userId;
$authId=Auth::id();
if ($currentUserId!==$authId) {
abort(404);
}
}
$userProfile = User::findOrFail($id);
return view('user.profiles.edit', compact('userProfile'));
}
public function update(UploadImageRequest $request, $id)
{
$id=$request->route()->parameter('profile');
if (!is_null($id)) {
$userId=User::findOrFail($id)->id;
$currentUserId=(int)$userId;
$authId=Auth::id();
if ($currentUserId!==$authId) {
abort(404);
}
}
$request->validate([
'name' => ['required', 'string', 'max:255'],
'comment' => [ 'string', 'max:200'],
'password' => ['required', 'confirmed','string', Password::defaults()],
'prefecture' => ['string', 'max:50'],
'comment' => ['string', 'max:100'],
]);
$userProfile = User::findOrFail($id);
$imageFile=$request->image;
if (!is_null($imageFile)&&$imageFile->isValid()) {
// Storage::putFile('public/profiles', $imageFile);//リサイズなし
$fileNameToStore=ImageService::upload($imageFile, 'profiles');
}
$user=User::findOrFail($id);
$user->name=$request->name;
$user->comment=$request->comment;
$user->prefecture=$request->prefecture;
$user->password=Hash::make($request->password);
if (!is_null($imageFile)&&$imageFile->isValid()) {
$user->img=$fileNameToStore;
}
$user->save();
return redirect()
->route('user.profiles.show', ['profile' => $userProfile->id])
}
public function destroy(Request $request,$id)
{
$this->middleware('auth:users');
//直接別ユーザーにアクセスするとはじくシステム
$this->middleware(function ($request, $next) {
$id=$request->route()->parameter('profile');
if (!is_null($id)) {
$userId=User::findOrFail($id)->id;
$currentUserId=(int)$userId;
$authId=Auth::id();
if ($currentUserId!==$authId) {
abort(404);
}
}
return $next($request);
});
try {
DB::transaction(function () use ($id) {
Product::select('id', )
->where('user_id', Auth::id())->delete();
User::select('id', 'name')
->where('id', Auth::id())->delete();
}, 2); //試行する回数
} catch (Throwable $e) {
Log::error($e);
throw $e;
}
Auth::guard('users')->logout();
return redirect('/');
}
}
Adminのコントローラーの使いまわしだけれど、ところどころそうではない部分があるので一つずつ説明
showメゾット
Userテーブルから、入力されたidの情報を取り出して終わり
editメゾット
ユーザー情報詳細はほかの人からも見られてもいいけれど、ユーザー編集、削除は本人以外からのアクセスをはじくようにする。
最初は、__constructに記述したが、それだとユーザー情報表示も見られなくなっちゃうので、edit,update,deleteのメゾットに書いたのがこれ。
$id=$request->route()->parameter('profile');
if (!is_null($id)) {
$userId=User::findOrFail($id)->id;
$currentUserId=(int)$userId;
$authId=Auth::id();
if ($currentUserId!==$authId) {
abort(404);
}
}
このコードが何を示しているかというと、ユーザーがアクセスしようとしているIDとログイン中のIDを照合して一致していれば、次の処理進み、そうでない場合は404ではじき返す仕組みです。
もう少し中身を見ていくと
まずはddヘルパーを利用して、$request->route()を入力すると。
このような画面が出ます
parametersのところに"1"がありますね。
$request->route()->parameter('profile')で"1"を取得しましょう。
その後、Userテーブルから、そのidを取得
ただし、このidは文字列で、照合したいAuth::id()は数字だから一致しません。
そのためidを数字に変換
あとはif文で照合させるだけです
画像の取り込み
webサイトには必須な機能ですね!
ただ画像をアップロードして表示するのだったら、素でもできますが、
と怒られそうなので、画像のリサイズをするためにInterventionImageを利用します
composer require intervention/image
インストールが終わったらconfig/app.phpへ
'providers' => [
Intervention\Image\ImageServiceProvider::class,
],
'aliases' => [
'InterventionImage'=>Intervention\Image\Facades\Image::class
],
を追記して php artisan cache:clearを押しましょう。
あとはuse InterventionImageで利用できる。
このサイトでも、ユーザーの画像、商品画像には画像をアップロードさせるシステムを作る必要がある。
そうなると2つの問題点が出てくる
- 画像名が重複せずにどうやって保存するか
- どこに保存するか
一つ目の問題について、アップロードした画像名をランダムに変更するプログラムを作る
二つ目の問題については、laravelのstorageフォルダに保存する
コードが多くなるのと商品投稿のコントローラーとも共有したいので、UploadImageRequestとImageServiceに切り分けて作成
public function authorize()
{
return true; //falseになっているのでtrueに切り替える
}
public function rules()
{
return [
'image' => 'image|mimes:jpg,jpeg,png|max:2048',
];
}
public function message()
{
return [
'image' => '指定されたファイルが画像ではありません',
'mines' => '指定された拡張子(jpg/jpeg/png)ではありません',
'max' => 'ファイルサイズは2MB以内にしてください',
];
}
class ImageService
{
public static function upload($imageFile, $folderName)
{
$fileName=uniqid(rand().'_'); //ファイル名をランダムに生成
$extension=$imageFile->extension(); //拡張子を判別
$fileNameToStore=$fileName.'.'.$extension; //上二つの文字列をつなげる
$resizedImage=InterventionImage::make($imageFile)->resize(400, 400)->encode();
//InterventionImageがリサイズしてくれる
Storage::put('public/'.$folderName.'/'.$fileNameToStore, $resizedImage);
//storageフォルダのpublicフォルダに$folderNameを作成(今回はProfiles)して保存
return $fileNameToStore;
}
}
準備は整ったのでコントローラーにも追記
if (!is_null($imageFile)&&$imageFile->isValid()) {
$fileNameToStore=ImageService::upload($imageFile, 'profiles');//ImageServiceに画像ファイルとフォルダ名の情報を送る
}
if (!is_null($imageFile)&&$imageFile->isValid()) {
$user->img=$fileNameToStore; //データベースに生成されたランダム名を書き込む
}
よし、これで大量の画像があっても重複せずに処理ができるぞい!
herokuに上げても大丈夫や!
あのお・・・herokuのストレージの画像は一定時間で消えますよ
えええええええ!!
対処法AWS使うのかよ・・・
今回で終わらなくてごめんなさい
次回はAWSに挑んできます