id = 0; $this->exercise = ''; $this->description = ''; $this->sound = ''; $this->type = ALL_ON_ONE_PAGE; $this->random = 0; $this->random_answers = 0; $this->active = 1; $this->questionList = array(); $this->timeLimit = 0; $this->end_time = '0000-00-00 00:00:00'; $this->start_time = '0000-00-00 00:00:00'; $this->results_disabled = 1; $this->expired_time = '0000-00-00 00:00:00'; $this->propagate_neg = 0; $this->review_answers = false; $this->randomByCat = 0; // $this->text_when_finished = ""; // $this->display_category_name = 0; $this->pass_percentage = null; $this->modelType = 1; $this->questionSelectionType = EX_Q_SELECTION_ORDERED; $this->endButton = 0; $this->scoreTypeModel = 0; $this->globalCategoryId = null; if (!empty($course_id)) { $course_info = api_get_course_info_by_id($course_id); } else { $course_info = api_get_course_info(); } $this->course_id = $course_info['real_id']; $this->course = $course_info; $this->specialCategoryOrders = api_get_configuration_value('exercise_enable_category_order'); } /** * Reads exercise information from the data base * * @author Olivier Brouckaert * @param integer $id - exercise Id * * @return boolean - true if exercise exists, otherwise false */ public function read($id, $parseQuestionList = true) { global $_configuration; $TBL_EXERCICES = Database::get_course_table(TABLE_QUIZ_TEST); $table_lp_item = Database::get_course_table(TABLE_LP_ITEM); $id = intval($id); if (empty($this->course_id)) { return false; } $sql = "SELECT * FROM $TBL_EXERCICES WHERE c_id = ".$this->course_id." AND id = ".$id; $result = Database::query($sql); // if the exercise has been found if ($object = Database::fetch_object($result)) { $this->id = $id; $this->exercise = $object->title; $this->name = $object->title; $this->title = $object->title; $this->description = $object->description; $this->sound = $object->sound; $this->type = $object->type; if (empty($this->type)) { $this->type = ONE_PER_PAGE; } $this->random = $object->random; $this->random_answers = $object->random_answers; $this->active = $object->active; $this->results_disabled = $object->results_disabled; $this->attempts = $object->max_attempt; $this->feedback_type = $object->feedback_type; $this->propagate_neg = $object->propagate_neg; $this->randomByCat = $object->random_by_category; $this->text_when_finished = $object->text_when_finished; $this->display_category_name = $object->display_category_name; $this->pass_percentage = $object->pass_percentage; $this->sessionId = $object->session_id; $this->is_gradebook_locked = api_resource_is_locked_by_gradebook($id, LINK_EXERCISE); $this->review_answers = (isset($object->review_answers) && $object->review_answers == 1) ? true : false; $this->globalCategoryId = isset($object->global_category_id) ? $object->global_category_id : null; $this->questionSelectionType = isset($object->question_selection_type) ? $object->question_selection_type : null; $sql = "SELECT lp_id, max_score FROM $table_lp_item WHERE c_id = {$this->course_id} AND item_type = '".TOOL_QUIZ."' AND path = '".$id."'"; $result = Database::query($sql); if (Database::num_rows($result) > 0) { $this->exercise_was_added_in_lp = true; $this->lpList = Database::store_result($result, 'ASSOC'); } $this->force_edit_exercise_in_lp = isset($_configuration['force_edit_exercise_in_lp']) ? $_configuration['force_edit_exercise_in_lp'] : false; if ($this->exercise_was_added_in_lp) { $this->edit_exercise_in_lp = $this->force_edit_exercise_in_lp == true; } else { $this->edit_exercise_in_lp = true; } if ($object->end_time != '0000-00-00 00:00:00') { $this->end_time = $object->end_time; } if ($object->start_time != '0000-00-00 00:00:00') { $this->start_time = $object->start_time; } //control time $this->expired_time = $object->expired_time; //Checking if question_order is correctly set //$this->questionList = $this->selectQuestionList(true); if ($parseQuestionList) { $this->setQuestionList(); } //overload questions list with recorded questions list //load questions only for exercises of type 'one question per page' //this is needed only is there is no questions /* // @todo not sure were in the code this is used somebody mess with the exercise tool // @todo don't know who add that config and why $_configuration['live_exercise_tracking'] global $_configuration, $questionList; if ($this->type == ONE_PER_PAGE && $_SERVER['REQUEST_METHOD'] != 'POST' && defined('QUESTION_LIST_ALREADY_LOGGED') && isset($_configuration['live_exercise_tracking']) && $_configuration['live_exercise_tracking']) { $this->questionList = $questionList; }*/ return true; } return false; } /** * @return string */ public function getCutTitle() { return cut($this->exercise, EXERCISE_MAX_NAME_SIZE); } /** * returns the exercise ID * * @author Olivier Brouckaert * @return int - exercise ID */ public function selectId() { return $this->id; } /** * returns the exercise title * * @author Olivier Brouckaert * @return string - exercise title */ public function selectTitle() { return $this->exercise; } /** * returns the number of attempts setted * * @return int - exercise attempts */ public function selectAttempts() { return $this->attempts; } /** returns the number of FeedbackType * * 0=>Feedback , 1=>DirectFeedback, 2=>NoFeedback * @return int - exercise attempts */ public function selectFeedbackType() { return $this->feedback_type; } /** * returns the time limit */ public function selectTimeLimit() { return $this->timeLimit; } /** * returns the exercise description * * @author Olivier Brouckaert * @return string - exercise description */ public function selectDescription() { return $this->description; } /** * returns the exercise sound file * * @author Olivier Brouckaert * @return string - exercise description */ public function selectSound() { return $this->sound; } /** * returns the exercise type * * @author Olivier Brouckaert * @return integer - exercise type */ public function selectType() { return $this->type; } /** * @return string */ public function selectEmailNotificationTemplate() { return $this->emailNotificationTemplate; } /** * @return string */ public function selectEmailNotificationTemplateToUser() { return $this->emailNotificationTemplateToUser; } /** * @return string */ public function getNotifyUserByEmail() { return $this->notifyUserByEmail; } /** * @return int */ public function getModelType() { return $this->modelType; } /** * @return int */ public function selectEndButton() { return $this->endButton; } /** * @return string */ public function getOnSuccessMessage() { return $this->onSuccessMessage; } /** * @return string */ public function getOnFailedMessage() { return $this->onFailedMessage; } /** * @author hubert borderiou 30-11-11 * @return integer : do we display the question category name for students */ public function selectDisplayCategoryName() { return $this->display_category_name; } /** * @return int */ public function selectPassPercentage() { return $this->pass_percentage; } /** * * Modify object to update the switch display_category_name * @author hubert borderiou 30-11-11 * @param int $in_txt is an integer 0 or 1 */ public function updateDisplayCategoryName($in_txt) { $this->display_category_name = $in_txt; } /** * @author hubert borderiou 28-11-11 * @return string html text : the text to display ay the end of the test. */ public function selectTextWhenFinished() { return $this->text_when_finished; } /** * @author hubert borderiou 28-11-11 * @return string html text : update the text to display ay the end of the test. */ public function updateTextWhenFinished($in_txt) { $this->text_when_finished = $in_txt; } /** * return 1 or 2 if randomByCat * @author hubert borderiou * @return integer - quiz random by category */ public function selectRandomByCat() { return $this->randomByCat; } /** * return 0 if no random by cat * return 1 if random by cat, categories shuffled * return 2 if random by cat, categories sorted by alphabetic order * @author hubert borderiou * @return integer - quiz random by category */ public function isRandomByCat() { /*$res = 0; if ($this->randomByCat == 1) { $res = 1; } else if ($this->randomByCat == 2) { $res = 2; } */ $res = EXERCISE_CATEGORY_RANDOM_DISABLED; if ($this->randomByCat == EXERCISE_CATEGORY_RANDOM_SHUFFLED) { $res = EXERCISE_CATEGORY_RANDOM_SHUFFLED; } else if ($this->randomByCat == EXERCISE_CATEGORY_RANDOM_ORDERED) { $res = EXERCISE_CATEGORY_RANDOM_ORDERED; } return $res; } /** * return nothing * update randomByCat value for object * @param int $random * * @author hubert borderiou */ public function updateRandomByCat($random) { if ($this->specialCategoryOrders) { if (in_array($random, array( EXERCISE_CATEGORY_RANDOM_SHUFFLED, EXERCISE_CATEGORY_RANDOM_ORDERED, EXERCISE_CATEGORY_RANDOM_DISABLED ) )) { $this->randomByCat = $random; } else { $this->randomByCat = EXERCISE_CATEGORY_RANDOM_DISABLED; } } else { if ($random == 1) { $this->randomByCat = 1; } else if ($random == 2) { $this->randomByCat = 2; } else { $this->randomByCat = 0; } } } /** * Tells if questions are selected randomly, and if so returns the draws * * @author Carlos Vargas * @return integer - results disabled exercise */ public function selectResultsDisabled() { return $this->results_disabled; } /** * tells if questions are selected randomly, and if so returns the draws * * @author Olivier Brouckaert * @return integer - 0 if not random, otherwise the draws */ public function isRandom() { if ($this->random > 0 || $this->random == -1) { return true; } else { return false; } } /** * returns random answers status. * * @author Juan Carlos Rana */ public function selectRandomAnswers() { return $this->random_answers; } /** * Same as isRandom() but has a name applied to values different than 0 or 1 */ public function getShuffle() { return $this->random; } /** * returns the exercise status (1 = enabled ; 0 = disabled) * * @author Olivier Brouckaert * @return boolean - true if enabled, otherwise false */ public function selectStatus() { return $this->active; } /** * If false the question list will be managed as always if true the question will be filtered * depending of the exercise settings (table c_quiz_rel_category) * @param bool active or inactive grouping **/ public function setCategoriesGrouping($status) { $this->categories_grouping = (bool) $status; } /** * @return int */ public function getHideQuestionTitle() { return $this->hideQuestionTitle; } /** * @param $value */ public function setHideQuestionTitle($value) { $this->hideQuestionTitle = intval($value); } /** * @return int */ public function getScoreTypeModel() { return $this->scoreTypeModel; } /** * @param int $value */ public function setScoreTypeModel($value) { $this->scoreTypeModel = intval($value); } /** * @return int */ public function getGlobalCategoryId() { return $this->globalCategoryId; } /** * @param int $value */ public function setGlobalCategoryId($value) { if (is_array($value) && isset($value[0])) { $value = $value[0]; } $this->globalCategoryId = intval($value); } /** * * @param int $start * @param int $limit * @param int $sidx * @param string $sord * @param array $where_condition * @param array $extraFields */ public function getQuestionListPagination($start, $limit, $sidx, $sord, $where_condition = array(), $extraFields = array()) { if (!empty($this->id)) { $category_list = Testcategory::getListOfCategoriesNameForTest($this->id, false); //$category_list = Testcategory::getListOfCategoriesIDForTestObject($this); $TBL_EXERCICE_QUESTION = Database::get_course_table(TABLE_QUIZ_TEST_QUESTION); $TBL_QUESTIONS = Database::get_course_table(TABLE_QUIZ_QUESTION); $sql = "SELECT q.iid FROM $TBL_EXERCICE_QUESTION e INNER JOIN $TBL_QUESTIONS q ON (e.question_id = q.iid AND e.c_id = ".$this->course_id." ) WHERE e.exercice_id = '".Database::escape_string($this->id)."' "; $orderCondition = "ORDER BY question_order"; if (!empty($sidx) && !empty($sord)) { if ($sidx == 'question') { if (in_array(strtolower($sord), array('desc', 'asc'))) { $orderCondition = " ORDER BY q.$sidx $sord"; } } } $sql .= $orderCondition; $limitCondition = null; if (isset($start) && isset($limit)) { $start = intval($start); $limit = intval($limit); $limitCondition = " LIMIT $start, $limit"; } $sql .= $limitCondition; $result = Database::query($sql); $questions = array(); if (Database::num_rows($result)) { if (!empty($extraFields)) { $extraFieldValue = new ExtraFieldValue('question'); } while ($question = Database::fetch_array($result, 'ASSOC')) { /** @var Question $objQuestionTmp */ $objQuestionTmp = Question::read($question['iid']); $category_labels = Testcategory::return_category_labels($objQuestionTmp->category_list, $category_list); if (empty($category_labels)) { $category_labels = "-"; } // Question type list($typeImg, $typeExpl) = $objQuestionTmp->get_type_icon_html(); $question_media = null; if (!empty($objQuestionTmp->parent_id)) { $objQuestionMedia = Question::read($objQuestionTmp->parent_id); $question_media = Question::getMediaLabel($objQuestionMedia->question); } $questionType = Display::tag('div', Display::return_icon($typeImg, $typeExpl, array(), ICON_SIZE_MEDIUM).$question_media); $question = array( 'id' => $question['iid'], 'question' => $objQuestionTmp->selectTitle(), 'type' => $questionType, 'category' => Display::tag('div', ''.$category_labels.''), 'score' => $objQuestionTmp->selectWeighting(), 'level' => $objQuestionTmp->level ); if (!empty($extraFields)) { foreach ($extraFields as $extraField) { $value = $extraFieldValue->get_values_by_handler_and_field_id($question['id'], $extraField['id']); $stringValue = null; if ($value) { $stringValue = $value['field_value']; } $question[$extraField['field_variable']] = $stringValue; } } $questions[] = $question; } } return $questions; } } /** * Get question count per exercise from DB (any special treatment) * @return int */ public function getQuestionCount() { $TBL_EXERCICE_QUESTION = Database::get_course_table(TABLE_QUIZ_TEST_QUESTION); $TBL_QUESTIONS = Database::get_course_table(TABLE_QUIZ_QUESTION); $sql = "SELECT count(q.id) as count FROM $TBL_EXERCICE_QUESTION e INNER JOIN $TBL_QUESTIONS q ON (e.question_id = q.id) WHERE e.c_id = {$this->course_id} AND e.exercice_id = ".Database::escape_string($this->id); $result = Database::query($sql); $count = 0; if (Database::num_rows($result)) { $row = Database::fetch_array($result); $count = $row['count']; } return $count; } /** * @return array */ public function getQuestionOrderedListByName() { $TBL_EXERCICE_QUESTION = Database::get_course_table(TABLE_QUIZ_TEST_QUESTION); $TBL_QUESTIONS = Database::get_course_table(TABLE_QUIZ_QUESTION); // Getting question list from the order (question list drag n drop interface ). $sql = "SELECT e.question_id FROM $TBL_EXERCICE_QUESTION e INNER JOIN $TBL_QUESTIONS q ON (e.question_id= q.id) WHERE e.c_id = {$this->course_id} AND e.exercice_id = '".Database::escape_string($this->id)."' ORDER BY q.question"; $result = Database::query($sql); $list = array(); if (Database::num_rows($result)) { $list = Database::store_result($result, 'ASSOC'); } return $list; } /** * Gets the question list ordered by the question_order setting (drag and drop) * @return array */ private function getQuestionOrderedList() { $questionList = array(); $TBL_EXERCICE_QUESTION = Database::get_course_table(TABLE_QUIZ_TEST_QUESTION); $TBL_QUESTIONS = Database::get_course_table(TABLE_QUIZ_QUESTION); // Getting question_order to verify that the question // list is correct and all question_order's were set $sql = "SELECT DISTINCT e.question_order FROM $TBL_EXERCICE_QUESTION e INNER JOIN $TBL_QUESTIONS q ON (e.question_id = q.id) WHERE e.c_id = {$this->course_id} AND e.exercice_id = ".Database::escape_string($this->id); $result = Database::query($sql); $count_question_orders = Database::num_rows($result); // Getting question list from the order (question list drag n drop interface ). $sql = "SELECT DISTINCT e.question_id, e.question_order FROM $TBL_EXERCICE_QUESTION e INNER JOIN $TBL_QUESTIONS q ON (e.question_id= q.id) WHERE e.c_id = {$this->course_id} AND e.exercice_id = '".Database::escape_string($this->id)."' ORDER BY question_order"; $result = Database::query($sql); // Fills the array with the question ID for this exercise // the key of the array is the question position $temp_question_list = array(); $counter = 1; while ($new_object = Database::fetch_object($result)) { // Correct order. $questionList[$new_object->question_order] = $new_object->question_id; // Just in case we save the order in other array $temp_question_list[$counter] = $new_object->question_id; $counter++; } if (!empty($temp_question_list)) { /* If both array don't match it means that question_order was not correctly set for all questions using the default mysql order */ if (count($temp_question_list) != $count_question_orders) { $questionList = $temp_question_list; } } return $questionList; } /** * Select N values from the questions per category array * * @param array $categoriesAddedInExercise * @param array $question_list * @param array $questions_by_category per category * @param bool $flatResult * @param bool $randomizeQuestions * * @return array */ private function pickQuestionsPerCategory( $categoriesAddedInExercise, $question_list, & $questions_by_category, $flatResult = true, $randomizeQuestions = false ) { $addAll = true; $categoryCountArray = array(); // Getting how many questions will be selected per category. if (!empty($categoriesAddedInExercise)) { $addAll = false; // Parsing question according the category rel exercise settings foreach ($categoriesAddedInExercise as $category_info) { $category_id = $category_info['category_id']; if (isset($questions_by_category[$category_id])) { // How many question will be picked from this category. $count = $category_info['count_questions']; // -1 means all questions if ($count == -1) { $categoryCountArray[$category_id] = 999; } else { $categoryCountArray[$category_id] = $count; } } } } if (!empty($questions_by_category)) { $temp_question_list = array(); foreach ($questions_by_category as $category_id => & $categoryQuestionList) { if (isset($categoryCountArray) && !empty($categoryCountArray)) { if (isset($categoryCountArray[$category_id])) { $numberOfQuestions = $categoryCountArray[$category_id]; } else { $numberOfQuestions = 0; } } if ($addAll) { $numberOfQuestions = 999; } if (!empty($numberOfQuestions)) { $elements = Testcategory::getNElementsFromArray( $categoryQuestionList, $numberOfQuestions, $randomizeQuestions ); if (!empty($elements)) { $temp_question_list[$category_id] = $elements; $categoryQuestionList = $elements; } } } if (!empty($temp_question_list)) { if ($flatResult) { $temp_question_list = array_flatten($temp_question_list); } $question_list = $temp_question_list; } } return $question_list; } /** * Selecting question list depending in the exercise-category * relationship (category table in exercise settings) * * @param array $question_list * @param int $questionSelectionType * @return array */ public function getQuestionListWithCategoryListFilteredByCategorySettings($question_list, $questionSelectionType) { $result = array( 'question_list' => array(), 'category_with_questions_list' => array() ); // Order/random categories $cat = new Testcategory(); // Setting category order. switch ($questionSelectionType) { case EX_Q_SELECTION_ORDERED: // 1 case EX_Q_SELECTION_RANDOM: // 2 // This options are not allowed here. break; case EX_Q_SELECTION_CATEGORIES_ORDERED_QUESTIONS_ORDERED: // 3 $categoriesAddedInExercise = $cat->getCategoryExerciseTree( $this, $this->course['real_id'], 'title ASC', false, true ); $questions_by_category = Testcategory::getQuestionsByCat( $this->id, $question_list, $categoriesAddedInExercise ); $question_list = $this->pickQuestionsPerCategory( $categoriesAddedInExercise, $question_list, $questions_by_category, true, false ); break; case EX_Q_SELECTION_CATEGORIES_RANDOM_QUESTIONS_ORDERED: // 4 case EX_Q_SELECTION_CATEGORIES_RANDOM_QUESTIONS_ORDERED_NO_GROUPED: // 7 $categoriesAddedInExercise = $cat->getCategoryExerciseTree( $this, $this->course['real_id'], null, true, true ); $questions_by_category = Testcategory::getQuestionsByCat( $this->id, $question_list, $categoriesAddedInExercise ); $question_list = $this->pickQuestionsPerCategory( $categoriesAddedInExercise, $question_list, $questions_by_category, true, false ); break; case EX_Q_SELECTION_CATEGORIES_ORDERED_QUESTIONS_RANDOM: // 5 $categoriesAddedInExercise = $cat->getCategoryExerciseTree( $this, $this->course['real_id'], 'title DESC', false, true ); $questions_by_category = Testcategory::getQuestionsByCat( $this->id, $question_list, $categoriesAddedInExercise ); $question_list = $this->pickQuestionsPerCategory( $categoriesAddedInExercise, $question_list, $questions_by_category, true, true ); break; case EX_Q_SELECTION_CATEGORIES_RANDOM_QUESTIONS_RANDOM: // 6 case EX_Q_SELECTION_CATEGORIES_RANDOM_QUESTIONS_RANDOM_NO_GROUPED: $categoriesAddedInExercise = $cat->getCategoryExerciseTree( $this, $this->course['real_id'], null, true, true ); $questions_by_category = Testcategory::getQuestionsByCat( $this->id, $question_list, $categoriesAddedInExercise ); $question_list = $this->pickQuestionsPerCategory( $categoriesAddedInExercise, $question_list, $questions_by_category, true, true ); break; case EX_Q_SELECTION_CATEGORIES_RANDOM_QUESTIONS_ORDERED_NO_GROUPED: // 7 break; case EX_Q_SELECTION_CATEGORIES_RANDOM_QUESTIONS_RANDOM_NO_GROUPED: // 8 break; case EX_Q_SELECTION_CATEGORIES_ORDERED_BY_PARENT_QUESTIONS_ORDERED: // 9 $categoriesAddedInExercise = $cat->getCategoryExerciseTree( $this, $this->course['real_id'], 'root ASC, lft ASC', false, true ); $questions_by_category = Testcategory::getQuestionsByCat( $this->id, $question_list, $categoriesAddedInExercise ); $question_list = $this->pickQuestionsPerCategory( $categoriesAddedInExercise, $question_list, $questions_by_category, true, false ); break; case EX_Q_SELECTION_CATEGORIES_ORDERED_BY_PARENT_QUESTIONS_RANDOM: // 10 $categoriesAddedInExercise = $cat->getCategoryExerciseTree( $this, $this->course['real_id'], 'root, lft ASC', false, true ); $questions_by_category = Testcategory::getQuestionsByCat( $this->id, $question_list, $categoriesAddedInExercise ); $question_list = $this->pickQuestionsPerCategory( $categoriesAddedInExercise, $question_list, $questions_by_category, true, true ); break; } $result['question_list'] = isset($question_list) ? $question_list : array(); $result['category_with_questions_list'] = isset($questions_by_category) ? $questions_by_category : array(); // Adding category info in the category list with question list: if (!empty($questions_by_category)) { /*$em = Database::getManager(); $repo = $em->getRepository('ChamiloCoreBundle:CQuizCategory');*/ $newCategoryList = array(); foreach ($questions_by_category as $categoryId => $questionList) { $cat = new Testcategory($categoryId); $cat = (array)$cat; $cat['iid'] = $cat['id']; //*$cat['name'] = $cat['name']; $categoryParentInfo = null; // Parent is not set no loop here if (!empty($cat['parent_id'])) { if (!isset($parentsLoaded[$cat['parent_id']])) { $categoryEntity = $em->find('ChamiloCoreBundle:CQuizCategory', $cat['parent_id']); $parentsLoaded[$cat['parent_id']] = $categoryEntity; } else { $categoryEntity = $parentsLoaded[$cat['parent_id']]; } $path = $repo->getPath($categoryEntity); $index = 0; if ($this->categoryMinusOne) { //$index = 1; } /** @var \Chamilo\Entity\CQuizCategory $categoryParent*/ foreach ($path as $categoryParent) { $visibility = $categoryParent->getVisibility(); if ($visibility == 0) { $categoryParentId = $categoryId; $categoryTitle = $cat['title']; if (count($path) > 1) { continue; } } else { $categoryParentId = $categoryParent->getIid(); $categoryTitle = $categoryParent->getTitle(); } $categoryParentInfo['id'] = $categoryParentId; $categoryParentInfo['iid'] = $categoryParentId; $categoryParentInfo['parent_path'] = null; $categoryParentInfo['title'] = $categoryTitle; $categoryParentInfo['name'] = $categoryTitle; $categoryParentInfo['parent_id'] = null; break; } } $cat['parent_info'] = $categoryParentInfo; $newCategoryList[$categoryId] = array( 'category' => $cat, 'question_list' => $questionList ); } $result['category_with_questions_list'] = $newCategoryList; } return $result; } /** * returns the array with the question ID list * * @author Olivier Brouckaert * @return array - question ID list */ public function selectQuestionList($from_db = false) { if ($this->specialCategoryOrders == false) { if ($from_db && !empty($this->id)) { $TBL_EXERCICE_QUESTION = Database::get_course_table( TABLE_QUIZ_TEST_QUESTION ); $TBL_QUESTIONS = Database::get_course_table( TABLE_QUIZ_QUESTION ); $sql = "SELECT DISTINCT e.question_order FROM $TBL_EXERCICE_QUESTION e INNER JOIN $TBL_QUESTIONS q ON (e.question_id = q.id AND e.c_id = ".$this->course_id." AND q.c_id = ".$this->course_id.") WHERE e.exercice_id = ".intval($this->id); $result = Database::query($sql); $count_question_orders = Database::num_rows($result); $sql = "SELECT e.question_id, e.question_order FROM $TBL_EXERCICE_QUESTION e INNER JOIN $TBL_QUESTIONS q ON (e.question_id= q.id AND e.c_id = ".$this->course_id." AND q.c_id = ".$this->course_id.") WHERE e.exercice_id = ".intval($this->id)." ORDER BY question_order"; $result = Database::query($sql); // fills the array with the question ID for this exercise // the key of the array is the question position $temp_question_list = array(); $counter = 1; $question_list = array(); while ($new_object = Database::fetch_object($result)) { $question_list[$new_object->question_order] = $new_object->question_id; $temp_question_list[$counter] = $new_object->question_id; $counter++; } if (!empty($temp_question_list)) { if (count($temp_question_list) != $count_question_orders) { $question_list = $temp_question_list; } } return $question_list; } return $this->questionList; } else { if ($from_db && !empty($this->id)) { $nbQuestions = $this->getQuestionCount(); $questionSelectionType = $this->getQuestionSelectionType(); switch ($questionSelectionType) { case EX_Q_SELECTION_ORDERED: $questionList = $this->getQuestionOrderedList(); break; case EX_Q_SELECTION_RANDOM: // Not a random exercise, or if there are not at least 2 questions if ($this->random == 0 || $nbQuestions < 2) { $questionList = $this->getQuestionOrderedList(); } else { $questionList = $this->selectRandomList(); } break; default: $questionList = $this->getQuestionOrderedList(); $result = $this->getQuestionListWithCategoryListFilteredByCategorySettings( $questionList, $questionSelectionType ); $this->categoryWithQuestionList = $result['category_with_questions_list']; $questionList = $result['question_list']; break; } return $questionList; } return $this->questionList; } } /** * returns the number of questions in this exercise * * @author Olivier Brouckaert * @return integer - number of questions */ public function selectNbrQuestions() { return sizeof($this->questionList); } /** * @return int */ public function selectPropagateNeg() { return $this->propagate_neg; } /** * Selects questions randomly in the question list * * @author Olivier Brouckaert * @author Hubert Borderiou 15 nov 2011 * @return array - if the exercise is not set to take questions randomly, returns the question list * without randomizing, otherwise, returns the list with questions selected randomly */ public function selectRandomList() { /*$nbQuestions = $this->selectNbrQuestions(); $temp_list = $this->questionList; //Not a random exercise, or if there are not at least 2 questions if($this->random == 0 || $nbQuestions < 2) { return $this->questionList; } if ($nbQuestions != 0) { shuffle($temp_list); $my_random_list = array_combine(range(1,$nbQuestions),$temp_list); $my_question_list = array(); // $this->random == -1 if random with all questions if ($this->random > 0) { $i = 0; foreach ($my_random_list as $item) { if ($i < $this->random) { $my_question_list[$i] = $item; } else { break; } $i++; } } else { $my_question_list = $my_random_list; } return $my_question_list; }*/ $TBL_EXERCISE_QUESTION = Database::get_course_table(TABLE_QUIZ_TEST_QUESTION); $TBL_QUESTIONS = Database::get_course_table(TABLE_QUIZ_QUESTION); $random = isset($this->random) && !empty($this->random) ? $this->random : 0; $randomLimit = "LIMIT $random"; // Random all questions so no limit if ($random == -1) { $randomLimit = null; } // @todo improve this query $sql = "SELECT e.question_id FROM $TBL_EXERCISE_QUESTION e INNER JOIN $TBL_QUESTIONS q ON (e.question_id= q.id) WHERE e.c_id = {$this->course_id} AND e.exercice_id = '".Database::escape_string($this->id)."' ORDER BY RAND() $randomLimit "; $result = Database::query($sql); $questionList = array(); while ($row = Database::fetch_object($result)) { $questionList[] = $row->question_id; } return $questionList; } /** * returns 'true' if the question ID is in the question list * * @author Olivier Brouckaert * @param integer $questionId - question ID * @return boolean - true if in the list, otherwise false */ public function isInList($questionId) { if (is_array($this->questionList)) return in_array($questionId,$this->questionList); else return false; } /** * changes the exercise title * * @author Olivier Brouckaert * @param string $title - exercise title */ public function updateTitle($title) { $this->exercise=$title; } /** * changes the exercise max attempts * * @param int $attempts - exercise max attempts */ public function updateAttempts($attempts) { $this->attempts=$attempts; } /** * changes the exercise feedback type * * @param int $feedback_type */ public function updateFeedbackType($feedback_type) { $this->feedback_type=$feedback_type; } /** * changes the exercise description * * @author Olivier Brouckaert * @param string $description - exercise description */ public function updateDescription($description) { $this->description=$description; } /** * changes the exercise expired_time * * @author Isaac flores * @param int $expired_time The expired time of the quiz */ public function updateExpiredTime($expired_time) { $this->expired_time = $expired_time; } /** * @param $value */ public function updatePropagateNegative($value) { $this->propagate_neg = $value; } /** * @param $value */ public function updateReviewAnswers($value) { $this->review_answers = isset($value) && $value ? true : false; } /** * @param $value */ public function updatePassPercentage($value) { $this->pass_percentage = $value; } /** * @param string $text */ public function updateEmailNotificationTemplate($text) { $this->emailNotificationTemplate = $text; } /** * @param string $text */ public function updateEmailNotificationTemplateToUser($text) { $this->emailNotificationTemplateToUser = $text; } /** * @param string $value */ public function setNotifyUserByEmail($value) { $this->notifyUserByEmail = $value; } /** * @param int $value */ public function updateEndButton($value) { $this->endButton = intval($value); } /** * @param string $value */ public function setOnSuccessMessage($value) { $this->onSuccessMessage = $value; } /** * @param string $value */ public function setOnFailedMessage($value) { $this->onFailedMessage = $value; } /** * @param $value */ public function setModelType($value) { $this->modelType = intval($value); } /** * @param intval $value */ public function setQuestionSelectionType($value) { $this->questionSelectionType = intval($value); } /** * @return int */ public function getQuestionSelectionType() { return $this->questionSelectionType; } /** * @param array $categories */ public function updateCategories($categories) { if (!empty($categories)) { $categories = array_map('intval', $categories); $this->categories = $categories; } } /** * changes the exercise sound file * * @author Olivier Brouckaert * @param string $sound - exercise sound file * @param string $delete - ask to delete the file */ public function updateSound($sound,$delete) { global $audioPath, $documentPath; $TBL_DOCUMENT = Database::get_course_table(TABLE_DOCUMENT); if ($sound['size'] && (strstr($sound['type'],'audio') || strstr($sound['type'],'video'))) { $this->sound=$sound['name']; if (@move_uploaded_file($sound['tmp_name'],$audioPath.'/'.$this->sound)) { $query = "SELECT 1 FROM $TBL_DOCUMENT WHERE c_id = ".$this->course_id." AND path='".str_replace($documentPath,'',$audioPath).'/'.$this->sound."'"; $result=Database::query($query); if (!Database::num_rows($result)) { $id = add_document( $this->course, str_replace($documentPath,'',$audioPath).'/'.$this->sound, 'file', $sound['size'], $sound['name'] ); api_item_property_update( $this->course, TOOL_DOCUMENT, $id, 'DocumentAdded', api_get_user_id() ); item_property_update_on_folder( $this->course, str_replace($documentPath, '', $audioPath), api_get_user_id() ); } } } elseif($delete && is_file($audioPath.'/'.$this->sound)) { $this->sound=''; } } /** * changes the exercise type * * @author Olivier Brouckaert * @param integer $type - exercise type */ public function updateType($type) { $this->type=$type; } /** * sets to 0 if questions are not selected randomly * if questions are selected randomly, sets the draws * * @author Olivier Brouckaert * @param integer $random - 0 if not random, otherwise the draws */ public function setRandom($random) { /*if ($random == 'all') { $random = $this->selectNbrQuestions(); }*/ $this->random = $random; } /** * sets to 0 if answers are not selected randomly * if answers are selected randomly * @author Juan Carlos Rana * @param integer $random_answers - random answers */ public function updateRandomAnswers($random_answers) { $this->random_answers = $random_answers; } /** * enables the exercise * * @author Olivier Brouckaert */ public function enable() { $this->active=1; } /** * disables the exercise * * @author Olivier Brouckaert */ public function disable() { $this->active=0; } /** * Set disable results */ public function disable_results() { $this->results_disabled = true; } /** * Enable results */ public function enable_results() { $this->results_disabled = false; } /** * @param int $results_disabled */ public function updateResultsDisabled($results_disabled) { $this->results_disabled = intval($results_disabled); } /** * updates the exercise in the data base * * @author Olivier Brouckaert */ public function save($type_e = '') { global $_course; $TBL_EXERCICES = Database::get_course_table(TABLE_QUIZ_TEST); $id = $this->id; $exercise = $this->exercise; $description = $this->description; $sound = $this->sound; $type = $this->type; $attempts = $this->attempts; $feedback_type = $this->feedback_type; $random = $this->random; $random_answers = $this->random_answers; $active = $this->active; $propagate_neg = $this->propagate_neg; $review_answers = (isset($this->review_answers) && $this->review_answers) ? 1 : 0; $randomByCat = $this->randomByCat; $text_when_finished = $this->text_when_finished; $display_category_name = intval($this->display_category_name); $pass_percentage = intval($this->pass_percentage); $session_id = api_get_session_id(); //If direct we do not show results if ($feedback_type == EXERCISE_FEEDBACK_TYPE_DIRECT) { $results_disabled = 0; } else { $results_disabled = intval($this->results_disabled); } $expired_time = intval($this->expired_time); // Exercise already exists if ($id) { // we prepare date in the database using the api_get_utc_datetime() function if (!empty($this->start_time) && $this->start_time != '0000-00-00 00:00:00') { $start_time = Database::escape_string($this->start_time); } else { $start_time = '0000-00-00 00:00:00'; } if (!empty($this->end_time) && $this->end_time != '0000-00-00 00:00:00') { $end_time = Database::escape_string($this->end_time); } else { $end_time = '0000-00-00 00:00:00'; } $sql = "UPDATE $TBL_EXERCICES SET title='".Database::escape_string($exercise)."', description='".Database::escape_string($description)."'"; if ($type_e != 'simple') { $sql .= ",sound='".Database::escape_string($sound)."', type = ".intval($type).", random = ".intval($random).", random_answers = ".intval($random_answers).", active = ".intval($active).", feedback_type = ".intval($feedback_type).", start_time = '$start_time', end_time = '$end_time', max_attempt = ".intval($attempts).", expired_time = ".intval($expired_time).", propagate_neg = ".intval($propagate_neg).", review_answers = ".intval($review_answers).", random_by_category= ".intval($randomByCat).", text_when_finished = '".Database::escape_string($text_when_finished)."', display_category_name = ".intval($display_category_name).", pass_percentage = ".intval($pass_percentage).", results_disabled= ".intval($results_disabled).""; } if ($this->specialCategoryOrders) { $sql .=", question_selection_type= ".intval($this->getQuestionSelectionType()); } $sql .= " WHERE c_id = ".$this->course_id." AND id = ".intval($id).""; Database::query($sql); //global_category_id = '".$this->getGlobalCategoryId()."', // update into the item_property table api_item_property_update($_course, TOOL_QUIZ, $id, 'QuizUpdated', api_get_user_id()); if (api_get_setting('search_enabled')=='true') { $this->search_engine_edit(); } } else { // creates a new exercise // In this case of new exercise, we don't do the api_get_utc_datetime() for date because, bellow, we call function api_set_default_visibility() // In this function, api_set_default_visibility, the Quiz is saved too, with an $id and api_get_utc_datetime() is done. // If we do it now, it will be done twice (cf. https://support.chamilo.org/issues/6586) if (!empty($this->start_time) && $this->start_time != '0000-00-00 00:00:00') { $start_time = Database::escape_string($this->start_time); } else { $start_time = '0000-00-00 00:00:00'; } if (!empty($this->end_time) && $this->end_time != '0000-00-00 00:00:00') { $end_time = Database::escape_string(($this->end_time)); } else { $end_time = '0000-00-00 00:00:00'; } $sql = "INSERT INTO $TBL_EXERCICES ( c_id, start_time, end_time, title, description, sound, type, random, random_answers, active, results_disabled, max_attempt, feedback_type, expired_time, session_id, review_answers, random_by_category, text_when_finished, display_category_name, pass_percentage ) VALUES( ".$this->course_id.", '$start_time','$end_time', '".Database::escape_string($exercise)."', '".Database::escape_string($description)."', '".Database::escape_string($sound)."', ".intval($type).", ".intval($random).", ".intval($random_answers).", ".intval($active).", ".intval($results_disabled).", ".intval($attempts).", ".intval($feedback_type).", ".intval($expired_time).", ".intval($session_id).", ".intval($review_answers).", ".intval($randomByCat).", '".Database::escape_string($text_when_finished)."', ".intval($display_category_name).", ".intval($pass_percentage)." )"; Database::query($sql); $this->id = Database::insert_id(); if ($this->quizRelCategoryTable) { $sql = "UPDATE $TBL_EXERCICES SET question_selection_type= ".intval($this->getQuestionSelectionType())." WHERE id = ".$this->id." AND c_id = ".$this->course_id; Database::query($sql); } // insert into the item_property table api_item_property_update($this->course, TOOL_QUIZ, $this->id, 'QuizAdded', api_get_user_id()); // This function save the quiz again, carefull about start_time and end_time if you remove this line (see above) api_set_default_visibility($this->id, TOOL_QUIZ, null, $this->course); if (api_get_setting('search_enabled')=='true' && extension_loaded('xapian')) { $this->search_engine_save(); } } $this->save_categories_in_exercise($this->categories); // Updates the question position $this->update_question_positions(); } /** * Updates question position */ function update_question_positions() { $quiz_question_table = Database::get_course_table(TABLE_QUIZ_TEST_QUESTION); //Fixes #3483 when updating order $question_list = $this->selectQuestionList(true); if (!empty($question_list)) { foreach ($question_list as $position => $questionId) { $sql="UPDATE $quiz_question_table SET question_order ='".intval($position)."'". "WHERE c_id = ".$this->course_id." AND question_id = ".intval($questionId)." AND exercice_id=".intval($this->id); Database::query($sql); } } } /** * Adds a question into the question list * * @author Olivier Brouckaert * @param integer $questionId - question ID * @return boolean - true if the question has been added, otherwise false */ public function addToList($questionId) { // checks if the question ID is not in the list if (!$this->isInList($questionId)) { // selects the max position if (!$this->selectNbrQuestions()) { $pos = 1; } else { if (is_array($this->questionList)) { $pos = max(array_keys($this->questionList)) + 1; } } $this->questionList[$pos] = $questionId; return true; } return false; } /** * removes a question from the question list * * @author Olivier Brouckaert * @param integer $questionId - question ID * @return boolean - true if the question has been removed, otherwise false */ public function removeFromList($questionId) { // searches the position of the question ID in the list $pos = array_search($questionId,$this->questionList); // question not found if ($pos === false) { return false; } else { // dont reduce the number of random question if we use random by category option, or if // random all questions if ($this->isRandom() && $this->isRandomByCat() == 0) { if (count($this->questionList) >= $this->random && $this->random > 0) { $this->random -= 1; $this->save(); } } // deletes the position from the array containing the wanted question ID unset($this->questionList[$pos]); return true; } } /** * deletes the exercise from the database * Notice : leaves the question in the data base * * @author Olivier Brouckaert */ public function delete() { $TBL_EXERCICES = Database::get_course_table(TABLE_QUIZ_TEST); $sql = "UPDATE $TBL_EXERCICES SET active='-1' WHERE c_id = ".$this->course_id." AND id = ".intval($this->id).""; Database::query($sql); api_item_property_update($this->course, TOOL_QUIZ, $this->id, 'QuizDeleted', api_get_user_id()); api_item_property_update($this->course, TOOL_QUIZ, $this->id, 'delete', api_get_user_id()); if (api_get_setting('search_enabled')=='true' && extension_loaded('xapian') ) { $this->search_engine_delete(); } } /** * Creates the form to create / edit an exercise * @param FormValidator $form */ public function createForm($form, $type='full') { if (empty($type)){ $type='full'; } // form title if (!empty($_GET['exerciseId'])) { $form_title = get_lang('ModifyExercise'); } else { $form_title = get_lang('NewEx'); } $form->addElement('header', $form_title); // Title. $form->addElement('text', 'exerciseTitle', get_lang('ExerciseName'), array('class' => 'span6','id'=>'exercise_title')); $form->addElement('advanced_settings', ' '. addslashes(api_htmlentities(get_lang('ExerciseDescription'))).' '); $editor_config = array('ToolbarSet' => 'TestQuestionDescription', 'Width' => '100%', 'Height' => '150'); if (is_array($type)){ $editor_config = array_merge($editor_config, $type); } $form->addElement ('html','
'.get_lang('Requirements').' | '.get_lang('YourAnswer').' | |
'.get_lang('Overlap').' | '.get_lang('Min').' '.$threadhold1.' | '.(($final_overlap < 0)?0:intval($final_overlap)).' |
'.get_lang('Excess').' | '.get_lang('Max').' '.$threadhold2.' | '.(($final_excess < 0)?0:intval($final_excess)).' |
'.get_lang('Missing').' | '.get_lang('Max').' '.$threadhold3.' | '.(($final_missing < 0)?0:intval($final_missing)).' |
'; $message='
'.get_lang('YourDelineation').'
'; $message.=$table_resume; $message.=''.get_lang('OARHit').'
'; } $message.=''.$comment.'
'; echo $message; } else { echo $hotspot_delineation_result[0]; //prints message $from_database = 1; // the hotspot_solution.swf needs this variable } //save the score attempts if (1) { $final_answer = $hotspot_delineation_result[1]; //getting the answer 1 or 0 comes from exercise_submit_modal.php if ($final_answer == 0) { $questionScore = 0; } exercise_attempt($questionScore, 1, $quesId, $exeId, 0); // we always insert the answer_id 1 = delineation //in delineation mode, get the answer from $hotspot_delineation_result[1] exercise_attempt_hotspot($exeId,$quesId,1, $hotspot_delineation_result[1], $exerciseResultCoordinates[$quesId]); } else { if ($final_answer==0) { $questionScore = 0; $answer=0; exercise_attempt($questionScore, $answer, $quesId, $exeId, 0); if (is_array($exerciseResultCoordinates[$quesId])) { foreach($exerciseResultCoordinates[$quesId] as $idx => $val) { exercise_attempt_hotspot($exeId,$quesId,$idx,0,$val); } } } else { exercise_attempt($questionScore, $answer, $quesId, $exeId, 0); if (is_array($exerciseResultCoordinates[$quesId])) { foreach($exerciseResultCoordinates[$quesId] as $idx => $val) { exercise_attempt_hotspot($exeId,$quesId,$idx,$choice[$idx],$val); } } } } $my_exe_id = $exeId; } } if ($answerType == HOT_SPOT || $answerType == HOT_SPOT_ORDER) { // We made an extra table for the answers if ($show_result) { // if ($origin != 'learnpath') { echo ''; echo ''.get_lang('ExerciseAttempted').' :
'.get_lang('AttemptDetails').' :
'.get_lang('CourseName').' |
#course# |
'.get_lang('TestAttempted').' | #exercise# |
'.get_lang('StudentName').' | #firstName# #lastName# |
'.get_lang('StudentEmail').' | #email# |
'.get_lang('OpenQuestionsAttempted').' :
'.get_lang('AttemptDetails').' :
'.get_lang('CourseName').' |
#course# |
'.get_lang('TestAttempted').' | #exercise# |
'.get_lang('StudentName').' | #firstName# #lastName# |
'.get_lang('StudentEmail').' | #mail# |
'.get_lang('OpenQuestionsAttemptedAre').' :
'.get_lang('Question').' | '.$question.' |
'.get_lang('Answer').' | '.$answer.' |
'.get_lang('OralQuestionsAttempted').' :
'.get_lang('AttemptDetails').' :
'.get_lang('CourseName').' |
#course# |
'.get_lang('TestAttempted').' | #exercise# |
'.get_lang('StudentName').' | #firstName# #lastName# |
'.get_lang('StudentEmail').' | #mail# |
* array (size=2)
* 999 =>
* array (size=3)
* 0 => int 7
* 1 => int 6
* 2 => int 3254
* 100 =>
* array (size=1)
* 0 => int 5
*
* @return array
*/
private function setMediaList($questionList)
{
$mediaList= array();
if (!empty($questionList)) {
foreach ($questionList as $questionId) {
$objQuestionTmp = Question::read($questionId);
// If a media question exists
if (isset($objQuestionTmp->parent_id) && $objQuestionTmp->parent_id != 0) {
$mediaList[$objQuestionTmp->parent_id][] = $objQuestionTmp->id;
} else {
// Always the last item
$mediaList[999][] = $objQuestionTmp->id;
}
}
}
$this->mediaList = $mediaList;
}
/**
* Returns an array with this form
* @example
*
* array (size=3)
999 =>
array (size=3)
0 => int 3422
1 => int 3423
2 => int 3424
100 =>
array (size=2)
0 => int 3469
1 => int 3470
101 =>
array (size=1)
0 => int 3482
*
* The array inside the key 999 means the question list that belongs to the media id = 999,
* this case is special because 999 means "no media".
* @return array
*/
public function getMediaList()
{
return $this->mediaList;
}
/**
* Is media question activated?
* @return bool
*/
public function mediaIsActivated()
{
$mediaQuestions = $this->getMediaList();
$active = false;
if (isset($mediaQuestions) && !empty($mediaQuestions)) {
$media_count = count($mediaQuestions);
if ($media_count > 1) {
return true;
} elseif ($media_count == 1) {
if (isset($mediaQuestions[999])) {
return false;
} else {
return true;
}
}
}
return $active;
}
/**
* Gets question list from the exercise
*
* @return array
*/
public function getQuestionList()
{
return $this->questionList;
}
/**
* Question list with medias compressed like this
* @example
*
* array(
* question_id_1,
* question_id_2,
* media_id, <- this media id contains question ids
* question_id_3,
* )
*
* @return array
*/
public function getQuestionListWithMediasCompressed()
{
return $this->questionList;
}
/**
* Question list with medias uncompressed like this
* @example
*
* array(
* question_id,
* question_id,
* question_id, <- belongs to a media id
* question_id, <- belongs to a media id
* question_id,
* )
*
* @return array
*/
public function getQuestionListWithMediasUncompressed()
{
return $this->questionListUncompressed;
}
/**
* Sets the question list when the exercise->read() is executed
*/
public function setQuestionList()
{
// Getting question list.
$questionList = $this->selectQuestionList(true);
$this->setMediaList($questionList);
$this->questionList = $this->transformQuestionListWithMedias($questionList, false);
$this->questionListUncompressed = $this->transformQuestionListWithMedias($questionList, true);
}
/**
*
* @params array question list
* @params bool expand or not question list (true show all questions, false show media question id instead of the question ids)
*
**/
public function transformQuestionListWithMedias($question_list, $expand_media_questions = false)
{
$new_question_list = array();
if (!empty($question_list)) {
$media_questions = $this->getMediaList();
$media_active = $this->mediaIsActivated($media_questions);
if ($media_active) {
$counter = 1;
foreach ($question_list as $question_id) {
$add_question = true;
foreach ($media_questions as $media_id => $question_list_in_media) {
if ($media_id != 999 && in_array($question_id, $question_list_in_media)) {
$add_question = false;
if (!in_array($media_id, $new_question_list)) {
$new_question_list[$counter] = $media_id;
$counter++;
}
break;
}
}
if ($add_question) {
$new_question_list[$counter] = $question_id;
$counter++;
}
}
if ($expand_media_questions) {
$media_key_list = array_keys($media_questions);
foreach ($new_question_list as &$question_id) {
if (in_array($question_id, $media_key_list)) {
$question_id = $media_questions[$question_id];
}
}
$new_question_list = array_flatten($new_question_list);
}
} else {
$new_question_list = $question_list;
}
}
return $new_question_list;
}
function get_validated_question_list()
{
$tabres = array();
$isRandomByCategory = $this->isRandomByCat();
if ($isRandomByCategory == 0) {
if ($this->isRandom()) {
$tabres = $this->selectRandomList();
} else {
$tabres = $this->selectQuestionList();
}
} else {
if ($this->isRandom()) {
// USE question categories
// get questions by category for this exercice
// we have to choice $objExercise->random question in each array values of $tabCategoryQuestions
// key of $tabCategoryQuestions are the categopy id (0 for not in a category)
// value is the array of question id of this category
$questionList = array();
$tabCategoryQuestions = Testcategory::getQuestionsByCat($this->id);
$isRandomByCategory = $this->selectRandomByCat();
// on tri les categories en fonction du terme entre [] en tete de la description de la categorie
/*
* ex de catégories :
* [biologie] Maitriser les mecanismes de base de la genetique
* [biologie] Relier les moyens de depenses et les agents infectieux
* [biologie] Savoir ou est produite l'enrgie dans les cellules et sous quelle forme
* [chimie] Classer les molles suivant leur pouvoir oxydant ou reacteur
* [chimie] Connaître la denition de la theoie acide/base selon Brönsted
* [chimie] Connaître les charges des particules
* On veut dans l'ordre des groupes definis par le terme entre crochet au debut du titre de la categorie
*/
// If test option is Grouped By Categories
if ($isRandomByCategory == 2) {
$tabCategoryQuestions = Testcategory::sortTabByBracketLabel($tabCategoryQuestions);
}
while (list($cat_id, $tabquestion) = each($tabCategoryQuestions)) {
$number_of_random_question = $this->random;
if ($this->random == -1) {
$number_of_random_question = count($this->questionList);
}
$questionList = array_merge($questionList, Testcategory::getNElementsFromArray($tabquestion, $number_of_random_question));
}
// shuffle the question list if test is not grouped by categories
if ($isRandomByCategory == 1) {
shuffle($questionList); // or not
}
$tabres = $questionList;
} else {
// Problem, random by category has been selected and we have no $this->isRandom nnumber of question selected
// Should not happened
}
}
return $tabres;
}
function get_question_list($expand_media_questions = false)
{
$question_list = $this->get_validated_question_list();
$question_list = $this->transform_question_list_with_medias($question_list, $expand_media_questions);
return $question_list;
}
function transform_question_list_with_medias($question_list, $expand_media_questions = false)
{
$new_question_list = array();
if (!empty($question_list)) {
$media_questions = $this->getMediaList();
$media_active = $this->mediaIsActivated($media_questions);
if ($media_active) {
$counter = 1;
foreach ($question_list as $question_id) {
$add_question = true;
foreach ($media_questions as $media_id => $question_list_in_media) {
if ($media_id != 999 && in_array($question_id, $question_list_in_media)) {
$add_question = false;
if (!in_array($media_id, $new_question_list)) {
$new_question_list[$counter] = $media_id;
$counter++;
}
break;
}
}
if ($add_question) {
$new_question_list[$counter] = $question_id;
$counter++;
}
}
if ($expand_media_questions) {
$media_key_list = array_keys($media_questions);
foreach ($new_question_list as &$question_id) {
if (in_array($question_id, $media_key_list)) {
$question_id = $media_questions[$question_id];
}
}
$new_question_list = array_flatten($new_question_list);
}
} else {
$new_question_list = $question_list;
}
}
return $new_question_list;
}
public function get_stat_track_exercise_info_by_exe_id($exe_id)
{
$track_exercises = Database :: get_statistic_table(TABLE_STATISTIC_TRACK_E_EXERCICES);
$exe_id = intval($exe_id);
$sql_track = "SELECT * FROM $track_exercises WHERE exe_id = $exe_id ";
$result = Database::query($sql_track);
$new_array = array();
if (Database::num_rows($result) > 0 ) {
$new_array = Database::fetch_array($result, 'ASSOC');
$new_array['duration'] = null;
$start_date = api_get_utc_datetime($new_array['start_date'], true);
$end_date = api_get_utc_datetime($new_array['exe_date'], true);
if (!empty($start_date) && !empty($end_date)) {
$start_date = api_strtotime($start_date, 'UTC');
$end_date = api_strtotime($end_date, 'UTC');
if ($start_date && $end_date) {
$mytime = $end_date- $start_date;
$new_learnpath_item = new learnpathItem(null);
$time_attemp = $new_learnpath_item->get_scorm_time('js', $mytime);
$h = get_lang('h');
$time_attemp = str_replace('NaN', '00' . $h . '00\'00"', $time_attemp);
$new_array['duration'] = $time_attemp;
}
}
}
return $new_array;
}
public function edit_question_to_remind($exe_id, $question_id, $action = 'add')
{
$exercise_info = self::get_stat_track_exercise_info_by_exe_id($exe_id);
$question_id = intval($question_id);
$exe_id = intval($exe_id);
$track_exercises = Database :: get_statistic_table(TABLE_STATISTIC_TRACK_E_EXERCICES);
if ($exercise_info) {
if (empty($exercise_info['questions_to_check'])) {
if ($action == 'add') {
$sql = "UPDATE $track_exercises SET questions_to_check = '$question_id' WHERE exe_id = $exe_id ";
$result = Database::query($sql);
}
} else {
$remind_list = explode(',',$exercise_info['questions_to_check']);
$remind_list_string = '';
if ($action == 'add') {
if (!in_array($question_id, $remind_list)) {
$remind_list[] = $question_id;
if (!empty($remind_list)) {
sort($remind_list);
array_filter($remind_list);
}
$remind_list_string = implode(',', $remind_list);
}
} elseif ($action == 'delete') {
if (!empty($remind_list)) {
if (in_array($question_id, $remind_list)) {
$remind_list = array_flip($remind_list);
unset($remind_list[$question_id]);
$remind_list = array_flip($remind_list);
if (!empty($remind_list)) {
sort($remind_list);
array_filter($remind_list);
$remind_list_string = implode(',', $remind_list);
}
}
}
}
$remind_list_string = Database::escape_string($remind_list_string);
$sql = "UPDATE $track_exercises SET questions_to_check = '$remind_list_string' WHERE exe_id = $exe_id ";
Database::query($sql);
}
}
}
public function fill_in_blank_answer_to_array($answer)
{
api_preg_match_all('/\[[^]]+\]/', $answer, $teacher_answer_list);
$teacher_answer_list = $teacher_answer_list[0];
return $teacher_answer_list;
}
public function fill_in_blank_answer_to_string($answer)
{
$teacher_answer_list = $this->fill_in_blank_answer_to_array($answer);
$result = '';
if (!empty($teacher_answer_list)) {
$i = 0;
foreach ($teacher_answer_list as $teacher_item) {
$value = null;
//Cleaning student answer list
$value = strip_tags($teacher_item);
$value = api_substr($value,1, api_strlen($value)-2);
$value = explode('/', $value);
if (!empty($value[0])) {
$value = trim($value[0]);
$value = str_replace(' ', '', $value);
$result .= $value;
}
}
}
return $result;
}
function return_time_left_div()
{
$html = ' ';
$html .= '';
return $html;
}
function get_count_question_list()
{
//Real question count
$question_count = 0;
$question_list = $this->get_question_list();
if (!empty($question_list)) {
$question_count = count($question_list);
}
return $question_count;
}
function get_exercise_list_ordered()
{
$table_exercise_order = Database::get_course_table(TABLE_QUIZ_ORDER);
$course_id = api_get_course_int_id();
$session_id = api_get_session_id();
$sql = "SELECT exercise_id, exercise_order
FROM $table_exercise_order
WHERE c_id = $course_id AND session_id = $session_id
ORDER BY exercise_order";
$result = Database::query($sql);
$list = array();
if (Database::num_rows($result)) {
while($row = Database::fetch_array($result, 'ASSOC')) {
$list[$row['exercise_order']] = $row['exercise_id'];
}
}
return $list;
}
/**
* Get categories added in the exercise--category matrix
* @return bool
*/
public function get_categories_in_exercise()
{
if (!$this->specialCategoryOrders) {
return false;
}
$table = Database::get_course_table(TABLE_QUIZ_REL_CATEGORY);
if (!empty($this->id)) {
$sql = "SELECT * FROM $table
WHERE exercise_id = {$this->id} AND c_id = {$this->course_id} ";
$result = Database::query($sql);
$list = array();
if (Database::num_rows($result)) {
while ($row = Database::fetch_array($result, 'ASSOC')) {
$list[$row['category_id']] = $row;
}
return $list;
}
}
return false;
}
/**
* @param null $order
* @return bool
*/
public function get_categories_with_name_in_exercise($order = null)
{
if (!$this->specialCategoryOrders) {
return false;
}
$table = Database::get_course_table(TABLE_QUIZ_REL_CATEGORY);
$table_category = Database::get_course_table(TABLE_QUIZ_QUESTION_CATEGORY);
$sql = "SELECT * FROM $table qc
INNER JOIN $table_category c
ON (category_id = c.iid)
WHERE exercise_id = {$this->id} AND qc.c_id = {$this->course_id} ";
if (!empty($order)) {
$sql .= "ORDER BY $order ";
}
$result = Database::query($sql);
if (Database::num_rows($result)) {
while ($row = Database::fetch_array($result, 'ASSOC')) {
$list[$row['category_id']] = $row;
}
return $list;
}
return false;
}
/**
* Get total number of question that will be parsed when using the category/exercise
*/
public function getNumberQuestionExerciseCategory()
{
if (!$this->specialCategoryOrders) {
return false;
}
$table = Database::get_course_table(TABLE_QUIZ_REL_CATEGORY);
if (!empty($this->id)) {
$sql = "SELECT SUM(count_questions) count_questions
FROM $table
WHERE exercise_id = {$this->id} AND c_id = {$this->course_id}";
$result = Database::query($sql);
if (Database::num_rows($result)) {
$row = Database::fetch_array($result);
return $row['count_questions'];
}
}
return 0;
}
/**
* Save categories in the TABLE_QUIZ_REL_CATEGORY table
* @param array $categories
*/
public function save_categories_in_exercise($categories)
{
if (!$this->specialCategoryOrders) {
return false;
}
if (!empty($categories) && !empty($this->id)) {
$table = Database::get_course_table(TABLE_QUIZ_REL_CATEGORY);
$sql = "DELETE FROM $table
WHERE exercise_id = {$this->id} AND c_id = {$this->course_id}";
Database::query($sql);
if (!empty($categories)) {
foreach ($categories as $category_id => $count_questions) {
$params = array(
'c_id' => $this->course_id,
'exercise_id' => $this->id,
'category_id' => $category_id,
'count_questions' => $count_questions
);
Database::insert($table, $params);
}
}
}
}
/**
* @param array $questionList
* @param int $currentQuestion
* @param array $conditions
* @param string $link
* @return string
*/
public function progressExercisePaginationBar($questionList, $currentQuestion, $conditions, $link)
{
$mediaQuestions = $this->getMediaList();
$html = '