upsc_quiz-1.0.x-dev/src/Controller/QuizController.php
src/Controller/QuizController.php
<?php
namespace Drupal\upsc_quiz\Controller;
use Drupal\Core\Controller\ControllerBase;
use Drupal\Core\Database\Connection;
use Drupal\Core\Session\AccountInterface;
use Drupal\Core\Url;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\HttpFoundation\RedirectResponse;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
/**
* Controller for UPSC Quiz main functionality.
*/
class QuizController extends ControllerBase {
/**
* The database connection.
*
* @var \Drupal\Core\Database\Connection
*/
protected $database;
/**
* The current user.
*
* @var \Drupal\Core\Session\AccountInterface
*/
protected $currentUser;
/**
* Constructs a QuizController object.
*
* @param \Drupal\Core\Database\Connection $database
* The database connection.
* @param \Drupal\Core\Session\AccountInterface $current_user
* The current user.
*/
public function __construct(Connection $database, AccountInterface $current_user) {
$this->database = $database;
$this->currentUser = $current_user;
}
/**
* {@inheritdoc}
*/
public static function create(ContainerInterface $container) {
return new static(
$container->get('database'),
$container->get('current_user')
);
}
/**
* Main quiz page.
*
* @return array
* Render array for the quiz main page.
*/
public function main() {
// Check if user is logged in for saving progress
if ($this->currentUser->isAnonymous()) {
$this->messenger()->addWarning($this->t('Please log in to save your quiz progress and view statistics.'));
}
$build = [
'#theme' => 'upsc_quiz_main',
'#quiz_data' => $this->getQuizData(),
'#user_data' => $this->getUserData(),
'#settings' => $this->getQuizSettings(),
'#attached' => [
'library' => [
'upsc_quiz/quiz-app',
'upsc_quiz/quiz-styles',
],
'drupalSettings' => [
'upscQuiz' => [
'userId' => $this->currentUser->id(),
'isLoggedIn' => !$this->currentUser->isAnonymous(),
'apiBase' => Url::fromRoute('upsc_quiz.api')->toString(),
'sections' => $this->getAvailableSections(),
],
],
],
'#cache' => [
'contexts' => ['user'],
'tags' => ['upsc_quiz:questions'],
],
];
return $build;
}
/**
* Section-specific quiz page.
*
* @param string $section
* The quiz section.
*
* @return array
* Render array for the section quiz page.
*/
public function section($section) {
$valid_sections = array_keys($this->getAvailableSections());
if (!in_array($section, $valid_sections)) {
throw new NotFoundHttpException();
}
$build = [
'#theme' => 'upsc_quiz_main',
'#quiz_data' => $this->getQuizData($section),
'#user_data' => $this->getUserData(),
'#settings' => $this->getQuizSettings(),
'#attached' => [
'library' => [
'upsc_quiz/quiz-app',
'upsc_quiz/quiz-styles',
],
'drupalSettings' => [
'upscQuiz' => [
'userId' => $this->currentUser->id(),
'isLoggedIn' => !$this->currentUser->isAnonymous(),
'apiBase' => Url::fromRoute('upsc_quiz.api')->toString(),
'selectedSection' => $section,
'sections' => $this->getAvailableSections(),
],
],
],
'#cache' => [
'contexts' => ['user', 'url.path'],
'tags' => ['upsc_quiz:questions', 'upsc_quiz:section:' . $section],
],
];
return $build;
}
/**
* Quiz results page.
*
* @param int $attempt_id
* The quiz attempt ID.
*
* @return array
* Render array for the results page.
*/
public function results($attempt_id) {
// Get attempt data
$attempt = $this->database->select('upsc_quiz_attempts', 'a')
->fields('a')
->condition('id', $attempt_id)
->condition('uid', $this->currentUser->id())
->execute()
->fetchObject();
if (!$attempt) {
throw new NotFoundHttpException();
}
$results = json_decode($attempt->results, TRUE);
$answers = json_decode($attempt->answers, TRUE);
$build = [
'#theme' => 'upsc_quiz_results',
'#results' => $results,
'#sections' => $this->getAvailableSections(),
'#user_answers' => $answers,
'#questions' => $this->getQuestionsForAttempt($attempt),
'#attached' => [
'library' => [
'upsc_quiz/quiz-styles',
],
],
'#cache' => [
'contexts' => ['user'],
'tags' => ['upsc_quiz:attempt:' . $attempt_id],
],
];
return $build;
}
/**
* User statistics page.
*
* @return array
* Render array for the user stats page.
*/
public function userStats() {
if ($this->currentUser->isAnonymous()) {
return new RedirectResponse(Url::fromRoute('user.login')->toString());
}
$stats = upsc_quiz_get_user_stats($this->currentUser->id());
// Get recent attempts
$recent_attempts = $this->database->select('upsc_quiz_attempts', 'a')
->fields('a')
->condition('uid', $this->currentUser->id())
->orderBy('created', 'DESC')
->range(0, 10)
->execute()
->fetchAll();
$build = [
'#theme' => 'user_stats',
'#stats' => $stats,
'#recent_attempts' => $recent_attempts,
'#sections' => $this->getAvailableSections(),
'#attached' => [
'library' => [
'upsc_quiz/quiz-styles',
],
],
'#cache' => [
'contexts' => ['user'],
'tags' => ['upsc_quiz:user_stats:' . $this->currentUser->id()],
],
];
return $build;
}
/**
* Get quiz data.
*
* @param string|null $section
* Optional section to filter by.
*
* @return array
* Quiz data array.
*/
private function getQuizData($section = NULL) {
$questions = upsc_quiz_get_questions_by_section($section);
$quiz_data = [
'questions' => [],
'sections' => $this->getAvailableSections(),
'total_questions' => count($questions),
];
foreach ($questions as $question) {
$quiz_data['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,
'weight' => $question->weight,
];
}
return $quiz_data;
}
/**
* Get user data.
*
* @return array
* User data array.
*/
private function getUserData() {
if ($this->currentUser->isAnonymous()) {
return ['anonymous' => TRUE];
}
return [
'anonymous' => FALSE,
'uid' => $this->currentUser->id(),
'name' => $this->currentUser->getAccountName(),
'stats' => upsc_quiz_get_user_stats($this->currentUser->id()),
];
}
/**
* Get quiz settings.
*
* @return array
* Quiz settings array.
*/
private function getQuizSettings() {
$config = $this->config('upsc_quiz.settings');
return [
'time_limit' => $config->get('time_limit') ?: 90,
'questions_per_section' => $config->get('questions_per_section') ?: [],
'enable_analytics' => $config->get('enable_analytics') ?: TRUE,
'allow_retake' => $config->get('allow_retake') ?: TRUE,
'show_correct_answers' => $config->get('show_correct_answers') ?: TRUE,
'randomize_questions' => $config->get('randomize_questions') ?: FALSE,
'randomize_options' => $config->get('randomize_options') ?: FALSE,
];
}
/**
* Get available sections.
*
* @return array
* Array of available sections.
*/
private function getAvailableSections() {
return [
'reasoning' => $this->t('Reasoning & Logic'),
'english' => $this->t('English Language'),
'polity' => $this->t('Indian Polity'),
'history' => $this->t('History'),
'geography' => $this->t('Geography'),
'current-affairs' => $this->t('Current Affairs'),
];
}
/**
* Get questions for a specific attempt.
*
* @param object $attempt
* The attempt object.
*
* @return array
* Array of questions used in the attempt.
*/
private function getQuestionsForAttempt($attempt) {
// This would typically be stored with the attempt
// For now, get current questions by section
return upsc_quiz_get_questions_by_section($attempt->section !== 'all' ? $attempt->section : NULL);
}
}