Process Essay Questions
Parse an essay rawquestion and add the result
to the array of questions already parsed.
@param object $quest rawquestion
@param array $questions array of Moodle questions already done.
11378
public function process_essay($quest, &$questions) {

        $question = $this->process_common($quest);
        $question->qtype = 'essay';

        $question->feedback = array();
        // Not sure where to get the correct answer from?
        foreach ($quest->feedback as $feedback) {
            // Added this code to put the possible solution that the
            // instructor gives as the Moodle answer for an essay question.
            if ($feedback->ident == 'solution') {
                $question->graderinfo = $this->cleaned_text_field($feedback->text);
            }
        }
        // Added because essay/questiontype.php:save_question_option is expecting a
        // fraction property - CT 8/10/06.
        $question->fraction[] = 1;
        $question->defaultmark = 1;
        $question->responseformat = 'editor';
        $question->responserequired = 1;
        $question->responsefieldlines = 15;
        $question->attachments = 0;
        $question->attachmentsrequired = 0;
        $question->responsetemplate = $this->text_field('');

        $questions[] = $question;
    }
995366
public function matchStatement($translatorevent, $questionAttempt, $question) {

        $translatorevent['interaction_type'] = 'matching';

        $targets = [];
        $sources = [];
        $correctResponses = [];
        $responseTargetsPos = [];
        $responseSourcesPos = [];

        foreach ($question->match->subquestions as $subquestion) {
            $target = strip_tags($subquestion->questiontext);
            $source = strip_tags($subquestion->answertext);
            $targetId = 'moodle_quiz_question_target_'.$subquestion->id;
            $sourceId = 'moodle_quiz_question_source_'.$subquestion->id;
            $targets[$targetId] = $target;
            $sources[$sourceId] = $source;
            array_push(
                $correctResponses, 
                $sourceId.'[.]'.$targetId
            );

            // Get the positions of the target and source within the response string.
            $responseTargetsPos[strpos($questionAttempt->responsesummary, $target)] = $targetId;
            $responseSourcesPos[strpos($questionAttempt->responsesummary, $source)] = $sourceId;
        }

        // Get ordered and indexed lists of target and source.
        ksort($responseTargetsPos);
        $responseTargets = array_values($responseTargetsPos);
        ksort($responseSourcesPos);
        $responseSources = array_values($responseSourcesPos);

        $translatorevent['attempt_response'] = '';
        if (count($responseTargets) == count($responseSources) && count($responseTargets) > 0) {
            $responses = [];
            foreach ($responseTargets as $index => $targetId) {
                array_push(
                    $responses,
                    $responseSources[$index].'[.]'.$targetId
                );
            }
            $translatorevent['attempt_response'] = implode('[,]', $responses);
        }

        $translatorevent['interaction_target'] = $targets;
        $translatorevent['interaction_source'] = $sources;
        $translatorevent['interaction_correct_responses'] = [implode('[,]', $correctResponses)];

        return $translatorevent;
    }
209455
function ask($question, array $answers) {
		// question loop
		$optstr = implode("|", $answers);
		do {
			$this->printf("$question [$optstr] ");
			$answer = $this->fgets();
		}
		while ( ! in_array($answer, $answers));

		return $answer;
	}
1136326
public static function createResponseWithAnswersForQuery(Query $query, array $answers)
    {
        $response = new Message();
        $response->header->set('id', self::generateId());
        $response->header->set('qr', 1);
        $response->header->set('opcode', Message::OPCODE_QUERY);
        $response->header->set('rd', 1);
        $response->header->set('rcode', Message::RCODE_OK);

        $response->questions[] = (array) $query;

        foreach ($answers as $record) {
            $response->answers[] = $record;
        }

        $response->prepare();

        return $response;
    }
667338
public function load_questions($questionids = null) {
        if ($this->questions === null) {
            throw new coding_exception('You must call preload_questions before calling load_questions.');
        }
        if (is_null($questionids)) {
            $questionids = array_keys($this->questions);
        }
        $questionstoprocess = array();
        foreach ($questionids as $id) {
            if (array_key_exists($id, $this->questions)) {
                $questionstoprocess[$id] = $this->questions[$id];
            }
        }
        get_question_options($questionstoprocess);
    }
