abortIfUnavailable($mealPost); $perPage = max(1, min($request->integer('per_page', 15), 100)); $reviews = $mealPost->reviews() ->with('user:id,name,avatar_url') ->latest() ->paginate($perPage) ->withQueryString(); return PostReviewsResource::collection($reviews); } public function store(PostReviewsRequest $request, MealPosts $mealPost): JsonResponse { $this->abortIfUnavailable($mealPost); $userId = $request->user()->getKey(); abort_if( PostReviews::query() ->where('meal_post_id', $mealPost->getKey()) ->where('user_id', $userId) ->exists(), 409, __('api.post_reviews.already_exists') ); $postReview = PostReviews::create([ ...$request->validated(), 'meal_post_id' => $mealPost->getKey(), 'user_id' => $userId, ]); $postReview->load('user:id,name,avatar_url'); $this->notifyMealOwner($mealPost, $postReview, $userId); return (new PostReviewsResource($postReview)) ->response() ->setStatusCode(201); } public function mine(Request $request, MealPosts $mealPost): JsonResponse|PostReviewsResource { $this->abortIfUnavailable($mealPost); $postReview = $mealPost->reviews() ->where('user_id', $request->user()->getKey()) ->with('user:id,name,avatar_url') ->first(); if (! $postReview) { return response()->json(['data' => null]); } return new PostReviewsResource($postReview); } public function show(PostReviews $postReview): PostReviewsResource { $postReview->loadMissing('mealPost.user'); $this->abortIfUnavailable($postReview->mealPost); return new PostReviewsResource($postReview->loadMissing( 'mealPost.ingredients', 'mealPost.user:id,name,avatar_url', 'user:id,name,avatar_url', )); } public function update(PostReviewsRequest $request, PostReviews $postReview): PostReviewsResource { $this->abortIfNotOwner($request, $postReview); $postReview->update($request->validated()); return new PostReviewsResource($postReview->refresh()->loadMissing('user:id,name,avatar_url')); } public function destroy(Request $request, PostReviews $postReview): Response { $this->abortIfNotOwner($request, $postReview); $postReview->delete(); return response()->noContent(); } private function abortIfNotOwner(Request $request, PostReviews $postReview): void { abort_unless($request->user(), 401); abort_unless($postReview->user_id === $request->user()->getKey(), 404); } private function abortIfUnavailable(MealPosts $mealPost): void { abort_if( $mealPost->isHidden() || $mealPost->user()->whereNotNull('suspended_at')->exists(), 404, ); } private function notifyMealOwner(MealPosts $mealPost, PostReviews $postReview, string $reviewerId): void { if ($mealPost->user_id === $reviewerId || blank($postReview->comment)) { return; } $mealPost->loadMissing('user'); $owner = $mealPost->user; if (! $owner) { return; } $owner->notify( (new MealPostCommentedNotification($postReview)) ->locale($owner->preferredLocale()) ); } }