user_id; $sql = "SELECT * FROM student_error_notebook WHERE student_id = ?"; $params = [$studentId]; $subject = trim((string)$request->getQuery('subject', '')); $status = trim((string)$request->getQuery('status', '')); if ($subject !== '') { $sql .= ' AND subject_id = ?'; $params[] = $subject; } if ($status !== '') { $sql .= ' AND status = ?'; $params[] = $status; } $items = Database::select($sql . ' ORDER BY created_at DESC', $params); $mastered = count(array_filter($items, fn($item) => ($item['status'] ?? '') === 'mastered')); $bySubject = []; foreach ($items as $item) { $name = (string)($item['subject_name'] ?? ''); if ($name !== '') $bySubject[$name] = ($bySubject[$name] ?? 0) + 1; } $total = count($items); $response->json(['status' => 'success', 'data' => [ 'summary' => [ 'total_errors' => $total, 'mastered_count' => $mastered, 'pending_count' => $total - $mastered, 'mastery_percentage' => $total ? round(($mastered / $total) * 100, 1) : 0.0, 'by_subject' => $bySubject, ], 'items' => $items, ]]); } public function logError(Request $request, Response $response): void { $body = $request->getBody(); foreach (['subject_id', 'subject_name', 'topic_name', 'source_type', 'question_text', 'student_wrong_answer', 'correct_answer'] as $field) { if (trim((string)($body[$field] ?? '')) === '') { $response->status(422)->json(['status' => 'error', 'message' => "الحقل {$field} مطلوب"]); return; } } $uuid = $this->uuid(); Database::insert( "INSERT INTO student_error_notebook (uuid, student_id, subject_id, subject_name, topic_name, lesson_id, source_type, question_text, options_json, student_wrong_answer, correct_answer, socratic_hint, error_category, status, created_at) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, 'pending_remediation', NOW())", [ $uuid, (int)$request->user_id, $body['subject_id'], $body['subject_name'], $body['topic_name'], !empty($body['lesson_id']) ? (int)$body['lesson_id'] : null, $body['source_type'], $body['question_text'], isset($body['options']) ? json_encode($body['options'], JSON_UNESCAPED_UNICODE) : null, $body['student_wrong_answer'], $body['correct_answer'], (string)($body['socratic_hint'] ?? ''), (string)($body['error_category'] ?? 'conceptual'), ] ); $response->status(201)->json(['status' => 'success', 'uuid' => $uuid]); } public function getRemediationQuiz(Request $request, Response $response): void { $uuid = trim((string)$request->getQuery('error_uuid', '')); $error = Database::selectOne( "SELECT id FROM student_error_notebook WHERE uuid = ? AND student_id = ? LIMIT 1", [$uuid, (int)$request->user_id] ); if (!$error) { $response->status(404)->json(['status' => 'error', 'message' => 'الفجوة التعليمية غير موجودة']); return; } $response->status(409)->json(['status' => 'error', 'message' => 'لم يُولّد الخادم اختباراً علاجياً موثقاً لهذه الفجوة بعد']); } public function resolveError(Request $request, Response $response): void { $response->status(409)->json([ 'status' => 'error', 'message' => 'يتم اعتماد الإتقان حصراً بعد تسليم اختبار علاجي وتصحيحه على الخادم', ]); } private function uuid(): string { $data = random_bytes(16); $data[6] = chr((ord($data[6]) & 0x0f) | 0x40); $data[8] = chr((ord($data[8]) & 0x3f) | 0x80); return vsprintf('%s%s-%s-%s-%s-%s%s%s', str_split(bin2hex($data), 4)); } }