setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); self::$pdo->setAttribute(PDO::ATTR_DEFAULT_FETCH_MODE, PDO::FETCH_ASSOC); self::$pdo->exec("PRAGMA journal_mode = WAL;"); self::$pdo->exec("PRAGMA synchronous = NORMAL;"); if ($needsInit) { require_once __DIR__ . '/../data/init_sqlite.php'; } } return self::$pdo; } /** * Format tire record from DB row */ private static function formatTire(array $row): array { return [ 'id' => $row['id'], 'name' => $row['name'], 'brand' => $row['brand'], 'country' => $row['country'] ?? '', 'category' => $row['category'] ?? '', 'width' => (int)$row['width'], 'aspect_ratio' => (int)$row['aspect_ratio'], 'rim' => (int)$row['rim'], 'size_str' => $row['size_str'], 'speed_index' => $row['speed_index'], 'load_index' => $row['load_index'], 'season' => $row['season'], 'season_fa' => $row['season_fa'], 'warranty_months' => (int)$row['warranty_months'], 'production_year' => (string)$row['production_year'], 'fuel_efficiency' => $row['fuel_efficiency'], 'wet_grip' => $row['wet_grip'], 'noise_level' => $row['noise_level'], 'price' => (int)$row['price'], 'discount_percent' => (int)$row['discount_percent'], 'stock' => (int)$row['stock'], 'rating' => (float)$row['rating'], 'reviews_count' => (int)$row['reviews_count'], 'vehicles' => is_string($row['vehicles']) ? (json_decode($row['vehicles'], true) ?: []) : ($row['vehicles'] ?? []), 'description' => $row['description'] ?? '', 'features' => is_string($row['features']) ? (json_decode($row['features'], true) ?: []) : ($row['features'] ?? []), 'image' => $row['image'] ?? '', 'is_featured' => !empty($row['is_featured']), 'is_best_seller' => !empty($row['is_best_seller']) ]; } public static function getTires(): array { $db = self::getConnection(); $stmt = $db->query("SELECT * FROM tires ORDER BY is_featured DESC, rating DESC"); $rows = $stmt->fetchAll(); return array_map([self::class, 'formatTire'], $rows); } public static function getTireById(string $id): ?array { $db = self::getConnection(); $stmt = $db->prepare("SELECT * FROM tires WHERE id = :id LIMIT 1"); $stmt->execute([':id' => $id]); $row = $stmt->fetch(); return $row ? self::formatTire($row) : null; } public static function addTire(array $tire): bool { $db = self::getConnection(); $stmt = $db->prepare(" INSERT INTO tires ( id, name, brand, country, category, width, aspect_ratio, rim, size_str, speed_index, load_index, season, season_fa, warranty_months, production_year, fuel_efficiency, wet_grip, noise_level, price, discount_percent, stock, rating, reviews_count, vehicles, description, features, image, is_featured, is_best_seller ) VALUES ( :id, :name, :brand, :country, :category, :width, :aspect_ratio, :rim, :size_str, :speed_index, :load_index, :season, :season_fa, :warranty_months, :production_year, :fuel_efficiency, :wet_grip, :noise_level, :price, :discount_percent, :stock, :rating, :reviews_count, :vehicles, :description, :features, :image, :is_featured, :is_best_seller ) "); return $stmt->execute([ ':id' => $tire['id'], ':name' => $tire['name'], ':brand' => $tire['brand'], ':country' => $tire['country'] ?? '', ':category' => $tire['category'] ?? '', ':width' => (int)($tire['width'] ?? 0), ':aspect_ratio' => (int)($tire['aspect_ratio'] ?? 0), ':rim' => (int)($tire['rim'] ?? 0), ':size_str' => $tire['size_str'] ?? '', ':speed_index' => $tire['speed_index'] ?? '', ':load_index' => $tire['load_index'] ?? '', ':season' => $tire['season'] ?? 'four_season', ':season_fa' => $tire['season_fa'] ?? 'چهار فصل', ':warranty_months' => (int)($tire['warranty_months'] ?? 36), ':production_year' => $tire['production_year'] ?? '2026', ':fuel_efficiency' => $tire['fuel_efficiency'] ?? 'B', ':wet_grip' => $tire['wet_grip'] ?? 'A', ':noise_level' => $tire['noise_level'] ?? '69 dB', ':price' => (int)($tire['price'] ?? 0), ':discount_percent' => (int)($tire['discount_percent'] ?? 0), ':stock' => (int)($tire['stock'] ?? 0), ':rating' => (float)($tire['rating'] ?? 5.0), ':reviews_count' => (int)($tire['reviews_count'] ?? 0), ':vehicles' => json_encode($tire['vehicles'] ?? [], JSON_UNESCAPED_UNICODE), ':description' => $tire['description'] ?? '', ':features' => json_encode($tire['features'] ?? [], JSON_UNESCAPED_UNICODE), ':image' => $tire['image'] ?? '', ':is_featured' => !empty($tire['is_featured']) ? 1 : 0, ':is_best_seller' => !empty($tire['is_best_seller']) ? 1 : 0 ]); } public static function updateTire(string $id, array $updatedFields): bool { $db = self::getConnection(); $allowed = [ 'name', 'brand', 'country', 'category', 'width', 'aspect_ratio', 'rim', 'size_str', 'speed_index', 'load_index', 'season', 'season_fa', 'warranty_months', 'production_year', 'fuel_efficiency', 'wet_grip', 'noise_level', 'price', 'discount_percent', 'stock', 'rating', 'reviews_count', 'vehicles', 'description', 'features', 'image', 'is_featured', 'is_best_seller' ]; $sets = []; $params = [':id' => $id]; foreach ($updatedFields as $key => $value) { if (in_array($key, $allowed, true)) { $sets[] = "{$key} = :{$key}"; if ($key === 'vehicles' || $key === 'features') { $params[":{$key}"] = is_array($value) ? json_encode($value, JSON_UNESCAPED_UNICODE) : $value; } elseif ($key === 'is_featured' || $key === 'is_best_seller') { $params[":{$key}"] = !empty($value) ? 1 : 0; } else { $params[":{$key}"] = $value; } } } if (empty($sets)) { return false; } $sql = "UPDATE tires SET " . implode(', ', $sets) . " WHERE id = :id"; $stmt = $db->prepare($sql); return $stmt->execute($params); } public static function deleteTire(string $id): bool { $db = self::getConnection(); $stmt = $db->prepare("DELETE FROM tires WHERE id = :id"); return $stmt->execute([':id' => $id]); } public static function getBrands(): array { $db = self::getConnection(); $stmt = $db->query("SELECT name, country, logo, desc FROM brands ORDER BY id ASC"); return $stmt->fetchAll(); } public static function getArticles(): array { $db = self::getConnection(); $stmt = $db->query("SELECT * FROM articles ORDER BY id ASC"); return $stmt->fetchAll(); } public static function getPressureGuide(): array { $db = self::getConnection(); $stmt = $db->query("SELECT vehicle, front_psi, rear_psi, standard_tire FROM pressure_guide ORDER BY id ASC"); return $stmt->fetchAll(); } public static function getConsultations(): array { $db = self::getConnection(); $stmt = $db->query("SELECT * FROM consultations ORDER BY created_at DESC"); return $stmt->fetchAll(); } public static function addConsultation(array $entry): array { $db = self::getConnection(); $countStmt = $db->query("SELECT COUNT(*) FROM consultations"); $total = (int)$countStmt->fetchColumn(); $id = 'CNS-' . ($total + 101); $entry['id'] = $id; $entry['created_at'] = date('Y-m-d H:i'); $entry['status'] = $entry['status'] ?? 'جدید'; $entry['admin_note'] = $entry['admin_note'] ?? ''; $stmt = $db->prepare(" INSERT INTO consultations (id, name, phone, car, message, created_at, status, admin_note) VALUES (:id, :name, :phone, :car, :message, :created_at, :status, :admin_note) "); $stmt->execute([ ':id' => $entry['id'], ':name' => $entry['name'], ':phone' => $entry['phone'], ':car' => $entry['car'] ?? '', ':message' => $entry['message'] ?? '', ':created_at' => $entry['created_at'], ':status' => $entry['status'], ':admin_note' => $entry['admin_note'] ]); return $entry; } public static function updateConsultationStatus(string $id, string $status, string $note = ''): bool { $db = self::getConnection(); if ($note !== '') { $stmt = $db->prepare("UPDATE consultations SET status = :status, admin_note = :note WHERE id = :id"); return $stmt->execute([':id' => $id, ':status' => $status, ':note' => $note]); } else { $stmt = $db->prepare("UPDATE consultations SET status = :status WHERE id = :id"); return $stmt->execute([':id' => $id, ':status' => $status]); } } public static function deleteConsultation(string $id): bool { $db = self::getConnection(); $stmt = $db->prepare("DELETE FROM consultations WHERE id = :id"); return $stmt->execute([':id' => $id]); } public static function getSettings(): array { $db = self::getConnection(); $stmt = $db->query("SELECT key, value FROM settings"); $rows = $stmt->fetchAll(); $settings = []; foreach ($rows as $r) { $settings[$r['key']] = $r['value']; } $defaults = [ "site_phone" => "021-88889900", "emergency_phone" => "09123456789", "announcement" => "تضمین اصالت کالا و گارانتی معتبر شرکتی تا ۶۰ ماه | تاریخ تولید روز (2026)", "central_address" => "تهران، خیابان آزادی، تقاطع یادگار امام، مجتمع تایر قاسمی" ]; return array_merge($defaults, $settings); } public static function updateSettings(array $settings): bool { $db = self::getConnection(); $stmt = $db->prepare("INSERT OR REPLACE INTO settings (key, value) VALUES (:key, :value)"); foreach ($settings as $k => $v) { $stmt->execute([':key' => $k, ':value' => (string)$v]); } return true; } public static function getData(): array { return [ 'tires' => self::getTires(), 'brands' => self::getBrands(), 'articles' => self::getArticles(), 'pressure_guide' => self::getPressureGuide(), 'consultations' => self::getConsultations(), 'settings' => self::getSettings() ]; } }