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();
}
/* Make sure that we have a valid $course_info. */
if (!isset($course_info['real_id'])) {
throw new Exception('Could not get a valid $course_info with the provided $course_id: '.$course_id.'.');
}
$this->course_id = $course_info['real_id'];
$this->course = $course_info;
$this->fastEdition = api_get_course_setting('allow_fast_exercise_edition', $course_info['code']) == 1 ? true : false;
$this->emailAlert = api_get_course_setting('email_alert_manager_on_new_quiz', $course_info['code']) == 1 ? true : false;
$this->hideQuestionTitle = 0;
}
/**
* Reads exercise information from the database
*
* @author Olivier Brouckaert
* @todo use Doctrine to manage read/writes
* @param int $id - exercise ID
* @param bool parse exercise question list
* @param int $chamilo_session_id - chamilo session ID
* @return boolean - true if exercise exists, otherwise false
*/
public function read($id, $parseQuestionList = true, $chamilo_session_id = null)
{
if (empty($this->course_id)) {
return false;
}
global $_configuration;
$TBL_EXERCICES = Database::get_course_table(TABLE_QUIZ_TEST);
$table_lp_item = Database::get_course_table(TABLE_LP_ITEM);
$id = intval($id);
$sql = "SELECT * FROM $TBL_EXERCICES WHERE c_id = ".$this->course_id." AND iid = ".$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->is_gradebook_locked = api_resource_is_locked_by_gradebook($id, LINK_EXERCISE);
$this->endButton = $object->end_button;
$this->emailNotificationTemplate = $object->email_notification_template;
$this->modelType = $object->model_type;
$this->questionSelectionType = $object->question_selection_type;
$this->hideQuestionTitle = $object->hide_question_title;
$this->scoreTypeModel = $object->score_type_model;
$this->globalCategoryId = $object->global_category_id;
$this->review_answers = (isset($object->review_answers) && $object->review_answers == 1) ? true : false;
$sql = "SELECT 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->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;
// 5. Getting user exercise info (if the user took the exam before) - generating exe_id
$this->trackExercise = $this->getStatTrackExerciseInfo();
if ($parseQuestionList) {
$this->setQuestionList($this->loadDistributions, $chamilo_session_id);
}
return true;
}
return false;
}
/**
* @return string
*/
public function getCutTitle()
{
return Text::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
*/
function selectTitle()
{
return $this->exercise;
}
/**
* returns the number of attempts setted
*
* @return numeric - exercise attempts
*/
function selectAttempts()
{
return $this->attempts;
}
/** returns the number of FeedbackType *
* 0=>Feedback , 1=>DirectFeedback, 2=>NoFeedback
*
* @return int exercise attempts
*/
function selectFeedbackType()
{
return $this->feedback_type;
}
/**
* returns the time limit
*/
function selectTimeLimit()
{
return $this->timeLimit;
}
/**
* returns the exercise description
*
* @author - Olivier Brouckaert
*
* @return string - exercise description
*/
function selectDescription()
{
return $this->description;
}
/**
* Returns the exercise sound file
*
* @author Olivier Brouckaert
* @return string - exercise description
*/
function selectSound()
{
return $this->sound;
}
/**
* Returns the exercise type
*
* @author - Olivier Brouckaert
* @return integer - exercise type
*/
public function selectType()
{
return $this->type;
}
/**
* @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 string
*/
public function selectPassPercentage()
{
return $this->pass_percentage;
}
/**
* @return string
*/
public function selectEmailNotificationTemplate()
{
return $this->emailNotificationTemplate;
}
public function getModelType()
{
return $this->modelType;
}
/**
* @return int
*/
public function selectEndButton()
{
return $this->endButton;
}
/**
* @author Hubert borderiou 30-11-11
* @param string
* @return void modify object to update the switch display_category_name
* $in_txt is an integer 0 or 1
*/
public function updateDisplayCategoryName($text)
{
$this->display_category_name = $text;
}
/**
* @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
* @param string
* @return string html text : update the text to display ay the end of the test.
*/
public function updateTextWhenFinished($text)
{
$this->text_when_finished = $text;
}
/**
* 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 = 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;
}
/**
* Sets the random by category value
* @author Julio Montoya
* @param int random by category
*/
public function updateRandomByCat($random)
{
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;
}
}
/**
* Tells if questions are selected randomly, and if so returns the draws
*
* @author - Carlos Vargas
*
* @return int 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 bool - 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 Ra�a
*/
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;
}
public function getHideQuestionTitle()
{
return $this->hideQuestionTitle;
}
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 $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);
$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(e.iid) as count
FROM $TBL_EXERCICE_QUESTION e INNER JOIN $TBL_QUESTIONS q
ON (e.question_id = q.iid)
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;
}
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.iid)
WHERE e.c_id = {$this->course_id} AND e.exercice_id = '".Database::escape_string($this->id)."'
ORDER BY q.question";
$result = Database::query($sql);
return $result->fetchAll();
}
/**
* Gets the question list ordered by the question_order setting (drag and drop)
* @return array
*/
public 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.iid)
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 e.question_id, e.question_order
FROM $TBL_EXERCICE_QUESTION e INNER JOIN $TBL_QUESTIONS q
ON (e.question_id= q.iid)
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 $question_list
* @param array $questions_by_category per category
* @param array how many questions per category
* @param bool $randomizeQuestions
* @param bool flat result
*
* @return array
*/
private function pickQuestionsPerCategory(
$categoriesAddedInExercise,
$question_list,
& $questions_by_category,
$flatResult = true,
$randomizeQuestions = false,
$shuffleQuestionsNoTakingSubcategories = 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 ($shuffleQuestionsNoTakingSubcategories) {
$temp_question_list = self::shuffleQuestionListPerCategory($temp_question_list, $categoriesAddedInExercise);
}
if (!empty($temp_question_list)) {
if ($flatResult) {
$temp_question_list = ArrayClass::array_flatten($temp_question_list);
}
$question_list = $temp_question_list;
}
}
return $question_list;
}
/**
* @param array $temp_question_list
* @param array $categoriesAddedInExercise
* @return array
*/
private function shuffleQuestionListPerCategory($temp_question_list, $categoriesAddedInExercise)
{
$questionsPerMainCategory = array();
foreach ($temp_question_list as $categoryId => $questionList) {
$parentId = $categoriesAddedInExercise[$categoryId]['parent_id'];
// Default values and the course_id passed.
$cat = new Testcategory(0, '', '', 0, 'simple', $this->course_id);
$cat->getCategory($parentId);
if (!isset($questionsPerMainCategory[$cat->parent_id])) {
$questionsPerMainCategory[$cat->parent_id] = array();
}
$questionsPerMainCategory[$cat->parent_id] = array_merge($questionsPerMainCategory[$cat->parent_id], $questionList);
}
if (!empty($questionsPerMainCategory)) {
$newQuestionList = array();
foreach ($questionsPerMainCategory as $questionList) {
shuffle($questionList);
$newQuestionList[] = $questionList;
}
$temp_question_list = $newQuestionList;
}
return $temp_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. Default values and the course_id passed.
$cat = new Testcategory(0, '', '', 0, 'simple', $this->course_id);
$courseId = $this->course_id;
// 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->id, $this->course['real_id'], 'title DESC', false, true);
$questions_by_category = Testcategory::getQuestionsByCat($this->id, $question_list, $categoriesAddedInExercise, $courseId);
$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->id, $this->course['real_id'], null, true, true);
$questions_by_category = Testcategory::getQuestionsByCat($this->id, $question_list, $categoriesAddedInExercise, $courseId);
$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->id, $this->course['real_id'], 'title DESC', false, true);
$questions_by_category = Testcategory::getQuestionsByCat($this->id, $question_list, $categoriesAddedInExercise, $courseId);
$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->id, $this->course['real_id'], null, true, true);
$questions_by_category = Testcategory::getQuestionsByCat($this->id, $question_list, $categoriesAddedInExercise, $courseId);
$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->id, $this->course['real_id'], 'root ASC, lft ASC', false, true);
$questions_by_category = Testcategory::getQuestionsByCat($this->id, $question_list, $categoriesAddedInExercise, $courseId);
$question_list = $this->pickQuestionsPerCategory($categoriesAddedInExercise, $question_list, $questions_by_category, true, false);
break;
case EX_Q_SELECTION_CATEGORIES_ORDERED_BY_PARENT_QUESTIONS_RANDOM: // 10
// Added new parameter in order to randomize sub categories see BT#6943
/*
@todo this should be false but because there's a new option called
EX_Q_SELECTION_CATEGORIES_ORDERED_BY_PARENT_SUB_CAT_RANDOM_QUESTIONS_RANDOM
I'm leaving this with true because there could be a lot of exercise already set with this behaviour.
*/
$subCategoryShuffle = true;
$categoriesAddedInExercise = $cat->getCategoryExerciseTree($this->id, $this->course['real_id'], 'root, lft ASC', false, true, $subCategoryShuffle);
$questions_by_category = Testcategory::getQuestionsByCat($this->id, $question_list, $categoriesAddedInExercise, $courseId);
$question_list = $this->pickQuestionsPerCategory($categoriesAddedInExercise, $question_list, $questions_by_category, true, true, true);
break;
case EX_Q_SELECTION_CATEGORIES_ORDERED_BY_PARENT_SUB_CAT_RANDOM_QUESTIONS_RANDOM://11
// Added new parameter in order to randomize sub categories see BT#6943
$subCategoryShuffle = true;
$categoriesAddedInExercise = $cat->getCategoryExerciseTree($this->id, $this->course['real_id'], 'root, lft ASC', false, true, $subCategoryShuffle);
$questions_by_category = Testcategory::getQuestionsByCat($this->id, $question_list, $categoriesAddedInExercise, $courseId);
$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)) {
$newCategoryList = $this->fillQuestionByCategoryArray($questions_by_category);
$result['category_with_questions_list'] = $newCategoryList;
}
return $result;
}
/**
* @param array $questions_by_category
* @return array
*/
function fillQuestionByCategoryArrayPerQuestion($questions_by_category)
{
global $app;
$em = $app['orm.em'];
$repo = $em->getRepository('Entity\CQuizCategory');
$newCategoryList = array();
if (!empty($questions_by_category)) {
foreach ($questions_by_category as $categoryInfo) {
$categoryId = $categoryInfo['categoryId'];
$questionList = array($categoryInfo['questionId']);
$cat = new Testcategory($categoryId);
$cat = (array)$cat;
$cat['iid'] = $cat['id'];
$cat['name'] = $cat['title'];
$categoryParentInfo = null;
if (!empty($cat['parent_id'])) {
if (!isset($parentsLoaded[$cat['parent_id']])) {
$categoryEntity = $em->find('Entity\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 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(
$newCategoryList[] = array(
'category' => $cat,
'question_list' => $questionList
);
}
}
return $newCategoryList;
}
/**
* @param array $questions_by_category
* @return array
*/
function fillQuestionByCategoryArray($questions_by_category)
{
global $app;
$em = $app['orm.em'];
$repo = $em->getRepository('Entity\CQuizCategory');
$newCategoryList = array();
if (!empty($questions_by_category)) {
foreach ($questions_by_category as $categoryId => $questionList) {
// Default values and the course_id passed.
$cat = new Testcategory($categoryId, '', '', 0, 'simple', $this->course_id);
$cat = (array)$cat;
$cat['iid'] = $cat['id'];
$cat['name'] = $cat['title'];
$categoryParentInfo = null;
if (!empty($cat['parent_id'])) {
if (!isset($parentsLoaded[$cat['parent_id']])) {
$categoryEntity = $em->find('Entity\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 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
);
}
}
return $newCategoryList;
}
/**
* Returns the array with the question ID list ordered by question order (including question list in medias)
*
* @author Olivier Brouckaert
* @param bool $from_db
* @return array question ID list
*/
public function selectQuestionList($from_db = false)
{
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);
}
public function selectPropagateNeg()
{
return $this->propagate_neg;
}
/**
* Selects questions randomly in the question list
* If the exercise is not set to take questions randomly, returns the question list
* without randomizing, otherwise, returns the list with questions selected randomly
*
* @author Olivier Brouckaert, Modified by Hubert Borderiou 15 nov 2011
* @param array question list
* @return array question list modified or unmodified
*
*/
public function selectRandomList()
{
$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.iid)
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 - numeric $attempts - exercise max attempts
*/
public function updateAttempts($attempts)
{
$this->attempts = $attempts;
}
public function updateActive($active)
{
$this->active = $active;
}
/**
* changes the exercise feedback type
*
* @param - numeric $attempts - exercise max attempts
*/
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 The expired time of the quiz
*/
public function updateExpiredTime($expired_time)
{
$this->expired_time = $expired_time;
}
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 $text
*/
public function updateEmailNotificationTemplate($text)
{
$this->emailNotificationTemplate = $text;
}
public function updateEndButton($value)
{
$this->endButton = intval($value);
}
public function setModelType($value)
{
$this->modelType = intval($value);
}
public function setQuestionSelectionType($value)
{
$this->questionSelectionType = intval($value);
}
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 = FileManager::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());
FileManager::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)
{
$this->random = $random;
}
/**
* sets to 0 if answers are not selected randomly
* if answers are selected randomly
* @author - Juan Carlos Ra�a
* @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;
}
public function disable_results()
{
$this->results_disabled = true;
}
public function enable_results()
{
$this->results_disabled = false;
}
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 = '')
{
$_course = $this->course;
$TBL_EXERCICES = Database::get_course_table(TABLE_QUIZ_TEST);
$id = $this->id;
$exercise = $this->exercise;
$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);
if (!empty($this->start_time) && $this->start_time != '0000-00-00 00:00:00') {
$start_time = Database::escape_string(api_get_utc_datetime($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(api_get_utc_datetime($this->end_time));
} else {
$end_time = '0000-00-00 00:00:00';
}
// Exercise already exists
if ($id) {
$sql = "UPDATE $TBL_EXERCICES SET
title='".Database::escape_string($exercise)."',
description='".Database::escape_string($this->description)."'";
if ($type_e != 'simple') {
$sql .= ",sound='".Database::escape_string($sound)."',
type ='".Database::escape_string($type)."',
random ='".Database::escape_string($random)."',
random_answers ='".Database::escape_string($random_answers)."',
active ='".Database::escape_string($active)."',
feedback_type ='".Database::escape_string($feedback_type)."',
start_time = '$start_time',
end_time = '$end_time',
max_attempt ='".Database::escape_string($attempts)."',
expired_time ='".Database::escape_string($expired_time)."',
propagate_neg ='".Database::escape_string($propagate_neg)."',
review_answers ='".Database::escape_string($review_answers)."',
random_by_category='".Database::escape_string($randomByCat)."',
text_when_finished = '".Database::escape_string($text_when_finished)."',
display_category_name = '".Database::escape_string($display_category_name)."',
pass_percentage = '".Database::escape_string($pass_percentage)."',
end_button = '".$this->selectEndButton()."',
email_notification_template = '".Database::escape_string($this->selectEmailNotificationTemplate())."',
model_type = '".$this->getModelType()."',
question_selection_type = '".$this->getQuestionSelectionType()."',
hide_question_title = '".$this->getHideQuestionTitle()."',
score_type_model = '".$this->getScoreTypeModel()."',
global_category_id = '".$this->getGlobalCategoryId()."',
results_disabled='".Database::escape_string($results_disabled)."'";
}
$sql .= " WHERE iid = ".Database::escape_string($id)." AND c_id = {$this->course_id}";
Database::query($sql);
// 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
$sql = "INSERT INTO $TBL_EXERCICES (
c_id, start_time, end_time, title, description, sound, type, random, random_answers, active,
max_attempt, feedback_type, expired_time, session_id, review_answers, random_by_category,
text_when_finished, display_category_name, pass_percentage, end_button, email_notification_template,
results_disabled, model_type, question_selection_type, score_type_model, global_category_id, hide_question_title)
VALUES(
".$this->course_id.",
'$start_time',
'$end_time',
'".Database::escape_string($exercise)."',
'".Database::escape_string($this->description)."',
'".Database::escape_string($sound)."',
'".Database::escape_string($type)."',
'".Database::escape_string($random)."',
'".Database::escape_string($random_answers)."',
'".Database::escape_string($active)."',
'".Database::escape_string($attempts)."',
'".Database::escape_string($feedback_type)."',
'".Database::escape_string($expired_time)."',
'".Database::escape_string($session_id)."',
'".Database::escape_string($review_answers)."',
'".Database::escape_string($randomByCat)."',
'".Database::escape_string($text_when_finished)."',
'".Database::escape_string($display_category_name)."',
'".Database::escape_string($pass_percentage)."',
'".Database::escape_string($this->selectEndButton())."',
'".Database::escape_string($this->selectEmailNotificationTemplate())."',
'".Database::escape_string($results_disabled)."',
'".Database::escape_string($this->getModelType())."',
'".Database::escape_string($this->getQuestionSelectionType())."',
'".Database::escape_string($this->getScoreTypeModel())."',
'".Database::escape_string($this->getGlobalCategoryId())."',
'".Database::escape_string($this->getHideQuestionTitle())."'
)";
Database::query($sql);
$this->id = Database::insert_id();
$this->addExerciseToOrderTable();
// insert into the item_property table
api_item_property_update($this->course, TOOL_QUIZ, $this->id, 'QuizAdded', api_get_user_id());
api_set_default_visibility($this->course, $this->id, TOOL_QUIZ);
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
*/
public 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) && !empty($this->course_id) && !empty($this->id)) {
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 = ".$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() == EXERCISE_CATEGORY_RANDOM_DISABLED) {
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 iid='".Database::escape_string($this->id)."'";
Database::query($sql);
api_item_property_update($this->course, TOOL_QUIZ, $this->id, 'QuizDeleted', api_get_user_id());
$this->delete_exercise_order();
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 the formvalidator instance (by reference)
* @param string
*/
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')
);
$editor_config = array('ToolbarSet' => 'TestQuestionDescription', 'Width' => '100%', 'Height' => '150');
if (is_array($type)) {
$editor_config = array_merge($editor_config, $type);
}
$form->add_html_editor('exerciseDescription', get_lang('ExerciseDescription'), false, false, $editor_config);
$form->addElement(
'advanced_settings',
'
'.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; } saveQuestionAttempt($questionScore, 1, $quesId, $exeId, 0, null, $updateResults); // we always insert the answer_id 1 = delineation //in delineation mode, get the answer from $hotspot_delineation_result[1] saveExerciseAttemptHotspot($exeId, $quesId, $objAnswerTmp->getRealAnswerIdFromList(1), $hotspot_delineation_result[1], $exerciseResultCoordinates[$quesId], $updateResults); } else { if ($final_answer == 0) { $questionScore = 0; $answer = 0; saveQuestionAttempt($questionScore, $answer, $quesId, $exeId, 0, null, $updateResults); if (is_array($exerciseResultCoordinates[$quesId])) { foreach ($exerciseResultCoordinates[$quesId] as $idx => $val) { saveExerciseAttemptHotspot($exeId, $quesId, $objAnswerTmp->getRealAnswerIdFromList($idx), 0, $val, $updateResults); } } } else { saveQuestionAttempt($questionScore, $answer, $quesId, $exeId, 0, null, $updateResults); if (is_array($exerciseResultCoordinates[$quesId])) { foreach ($exerciseResultCoordinates[$quesId] as $idx => $val) { saveExerciseAttemptHotspot($exeId, $quesId, $objAnswerTmp->getRealAnswerIdFromList($idx), $choice[$idx], $val, $updateResults); } } } } $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('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, $course_id)
{
$mediaList= array();
if (!empty($questionList)) {
foreach ($questionList as $questionId) {
$objQuestionTmp = Question::read($questionId, $course_id);
// 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($loadDistributions = false, $sessionId = null)
{
// Getting question list.
$questionList = $this->selectQuestionList(true);
// Looking for distributions
if (!$sessionId) {
$sessionId = api_get_session_id();
}
if (!empty($sessionId)) {
$dataExists = !empty($this->trackExercise) && isset($this->trackExercise['data_tracking']) && !empty($this->trackExercise['data_tracking']) ? true : false;
if ($dataExists) {
$questionList = explode(',', $this->trackExercise['data_tracking']);
} else {
// Counting how many attempts from session are in the DB
$trackExercises = Database::get_main_table(TABLE_STATISTIC_TRACK_E_EXERCICES);
$sql = "SELECT count(exe_id) as count FROM $trackExercises WHERE session_id = $sessionId";
$result = Database::query($sql);
$count = 0;
if (Database::num_rows($result)) {
$result = Database::fetch_array($result);
$count = $result['count'];
}
global $app;
/** @var \Doctrine\manager $em */
$em = $app['orm.em'];
$params = array(
'exerciseId' => $this->id,
'sessionId' => $sessionId,
'cId' => $this->course_id
);
// Searching for forms in this session.
$quizDistributionRelSessions = $em->getRepository("Entity\CQuizDistributionRelSession")->findBy($params);
if (!empty($quizDistributionRelSessions)) {
// Getting a distribution. It depends of the count of attempts and count of distributions.
$formToUse = $count % (count($quizDistributionRelSessions));
/** @var \Entity\CQuizDistributionRelSession $quizDistributionRelSession */
if (isset($quizDistributionRelSessions[$formToUse])) {
// We found a distribution!
$quizDistributionRelSession = $quizDistributionRelSessions[$formToUse];
$this->distributionId = $quizDistributionRelSession->getQuizDistributionId();
$distribution = $quizDistributionRelSession->getDistribution();
$dataTracking = array();
if (!empty($distribution)) {
$dataTracking = $distribution->getDataTracking();
}
// Form question list found!
if (!empty($dataTracking)) {
$questionList = explode(',', $dataTracking);
// We make a little shuffle now.
$questionByCategory = Testcategory::getCategoriesFromQuestionList(
$questionList,
$this->course_id
);
$cat = new Testcategory();
$categoriesAddedInExercise = $cat->getCategoryExerciseTree(
$this->id,
null,
null,
false,
false,
false
);
$questionList = self::shuffleQuestionListPerCategory($questionByCategory, $categoriesAddedInExercise);
$questionList = ArrayClass::array_flatten($questionList);
}
}
}
}
}
$this->setMediaList($questionList, $this->course_id);
$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 = ArrayClass::array_flatten($new_question_list);
}
} else {
$new_question_list = $question_list;
}
}
return $new_question_list;
}
/**
* @param int $exe_id
* @return array
*/
public function getStatTrackExerciseInfoByExeId($exe_id)
{
$track_exercises = Database :: get_main_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;
}
/**
* @param int $exe_id
* @param int $question_id
* @param string $action
*/
public function edit_question_to_remind($exe_id, $question_id, $action = 'add')
{
$exercise_info = self::getStatTrackExerciseInfoByExeId($exe_id);
$question_id = intval($question_id);
$exe_id = intval($exe_id);
$track_exercises = Database :: get_main_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 ";
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);
}
}
}
/**
* @param string $answer
* @return mixed
*/
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;
}
/**
* @param $answer
* @return string
*/
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)) {
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;
}
/**
* Returns a time limit message
* @return string
*/
public function returnTimeLeftDiv()
{
$message = Display::return_message(
get_lang('ReachedTimeLimit'), 'warning' ).' '.sprintf(get_lang('YouWillBeRedirectedInXSeconds'),
''
);
$html = ' ';
$html .= '