1186486
protected function readquestions($text) {

        // This converts xml to big nasty data structure,
        // the 0 means keep white space as it is.
        try {
            $xml = xmlize($text, 0, 'UTF-8', true);
        } catch (xml_format_exception $e) {
            $this->error($e->getMessage(), '');
            return false;
        }

        $questions = array();

        // Treat the assessment title as a category title.
        $this->process_category($xml, $questions);

        // First step : we are only interested in the <item> tags.
        $rawquestions = $this->getpath($xml,
                array('questestinterop', '#', 'assessment', 0, '#', 'section', 0, '#', 'item'),
                array(), false);
        // Each <item> tag contains data related to a single question.
        foreach ($rawquestions as $quest) {
            // Second step : parse each question data into the intermediate
            // rawquestion structure array.
            // Warning : rawquestions are not Moodle questions.
            $question = $this->create_raw_question($quest);
            // Third step : convert a rawquestion into a Moodle question.
            switch($question->qtype) {
                case "Matching":
                    $this->process_matching($question, $questions);
                    break;
                case "Multiple Choice":
                    $this->process_mc($question, $questions);
                    break;
                case "Essay":
                    $this->process_essay($question, $questions);
                    break;
                case "Multiple Answer":
                    $this->process_ma($question, $questions);
                    break;
                case "True/False":
                    $this->process_tf($question, $questions);
                    break;
                case 'Fill in the Blank':
                    $this->process_fblank($question, $questions);
                    break;
                case 'Short Response':
                    $this->process_essay($question, $questions);
                    break;
                default:
                    $this->error(get_string('unknownorunhandledtype', 'question', $question->qtype));
                    break;
            }
        }
        return $questions;
    }
800448
public function askWithCompletion($question, array $choices, $default = null)
    {
        $helper = $this->getHelperSet()->get('question');

        $question = new Question("<question>$question</question> ", $default);

        $question->setAutocompleterValues($choices);

        return $helper->ask($this->input, $this->output, $question);
    }
445515
protected function process_tf($quest, &$questions) {
        $question = $this->process_common($quest);

        $question->qtype = 'truefalse';
        $question->single = 1; // Only one answer is allowed.
        $question->penalty = 1; // Penalty = 1 for truefalse questions.
        // 0th [response] is the correct answer.
        $responses = $quest->responses;
        $correctresponse = $this->getpath($responses[0]->ident[0],
                array('varequal', 0, '#'), '', true);
        if ($correctresponse != 'false') {
            $correct = true;
        } else {
            $correct = false;
        }
        $fback = new stdClass();

        foreach ($quest->feedback as $fb) {
            $fback->{$fb->ident} = $fb->text;
        }

        if ($correct) {  // True is correct.
            $question->answer = 1;
            $question->feedbacktrue = $this->cleaned_text_field($fback->correct);
            $question->feedbackfalse = $this->cleaned_text_field($fback->incorrect);
        } else {  // False is correct.
            $question->answer = 0;
            $question->feedbacktrue = $this->cleaned_text_field($fback->incorrect);
            $question->feedbackfalse = $this->cleaned_text_field($fback->correct);
        }
        $question->correctanswer = $question->answer;
        $questions[] = $question;
    }
