db = $db; } /** * GET /users/:id */ public function show(Request $request, array $params): void { $userId = $params['id'] ?? $request->userId ?? null; if (!$userId) { Response::unauthorized(); return; } $pdo = $this->db->getInstance(); $stmt = $pdo->prepare(' SELECT id, username, email, display_name, bio, avatar_url, photos, gender, interested_in, age, location, interests, is_online, last_seen, settings, created_at FROM users WHERE id = ? '); $stmt->execute([$userId]); $user = $stmt->fetch(); if (!$user) { Response::notFound('User not found'); return; } // Parse JSON fields $user['photos'] = Helpers::parseJson($user['photos'], []); $user['interested_in'] = Helpers::parseJson($user['interested_in'], []); $user['location'] = Helpers::parseJson($user['location'], null); $user['interests'] = Helpers::parseJson($user['interests'], []); $user['settings'] = Helpers::parseJson($user['settings'], []); $user['is_online'] = (bool) $user['is_online']; // Check if own profile to show full data $isOwnProfile = isset($request->userId) && $request->userId === $userId; if (!$isOwnProfile) { // Hide sensitive data for other users unset($user['email']); unset($user['settings']); } Response::success(['user' => $user]); } /** * PATCH /users/:id */ public function update(Request $request, array $params): void { $userId = $params['id'] ?? $request->userId ?? null; if (!$userId) { Response::unauthorized(); return; } // Can only update own profile if (!isset($request->userId) || $request->userId !== $userId) { Response::forbidden('You can only update your own profile'); return; } $body = $request->getBody(); $pdo = $this->db->getInstance(); // Build update query dynamically $allowedFields = [ 'display_name', 'bio', 'avatar_url', 'photos', 'gender', 'interested_in', 'age', 'location', 'interests', 'settings' ]; $updates = []; $values = []; foreach ($allowedFields as $field) { if (isset($body[$field])) { $value = $body[$field]; // Encode arrays to JSON if (in_array($field, ['photos', 'interested_in', 'interests'])) { $value = Helpers::jsonEncode($value); } elseif ($field === 'location') { $value = Helpers::jsonEncode($value); } elseif ($field === 'settings') { $value = Helpers::jsonEncode($value); } elseif ($field === 'bio') { $value = substr($value, 0, 500); // Max 500 chars } elseif ($field === 'age') { $value = (int) $value; if ($value < 18 || $value > 120) { Response::validationError(['age' => 'Age must be between 18 and 120']); return; } } $updates[] = "{$field} = ?"; $values[] = $value; } } if (empty($updates)) { Response::validationError(['general' => 'No valid fields to update']); return; } $updates[] = 'updated_at = ?'; $values[] = Helpers::timestamp(); $values[] = $userId; $sql = 'UPDATE users SET ' . implode(', ', $updates) . ' WHERE id = ?'; $stmt = $pdo->prepare($sql); $stmt->execute($values); // Fetch updated user $stmt = $pdo->prepare('SELECT * FROM users WHERE id = ?'); $stmt->execute([$userId]); $user = $stmt->fetch(); // Parse JSON fields $user['photos'] = Helpers::parseJson($user['photos'], []); $user['interested_in'] = Helpers::parseJson($user['interested_in'], []); $user['location'] = Helpers::parseJson($user['location'], null); $user['interests'] = Helpers::parseJson($user['interests'], []); $user['settings'] = Helpers::parseJson($user['settings'], []); Response::success(['user' => $user], 'Profile updated successfully'); } /** * DELETE /users/:id */ public function destroy(Request $request, array $params): void { $userId = $params['id'] ?? $request->userId ?? null; if (!$userId) { Response::unauthorized(); return; } // Can only delete own account if (!isset($request->userId) || $request->userId !== $userId) { Response::forbidden('You can only delete your own account'); return; } $pdo = $this->db->getInstance(); // Delete user (cascade will handle related records) $stmt = $pdo->prepare('DELETE FROM users WHERE id = ?'); $stmt->execute([$userId]); Response::success(null, 'Account deleted successfully'); } /** * GET /users/search */ public function search(Request $request): void { $query = $request->getQuery('q', ''); $limit = min((int) $request->getQuery('limit', 20), 100); $offset = (int) $request->getQuery('offset', 0); if (strlen($query) < 2) { Response::validationError(['q' => 'Search query must be at least 2 characters']); return; } $pdo = $this->db->getInstance(); $searchTerm = "%{$query}%"; $stmt = $pdo->prepare(' SELECT id, username, display_name, bio, avatar_url, age, location, interests, is_online FROM users WHERE (username LIKE ? OR display_name LIKE ?) LIMIT ? OFFSET ? '); $stmt->execute([$searchTerm, $searchTerm, $limit, $offset]); $users = $stmt->fetchAll(); // Parse JSON fields for each user foreach ($users as &$user) { $user['location'] = Helpers::parseJson($user['location'], null); $user['interests'] = Helpers::parseJson($user['interests'], []); $user['is_online'] = (bool) $user['is_online']; } Response::success([ 'users' => $users, 'limit' => $limit, 'offset' => $offset ]); } /** * GET /users/:id/posts */ public function posts(Request $request, array $params): void { $userId = $params['id'] ?? null; if (!$userId) { Response::notFound('User ID required'); return; } $limit = min((int) $request->getQuery('limit', 20), 100); $offset = (int) $request->getQuery('offset', 0); $pdo = $this->db->getInstance(); $stmt = $pdo->prepare(' SELECT * FROM posts WHERE user_id = ? ORDER BY created_at DESC LIMIT ? OFFSET ? '); $stmt->execute([$userId, $limit, $offset]); $posts = $stmt->fetchAll(); // Parse JSON fields foreach ($posts as &$post) { $post['media_urls'] = Helpers::parseJson($post['media_urls'], []); $post['location'] = Helpers::parseJson($post['location'], null); } Response::success([ 'posts' => $posts, 'limit' => $limit, 'offset' => $offset ]); } /** * GET /users/:id/friends */ public function friends(Request $request, array $params): void { $userId = $params['id'] ?? null; if (!$userId) { Response::notFound('User ID required'); return; } $pdo = $this->db->getInstance(); // Get mutual friends (where both users follow each other) $stmt = $pdo->prepare(' SELECT u.id, u.username, u.display_name, u.avatar_url, u.bio, u.is_online FROM users u INNER JOIN relationships r1 ON u.id = r1.following_id INNER JOIN relationships r2 ON u.id = r2.follower_id WHERE r1.follower_id = ? AND r2.following_id = ? AND r1.type = "friend" AND r2.type = "friend" AND r1.status = "active" AND r2.status = "active" '); $stmt->execute([$userId, $userId]); $friends = $stmt->fetchAll(); foreach ($friends as &$friend) { $friend['is_online'] = (bool) $friend['is_online']; } Response::success(['friends' => $friends]); } /** * GET /users/:id/followers */ public function followers(Request $request, array $params): void { $userId = $params['id'] ?? null; if (!$userId) { Response::notFound('User ID required'); return; } $pdo = $this->db->getInstance(); $stmt = $pdo->prepare(' SELECT u.id, u.username, u.display_name, u.avatar_url, u.bio, u.is_online FROM users u INNER JOIN relationships r ON u.id = r.follower_id WHERE r.following_id = ? AND r.status = "active" '); $stmt->execute([$userId]); $followers = $stmt->fetchAll(); foreach ($followers as &$follower) { $follower['is_online'] = (bool) $follower['is_online']; } Response::success(['followers' => $followers]); } /** * GET /users/:id/following */ public function following(Request $request, array $params): void { $userId = $params['id'] ?? null; if (!$userId) { Response::notFound('User ID required'); return; } $pdo = $this->db->getInstance(); $stmt = $pdo->prepare(' SELECT u.id, u.username, u.display_name, u.avatar_url, u.bio, u.is_online FROM users u INNER JOIN relationships r ON u.id = r.following_id WHERE r.follower_id = ? AND r.status = "active" '); $stmt->execute([$userId]); $following = $stmt->fetchAll(); foreach ($following as &$user) { $user['is_online'] = (bool) $user['is_online']; } Response::success(['following' => $following]); } }