upsc_quiz-1.0.x-dev/src/Controller/ApiController.php
src/Controller/ApiController.php
<?php
namespace Drupal\upsc_quiz\Controller;
use Drupal\Core\Controller\ControllerBase;
use Drupal\Core\Database\Connection;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Request;
/**
* API Controller for UPSC Quiz AJAX endpoints.
*/
class ApiController extends ControllerBase {
/**
* The database connection.
*
* @var \Drupal\Core\Database\Connection
*/
protected $database;
/**
* Constructs an ApiController object.
*
* @param \Drupal\Core\Database\Connection $database
* The database connection.
*/
public function __construct(Connection $database) {
$this->database = $database;
}
/**
* {@inheritdoc}
*/
public static function create(ContainerInterface $container) {
return new static(
$container->get('database')
);
}
/**
* General API endpoint.
*
* @param \Symfony\Component\HttpFoundation\Request $request
* The request object.
*
* @return \Symfony\Component\HttpFoundation\JsonResponse
* JSON response.
*/
public function api(Request $request) {
$method = $request->getMethod();
$action = $request->query->get('action') ?: $request->request->get('action');
switch ($action) {
case 'get_questions':
return $this->getQuestions($request);
case 'submit_quiz':
return $this->submitQuiz($request);
case 'get_stats':
return $this->getUserStats($request);
default:
return new JsonResponse(['error' => 'Invalid action'], 400);
}
}
/**
* Get questions API endpoint.
*
* @param \Symfony\Component\HttpFoundation\Request $request
* The request object.
*
* @return \Symfony\Component\HttpFoundation\JsonResponse
* JSON response with questions.
*/
public function getQuestions(Request $request) {
$section = $request->query->get('section');
$limit = $request->query->get('limit', 0);
$randomize = $request->query->get('randomize', FALSE);
$query = $this->database->select('upsc_quiz_questions', 'q')
->fields('q', ['id', 'section', 'question', 'options', 'correct_answer', 'explanation', 'difficulty'])
->condition('status', 1);
if ($section && $section !== 'all') {
$query->condition('section', $section);
}
if ($randomize) {
$query->orderRandom();
} else {
$query->orderBy('weight', 'ASC');
$query->orderBy('id', 'ASC');
}
if ($limit > 0) {
$query->range(0, $limit);
}
$questions = $query->execute()->fetchAll();
$formatted_questions = [];
foreach ($questions as $question) {
$formatted_questions[] = [
'id' => $question->id,
'section' => $question->section,
'question' => $question->question,
'options' => json_decode($question->options, TRUE),
'correct' => $question->correct_answer,
'explanation' => $question->explanation,
'difficulty' => $question->difficulty,
];
}
return new JsonResponse([
'success' => TRUE,
'questions' => $formatted_questions,
'total' => count($formatted_questions),
]);
}
/**
* Submit quiz API endpoint.
*
* @param \Symfony\Component\HttpFoundation\Request $request
* The request object.
*
* @return \Symfony\Component\HttpFoundation\JsonResponse
* JSON response with results.
*/
public function submitQuiz(Request $request) {
$current_user = $this->currentUser();
if ($current_user->isAnonymous()) {
return new JsonResponse(['error' => 'Must be logged in to submit quiz'], 403);
}
$data = json_decode($request->getContent(), TRUE);
if (!$data) {
return new JsonResponse(['error' => 'Invalid data'], 400);
}
// Validate required fields
$required_fields = ['mode', 'answers', 'timeSpent', 'totalQuestions'];
foreach ($required_fields as $field) {
if (!isset($data[$field])) {
return new JsonResponse(['error' => "Missing required field: $field"], 400);
}
}
// Calculate results
$results = $this->calculateQuizResults($data);
// Save attempt to database
$attempt_id = upsc_quiz_save_attempt($current_user->id(), [
'mode' => $data['mode'],
'section' => $data['section'] ?? 'all',
'score' => $results['correct'],
'total_questions' => $data['totalQuestions'],
'time_spent' => $data['timeSpent'],
'answers' => $data['answers'],
'results' => $results,
]);
return new JsonResponse([
'success' => TRUE,
'attempt_id' => $attempt_id,
'results' => $results,
'redirect_url' => "/quiz/results/$attempt_id",
]);
}
/**
* Get user statistics API endpoint.
*
* @param \Symfony\Component\HttpFoundation\Request $request
* The request object.
*
* @return \Symfony\Component\HttpFoundation\JsonResponse
* JSON response with user stats.
*/
public function getUserStats(Request $request) {
$current_user = $this->currentUser();
if ($current_user->isAnonymous()) {
return new JsonResponse(['error' => 'Must be logged in'], 403);
}
$stats = upsc_quiz_get_user_stats($current_user->id());
return new JsonResponse([
'success' => TRUE,
'stats' => $stats,
]);
}
/**
* Calculate quiz results from submitted data.
*
* @param array $data
* The submitted quiz data.
*
* @return array
* Calculated results.
*/
private function calculateQuizResults(array $data) {
$answers = $data['answers'];
$question_ids = array_keys($answers);
// Get correct answers from database
$questions = $this->database->select('upsc_quiz_questions', 'q')
->fields('q', ['id', 'section', 'correct_answer'])
->condition('id', $question_ids, 'IN')
->execute()
->fetchAllAssoc('id');
$results = [
'totalQuestions' => $data['totalQuestions'],
'answered' => count($answers),
'correct' => 0,
'incorrect' => 0,
'skipped' => $data['totalQuestions'] - count($answers),
'sections' => [],
'timeSpent' => $data['timeSpent'],
];
foreach ($answers as $question_id => $user_answer) {
if (!isset($questions[$question_id])) {
continue;
}
$question = $questions[$question_id];
$section = $question->section;
// Initialize section if not exists
if (!isset($results['sections'][$section])) {
$results['sections'][$section] = [
'total' => 0,
'correct' => 0,
'incorrect' => 0,
'skipped' => 0,
];
}
$results['sections'][$section]['total']++;
if ($user_answer === NULL) {
$results['skipped']++;
$results['sections'][$section]['skipped']++;
} elseif ($user_answer == $question->correct_answer) {
$results['correct']++;
$results['sections'][$section]['correct']++;
} else {
$results['incorrect']++;
$results['sections'][$section]['incorrect']++;
}
}
return $results;
}
}