146884
public function multichoiceStatement($translatorevent, $questionAttempt, $question) {
        $choices = [];
        foreach ($question->answers as $answer) {
            $choices['moodle_quiz_question_answer_'.$answer->id] = strip_tags($answer->answer);
        }

        // If there are answers, assume multiple choice until proven otherwise.
        $translatorevent['interaction_type'] = 'choice';
        $translatorevent['interaction_choices'] = $choices;

        $responses = [];
        $correctResponses = [];

        // We can't simply explode $questionAttempt->responsesummary because responses may contain "; ". 
        foreach ($choices as $answerId => $choice) {
            if ($this->inResponsesSummary($questionAttempt->responsesummary, $choice, '; ', '; ')) {
                array_push($responses, $answerId);
            }
            if (!(strpos($questionAttempt->rightanswer, $choice) === false)) {
                array_push($correctResponses, $answerId);
            }
        }

        if ($responses != []) {
            $translatorevent['attempt_response'] = implode('[,]', $responses);
        }

        $translatorevent['interaction_correct_responses'] = [implode('[,]', $correctResponses)];

        // Special handling of true-false question type (some overlap with multichoice).
        if ($question->qtype == 'truefalse') {
            $translatorevent['interaction_type'] = 'true-false';
            $translatorevent['interaction_choices'] = null;

            if ($questionAttempt->responsesummary == 'True') {
                $translatorevent['attempt_response'] = 'true';
            } else if ($questionAttempt->responsesummary == 'False') {
                $translatorevent['attempt_response'] = 'false';
            }

            if ($questionAttempt->rightanswer == 'True') {
                $translatorevent['interaction_correct_responses'] = ['true'];
            } else if ($questionAttempt->rightanswer == 'False') {
                $translatorevent['interaction_correct_responses'] = ['false'];
            }
        }


        return $translatorevent;
    }
89523
public function process_common($questiondata) {

        // This routine initialises the question object.
        $question = $this->defaultquestion();

        // Determine if the question is already escaped html.
        $this->ishtml = $this->getpath($questiondata,
                array('#', 'BODY', 0, '#', 'FLAGS', 0, '#', 'ISHTML', 0, '@', 'value'),
                false, false);

        // Put questiontext in question object.
        $text = $this->getpath($questiondata,
                array('#', 'BODY', 0, '#', 'TEXT', 0, '#'),
                '', true, get_string('importnotext', 'qformat_blackboard_six'));

        $questiontext = $this->cleaned_text_field($text);
        $question->questiontext = $questiontext['text'];
        $question->questiontextformat = $questiontext['format']; // Needed because add_blank_combined_feedback uses it.
        if (isset($questiontext['itemid'])) {
            $question->questiontextitemid = $questiontext['itemid'];
        }

        // Put name in question object. We must ensure it is not empty and it is less than 250 chars.
        $id = $this->getpath($questiondata, array('@', 'id'), '',  true);
        $question->name = $this->create_default_question_name($question->questiontext,
                get_string('defaultname', 'qformat_blackboard_six' , $id));

        $question->generalfeedback = '';
        $question->generalfeedbackformat = FORMAT_HTML;
        $question->generalfeedbackfiles = array();

        // TODO : read the mark from the POOL TITLE QUESTIONLIST section.
        $question->defaultmark = 1;
        return $question;
    }
833605
public function evaluateQuestion(array $questionRaw, PhpStringParser $parser, GeneratorDataObject $generator)
    {
        $iterator       = $this->iteratorValidator->retrieveValidIteration($questionRaw, $generator, $parser);
        $iteratorParser = clone $parser;

        foreach ($iterator as $iteration) {
            $iteratorParser->addVariable('iteration', $iteration);

            $origine = $iteratorParser->parse($questionRaw['iteration']['retrieveBy']);

            $question = new SimpleQuestion(
                $iteratorParser->parse($questionRaw['iteration']['text']),
                $questionRaw['setter'] . $origine
            );
            $question->setDefaultResponse((isset($questionRaw['iteration']['response']['default']) === true)
                    ? $iteratorParser->parse($questionRaw['iteration']['response']['default']) : null);
            $question->setRequired($questionRaw['required']);
            $question->setHelpMessage($questionRaw['helpMessage']);
            $question->setResponseType(new QuestionResponseTypeEnum($questionRaw['iteration']['response']['type']));

            $response = $this->context->ask($question);

            $questionName = $questionRaw['setter'];
            if ($response !== null) {
                $generator->getDto()->$questionName($origine, $response);
            }
        }

        return $generator;
    }
