upsc_quiz-1.0.x-dev/upsc_quiz.module
upsc_quiz.module
<?php
/**
* @file
* Main module file for the UPSC Quiz module.
*/
use Drupal\Core\Routing\RouteMatchInterface;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Entity\EntityInterface;
use Drupal\Core\Database\Database;
/**
* Implements hook_help().
*/
function upsc_quiz_help($route_name, RouteMatchInterface $route_match) {
switch ($route_name) {
case 'help.page.upsc_quiz':
$output = [
'<h3>' . t('About') . '</h3>',
'<p>' . t('The UPSC Quiz module provides an interactive quiz application for Union Public Service Commission exam preparation. It includes multiple sections like Reasoning, English, Polity, History, Geography, and Current Affairs with comprehensive analytics and performance tracking.') . '</p>',
'<h3>' . t('Features') . '</h3>',
'<ul>',
'<li>' . t('Multiple quiz modes: Practice, Exam, and Section-wise') . '</li>',
'<li>' . t('Timer functionality for exam simulation') . '</li>',
'<li>' . t('Section-wise performance analysis') . '</li>',
'<li>' . t('Detailed answer review with explanations') . '</li>',
'<li>' . t('Progress tracking and scoring') . '</li>',
'<li>' . t('Responsive design for mobile and desktop') . '</li>',
'</ul>',
'<h3>' . t('Usage') . '</h3>',
'<p>' . t('Navigate to /quiz to start taking quizzes. Administrators can manage questions and settings from the configuration page.') . '</p>',
];
return implode('', $output);
case 'upsc_quiz.admin_settings':
return '<p>' . t('Configure quiz settings, manage questions, and view analytics.') . '</p>';
}
}
/**
* Implements hook_theme().
*/
function upsc_quiz_theme($existing, $type, $theme, $path) {
return [
'upsc_quiz_main' => [
'variables' => [
'quiz_data' => NULL,
'user_data' => NULL,
'settings' => NULL,
],
'template' => 'upsc-quiz-main',
],
'upsc_quiz_results' => [
'variables' => [
'results' => NULL,
'sections' => NULL,
'user_answers' => NULL,
'questions' => NULL,
],
'template' => 'upsc-quiz-results',
],
'upsc_quiz_question' => [
'variables' => [
'question' => NULL,
'options' => NULL,
'section' => NULL,
'number' => NULL,
],
'template' => 'upsc-quiz-question',
],
'upsc_quiz_admin' => [
'variables' => [
'stats' => NULL,
'recent_attempts' => NULL,
],
'template' => 'upsc-quiz-admin',
],
];
}
/**
* Implements hook_page_attachments().
*/
function upsc_quiz_page_attachments(array &$attachments) {
$route_match = \Drupal::routeMatch();
$route_name = $route_match->getRouteName();
// Attach libraries only on quiz pages
if (strpos($route_name, 'upsc_quiz') === 0) {
$attachments['#attached']['library'][] = 'upsc_quiz/quiz-app';
$attachments['#attached']['library'][] = 'upsc_quiz/quiz-styles';
// Add quiz configuration to drupalSettings
$config = \Drupal::config('upsc_quiz.settings');
$attachments['#attached']['drupalSettings']['upscQuiz'] = [
'timeLimit' => $config->get('time_limit') ?: 90,
'questionsPerSection' => $config->get('questions_per_section') ?: [],
'enableAnalytics' => $config->get('enable_analytics') ?: TRUE,
'apiEndpoint' => \Drupal\Core\Url::fromRoute('upsc_quiz.api')->toString(),
];
}
}
/**
* Implements hook_user_login().
*/
function upsc_quiz_user_login($account) {
// Track user login for quiz analytics
if (\Drupal::config('upsc_quiz.settings')->get('enable_analytics')) {
\Drupal::service('upsc_quiz.analytics')->trackUserLogin($account->id());
}
}
/**
* Get quiz questions by section.
*/
function upsc_quiz_get_questions_by_section($section = NULL) {
$database = \Drupal::database();
$query = $database->select('upsc_quiz_questions', 'q')
->fields('q')
->condition('status', 1);
if ($section) {
$query->condition('section', $section);
}
$query->orderBy('weight', 'ASC');
return $query->execute()->fetchAll();
}
/**
* Save quiz attempt results.
*/
function upsc_quiz_save_attempt($user_id, $data) {
$database = \Drupal::database();
return $database->insert('upsc_quiz_attempts')
->fields([
'uid' => $user_id,
'quiz_mode' => $data['mode'],
'section' => $data['section'] ?? 'all',
'score' => $data['score'],
'total_questions' => $data['total_questions'],
'time_spent' => $data['time_spent'],
'answers' => json_encode($data['answers']),
'results' => json_encode($data['results']),
'created' => time(),
])
->execute();
}
/**
* Get user's quiz statistics.
*/
function upsc_quiz_get_user_stats($user_id) {
$database = \Drupal::database();
$stats = [];
// Total attempts
$stats['total_attempts'] = $database->select('upsc_quiz_attempts', 'a')
->condition('uid', $user_id)
->countQuery()
->execute()
->fetchField();
// Average score
$avg_score_query = $database->select('upsc_quiz_attempts', 'a')
->condition('uid', $user_id)
->addExpression('AVG(score / total_questions * 100)', 'avg_score');
$avg_score = $avg_score_query->execute()->fetchField();
$stats['average_score'] = $avg_score ? round($avg_score, 2) : 0;
// Best score
$best_score_query = $database->select('upsc_quiz_attempts', 'a')
->condition('uid', $user_id)
->addExpression('MAX(score / total_questions * 100)', 'best_score');
$best_score = $best_score_query->execute()->fetchField();
$stats['best_score'] = $best_score ? round($best_score, 2) : 0;
// Section-wise performance
$section_query = $database->select('upsc_quiz_attempts', 'a')
->fields('a', ['section'])
->condition('uid', $user_id)
->addExpression('AVG(score / total_questions * 100)', 'avg_score')
->addExpression('COUNT(*)', 'attempts')
->groupBy('section');
$section_stats = $section_query->execute()->fetchAll();
$stats['sections'] = [];
foreach ($section_stats as $section) {
$stats['sections'][$section->section] = [
'average_score' => $section->avg_score ? round($section->avg_score, 2) : 0,
'attempts' => $section->attempts,
];
}
return $stats;
}
/**
* Implements hook_cron().
*/
function upsc_quiz_cron() {
// Clean up old quiz attempts (older than 1 year)
$cutoff = time() - (365 * 24 * 60 * 60);
\Drupal::database()->delete('upsc_quiz_attempts')
->condition('created', $cutoff, '<')
->execute();
\Drupal::logger('upsc_quiz')->info('Cleaned up old quiz attempts.');
}