withoutTrashed()->with([ 'user' => fn ($query) => $query->withCount('posts')->with('rank'), ]); $threadParam = $request->query('thread'); if (is_string($threadParam)) { $threadId = $this->parseIriId($threadParam); if ($threadId !== null) { $query->where('thread_id', $threadId); } } $posts = $query ->oldest('created_at') ->get() ->map(fn (Post $post) => $this->serializePost($post)); return response()->json($posts); } public function store(Request $request): JsonResponse { $data = $request->validate([ 'body' => ['required', 'string'], 'thread' => ['required', 'string'], ]); $threadId = $this->parseIriId($data['thread']); $thread = Thread::findOrFail($threadId); $post = Post::create([ 'thread_id' => $thread->id, 'user_id' => $request->user()?->id, 'body' => $data['body'], ]); $post->loadMissing([ 'user' => fn ($query) => $query->withCount('posts')->with('rank'), ]); return response()->json($this->serializePost($post), 201); } public function destroy(Request $request, Post $post): JsonResponse { $post->deleted_by = $request->user()?->id; $post->save(); $post->delete(); return response()->json(null, 204); } private function parseIriId(?string $value): ?int { if (!$value) { return null; } if (preg_match('#/threads/(\d+)$#', $value, $matches)) { return (int) $matches[1]; } if (is_numeric($value)) { return (int) $value; } return null; } private function serializePost(Post $post): array { return [ 'id' => $post->id, 'body' => $post->body, 'thread' => "/api/threads/{$post->thread_id}", 'user_id' => $post->user_id, 'user_name' => $post->user?->name, 'user_avatar_url' => $post->user?->avatar_path ? Storage::url($post->user->avatar_path) : null, 'user_posts_count' => $post->user?->posts_count, 'user_created_at' => $post->user?->created_at?->toIso8601String(), 'user_rank_name' => $post->user?->rank?->name, 'user_rank_badge_type' => $post->user?->rank?->badge_type, 'user_rank_badge_text' => $post->user?->rank?->badge_text, 'user_rank_badge_url' => $post->user?->rank?->badge_image_path ? Storage::url($post->user->rank->badge_image_path) : null, 'created_at' => $post->created_at?->toIso8601String(), 'updated_at' => $post->updated_at?->toIso8601String(), ]; } }