221813
public function getMissingQuestions($categories, $limit, $questions, $questionsLevel = array())
    {
        $query = $this->createQueryBuilder('q')
            ->addSelect('RAND() as HIDDEN rand, q, c, a')
            ->leftJoin('q.category', 'c')
            ->leftJoin('q.answers', 'a')
            ->where('q.category IN(:category)')
            ->andWhere('q.enabled = 1')
            ->andWhere('q.id NOT IN (:questions)')
            ->setParameter('category', $categories)
            ->setParameter('questions', $questions)
            ->setMaxResults($limit)
            ->orderBy('rand');

        if (!empty($questionsLevel)) {
            $query->andWhere('q.level IN(:level)')
                ->setParameter('level', $questionsLevel);
        }

        $questions = $query->getQuery()->getResult();

        return $questions;
    }
795347
protected function initialise_question_instance(question_definition $question, $questiondata) {
        $question->id = $questiondata->id;
        $question->category = $questiondata->category;
        $question->contextid = $questiondata->contextid;
        $question->parent = $questiondata->parent;
        $question->qtype = $this;
        $question->name = $questiondata->name;
        $question->questiontext = $questiondata->questiontext;
        $question->questiontextformat = $questiondata->questiontextformat;
        $question->generalfeedback = $questiondata->generalfeedback;
        $question->generalfeedbackformat = $questiondata->generalfeedbackformat;
        $question->defaultmark = $questiondata->defaultmark + 0;
        $question->length = $questiondata->length;
        $question->penalty = $questiondata->penalty;
        $question->stamp = $questiondata->stamp;
        $question->version = $questiondata->version;
        $question->hidden = $questiondata->hidden;
        $question->idnumber = $questiondata->idnumber;
        $question->timecreated = $questiondata->timecreated;
        $question->timemodified = $questiondata->timemodified;
        $question->createdby = $questiondata->createdby;
        $question->modifiedby = $questiondata->modifiedby;

        // Fill extra question fields values.
        $extraquestionfields = $this->extra_question_fields();
        if (is_array($extraquestionfields)) {
            // Omit table name.
            array_shift($extraquestionfields);
            foreach ($extraquestionfields as $field) {
                $question->$field = $questiondata->options->$field;
            }
        }

        $this->initialise_question_hints($question, $questiondata);
    }
671002
protected function process_mc($quest, &$questions) {
        $question = $this->process_common($quest);
        $question->qtype = 'multichoice';
        $question = $this->add_blank_combined_feedback($question);
        $question->single = 1;
        $feedback = array();
        foreach ($quest->feedback as $fback) {
            $feedback[$fback->ident] = $fback->text;
        }

        foreach ($quest->responses as $response) {
            if (isset($response->title)) {
                if ($response->title == 'correct') {
                    // Only one answer possible for this qtype so first index is correct answer.
                    $correct = $this->getpath($response->ident[0],
                            array('varequal', 0, '#'), '', true);
                }
            } else {
                // Fallback method for when the title is not set.
                if ($response->feedback == 'correct') {
                    // Only one answer possible for this qtype so first index is correct answer.
                    $correct = $this->getpath($response->ident[0],
                            array('varequal', 0, '#'), '', true);
                }
            }
        }

        $i = 0;
        foreach ($quest->RESPONSE_BLOCK->choices as $response) {
            $question->answer[$i] = $this->cleaned_text_field($response->text);
            if ($correct == $response->ident) {
                $question->fraction[$i] = 1;
                // This is a bit of a hack to catch the feedback... first we see if a  'specific'
                // feedback for this response exists, then if a 'correct' feedback exists.

                if (!empty($feedback[$response->ident]) ) {
                    $question->feedback[$i] = $this->cleaned_text_field($feedback[$response->ident]);
                } else if (!empty($feedback['correct'])) {
                    $question->feedback[$i] = $this->cleaned_text_field($feedback['correct']);
                } else if (!empty($feedback[$i])) {
                    $question->feedback[$i] = $this->cleaned_text_field($feedback[$i]);
                } else {
                    $question->feedback[$i] = $this->cleaned_text_field(get_string('correct', 'question'));
                }
            } else {
                $question->fraction[$i] = 0;
                if (!empty($feedback[$response->ident]) ) {
                    $question->feedback[$i] = $this->cleaned_text_field($feedback[$response->ident]);
                } else if (!empty($feedback['incorrect'])) {
                    $question->feedback[$i] = $this->cleaned_text_field($feedback['incorrect']);
                } else if (!empty($feedback[$i])) {
                    $question->feedback[$i] = $this->cleaned_text_field($feedback[$i]);
                } else {
                    $question->feedback[$i] = $this->cleaned_text_field(get_string('incorrect', 'question'));
                }
            }
            $i++;
        }

        if (!empty($question)) {
            $questions[] = $question;
        }
    }
