published() ->editorialOrder() ->first(); $highlightQuery = NewsArticle::with('author', 'category') ->published() ->editorialOrder(); if ($featured) { $highlightQuery->where('id', '!=', $featured->id); } $highlights = $highlightQuery->limit(3)->get(); $excludedIds = collect([$featured?->id])->merge($highlights->pluck('id'))->filter()->all(); $articles = NewsArticle::with('author', 'category') ->published() ->when($excludedIds !== [], fn ($query) => $query->whereNotIn('id', $excludedIds)) ->editorialOrder() ->paginate($perPage); return view('news.index', [ 'featured' => $featured, 'highlights' => $highlights, 'articles' => $articles, ] + $this->sidebarData()); } // ----------------------------------------------------------------------- // Category page — /news/category/{slug} // ----------------------------------------------------------------------- public function category(Request $request, string $slug): View { $category = NewsCategory::where('slug', $slug)->where('is_active', true)->firstOrFail(); $perPage = config('news.articles_per_page', 12); $articles = NewsArticle::with('author', 'category') ->published() ->byCategory($category->id) ->editorialOrder() ->paginate($perPage); return view('news.category', [ 'category' => $category, 'articles' => $articles, ] + $this->sidebarData()); } // ----------------------------------------------------------------------- // Tag page — /news/tag/{slug} // ----------------------------------------------------------------------- public function tag(Request $request, string $slug): View { $tag = NewsTag::where('slug', $slug)->firstOrFail(); $perPage = config('news.articles_per_page', 12); $articles = NewsArticle::with('author', 'category') ->published() ->whereHas('tags', fn ($q) => $q->where('news_tags.slug', $slug)) ->editorialOrder() ->paginate($perPage); return view('news.tag', [ 'tag' => $tag, 'articles' => $articles, ] + $this->sidebarData()); } public function archive(Request $request, int $year, int $month): View { abort_unless($month >= 1 && $month <= 12, 404); $perPage = config('news.articles_per_page', 12); $articles = NewsArticle::with('author', 'category') ->published() ->whereYear('published_at', $year) ->whereMonth('published_at', $month) ->editorialOrder() ->paginate($perPage); return view('news.archive', [ 'archiveDate' => now()->setDate($year, $month, 1), 'articles' => $articles, ] + $this->sidebarData()); } public function author(Request $request, string $username): View { $author = User::query()->with('profile')->where('username', $username)->firstOrFail(); $perPage = config('news.articles_per_page', 12); $articles = NewsArticle::with('author', 'category') ->published() ->where('author_id', $author->id) ->editorialOrder() ->paginate($perPage); return view('news.author', [ 'author' => $author, 'articles' => $articles, ] + $this->sidebarData()); } // ----------------------------------------------------------------------- // Article page — /news/{slug} // ----------------------------------------------------------------------- public function show(Request $request, string $slug): View { $article = NewsArticle::with('author.profile', 'category', 'tags', 'relatedEntities') ->published() ->where('slug', $slug) ->firstOrFail(); // Track view (once per session / IP) $this->trackView($request, $article); // Related articles (same category, excluding current) $related = NewsArticle::with('author', 'category') ->published() ->when($article->category_id, fn ($q) => $q->where('category_id', $article->category_id)) ->where('id', '!=', $article->id) ->editorialOrder() ->limit(config('news.related_limit', 4)) ->get(); return view('news.show', [ 'article' => $article, 'related' => $related, 'relatedEntities' => $this->news->resolveRelatedEntities($article, $request->user()), ] + $this->sidebarData()); } // ----------------------------------------------------------------------- // Helpers // ----------------------------------------------------------------------- private function trackView(Request $request, NewsArticle $article): void { $ip = $request->ip(); $userId = Auth::id(); $session = 'news_view_' . $article->id; if ($request->session()->has($session)) { return; } NewsView::create([ 'article_id' => $article->id, 'user_id' => $userId, 'ip' => $ip, 'created_at' => now(), ]); $article->incrementViews(); $request->session()->put($session, true); } private function sidebarData(): array { return $this->news->sidebarData(); } }