<?php
// Start session
session_start();
// Include database configuration
require_once '../config/database.php';
// Check if user is logged in and has admin role
if (!isset($_SESSION['user_id']) || $_SESSION['role'] !== 'admin') {
header("Location: ../login.php");
exit();
}
// Check if bank_id and question_id are provided
if (!isset($_GET['bank_id']) || !isset($_GET['id'])) {
$_SESSION['error_message'] = "Missing question or bank information.";
header("Location: banks.php");
exit;
}
$bank_id = intval($_GET['bank_id']);
$question_id = intval($_GET['id']);
// Validate bank_id and question_id
if ($bank_id <= 0 || $question_id <= 0) {
$_SESSION['error_message'] = "Invalid question or bank information.";
header("Location: banks.php");
exit;
}
// Get question details
$question_query = "SELECT q.*, qb.title as bank_title, qb.id as bank_id
FROM questions q
JOIN question_banks qb ON q.question_bank_id = qb.id
WHERE q.id = ?";
$stmt = $conn->prepare($question_query);
$stmt->bind_param("i", $question_id);
$stmt->execute();
$question_result = $stmt->get_result();
if ($question_result->num_rows === 0) {
header("Location: question_banks.php");
exit();
}
$question = $question_result->fetch_assoc();
$bank_id = $question['bank_id'];
// Get question options
$options_query = "SELECT * FROM question_options WHERE question_id = ?";
$stmt = $conn->prepare($options_query);
$stmt->bind_param("i", $question_id);
$stmt->execute();
$options_result = $stmt->get_result();
$options = [];
$correct_options = [];
while ($option = $options_result->fetch_assoc()) {
$options[] = $option;
if ($option['is_correct']) {
$correct_options[] = $option['id'];
}
}
// Process form submission
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
// Get common question data
$question_text = trim($_POST['question_text']);
$question_type = $_POST['question_type'];
$difficulty = $_POST['difficulty'];
$marks = $_POST['marks'];
$is_practice = isset($_POST['is_practice']) ? 1 : 0;
$explanation = trim($_POST['explanation']);
// Validate inputs
$errors = [];
if (empty($question_text)) {
$errors[] = "Question text is required";
}
if (empty($question_type)) {
$errors[] = "Question type is required";
}
if (empty($difficulty)) {
$errors[] = "Difficulty level is required";
}
if (!is_numeric($marks) || $marks <= 0) {
$errors[] = "Marks must be a positive number";
}
// If no errors, proceed with updating the question
if (empty($errors)) {
// Start transaction
$conn->begin_transaction();
try {
// Update question
$update_question = "UPDATE questions SET
question_text = ?,
question_type = ?,
difficulty = ?,
marks = ?,
is_practice = ?,
explanation = ?
WHERE id = ?";
$stmt = $conn->prepare($update_question);
$stmt->bind_param("sssdisi", $question_text, $question_type, $difficulty, $marks, $is_practice, $explanation, $question_id);
$stmt->execute();
// Delete existing options
$delete_options = "DELETE FROM question_options WHERE question_id = ?";
$stmt = $conn->prepare($delete_options);
$stmt->bind_param("i", $question_id);
$stmt->execute();
// Handle options based on question type
if ($question_type === 'multiple_choice' || $question_type === 'true_false') {
$options = $_POST['options'] ?? [];
$correct_options = $_POST['correct_options'] ?? [];
// For multiple choice, require at least 2 options and 1 correct
if ($question_type === 'multiple_choice' && count($options) < 2) {
throw new Exception("Multiple choice questions must have at least 2 options");
}
if (empty($correct_options)) {
throw new Exception("At least one correct option must be selected");
}
// Insert options
foreach ($options as $index => $option_text) {
$option_text = trim($option_text);
if (empty($option_text)) continue;
$is_correct = in_array($index, $correct_options) ? 1 : 0;
$insert_option = "INSERT INTO question_options (question_id, option_text, is_correct) VALUES (?, ?, ?)";
$stmt = $conn->prepare($insert_option);
$stmt->bind_param("isi", $question_id, $option_text, $is_correct);
$stmt->execute();
}
} elseif ($question_type === 'short_answer') {
// For short answer, require an answer key
$answer_key = trim($_POST['answer_key'] ?? '');
if (empty($answer_key)) {
throw new Exception("Answer key is required for short answer questions");
}
$insert_option = "INSERT INTO question_options (question_id, option_text, is_correct) VALUES (?, ?, 1)";
$stmt = $conn->prepare($insert_option);
$stmt->bind_param("is", $question_id, $answer_key);
$stmt->execute();
}
// Commit transaction
$conn->commit();
// Set success message and redirect
$_SESSION['success_message'] = "Question updated successfully!";
header("Location: questions.php?bank_id=" . $bank_id);
exit();
} catch (Exception $e) {
// Roll back transaction
$conn->rollback();
$error_message = "Error: " . $e->getMessage();
}
} else {
$error_message = "Please fix the following errors:<br>" . implode("<br>", $errors);
}
}
// Get answer key for short answer questions
$answer_key = '';
if ($question['question_type'] === 'short_answer' && !empty($options)) {
$answer_key = $options[0]['option_text'];
}
// Include header
include 'includes/header.php';
?>
<div class="container-fluid">
<div class="d-sm-flex align-items-center justify-content-between mb-4">
<h1 class="h3 mb-0 text-gray-800">Edit Question</h1>
<a href="questions.php?bank_id=<?php echo $bank_id; ?>" class="btn btn-secondary btn-sm shadow-sm">
<i class="fas fa-arrow-left fa-sm text-white-50"></i> Back to Questions
</a>
</div>
<div class="card shadow mb-4">
<div class="card-header py-3">
<h6 class="m-0 font-weight-bold text-primary">
Editing Question from: <?php echo htmlspecialchars($question['bank_title']); ?>
</h6>
</div>
<div class="card-body">
<?php if (isset($error_message)): ?>
<div class="alert alert-danger alert-dismissible fade show" role="alert">
<?php echo $error_message; ?>
<button type="button" class="close" data-dismiss="alert" aria-label="Close">
<span aria-hidden="true">×</span>
</button>
</div>
<?php endif; ?>
<form method="post" action="" id="questionForm">
<div class="form-group">
<label for="question_text"><strong>Question Text *</strong></label>
<textarea class="form-control" id="question_text" name="question_text" rows="4" required><?php echo isset($_POST['question_text']) ? htmlspecialchars($_POST['question_text']) : htmlspecialchars($question['question_text']); ?></textarea>
<small class="form-text text-muted">
Enter the full text of your question. You can use basic HTML for formatting.
</small>
</div>
<div class="form-row">
<div class="form-group col-md-4">
<label for="question_type"><strong>Question Type *</strong></label>
<select class="form-control" id="question_type" name="question_type" required>
<option value="">Select Type</option>
<option value="multiple_choice" <?php echo (isset($_POST['question_type']) ? $_POST['question_type'] === 'multiple_choice' : $question['question_type'] === 'multiple_choice') ? 'selected' : ''; ?>>Multiple Choice</option>
<option value="true_false" <?php echo (isset($_POST['question_type']) ? $_POST['question_type'] === 'true_false' : $question['question_type'] === 'true_false') ? 'selected' : ''; ?>>True/False</option>
<option value="short_answer" <?php echo (isset($_POST['question_type']) ? $_POST['question_type'] === 'short_answer' : $question['question_type'] === 'short_answer') ? 'selected' : ''; ?>>Short Answer</option>
<option value="essay" <?php echo (isset($_POST['question_type']) ? $_POST['question_type'] === 'essay' : $question['question_type'] === 'essay') ? 'selected' : ''; ?>>Essay</option>
</select>
</div>
<div class="form-group col-md-4">
<label for="difficulty"><strong>Difficulty *</strong></label>
<select class="form-control" id="difficulty" name="difficulty" required>
<option value="">Select Difficulty</option>
<option value="easy" <?php echo (isset($_POST['difficulty']) ? $_POST['difficulty'] === 'easy' : $question['difficulty'] === 'easy') ? 'selected' : ''; ?>>Easy</option>
<option value="medium" <?php echo (isset($_POST['difficulty']) ? $_POST['difficulty'] === 'medium' : $question['difficulty'] === 'medium') ? 'selected' : ''; ?>>Medium</option>
<option value="hard" <?php echo (isset($_POST['difficulty']) ? $_POST['difficulty'] === 'hard' : $question['difficulty'] === 'hard') ? 'selected' : ''; ?>>Hard</option>
</select>
</div>
<div class="form-group col-md-4">
<label for="marks"><strong>Marks *</strong></label>
<input type="number" class="form-control" id="marks" name="marks" min="1" max="100" required value="<?php echo isset($_POST['marks']) ? htmlspecialchars($_POST['marks']) : htmlspecialchars($question['marks']); ?>">
</div>
</div>
<div class="form-group">
<div class="custom-control custom-checkbox mb-3">
<input type="checkbox" class="custom-control-input" id="is_practice" name="is_practice" <?php echo (isset($_POST['is_practice']) || (!isset($_POST['is_practice']) && $question['is_practice'])) ? 'checked' : ''; ?>>
<label class="custom-control-label" for="is_practice">Include in practice questions</label>
<small class="form-text text-muted">
Check this if you want to include this question in practice sessions.
</small>
</div>
</div>
<!-- Options for Multiple Choice -->
<div id="multiple_choice_options" class="options-section" style="display: none;">
<h5 class="mt-4 mb-3">Answer Options</h5>
<div class="alert alert-info">
<i class="fas fa-info-circle"></i> Add at least 2 options and select the correct answer(s).
</div>
<div id="options_container">
<!-- Options will be added here dynamically -->
<?php if ($question['question_type'] === 'multiple_choice'): ?>
<?php foreach ($options as $index => $option): ?>
<div class="option-row mb-2">
<div class="input-group">
<div class="input-group-prepend">
<div class="input-group-text">
<input type="checkbox" name="correct_options[]" value="<?php echo $index; ?>" <?php echo $option['is_correct'] ? 'checked' : ''; ?>>
</div>
</div>
<input type="text" class="form-control" name="options[]" placeholder="Option <?php echo $index + 1; ?>" value="<?php echo htmlspecialchars($option['option_text']); ?>">
<div class="input-group-append">
<button type="button" class="btn btn-danger remove-option" <?php echo count($options) <= 2 ? 'disabled' : ''; ?>>
<i class="fas fa-times"></i>
</button>
</div>
</div>
</div>
<?php endforeach; ?>
<?php else: ?>
<div class="option-row mb-2">
<div class="input-group">
<div class="input-group-prepend">
<div class="input-group-text">
<input type="checkbox" name="correct_options[]" value="0">
</div>
</div>
<input type="text" class="form-control" name="options[]" placeholder="Option 1">
<div class="input-group-append">
<button type="button" class="btn btn-danger remove-option" disabled>
<i class="fas fa-times"></i>
</button>
</div>
</div>
</div>
<div class="option-row mb-2">
<div class="input-group">
<div class="input-group-prepend">
<div class="input-group-text">
<input type="checkbox" name="correct_options[]" value="1">
</div>
</div>
<input type="text" class="form-control" name="options[]" placeholder="Option 2">
<div class="input-group-append">
<button type="button" class="btn btn-danger remove-option" disabled>
<i class="fas fa-times"></i>
</button>
</div>
</div>
</div>
<?php endif; ?>
</div>
<button type="button" id="add_option" class="btn btn-secondary btn-sm mt-2">
<i class="fas fa-plus"></i> Add Option
</button>
</div>
<!-- Options for True/False -->
<div id="true_false_options" class="options-section" style="display: none;">
<h5 class="mt-4 mb-3">Answer Options</h5>
<?php
$true_is_correct = false;
$false_is_correct = false;
if ($question['question_type'] === 'true_false' && !empty($options)) {
foreach ($options as $option) {
if ($option['option_text'] === 'True' && $option['is_correct']) {
$true_is_correct = true;
}
if ($option['option_text'] === 'False' && $option['is_correct']) {
$false_is_correct = true;
}
}
}
?>
<div class="form-check mb-2">
<input class="form-check-input" type="radio" name="true_false_answer" id="true_option" value="true" <?php echo $true_is_correct ? 'checked' : ''; ?>>
<label class="form-check-label" for="true_option">
True
</label>
</div>
<div class="form-check">
<input class="form-check-input" type="radio" name="true_false_answer" id="false_option" value="false" <?php echo $false_is_correct ? 'checked' : ''; ?>>
<label class="form-check-label" for="false_option">
False
</label>
</div>
</div>
<!-- Options for Short Answer -->
<div id="short_answer_options" class="options-section" style="display: none;">
<h5 class="mt-4 mb-3">Answer Key</h5>
<div class="form-group">
<label for="answer_key">Correct Answer</label>
<input type="text" class="form-control" id="answer_key" name="answer_key" placeholder="Enter the correct answer" value="<?php echo htmlspecialchars($answer_key); ?>">
<small class="form-text text-muted">
The student's answer must match this exactly.
</small>
</div>
</div>
<!-- No options for Essay -->
<div id="essay_options" class="options-section" style="display: none;">
<div class="alert alert-info mt-4">
<i class="fas fa-info-circle"></i> Essay questions require manual grading.
</div>
</div>
<div class="form-group mt-4">
<label for="explanation">Explanation (Optional)</label>
<textarea class="form-control" id="explanation" name="explanation" rows="3" placeholder="Provide an explanation for this question and its answer"><?php echo isset($_POST['explanation']) ? htmlspecialchars($_POST['explanation']) : htmlspecialchars($question['explanation']); ?></textarea>
<small class="form-text text-muted">
This will be shown to students after they answer or in review mode.
</small>
</div>
<div class="mt-4">
<button type="submit" class="btn btn-primary">Update Question</button>
<a href="questions.php?bank_id=<?php echo $bank_id; ?>" class="btn btn-secondary">Cancel</a>
</div>
</form>
</div>
</div>
</div>
<script>
$(document).ready(function() {
// Handle question type change
$('#question_type').change(function() {
// Hide all options sections
$('.options-section').hide();
// Show the relevant section based on the selected type
var selectedType = $(this).val();
switch(selectedType) {
case 'multiple_choice':
$('#multiple_choice_options').show();
break;
case 'true_false':
$('#true_false_options').show();
break;
case 'short_answer':
$('#short_answer_options').show();
break;
case 'essay':
$('#essay_options').show();
break;
}
});
// Trigger change to show the correct options section initially
$('#question_type').trigger('change');
// Add option button
$('#add_option').click(function() {
var optionCount = $('.option-row').length;
var newOption = `
<div class="option-row mb-2">
<div class="input-group">
<div class="input-group-prepend">
<div class="input-group-text">
<input type="checkbox" name="correct_options[]" value="${optionCount}">
</div>
</div>
<input type="text" class="form-control" name="options[]" placeholder="Option ${optionCount + 1}">
<div class="input-group-append">
<button type="button" class="btn btn-danger remove-option">
<i class="fas fa-times"></i>
</button>
</div>
</div>
</div>
`;
$('#options_container').append(newOption);
// Enable remove buttons if we have more than 2 options
if (optionCount + 1 > 2) {
$('.remove-option').prop('disabled', false);
}
});
// Remove option button (delegated event for dynamically added elements)
$('#options_container').on('click', '.remove-option', function() {
$(this).closest('.option-row').remove();
// Update value attributes for correct_options checkboxes
$('.option-row').each(function(index) {
$(this).find('input[type="checkbox"]').val(index);
$(this).find('input[type="text"]').attr('placeholder', 'Option ' + (index + 1));
});
// Disable remove buttons if we have 2 or fewer options
if ($('.option-row').length <= 2) {
$('.remove-option').prop('disabled', true);
}
});
// Form validation before submit
$('#questionForm').submit(function(e) {
var isValid = true;
var questionType = $('#question_type').val();
// Check if question type specific validations pass
if (questionType === 'multiple_choice') {
if ($('.option-row').length < 2) {
alert('Multiple choice questions must have at least 2 options');
isValid = false;
}
if ($('input[name="correct_options[]"]:checked').length === 0) {
alert('Please select at least one correct option');
isValid = false;
}
// Check if all options have text
$('.option-row input[type="text"]').each(function() {
if ($(this).val().trim() === '') {
alert('All options must have text');
isValid = false;
return false; // break the loop
}
});
} else if (questionType === 'true_false') {
if (!$('input[name="true_false_answer"]:checked').val()) {
alert('Please select True or False as the correct answer');
isValid = false;
}
} else if (questionType === 'short_answer') {
if ($('#answer_key').val().trim() === '') {
alert('Please provide an answer key for the short answer question');
isValid = false;
}
}
if (!isValid) {
e.preventDefault();
}
});
// Handle True/False special case
$('input[name="true_false_answer"]').change(function() {
if ($(this).val() === 'true') {
// Set up hidden inputs for true/false options
if ($('#true_false_hidden').length === 0) {
$('#true_false_options').append(`
<div id="true_false_hidden" style="display: none;">
<input type="hidden" name="options[]" value="True">
<input type="hidden" name="options[]" value="False">
<input type="hidden" name="correct_options[]" value="0">
</div>
`);
} else {
$('#true_false_hidden').html(`
<input type="hidden" name="options[]" value="True">
<input type="hidden" name="options[]" value="False">
<input type="hidden" name="correct_options[]" value="0">
`);
}
} else {
if ($('#true_false_hidden').length === 0) {
$('#true_false_options').append(`
<div id="true_false_hidden" style="display: none;">
<input type="hidden" name="options[]" value="True">
<input type="hidden" name="options[]" value="False">
<input type="hidden" name="correct_options[]" value="1">
</div>
`);
} else {
$('#true_false_hidden').html(`
<input type="hidden" name="options[]" value="True">
<input type="hidden" name="options[]" value="False">
<input type="hidden" name="correct_options[]" value="1">
`);
}
}
});
// Trigger true/false radio buttons if needed
if ($('#question_type').val() === 'true_false') {
// If none checked, default to true
if (!$('input[name="true_false_answer"]:checked').length) {
$('#true_option').prop('checked', true);
}
$('input[name="true_false_answer"]:checked').trigger('change');
}
});
</script>
<?php
// Include footer
include 'includes/footer.php';
?>