821282
public function process_question(array $data, array $raw) {

        // Convert and write the answers first.
        if (isset($data['answers'])) {
            $this->write_answers($data['answers'], $this->pluginname);
        }

        // Convert and write the shortanswer extra fields.
        foreach ($data['shortanswer'] as $shortanswer) {
            $shortanswer['id'] = $this->converter->get_nextid();
            $this->write_xml('shortanswer', $shortanswer, array('/shortanswer/id'));
        }
    }
766008
public function evaluateQuestion(array $question, PhpStringParser $parser, GeneratorDataObject $generator)
    {
        $iterator       = $this->iteratorValidator->retrieveValidIteration($question, $generator, $parser);
        $iteratorParser = clone $parser;

        foreach ($iterator as $iteration) {
            $iteratorParser->addVariable('iteration', $iteration);

            $origine            = $iteratorParser->parse($question['iteration']['retrieveBy']);
            $responseCollection = new PredefinedResponseCollection();

            foreach ($question['iteration']['response']['predefined'] as $predefinedResponse) {
                $responseCollection->append(
                    new PredefinedResponse(
                        $predefinedResponse['response'],
                        $iteratorParser->parse($predefinedResponse['text']),
                        $predefinedResponse['response']
                    )
                );
            }

            $questionWithPredefinedResponse = new QuestionWithPredefinedResponse(
                $iteratorParser->parse($question['iteration']['text']),
                'set_predefined_' . ucfirst($question['dtoAttribute']) . $origine,
                $responseCollection
            );

            $questionWithPredefinedResponse->setDefaultResponse(
                (isset($question['iteration']['response']['default']) === true) ?
                    $iteratorParser->parse($question['iteration']['response']['default']) : null
            )->setRequired($question['required'])
             ->setResponseType(new QuestionResponseTypeEnum($question['iteration']['response']['type']));

            $response = $this->context->askCollection($questionWithPredefinedResponse);

            $questionName = $question['setter'];
            if ($response !== null) {
                $generator->getDto()->$questionName($origine, $response);
            }
        }

        return $generator;
    }
735591
public function correctAnswer(AbstractItem $question, $answer)
    {
        $corrected = new CorrectedAnswer();

        if (is_array($answer)) {
            foreach ($question->getAssociations() as $association) {
                $found = false;

                foreach ($answer as $index => $givenAnswer) {
                    if ($association->getProposal()->getUuid() === $givenAnswer['firstId'] && $association->getLabel()->getUuid() === $givenAnswer['secondId']) {
                        $found = true;

                        if (0 < $association->getScore()) {
                            $corrected->addExpected($association);
                        } else {
                            $corrected->addUnexpected($association);
                        }

                        unset($answer[$index]);
                    }
                }

                if (!$found && 0 < $association->getScore()) {
                    $corrected->addMissing($association);
                }
            }

            if (!empty($answer) && $question->getPenalty()) {
                // there are association not defined in the exercise
                $corrected->addPenalty(
                    new GenericPenalty(count($answer) * $question->getPenalty())
                );
            }
        } else {
            foreach ($question->getAssociations() as $association) {
                if (0 < $association->getScore()) {
                    $corrected->addMissing($association);
                }
            }
        }

        return $corrected;
    }