153 lines
5.0 KiB
PHP
153 lines
5.0 KiB
PHP
<?php
|
|
|
|
namespace App\Http\Controllers\News;
|
|
|
|
use App\Http\Controllers\Controller;
|
|
use Illuminate\Http\Request;
|
|
use Illuminate\Support\Facades\Auth;
|
|
use cPad\Plugins\News\Models\NewsArticle;
|
|
use cPad\Plugins\News\Models\NewsCategory;
|
|
use cPad\Plugins\News\Models\NewsTag;
|
|
use cPad\Plugins\News\Models\NewsView;
|
|
|
|
class NewsController extends Controller
|
|
{
|
|
// -----------------------------------------------------------------------
|
|
// Homepage — /news
|
|
// -----------------------------------------------------------------------
|
|
|
|
public function index(Request $request)
|
|
{
|
|
$perPage = config('news.articles_per_page', 12);
|
|
|
|
$featured = NewsArticle::with('author', 'category')
|
|
->published()
|
|
->featured()
|
|
->orderByDesc('published_at')
|
|
->first();
|
|
|
|
$query = NewsArticle::with('author', 'category')
|
|
->published()
|
|
->orderByDesc('published_at');
|
|
|
|
if ($featured) {
|
|
$query->where('id', '!=', $featured->id);
|
|
}
|
|
|
|
$articles = $query->paginate($perPage);
|
|
return view('news.index', [
|
|
'featured' => $featured,
|
|
'articles' => $articles,
|
|
] + $this->sidebarData());
|
|
}
|
|
|
|
// -----------------------------------------------------------------------
|
|
// Category page — /news/category/{slug}
|
|
// -----------------------------------------------------------------------
|
|
|
|
public function category(Request $request, string $slug)
|
|
{
|
|
$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)
|
|
->orderByDesc('published_at')
|
|
->paginate($perPage);
|
|
|
|
return view('news.category', [
|
|
'category' => $category,
|
|
'articles' => $articles,
|
|
] + $this->sidebarData());
|
|
}
|
|
|
|
// -----------------------------------------------------------------------
|
|
// Tag page — /news/tag/{slug}
|
|
// -----------------------------------------------------------------------
|
|
|
|
public function tag(Request $request, string $slug)
|
|
{
|
|
$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))
|
|
->orderByDesc('published_at')
|
|
->paginate($perPage);
|
|
|
|
return view('news.tag', [
|
|
'tag' => $tag,
|
|
'articles' => $articles,
|
|
] + $this->sidebarData());
|
|
}
|
|
|
|
// -----------------------------------------------------------------------
|
|
// Article page — /news/{slug}
|
|
// -----------------------------------------------------------------------
|
|
|
|
public function show(Request $request, string $slug)
|
|
{
|
|
$article = NewsArticle::with('author', 'category', 'tags')
|
|
->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')
|
|
->published()
|
|
->when($article->category_id, fn ($q) => $q->where('category_id', $article->category_id))
|
|
->where('id', '!=', $article->id)
|
|
->orderByDesc('published_at')
|
|
->limit(config('news.related_limit', 4))
|
|
->get();
|
|
|
|
return view('news.show', [
|
|
'article' => $article,
|
|
'related' => $related,
|
|
] + $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 [
|
|
'categories' => NewsCategory::active()->withCount('publishedArticles')->ordered()->get(),
|
|
'trending' => NewsArticle::published()
|
|
->orderByDesc('views')
|
|
->limit(config('news.trending_limit', 5))
|
|
->get(['id', 'title', 'slug', 'views', 'published_at']),
|
|
'tags' => NewsTag::has('articles')->orderBy('name')->get(),
|
|
];
|
|
}
|
|
}
|