diff --git a/main/exercise/multiple_answer.class.php b/main/exercise/multiple_answer.class.php index d229587d24a..c3e69b85e84 100755 --- a/main/exercise/multiple_answer.class.php +++ b/main/exercise/multiple_answer.class.php @@ -184,11 +184,58 @@ public function createAnswersForm($form) $form->setConstants(['nb_answers' => $nb_answers]); } + /** + * Validate question answers before saving. + * + * @param object $form The form object. + * @return array|bool True if valid, or an array with errors if invalid. + */ + public function validateAnswers($form) + { + $nb_answers = $form->getSubmitValue('nb_answers'); + $hasCorrectAnswer = false; + $hasValidWeighting = false; + $errors = []; + $error_fields = []; + + for ($i = 1; $i <= $nb_answers; $i++) { + $isCorrect = $form->getSubmitValue("correct[$i]"); + $weighting = trim($form->getSubmitValue("weighting[$i]") ?? ''); + + if ($isCorrect) { + $hasCorrectAnswer = true; + + if (is_numeric($weighting) && floatval($weighting) > 0) { + $hasValidWeighting = true; + } + } + } + + if (!$hasCorrectAnswer) { + $errors[] = get_lang('AtLeastOneCorrectAnswerRequired'); + $error_fields[] = "correct"; + } + + if ($hasCorrectAnswer && !$hasValidWeighting) { + // Only show if at least one correct answer exists but its weighting is not valid + $errors[] = get_lang('AtLeastOneCorrectAnswerMustHaveAPositiveScore'); + } + + return empty($errors) ? true : ['errors' => $errors, 'error_fields' => $error_fields]; + } + /** * {@inheritdoc} */ public function processAnswersCreation($form, $exercise) { + $validationResult = $this->validateAnswers($form); + if ($validationResult !== true) { + Display::addFlash(Display::return_message(implode("
", $validationResult['errors']), 'error')); + + return; + } + $questionWeighting = 0; $objAnswer = new Answer($this->iid); $nb_answers = $form->getSubmitValue('nb_answers'); diff --git a/main/exercise/question_admin.inc.php b/main/exercise/question_admin.inc.php index 44573ca2a21..2560d044104 100755 --- a/main/exercise/question_admin.inc.php +++ b/main/exercise/question_admin.inc.php @@ -51,50 +51,53 @@ } // FORM VALIDATION - if (isset($_POST['submitQuestion']) && $form->validate()) { - // Question - $objQuestion->processCreation($form, $objExercise); - $objQuestion->processAnswersCreation($form, $objExercise); - // TODO: maybe here is the better place to index this tool, including answers text - // redirect - if (in_array($objQuestion->type, [HOT_SPOT, HOT_SPOT_COMBINATION, HOT_SPOT_DELINEATION])) { - echo ''; - } elseif (in_array($objQuestion->type, [MULTIPLE_ANSWER_DROPDOWN, MULTIPLE_ANSWER_DROPDOWN_COMBINATION])) { - $url = 'admin.php?' - .api_get_cidreq().'&' - .http_build_query(['exerciseId' => $exerciseId, 'page' => $page, 'mad_admin' => $objQuestion->iid]); - echo ''; - } else { - if (isset($_GET['editQuestion'])) { - if (empty($exerciseId)) { - Display::addFlash(Display::return_message(get_lang('ItemUpdated'))); - $url = 'admin.php?exerciseId='.$exerciseId.'&'.api_get_cidreq().'&editQuestion='.$objQuestion->iid; - echo ''; - exit; - } - echo ''; + if (isset($_POST['submitQuestion'])) { + $validationResult = true; + if (method_exists($objQuestion, 'validateAnswers')) { + $validationResult = $objQuestion->validateAnswers($form); + } + if (is_array($validationResult) && !empty($validationResult['errors'])) { + echo Display::return_message(implode("
", $validationResult['errors']), 'error', false); + } elseif ($form->validate()) { + $objQuestion->processCreation($form, $objExercise); + $objQuestion->processAnswersCreation($form, $objExercise); + if (in_array($objQuestion->type, [HOT_SPOT, HOT_SPOT_COMBINATION, HOT_SPOT_DELINEATION])) { + echo ''; + } elseif (in_array($objQuestion->type, [MULTIPLE_ANSWER_DROPDOWN, MULTIPLE_ANSWER_DROPDOWN_COMBINATION])) { + $url = 'admin.php?'.api_get_cidreq().'&'.http_build_query(['exerciseId' => $exerciseId, 'page' => $page, 'mad_admin' => $objQuestion->iid]); + echo ''; } else { - // New question - $page = 1; - $length = api_get_configuration_value('question_pagination_length'); - if (!empty($length)) { - $page = round($objExercise->getQuestionCount() / $length); + if (isset($_GET['editQuestion'])) { + if (empty($exerciseId)) { + Display::addFlash(Display::return_message(get_lang('ItemUpdated'))); + $url = 'admin.php?exerciseId='.$exerciseId.'&'.api_get_cidreq().'&editQuestion='.$objQuestion->iid; + echo ''; + exit; + } + echo ''; + } else { + // New question + $page = 1; + $length = api_get_configuration_value('question_pagination_length'); + if (!empty($length)) { + $page = round($objExercise->getQuestionCount() / $length); + } + echo ''; } - echo ''; } + exit(); } - } else { - if (isset($questionName)) { - echo '

'.$questionName.'

'; - } - if (!empty($pictureName)) { - echo ''; - } - if (!empty($msgErr)) { - echo Display::return_message($msgErr); - } - // display the form - $form->display(); } + + if (isset($questionName)) { + echo '

'.$questionName.'

'; + } + if (!empty($pictureName)) { + echo ''; + } + if (!empty($msgErr)) { + echo Display::return_message($msgErr); + } + + $form->display(); } diff --git a/main/exercise/unique_answer.class.php b/main/exercise/unique_answer.class.php index bb60d918a39..9696d1df5b7 100755 --- a/main/exercise/unique_answer.class.php +++ b/main/exercise/unique_answer.class.php @@ -335,11 +335,64 @@ public function setDirectOptions($i, FormValidator $form, $renderer, $select_lp_ ); } + /** + * Validate question answers before saving. + * @return bool|string True if valid, error message if invalid. + */ + public function validateAnswers($form) + { + $correct = $form->getSubmitValue('correct'); + $nb_answers = $form->getSubmitValue('nb_answers'); + $hasCorrectAnswer = false; + $hasPositiveScore = false; + $errors = []; + $error_fields = []; + + for ($i = 1; $i <= $nb_answers; $i++) { + $answer = trim($form->getSubmitValue("answer[$i]") ?? ''); + $weighting = trim($form->getSubmitValue("weighting[$i]") ?? ''); + $isCorrect = ($correct == $i); + if (empty($answer)) { + $errors[] = sprintf(get_lang('NoAnswerCanBeEmpty'), $i); + $error_fields[] = "answer[$i]"; + } + + if ($weighting === '' || !is_numeric($weighting)) { + $errors[] = sprintf(get_lang('ScoreMustBeNumeric'), $i); + $error_fields[] = "weighting[$i]"; + } + + if ($isCorrect) { + $hasCorrectAnswer = true; + if (floatval($weighting) > 0) { + $hasPositiveScore = true; + } + } + } + + if (!$hasCorrectAnswer) { + $errors[] = get_lang('ACorrectAnswerIsRequired'); + $error_fields[] = "correct"; + } + + if (!$hasPositiveScore) { + $errors[] = get_lang('TheCorrectAnswerMustHaveAPositiveScore'); + } + + return empty($errors) ? true : ['errors' => $errors, 'error_fields' => $error_fields]; + } + /** * {@inheritdoc} */ public function processAnswersCreation($form, $exercise) { + $validationResult = $this->validateAnswers($form); + if ($validationResult !== true) { + Display::addFlash(Display::return_message(implode("
", $validationResult['errors']), 'error')); + return; + } + $questionWeighting = $nbrGoodAnswers = 0; $correct = $form->getSubmitValue('correct'); $objAnswer = new Answer($this->iid);