?php class NewsController { private $pdo; public function __construct($pdo) { $this->pdo = $pdo; } public function show($slug = null) { if (!$slug) { $this->list(); return; } // افزایش تعداد بازدید $this->pdo->prepare("UPDATE news SET view_count = view_count + 1, updated_at = NOW() WHERE slug = ?") ->execute([$slug]); // دریافت خبر $stmt = $this->pdo->prepare(" SELECT n.*, GROUP_CONCAT(DISTINCT c.name SEPARATOR ', ') as categories, GROUP_CONCAT(DISTINCT c.slug SEPARATOR ',') as category_slugs FROM news n LEFT JOIN news_categories nc ON n.id = nc.news_id LEFT JOIN categories c ON nc.category_id = c.id WHERE n.slug = ? AND n.status = 'published' GROUP BY n.id "); $stmt->execute([$slug]); $news = $stmt->fetch(); if (!$news) { $this->notFound(); return; } // محاسبه زمان خواندن $reading_time = $this->calculateReadingTime($news['content']); // دریافت اخبار مرتبط $relatedNews = $this->getRelatedNews($news['id'], $news['category_slugs']); // دریافت آخرین اخبار $latestNews = $this->getLatestNews(5, $news['id']); // دریافت پربازدیدترین‌ها $popularNews = $this->getPopularNews(5, $news['id']); // ساختار JSON-LD $jsonLd = $this->generateJsonLd($news); $this->render('news/single', [ 'news' => $news, 'relatedNews' => $relatedNews, 'latestNews' => $latestNews, 'popularNews' => $popularNews, 'reading_time' => $reading_time, 'jsonLd' => $jsonLd ]); } private function calculateReadingTime($content) { $wordCount = str_word_count(strip_tags($content)); $minutes = ceil($wordCount / 200); // 200 کلمه در دقیقه return max(1, $minutes); // حداقل 1 دقیقه } public function list() { $page = max(1, intval($_GET['page'] ?? 1)); $limit = 12; $offset = ($page - 1) * $limit; $news = $this->pdo->query(" SELECT n.* FROM news n WHERE n.status = 'published' ORDER BY n.published_at DESC LIMIT $limit OFFSET $offset ")->fetchAll(); $total = $this->pdo->query("SELECT COUNT(*) as count FROM news WHERE status = 'published'")->fetch()['count']; $this->render('news/list', [ 'news' => $news, 'total' => $total, 'page' => $page, 'limit' => $limit ]); } public function category($slug) { if (!$slug) { $this->notFound(); return; } // دریافت اطلاعات دسته‌بندی $stmt = $this->pdo->prepare("SELECT * FROM categories WHERE slug = ? AND is_active = 1"); $stmt->execute([$slug]); $category = $stmt->fetch(); if (!$category) { $this->notFound(); return; } $page = $_GET['page'] ?? 1; $limit = 12; $offset = ($page - 1) * $limit; // دریافت اخبار این دسته $stmt = $this->pdo->prepare(" SELECT n.* FROM news n INNER JOIN news_categories nc ON n.id = nc.news_id WHERE nc.category_id = ? AND n.status = 'published' ORDER BY n.published_at DESC LIMIT ? OFFSET ? "); $stmt->execute([$category['id'], $limit, $offset]); $news = $stmt->fetchAll(); // تعداد کل // تعداد کل $stmt = $this->pdo->prepare(" SELECT COUNT(*) as count FROM news n INNER JOIN news_categories nc ON n.id = nc.news_id WHERE nc.category_id = ? AND n.status = 'published' "); $stmt->execute([$category['id']]); $total = $stmt->fetch()['count']; $this->render('news/category', [ 'category' => $category, 'news' => $news, 'total' => $total, 'page' => $page, 'limit' => $limit ]); } private function getRelatedNews($newsId, $categorySlugs) { if (!$categorySlugs) return []; $categorySlugsArray = explode(',', $categorySlugs); $placeholders = str_repeat('?,', count($categorySlugsArray) - 1) . '?'; $stmt = $this->pdo->prepare(" SELECT DISTINCT n.* FROM news n INNER JOIN news_categories nc ON n.id = nc.news_id INNER JOIN categories c ON nc.category_id = c.id WHERE c.slug IN ($placeholders) AND n.id != ? AND n.status = 'published' ORDER BY n.published_at DESC LIMIT 4 "); $params = array_merge($categorySlugsArray, [$newsId]); $stmt->execute($params); return $stmt->fetchAll(); } private function getLatestNews($limit = 5, $excludeId = null) { $sql = "SELECT n.* FROM news n WHERE n.status = 'published'"; $params = []; if ($excludeId) { $sql .= " AND n.id != ?"; $params[] = $excludeId; } $sql .= " ORDER BY n.published_at DESC LIMIT ?"; $params[] = $limit; $stmt = $this->pdo->prepare($sql); $stmt->execute($params); return $stmt->fetchAll(); } private function getPopularNews($limit = 5, $excludeId = null) { $sql = "SELECT n.* FROM news n WHERE n.status = 'published'"; $params = []; if ($excludeId) { $sql .= " AND n.id != ?"; $params[] = $excludeId; } $sql .= " ORDER BY n.view_count DESC LIMIT ?"; $params[] = $limit; $stmt = $this->pdo->prepare($sql); $stmt->execute($params); return $stmt->fetchAll(); } private function generateJsonLd($news) { $siteUrl = 'https://bilgix.click'; return [ '@context' => 'https://schema.org', '@type' => 'NewsArticle', 'headline' => $news['title'], 'description' => $news['lead'], 'image' => $news['featured_image'] ? [ $siteUrl . '/uploads/news/' . $news['featured_image'] ] : [ $siteUrl . '/logo.jpeg' ], 'datePublished' => $news['published_at'], 'dateModified' => $news['updated_at'], 'author' => [ '@type' => 'Organization', 'name' => 'BilgiX News Agency' ], 'publisher' => [ '@type' => 'Organization', 'name' => 'BilgiX', 'logo' => [ '@type' => 'ImageObject', 'url' => $siteUrl . '/logo.jpeg' ] ], 'mainEntityOfPage' => [ '@type' => 'WebPage', '@id' => $siteUrl . '/?route=' . $news['slug'] ] ]; } private function notFound() { http_response_code(404); $this->render('errors/404'); } private function render($view, $data = []) { // اطلاعات عمومی $generalData = [ 'breakingNews' => $this->getBreakingNews(), 'categories' => $this->getCategories(), 'settings' => $this->getSettings() ]; extract($generalData); extract($data); include __DIR__ . '/../views/layouts/frontend/header.php'; if (file_exists(__DIR__ . "/../views/frontend/{$view}.php")) { include __DIR__ . "/../views/frontend/{$view}.php"; } elseif (file_exists(__DIR__ . "/../views/{$view}.php")) { include __DIR__ . "/../views/{$view}.php"; } else { echo "

صفحه در حال توسعه

"; } include __DIR__ . '/../views/layouts/frontend/footer.php'; } private function getBreakingNews() { return $this->pdo->query(" SELECT id, title, slug FROM news WHERE status = 'published' AND is_breaking = 1 ORDER BY created_at DESC LIMIT 5 ")->fetchAll(); } private function getCategories() { return $this->pdo->query(" SELECT c.*, COUNT(nc.news_id) as news_count FROM categories c LEFT JOIN news_categories nc ON c.id = nc.category_id LEFT JOIN news n ON nc.news_id = n.id AND n.status = 'published' WHERE c.parent_id IS NULL AND c.is_active = 1 GROUP BY c.id ORDER BY c.display_order ASC LIMIT 15 ")->fetchAll(); } private function getSettings() { $settings = $this->pdo->query("SELECT setting_key, setting_value FROM settings WHERE is_public = 1")->fetchAll(); $result = []; foreach ($settings as $setting) { $result[$setting['setting_key']] = $setting['setting_value']; } if (empty($result)) { $result = [ 'site_title' => 'BilgiX - خبرگزاری فناوری', 'site_description' => 'مرجع اخبار تکنولوژی، هوش مصنوعی و فناوری‌های نوین', 'contact_address' => 'تبریز، خیابان آزادی، پلاک ۱۰۰', 'contact_phone' => '۰۴۱-۳۲۲۰۰۰۰۰', 'contact_email' => 'info@bilgix.click', 'telegram_url' => 'https://t.me/bilgix_news', 'instagram_url' => 'https://instagram.com/bilgix.news', 'twitter_url' => 'https://twitter.com/bilgix_news' ]; } return $result; } // تابع کمکی برای زمان public function timeAgo($datetime) { $time = strtotime($datetime); $now = time(); $diff = $now - $time; if ($diff < 60) { return 'همین الان'; } elseif ($diff < 3600) { $minutes = floor($diff / 60); return $minutes . ' دقیقه پیش'; } elseif ($diff < 86400) { $hours = floor($diff / 3600); return $hours . ' ساعت پیش'; } else { $days = floor($diff / 86400); return $days . ' روز پیش'; } } }
Fatal error: Uncaught Error: Class "NewsController" not found in /var/www/bilgix.click/index.php:114 Stack trace: #0 /var/www/bilgix.click/public/index.php(2): require_once() #1 {main} thrown in /var/www/bilgix.click/index.php on line 114