12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343 |
- <?php
- /* For licensing terms, see /license.txt */
- use ChamiloSession as Session;
- /**
- * Class MultipleAnswerTrueFalseDegreeCertainty
- * This class allows to instantiate an object of type MULTIPLE_ANSWER
- * (MULTIPLE CHOICE, MULTIPLE ANSWER), extending the class question.
- *
- * @package chamilo.exercise
- */
- class MultipleAnswerTrueFalseDegreeCertainty extends Question
- {
- const LEVEL_DARKGREEN = 1;
- const LEVEL_LIGHTGREEN = 2;
- const LEVEL_WHITE = 3;
- const LEVEL_LIGHTRED = 4;
- const LEVEL_DARKRED = 5;
- public static $typePicture = 'mccert.png';
- public static $explanationLangVar = 'MultipleAnswerTrueFalseDegreeCertainty';
- public $optionsTitle;
- public $options;
- /**
- * Constructor.
- */
- public function __construct()
- {
- parent::__construct();
- $this->type = MULTIPLE_ANSWER_TRUE_FALSE_DEGREE_CERTAINTY;
- $this->isContent = $this->getIsContent();
- $this->optionsTitle = [1 => 'Answers', 2 => 'DegreeOfCertaintyThatMyAnswerIsCorrect'];
- $this->options = [
- 1 => 'True',
- 2 => 'False',
- 3 => '50%',
- 4 => '60%',
- 5 => '70%',
- 6 => '80%',
- 7 => '90%',
- 8 => '100%',
- ];
- }
- /**
- * Redefines Question::createAnswersForm: creates the HTML form to answer the question.
- *
- * @uses \globals $text and $class, defined in the calling script
- *
- * @param FormValidator $form
- *
- * @throws Exception
- * @throws HTML_QuickForm_Error
- */
- public function createAnswersForm($form)
- {
- global $text;
- $nbAnswers = isset($_POST['nb_answers']) ? (int) $_POST['nb_answers'] : 4;
- // The previous default value was 2. See task #1759.
- $nbAnswers += (isset($_POST['lessAnswers']) ? -1 : (isset($_POST['moreAnswers']) ? 1 : 0));
- $courseId = api_get_course_int_id();
- $objEx = Session::read('objExercise');
- $renderer = &$form->defaultRenderer();
- $defaults = [];
- $html = '<table class="data_table"><tr style="text-align: center;"><th>'
- .get_lang('Number')
- .'</th><th>'
- .get_lang('True')
- .'</th><th>'
- .get_lang('False')
- .'</th><th>'
- .get_lang('Answer')
- .'</th>';
- // show column comment when feedback is enable
- if ($objEx->getFeedbackType() != EXERCISE_FEEDBACK_TYPE_EXAM) {
- $html .= '<th>'.get_lang('Comment').'</th>';
- }
- $html .= '</tr>';
- $form->addElement('label', get_lang('Answers').'<br /> <img src="../img/fill_field.png">', $html);
- $correct = 0;
- $answer = null;
- if (!empty($this->id)) {
- $answer = new Answer($this->id);
- $answer->read();
- if ($answer->nbrAnswers > 0 && !$form->isSubmitted()) {
- $nbAnswers = $answer->nbrAnswers;
- }
- }
- $form->addElement('hidden', 'nb_answers');
- $boxesNames = [];
- if ($nbAnswers < 1) {
- $nbAnswers = 1;
- echo Display::return_message(get_lang('YouHaveToCreateAtLeastOneAnswer'));
- }
- // Can be more options
- $optionData = Question::readQuestionOption($this->id, $courseId);
- for ($i = 1; $i <= $nbAnswers; $i++) {
- $renderer->setElementTemplate(
- '<td><!-- BEGIN error --><span class="form_error">{error}</span><!-- END error --><br/>{element}</td>',
- 'correct['.$i.']'
- );
- $renderer->setElementTemplate(
- '<td><!-- BEGIN error --><span class="form_error">{error}</span><!-- END error --><br/>{element}</td>',
- 'counter['.$i.']'
- );
- $renderer->setElementTemplate(
- '<td><!-- BEGIN error --><span class="form_error">{error}</span><!-- END error --><br/>{element}</td>',
- 'answer['.$i.']'
- );
- $renderer->setElementTemplate(
- '<td><!-- BEGIN error --><span class="form_error">{error}</span><!-- END error --><br/>{element}</td>',
- 'comment['.$i.']'
- );
- $answerNumber = $form->addElement('text', 'counter['.$i.']', null, 'value="'.$i.'"');
- $answerNumber->freeze();
- $defaults['answer['.$i.']'] = '';
- $defaults['comment['.$i.']'] = '';
- $defaults['correct['.$i.']'] = '';
- if (is_object($answer)) {
- $defaults['answer['.$i.']'] = isset($answer->answer[$i]) ? $answer->answer[$i] : '';
- if (isset($_POST['answer']) && isset($_POST['answer'][$i])) {
- $defaults['answer['.$i.']'] = Security::remove_XSS($_POST['answer'][$i]);
- }
- $defaults['comment['.$i.']'] = isset($answer->comment[$i]) ? $answer->comment[$i] : '';
- if (isset($_POST['comment']) && isset($_POST['comment'][$i])) {
- $defaults['comment['.$i.']'] = Security::remove_XSS($_POST['comment'][$i]);
- }
- $defaults['weighting['.$i.']'] = isset($answer->weighting[$i]) ? float_format($answer->weighting[$i], 1) : '';
- $correct = isset($answer->correct[$i]) ? $answer->correct[$i] : '';
- $defaults['correct['.$i.']'] = $correct;
- if (isset($_POST['correct']) && isset($_POST['correct'][$i])) {
- $defaults['correct['.$i.']'] = Security::remove_XSS($_POST['correct'][$i]);
- }
- $j = 1;
- if (!empty($optionData)) {
- foreach ($optionData as $id => $data) {
- $form->addElement('radio', 'correct['.$i.']', null, null, $id);
- $j++;
- if ($j == 3) {
- break;
- }
- }
- }
- } else {
- $form->addElement('radio', 'correct['.$i.']', null, null, 1);
- $form->addElement('radio', 'correct['.$i.']', null, null, 2);
- }
- $boxesNames[] = 'correct['.$i.']';
- $form->addElement(
- 'html_editor',
- 'answer['.$i.']',
- null,
- ['style' => 'vertical-align:middle;'],
- ['ToolbarSet' => 'TestProposedAnswer', 'Width' => '100%', 'Height' => '100']
- );
- $form->addRule('answer['.$i.']', get_lang('ThisFieldIsRequired'), 'required');
- // show comment when feedback is enable
- if ($objEx->getFeedbackType() != EXERCISE_FEEDBACK_TYPE_EXAM) {
- $form->addElement(
- 'html_editor',
- 'comment['.$i.']',
- null,
- ['style' => 'vertical-align:middle;'],
- ['ToolbarSet' => 'TestProposedAnswer', 'Width' => '100%', 'Height' => '100']
- );
- }
- $form->addElement('html', '</tr>');
- }
- $form->addElement('html', '</table>');
- $form->addElement('html', '<br />');
- // 3 scores
- $form->addElement('text', 'option[1]', get_lang('Correct'), ['class' => 'span1', 'value' => '1']);
- $form->addElement('text', 'option[2]', get_lang('Wrong'), ['class' => 'span1', 'value' => '-0.5']);
- $form->addElement('hidden', 'option[3]', 0);
- $form->addRule('option[1]', get_lang('ThisFieldIsRequired'), 'required');
- $form->addRule('option[2]', get_lang('ThisFieldIsRequired'), 'required');
- $form->addElement('html', '</tr><table>');
- $form->addElement('hidden', 'options_count', 3);
- $form->addElement('html', '</table><br /><br />');
- //Extra values True, false, Dont known
- if (!empty($this->extra)) {
- $scores = explode(':', $this->extra);
- if (!empty($scores)) {
- for ($i = 1; $i <= 3; $i++) {
- $defaults['option['.$i.']'] = $scores[$i - 1];
- }
- }
- }
- if ($objEx->edit_exercise_in_lp === true ||
- (empty($this->exerciseList) && empty($objEx->id))
- ) {
- $form->addElement('submit', 'lessAnswers', get_lang('LessAnswer'), 'class="btn btn-danger minus"');
- $form->addElement('submit', 'moreAnswers', get_lang('PlusAnswer'), 'class="btn btn-primary plus"');
- //$text and $class defined in calling script
- $form->addElement('submit', 'submitQuestion', $text, 'class = "btn btn-primary"');
- }
- $renderer->setElementTemplate('{element} ', 'lessAnswers');
- $renderer->setElementTemplate('{element} ', 'submitQuestion');
- $renderer->setElementTemplate('{element} ', 'moreAnswers');
- $form->addElement('html', '</div></div>');
- $defaults['correct'] = $correct;
- if (!empty($this->id)) {
- $form->setDefaults($defaults);
- } else {
- $form->setDefaults($defaults);
- }
- $form->setConstants(['nb_answers' => $nbAnswers]);
- }
- /**
- * abstract function which creates the form to create / edit the answers of the question.
- *
- * @param FormValidator $form
- * @param Exercise $exercise
- */
- public function processAnswersCreation($form, $exercise)
- {
- $questionWeighting = 0;
- $objAnswer = new Answer($this->id);
- $nbAnswers = $form->getSubmitValue('nb_answers');
- $courseId = api_get_course_int_id();
- $correct = [];
- $options = Question::readQuestionOption($this->id, $courseId);
- if (!empty($options)) {
- foreach ($options as $optionData) {
- $id = $optionData['id'];
- unset($optionData['id']);
- Question::updateQuestionOption($id, $optionData, $courseId);
- }
- } else {
- for ($i = 1; $i <= 8; $i++) {
- $lastId = Question::saveQuestionOption($this->id, $this->options[$i], $courseId, $i);
- $correct[$i] = $lastId;
- }
- }
- /* Getting quiz_question_options (true, false, doubt) because
- it's possible that there are more options in the future */
- $newOptions = Question::readQuestionOption($this->id, $courseId);
- $sortedByPosition = [];
- foreach ($newOptions as $item) {
- $sortedByPosition[$item['position']] = $item;
- }
- /* Saving quiz_question.extra values that has the correct scores of
- the true, false, doubt options registered in this format
- XX:YY:ZZZ where XX is a float score value. */
- $extraValues = [];
- for ($i = 1; $i <= 3; $i++) {
- $score = trim($form->getSubmitValue('option['.$i.']'));
- $extraValues[] = $score;
- }
- $this->setExtra(implode(':', $extraValues));
- for ($i = 1; $i <= $nbAnswers; $i++) {
- $answer = trim($form->getSubmitValue('answer['.$i.']'));
- $comment = trim($form->getSubmitValue('comment['.$i.']'));
- $goodAnswer = trim($form->getSubmitValue('correct['.$i.']'));
- if (empty($options)) {
- // If this is the first time that the question is created then change
- // the default values from the form 1 and 2 by the correct "option id" registered
- $goodAnswer = $sortedByPosition[$goodAnswer]['id'];
- }
- $questionWeighting += $extraValues[0]; //By default 0 has the correct answers
- $objAnswer->createAnswer($answer, $goodAnswer, $comment, '', $i);
- }
- // saves the answers into the data base
- $objAnswer->save();
- // sets the total weighting of the question
- $this->updateWeighting($questionWeighting);
- $this->save($exercise);
- }
- /**
- * {@inheritdoc}
- */
- public function return_header(Exercise $exercise, $counter = null, $score = [])
- {
- $header = parent::return_header($exercise, $counter, $score);
- $header .= '<table class="'.$this->question_table_class.'"><tr>';
- $header .= '<th>'.get_lang('Choice').'</th>';
- if ($exercise->showExpectedChoiceColumn()) {
- $header .= '<th>'.get_lang('ExpectedChoice').'</th>';
- }
- $header .= '<th>'
- .get_lang('Answer')
- .'</th><th colspan="2" style="text-align:center;">'
- .get_lang('YourDegreeOfCertainty')
- .'</th>'
- ;
- if ($exercise->getFeedbackType() != EXERCISE_FEEDBACK_TYPE_EXAM) {
- $header .= '<th>'.get_lang('Comment').'</th>';
- } else {
- $header .= '<th> </th>';
- }
- $header .= '</tr>';
- return $header;
- }
- /**
- * Get color code, status, label and description for the current answer.
- *
- * @param string $studentAnswer
- * @param string $expectedAnswer
- * @param int $studentDegreeChoicePosition
- *
- * @return array An array with indexes 'color', 'background-color', 'status', 'label' and 'description'
- */
- public function getResponseDegreeInfo($studentAnswer, $expectedAnswer, $studentDegreeChoicePosition)
- {
- $result = [];
- if ($studentDegreeChoicePosition == 3) {
- $result = [
- 'color' => '#000000',
- 'background-color' => '#F6BA2A',
- 'status' => self::LEVEL_WHITE,
- 'label' => get_lang('DegreeOfCertaintyDeclaredIgnorance'),
- 'description' => get_lang('DegreeOfCertaintyDeclaredIgnoranceDescription'),
- ];
- } else {
- $checkResult = $studentAnswer == $expectedAnswer ? true : false;
- if ($checkResult) {
- if ($studentDegreeChoicePosition >= 6) {
- $result = [
- 'color' => '#FFFFFF',
- 'background-color' => '#1E9C55',
- 'status' => self::LEVEL_DARKGREEN,
- 'label' => get_lang('DegreeOfCertaintyVerySure'),
- 'description' => get_lang('DegreeOfCertaintyVerySureDescription'),
- ];
- } elseif ($studentDegreeChoicePosition >= 4 && $studentDegreeChoicePosition <= 5) {
- $result = [
- 'color' => '#000000',
- 'background-color' => '#B1E183',
- 'status' => self::LEVEL_LIGHTGREEN,
- 'label' => get_lang('DegreeOfCertaintyPrettySure'),
- 'description' => get_lang('DegreeOfCertaintyPrettySureDescription'),
- ];
- }
- } else {
- if ($studentDegreeChoicePosition >= 6) {
- $result = [
- 'color' => '#FFFFFF',
- 'background-color' => '#ED4040',
- 'status' => self::LEVEL_DARKRED,
- 'label' => get_lang('DegreeOfCertaintyVeryUnsure'),
- 'description' => get_lang('DegreeOfCertaintyVeryUnsureDescription'),
- ];
- } elseif ($studentDegreeChoicePosition >= 4 && $studentDegreeChoicePosition <= 5) {
- $result = [
- 'color' => '#000000',
- 'background-color' => '#F79B88',
- 'status' => self::LEVEL_LIGHTRED,
- 'label' => get_lang('DegreeOfCertaintyUnsure'),
- 'description' => get_lang('DegreeOfCertaintyUnsureDescription'),
- ];
- }
- }
- }
- return $result;
- }
- /**
- * Method to show the code color and his meaning for the test result.
- */
- public static function showColorCodes()
- {
- ?>
- <table class="fc-border-separate" cellspacing="0" style="width:600px;
- margin: auto; border: 3px solid #A39E9E;" >
- <tr style="border-bottom: 1px solid #A39E9E;">
- <td style="width:15%; height:30px; background-color: #088A08; border-right: 1px solid #A39E9E;">
-
- </td>
- <td style="padding-left:10px;">
- <b><?php echo get_lang('DegreeOfCertaintyVerySure'); ?> :</b>
- <?php echo get_lang('DegreeOfCertaintyVerySureDescription'); ?>
- </td>
- </tr>
- <tr style="border-bottom: 1px solid #A39E9E;">
- <td style="width:15%; height:30px; background-color: #A9F5A9; border-right: 1px solid #A39E9E;">
-
- </td>
- <td style="padding-left:10px;">
- <b><?php echo get_lang('DegreeOfCertaintyPrettySure'); ?> :</b>
- <?php echo get_lang('DegreeOfCertaintyPrettySureDescription'); ?>
- </td>
- </tr>
- <tr style="border: 1px solid #A39E9E;">
- <td style="width:15%; height:30px; background-color: #FFFFFF; border-right: 1px solid #A39E9E;">
-
- </td>
- <td style="padding-left:10px;">
- <b><?php echo get_lang('DegreeOfCertaintyDeclaredIgnorance'); ?> :</b>
- <?php echo get_lang('DegreeOfCertaintyDeclaredIgnoranceDescription'); ?>
- </td>
- </tr>
- <tr style="border: 1px solid #A39E9E;">
- <td style="width:15%; height:30px; background-color: #F6CECE; border-right: 1px solid #A39E9E;">
-
- </td>
- <td style="padding-left:10px;">
- <b><?php echo get_lang('DegreeOfCertaintyUnsure'); ?> :</b>
- <?php echo get_lang('DegreeOfCertaintyUnsureDescription'); ?>
- </td>
- </tr>
- <tr style="border-bottom: 1px solid #A39E9E;">
- <td style="width:15%; height:30px; background-color: #FE2E2E; border-right: 1px solid #A39E9E;">
-
- </td>
- <td style="padding-left:10px;">
- <b><?php echo get_lang('DegreeOfCertaintyVeryUnsure'); ?> :</b>
- <?php echo get_lang('DegreeOfCertaintyVeryUnsureDescription'); ?>
- </td>
- </tr>
- </table><br/>
- <?php
- }
- /**
- * Display basic bar charts of results by category of questions.
- *
- * @param array $scoreListAll
- * @param string $title The block title
- * @param int $sizeRatio
- *
- * @return string The HTML/CSS code for the charts block
- */
- public static function displayDegreeChartByCategory($scoreListAll, $title, $sizeRatio = 1)
- {
- $maxHeight = 0;
- $groupCategoriesByBracket = false;
- if ($groupCategoriesByBracket) {
- $scoreList = [];
- $categoryPrefixList = [];
- // categoryPrefix['Math'] = firstCategoryId for this prefix
- // rebuild $scoreList factorizing data with category prefix
- foreach ($scoreListAll as $categoryId => $scoreListForCategory) {
- $objCategory = new Testcategory();
- $objCategoryNum = $objCategory->getCategory($categoryId);
- preg_match("/^\[([^]]+)\]/", $objCategoryNum->name, $matches);
- if (count($matches) > 1) {
- // check if we have already see this prefix
- if (array_key_exists($matches[1], $categoryPrefixList)) {
- // add the result color for this entry
- $scoreList[$categoryPrefixList[$matches[1]]][self::LEVEL_DARKGREEN] +=
- $scoreListForCategory[self::LEVEL_DARKGREEN];
- $scoreList[$categoryPrefixList[$matches[1]]][self::LEVEL_LIGHTGREEN] +=
- $scoreListForCategory[self::LEVEL_LIGHTGREEN];
- $scoreList[$categoryPrefixList[$matches[1]]][self::LEVEL_WHITE] +=
- $scoreListForCategory[self::LEVEL_WHITE];
- $scoreList[$categoryPrefixList[$matches[1]]][self::LEVEL_LIGHTRED] +=
- $scoreListForCategory[self::LEVEL_LIGHTRED];
- $scoreList[$categoryPrefixList[$matches[1]]][self::LEVEL_DARKRED] +=
- $scoreListForCategory[self::LEVEL_DARKRED];
- } else {
- $categoryPrefixList[$matches[1]] = $categoryId;
- $scoreList[$categoryId] = $scoreListAll[$categoryId];
- }
- } else {
- // doesn't match the prefix '[math] Math category'
- $scoreList[$categoryId] = $scoreListAll[$categoryId];
- }
- }
- } else {
- $scoreList = $scoreListAll;
- }
- // get the max height of item to have each table the same height if displayed side by side
- $testCategory = new TestCategory();
- foreach ($scoreList as $categoryId => $scoreListForCategory) {
- $category = $testCategory->getCategory($categoryId);
- if ($category) {
- $categoryQuestionName = $category->name;
- }
- list($noValue, $height) = self::displayDegreeChartChildren(
- $scoreListForCategory,
- 300,
- '',
- 1,
- 0,
- false,
- true,
- 0
- );
- if ($height > $maxHeight) {
- $maxHeight = $height;
- }
- }
- if (count($scoreList) > 1) {
- $boxWidth = $sizeRatio * 300 * 2 + 54;
- } else {
- $boxWidth = $sizeRatio * 300 + 54;
- }
- $html = '<div class="row-chart">';
- $html .= '<h4 class="chart-title">'.$title.'</h4>';
- $legendTitle = [
- 'DegreeOfCertaintyVeryUnsure',
- 'DegreeOfCertaintyUnsure',
- 'DegreeOfCertaintyDeclaredIgnorance',
- 'DegreeOfCertaintyPrettySure',
- 'DegreeOfCertaintyVerySure',
- ];
- $html .= '<ul class="chart-legend">';
- foreach ($legendTitle as $i => $item) {
- $html .= '<li><i class="fa fa-square square_color'.$i.'" aria-hidden="true"></i> '.get_lang($item).'</li>';
- }
- $html .= '</ul>';
- // get the html of items
- $i = 0;
- $testCategory = new Testcategory();
- foreach ($scoreList as $categoryId => $scoreListForCategory) {
- $category = $testCategory->getCategory($categoryId);
- $categoryQuestionName = '';
- if ($category) {
- $categoryQuestionName = $category->name;
- }
- if ($categoryQuestionName === '') {
- $categoryName = get_lang('WithoutCategory');
- } else {
- $categoryName = $categoryQuestionName;
- }
- $html .= '<div class="col-md-4">';
- $html .= self::displayDegreeChartChildren(
- $scoreListForCategory,
- 300,
- $categoryName,
- 1,
- $maxHeight,
- false,
- false,
- $groupCategoriesByBracket
- );
- $html .= '</div>';
- if ($i == 2) {
- $html .= '<div style="clear:both; height: 10px;"> </div>';
- $i = 0;
- } else {
- $i++;
- }
- }
- $html .= '</div>';
- return $html.'<div style="clear:both; height: 10px;" > </div>';
- }
- /**
- * Return HTML code for the $scoreList of MultipleAnswerTrueFalseDegreeCertainty questions.
- *
- * @param $scoreList
- * @param $widthTable
- * @param string $title
- * @param int $sizeRatio
- * @param int $minHeight
- * @param bool $displayExplanationText
- * @param bool $returnHeight
- * @param bool $groupCategoriesByBracket
- * @param int $numberOfQuestions
- *
- * @return array|string
- */
- public static function displayDegreeChart(
- $scoreList,
- $widthTable,
- $title = '',
- $sizeRatio = 1,
- $minHeight = 0,
- $displayExplanationText = true,
- $returnHeight = false,
- $groupCategoriesByBracket = false,
- $numberOfQuestions = 0
- ) {
- $topAndBottomMargin = 10;
- $colorList = [
- self::LEVEL_DARKRED,
- self::LEVEL_LIGHTRED,
- self::LEVEL_WHITE,
- self::LEVEL_LIGHTGREEN,
- self::LEVEL_DARKGREEN,
- ];
- // get total attempt number
- $highterColorHeight = 0;
- foreach ($scoreList as $color => $number) {
- if ($number > $highterColorHeight) {
- $highterColorHeight = $number;
- }
- }
- $totalAttemptNumber = $numberOfQuestions;
- $verticalLineHeight = $highterColorHeight * $sizeRatio * 2 + 122 + $topAndBottomMargin * 2;
- if ($verticalLineHeight < $minHeight) {
- $minHeightCorrection = $minHeight - $verticalLineHeight;
- $verticalLineHeight += $minHeightCorrection;
- }
- // draw chart
- $html = '';
- if ($groupCategoriesByBracket) {
- $title = api_preg_replace("/[^]]*$/", '', $title);
- $title = ucfirst(api_preg_replace("/[\[\]]/", '', $title));
- }
- $titleDisplay = (strpos($title, "ensemble") > 0) ?
- $title."<br/>($totalAttemptNumber questions)" :
- $title;
- $textSize = (
- strpos($title, 'ensemble') > 0 ||
- strpos($title, 'votre dernier résultat à ce test') > 0
- ) ? 100 : 80;
- $html .= '<div class="row-chart">';
- $html .= '<h4 class="chart-title">'.$titleDisplay.'</h4>';
- $nbResponsesInc = 0;
- if (isset($scoreList[4])) {
- $nbResponsesInc += (int) $scoreList[4];
- }
- if (isset($scoreList[5])) {
- $nbResponsesInc += (int) $scoreList[5];
- }
- $nbResponsesIng = isset($scoreList[3]) ? $scoreList[3] : 0;
- $nbResponsesCor = 0;
- if (isset($scoreList[1])) {
- $nbResponsesCor += (int) $scoreList[1];
- }
- if (isset($scoreList[2])) {
- $nbResponsesCor += (int) $scoreList[2];
- }
- $IncorrectAnswers = sprintf(get_lang('IncorrectAnswersX'), $nbResponsesInc);
- $IgnoranceAnswers = sprintf(get_lang('IgnoranceAnswersX'), $nbResponsesIng);
- $CorrectAnswers = sprintf(get_lang('CorrectAnswersX'), $nbResponsesCor);
- $html .= '<div class="chart-grid">';
- $explainHistoList = null;
- if ($displayExplanationText) {
- // Display of histogram text
- $explainHistoList = [
- 'DegreeOfCertaintyVeryUnsure',
- 'DegreeOfCertaintyUnsure',
- 'DegreeOfCertaintyDeclaredIgnorance',
- 'DegreeOfCertaintyPrettySure',
- 'DegreeOfCertaintyVerySure',
- ];
- }
- foreach ($colorList as $i => $color) {
- if (array_key_exists($color, $scoreList)) {
- $scoreOnBottom = $scoreList[$color]; // height of the colored area on the bottom
- } else {
- $scoreOnBottom = 0;
- }
- $sizeBar = ($scoreOnBottom * $sizeRatio * 2).'px;';
- if ($i == 0) {
- $html .= '<div class="item">';
- $html .= '<div class="panel-certaint" style="min-height:'.$verticalLineHeight.'px; position: relative;">';
- $html .= '<div class="answers-title">'.$IncorrectAnswers.'</div>';
- $html .= '<ul class="certaint-list-two">';
- } elseif ($i == 3) {
- $html .= '<div class="item">';
- $html .= '<div class="panel-certaint" style="height:'.$verticalLineHeight.'px; position: relative;">';
- $html .= '<div class="answers-title">'.$CorrectAnswers.'</div>';
- $html .= '<ul class="certaint-list-two">';
- } elseif ($i == 2) {
- $html .= '<div class="item">';
- $html .= '<div class="panel-certaint" style="height:'.$verticalLineHeight.'px; position: relative;">';
- $html .= '<div class="answers-title">'.$IgnoranceAnswers.'</div>';
- $html .= '<ul class="certaint-list">';
- }
- $html .= '<li>';
- $html .= '<div class="certaint-score">';
- $html .= $scoreOnBottom;
- $html .= '</div>';
- $html .= '<div class="levelbar_'.$color.'" style="height:'.$sizeBar.'"> </div>';
- $html .= '<div class="certaint-text">'.get_lang($explainHistoList[$i]).'</div>';
- $html .= '</li>';
- if ($i == 1 || $i == 2 || $i == 4) {
- $html .= '</ul>';
- $html .= '</div>';
- $html .= '</div>';
- }
- }
- $html .= '</div>';
- $html .= '</div>';
- if ($returnHeight) {
- return [$html, $verticalLineHeight];
- } else {
- return $html;
- }
- }
- /**
- * Return HTML code for the $scoreList of MultipleAnswerTrueFalseDegreeCertainty questions.
- *
- * @param $scoreList
- * @param $widthTable
- * @param string $title
- * @param int $sizeRatio
- * @param int $minHeight
- * @param bool $displayExplanationText
- * @param bool $returnHeight
- * @param bool $groupCategoriesByBracket
- * @param int $numberOfQuestions
- *
- * @return array|string
- */
- public static function displayDegreeChartChildren(
- $scoreList,
- $widthTable,
- $title = '',
- $sizeRatio = 1,
- $minHeight = 0,
- $displayExplanationText = true,
- $returnHeight = false,
- $groupCategoriesByBracket = false,
- $numberOfQuestions = 0
- ) {
- $topAndBottomMargin = 10;
- $colorList = [
- self::LEVEL_DARKRED,
- self::LEVEL_LIGHTRED,
- self::LEVEL_WHITE,
- self::LEVEL_LIGHTGREEN,
- self::LEVEL_DARKGREEN,
- ];
- // get total attempt number
- $highterColorHeight = 0;
- foreach ($scoreList as $color => $number) {
- if ($number > $highterColorHeight) {
- $highterColorHeight = $number;
- }
- }
- $totalAttemptNumber = $numberOfQuestions;
- $verticalLineHeight = $highterColorHeight * $sizeRatio * 2 + 122 + $topAndBottomMargin * 2;
- if ($verticalLineHeight < $minHeight) {
- $minHeightCorrection = $minHeight - $verticalLineHeight;
- $verticalLineHeight += $minHeightCorrection;
- }
- // draw chart
- $html = '';
- if ($groupCategoriesByBracket) {
- $title = api_preg_replace("/[^]]*$/", '', $title);
- $title = ucfirst(api_preg_replace("/[\[\]]/", '', $title));
- }
- $textSize = 80;
- $classGlobalChart = '';
- if ($displayExplanationText) {
- // global chart
- $classGlobalChart = 'globalChart';
- }
- $html .= '<table class="certaintyTable" style="height :'.$verticalLineHeight.'px; margin-bottom: 10px;" >';
- $html .= '<tr><th colspan="5" class="'.$classGlobalChart.'">'
- .$title
- .'</th><tr>'
- ;
- $nbResponsesInc = 0;
- if (isset($scoreList[4])) {
- $nbResponsesInc += (int) $scoreList[4];
- }
- if (isset($scoreList[5])) {
- $nbResponsesInc += (int) $scoreList[5];
- }
- $nbResponsesIng = isset($scoreList[3]) ? $scoreList[3] : 0;
- $nbResponsesCor = 0;
- if (isset($scoreList[1])) {
- $nbResponsesCor += (int) $scoreList[1];
- }
- if (isset($scoreList[2])) {
- $nbResponsesCor += (int) $scoreList[2];
- }
- $colWidth = $widthTable / 5;
- $html .= '<tr>
- <td class="firstLine borderRight '.$classGlobalChart.'"
- colspan="2"
- style="width:'.($colWidth * 2).'px; line-height: 15px; font-size:'.$textSize.'%;">'.
- sprintf(get_lang('IncorrectAnswersX'), $nbResponsesInc).'
- </td>
- <td class="firstLine borderRight '.$classGlobalChart.'"
- style="width:'.$colWidth.'px; line-height: 15px; font-size :'.$textSize.'%;">'.
- sprintf(get_lang('IgnoranceAnswersX'), $nbResponsesIng).'
- </td>
- <td class="firstLine '.$classGlobalChart.'"
- colspan="2"
- style="width:'.($colWidth * 2).'px; line-height: 15px; font-size:'.$textSize.'%;">'.
- sprintf(get_lang('CorrectAnswersX'), $nbResponsesCor).'
- </td>
- </tr>';
- $html .= '<tr>';
- foreach ($colorList as $i => $color) {
- if (array_key_exists($color, $scoreList)) {
- $scoreOnBottom = $scoreList[$color]; // height of the colored area on the bottom
- } else {
- $scoreOnBottom = 0;
- }
- $sizeOnBottom = $scoreOnBottom * $sizeRatio * 2;
- if ($i == 1 || $i == 2) {
- $html .= '<td width="'
- .$colWidth
- .'px" style="border-right: 1px dotted #7FC5FF; vertical-align: bottom;font-size: '
- .$textSize
- .'%;">'
- ;
- } else {
- $html .= '<td width="'
- .$colWidth
- .'px" style="vertical-align: bottom;font-size: '
- .$textSize
- .'%;">'
- ;
- }
- $html .= '<div class="certaint-score">'
- .$scoreOnBottom
- .'</div><div class="levelbar_'
- .$color
- .'" style="height: '
- .$sizeOnBottom
- .'px;"> </div>'
- ;
- $html .= '</td>';
- }
- $html .= '</tr>';
- if ($displayExplanationText) {
- // Display of histogram text
- $explainHistoList = [
- 'DegreeOfCertaintyVeryUnsure',
- 'DegreeOfCertaintyUnsure',
- 'DegreeOfCertaintyDeclaredIgnorance',
- 'DegreeOfCertaintyPrettySure',
- 'DegreeOfCertaintyVerySure',
- ];
- $html .= '<tr>';
- $i = 0;
- foreach ($explainHistoList as $explain) {
- if ($i == 1 || $i == 2) {
- $class = 'borderRight';
- } else {
- $class = '';
- }
- $html .= '<td class="firstLine '
- .$class
- .' '
- .$classGlobalChart
- .'" style="width="'
- .$colWidth
- .'px; font-size:'
- .$textSize
- .'%;">'
- ;
- $html .= get_lang($explain);
- $html .= '</td>';
- $i++;
- }
- $html .= '</tr>';
- }
- $html .= '</table></center>';
- if ($returnHeight) {
- return [$html, $verticalLineHeight];
- } else {
- return $html;
- }
- }
- /**
- * return previous attempt id for this test for student, 0 if no previous attempt.
- *
- * @param $exeId
- *
- * @return int
- */
- public static function getPreviousAttemptId($exeId)
- {
- $tblTrackEExercise = Database::get_main_table(TABLE_STATISTIC_TRACK_E_EXERCISES);
- $exeId = (int) $exeId;
- $sql = "SELECT * FROM $tblTrackEExercise
- WHERE exe_id = ".$exeId;
- $res = Database::query($sql);
- if (empty(Database::num_rows($res))) {
- // if we cannot find the exe_id
- return 0;
- }
- $data = Database::fetch_assoc($res);
- $courseCode = $data['c_id'];
- $exerciseId = $data['exe_exo_id'];
- $userId = $data['exe_user_id'];
- $attemptDate = $data['exe_date'];
- if ($attemptDate == '0000-00-00 00:00:00') {
- // incomplete attempt, close it before continue
- return 0;
- }
- // look for previous attempt
- $exerciseId = (int) $exerciseId;
- $userId = (int) $userId;
- $sql = "SELECT *
- FROM $tblTrackEExercise
- WHERE c_id = '$courseCode'
- AND exe_exo_id = $exerciseId
- AND exe_user_id = $userId
- AND status = ''
- AND exe_date > '0000-00-00 00:00:00'
- AND exe_date < '$attemptDate'
- ORDER BY exe_date DESC";
- $res = Database::query($sql);
- if (Database::num_rows($res) == 0) {
- // no previous attempt
- return 0;
- }
- $data = Database::fetch_assoc($res);
- return $data['exe_id'];
- }
- /**
- * return an array of number of answer color for exe attempt
- * for question type = MULTIPLE_ANSWER_TRUE_FALSE_DEGREE_CERTAINTY
- * e.g.
- * [LEVEL_DARKGREEN => 3, LEVEL_LIGHTGREEN => 0, LEVEL_WHITE => 5, LEVEL_LIGHTRED => 12, LEVEL_DARKTRED => 0].
- *
- * @param $exeId
- *
- * @return array
- */
- public static function getColorNumberListForAttempt($exeId)
- {
- $result = [
- self::LEVEL_DARKGREEN => 0,
- self::LEVEL_LIGHTGREEN => 0,
- self::LEVEL_WHITE => 0,
- self::LEVEL_LIGHTRED => 0,
- self::LEVEL_DARKRED => 0,
- ];
- $attemptInfoList = self::getExerciseAttemptInfo($exeId);
- foreach ($attemptInfoList as $attemptInfo) {
- $oQuestion = new MultipleAnswerTrueFalseDegreeCertainty();
- $oQuestion->read($attemptInfo['question_id']);
- if ($oQuestion->type == MULTIPLE_ANSWER_TRUE_FALSE_DEGREE_CERTAINTY) {
- $answerColor = self::getAnswerColor($exeId, $attemptInfo['question_id'], $attemptInfo['position']);
- if ($answerColor) {
- $result[$answerColor]++;
- }
- }
- }
- return $result;
- }
- /**
- * return an array of number of color for question type = MULTIPLE_ANSWER_TRUE_FALSE_DEGREE_CERTAINTY
- * for each question category.
- *
- * e.g.
- * [
- * (categoryId=)5 => [LEVEL_DARKGREEN => 3, LEVEL_WHITE => 5, LEVEL_LIGHTRED => 12]
- * (categoryId=)2 => [LEVEL_DARKGREEN => 8, LEVEL_LIGHTRED => 2, LEVEL_DARKTRED => 8]
- * (categoryId=)0 => [LEVEL_DARKGREEN => 1,
- * LEVEL_LIGHTGREEN => 2,
- * LEVEL_WHITE => 6,
- * LEVEL_LIGHTRED => 1,
- * LEVEL_DARKTRED => 9]
- * ]
- *
- * @param int $exeId
- *
- * @return array
- */
- public static function getColorNumberListForAttemptByCategory($exeId)
- {
- $result = [];
- $attemptInfoList = self::getExerciseAttemptInfo($exeId);
- foreach ($attemptInfoList as $attemptInfo) {
- $oQuestion = new MultipleAnswerTrueFalseDegreeCertainty();
- $oQuestion->read($attemptInfo['question_id']);
- if ($oQuestion->type == MULTIPLE_ANSWER_TRUE_FALSE_DEGREE_CERTAINTY) {
- $questionCategory = Testcategory::getCategoryForQuestion($attemptInfo['question_id']);
- if (!array_key_exists($questionCategory, $result)) {
- $result[$questionCategory] = [];
- }
- $answerColor = self::getAnswerColor($exeId, $attemptInfo['question_id'], $attemptInfo['position']);
- if ($answerColor && isset($result[$questionCategory])) {
- if (!isset($result[$questionCategory][$answerColor])) {
- $result[$questionCategory][$answerColor] = 0;
- }
- $result[$questionCategory][$answerColor]++;
- }
- }
- }
- return $result;
- }
- /**
- * Return true if answer of $exeId, $questionId, $position is correct, otherwise return false.
- *
- * @param $exeId
- * @param $questionId
- * @param $position
- *
- * @return int
- */
- public static function getAnswerColor($exeId, $questionId, $position)
- {
- $attemptInfoList = self::getExerciseAttemptInfo($exeId, $questionId, $position);
- if (count($attemptInfoList) != 1) {
- // havent got the answer
- return 0;
- }
- $answerCodes = $attemptInfoList[0]['answer'];
- // student answer
- $splitAnswer = preg_split("/:/", $answerCodes);
- // get correct answer option id
- $correctAnswerOptionId = self::getCorrectAnswerOptionId($splitAnswer[0]);
- if ($correctAnswerOptionId == 0) {
- // error returning the correct answer option id
- return 0;
- }
- // get student answer option id
- $studentAnswerOptionId = isset($splitAnswer[1]) ? $splitAnswer[1] : null;
- // we got the correct answer option id, let's compare ti with the student answer
- $percentage = null;
- if (isset($splitAnswer[2])) {
- $percentage = self::getPercentagePosition($splitAnswer[2]);
- }
- if ($studentAnswerOptionId == $correctAnswerOptionId) {
- // yeah, student got correct answer
- switch ($percentage) {
- case 3:
- return self::LEVEL_WHITE;
- case 4:
- case 5:
- return self::LEVEL_LIGHTGREEN;
- case 6:
- case 7:
- case 8:
- return self::LEVEL_DARKGREEN;
- default:
- return 0;
- }
- } else {
- // bummer, wrong answer dude
- switch ($percentage) {
- case 3:
- return self::LEVEL_WHITE;
- case 4:
- case 5:
- return self::LEVEL_LIGHTRED;
- case 6:
- case 7:
- case 8:
- return self::LEVEL_DARKRED;
- default:
- return 0;
- }
- }
- }
- /**
- * Return the position of certitude %age choose by student.
- *
- * @param $optionId
- *
- * @return int
- */
- public static function getPercentagePosition($optionId)
- {
- $tblAnswerOption = Database::get_course_table(TABLE_QUIZ_QUESTION_OPTION);
- $courseId = api_get_course_int_id();
- $optionId = (int) $optionId;
- $sql = "SELECT position
- FROM $tblAnswerOption
- WHERE c_id = $courseId AND id = $optionId";
- $res = Database::query($sql);
- if (Database::num_rows($res) == 0) {
- return 0;
- }
- $data = Database::fetch_assoc($res);
- return $data['position'];
- }
- /**
- * return the correct id from c_quiz_question_option for question idAuto.
- *
- * @param $idAuto
- *
- * @return int
- */
- public static function getCorrectAnswerOptionId($idAuto)
- {
- $tblAnswer = Database::get_course_table(TABLE_QUIZ_ANSWER);
- $courseId = api_get_course_int_id();
- $idAuto = (int) $idAuto;
- $sql = "SELECT correct FROM $tblAnswer
- WHERE c_id = $courseId AND id_auto = $idAuto";
- $res = Database::query($sql);
- $data = Database::fetch_assoc($res);
- if (Database::num_rows($res) > 0) {
- return $data['correct'];
- } else {
- return 0;
- }
- }
- /**
- * return an array of exe info from track_e_attempt.
- *
- * @param int $exeId
- * @param int $questionId
- * @param int $position
- *
- * @return array
- */
- public static function getExerciseAttemptInfo($exeId, $questionId = -1, $position = -1)
- {
- $result = [];
- $and = '';
- $questionId = (int) $questionId;
- $position = (int) $position;
- $exeId = (int) $exeId;
- if ($questionId >= 0) {
- $and .= " AND question_id = $questionId";
- }
- if ($position >= 0) {
- $and .= " AND position = $position";
- }
- $tblExeAttempt = Database::get_main_table(TABLE_STATISTIC_TRACK_E_ATTEMPT);
- $cId = api_get_course_int_id();
- $sql = "SELECT * FROM $tblExeAttempt
- WHERE c_id = $cId AND exe_id = $exeId $and";
- $res = Database::query($sql);
- while ($data = Database::fetch_assoc($res)) {
- $result[] = $data;
- }
- return $result;
- }
- /**
- * @param int $exeId
- *
- * @return int
- */
- public static function getNumberOfQuestionsForExeId($exeId)
- {
- $tableTrackEExercise = Database::get_main_table(TABLE_STATISTIC_TRACK_E_EXERCISES);
- $exeId = (int) $exeId;
- $sql = "SELECT exe_exo_id
- FROM $tableTrackEExercise
- WHERE exe_id=".$exeId;
- $res = Database::query($sql);
- $data = Database::fetch_assoc($res);
- if ($data) {
- $exerciseId = $data['exe_exo_id'];
- $objectExercise = new Exercise();
- $objectExercise->read($exerciseId);
- return $objectExercise->getQuestionCount();
- }
- return 0;
- }
- /**
- * Display student chart results for these question types.
- *
- * @param int $exeId
- * @param Exercise $objExercice
- *
- * @return string
- */
- public static function displayStudentsChartResults($exeId, $objExercice)
- {
- $numberOfQuestions = self::getNumberOfQuestionsForExeId($exeId);
- $globalScoreList = self::getColorNumberListForAttempt($exeId);
- $html = self::displayDegreeChart(
- $globalScoreList,
- 600,
- get_lang('YourOverallResultForTheTest'),
- 2,
- 0,
- true,
- false,
- false,
- $numberOfQuestions
- );
- $html .= '<br/>';
- $previousAttemptId = self::getPreviousAttemptId($exeId);
- if ($previousAttemptId > 0) {
- $previousAttemptScoreList = self::getColorNumberListForAttempt(
- $previousAttemptId
- );
- $html .= self::displayDegreeChart(
- $previousAttemptScoreList,
- 600,
- get_lang('ForComparisonYourLastResultToThisTest'),
- 2
- );
- $html .= '<br/>';
- }
- $list = self::getColorNumberListForAttemptByCategory($exeId);
- $html .= self::displayDegreeChartByCategory(
- $list,
- get_lang('YourResultsByDiscipline'),
- 1,
- $objExercice
- );
- $html .= '<br/>';
- return $html;
- }
- /**
- * send mail to student with degre certainty result test.
- *
- * @param int $userId
- * @param Exercise $objExercise
- * @param int $exeId
- */
- public static function sendQuestionCertaintyNotification($userId, $objExercise, $exeId)
- {
- $userInfo = api_get_user_info($userId);
- $recipientName = api_get_person_name($userInfo['firstname'],
- $userInfo['lastname'],
- null,
- PERSON_NAME_EMAIL_ADDRESS
- );
- $subject = "[".get_lang('DoNotReply')."] "
- .html_entity_decode(get_lang('ResultAccomplishedTest')." \"".$objExercise->title."\"");
- // message sended to the student
- $message = get_lang('Dear').' '.$recipientName.",<br /><br />";
- $exerciseLink = "<a href='".api_get_path(WEB_CODE_PATH)."/exercise/result.php?show_headers=1&"
- .api_get_cidreq()
- ."&id=$exeId'>";
- $exerciseTitle = $objExercise->title;
- $message .= sprintf(
- get_lang('MessageQuestionCertainty'),
- $exerciseTitle,
- api_get_path(WEB_PATH),
- $exerciseLink
- );
- // show histogram
- $message .= self::displayStudentsChartResults($exeId, $objExercise);
- $message .= get_lang('KindRegards');
- $message = api_preg_replace("/\\\n/", '', $message);
- MessageManager::send_message_simple($userId, $subject, $message);
- }
- }
|