function parseFile($basename) { $notify = $this->delegate; $notify("Parsing file: {$basename} <br/>\nConcepts: "); // Begin Processing $vQuestion = new Model_Shell_GenericQuestion($this->path . '/' . $basename); // Add to questionBase (if not already there) $vQuestionBase = Model_Quiz_QuestionBase::fromXml($basename); if ($vQuestionBase == null) { $vQuestionBase = Model_Quiz_QuestionBase::fromScratch($basename, $vQuestion->getDifficulty(), $vQuestion->getEstimatedTime(), $vQuestion->getFriendlyType(), strtotime("today")); } // Now look at the concepts $vConcepts = $vQuestion->getConcepts(); foreach ($vConcepts as $vConcept) { // Make sure this concept exists in the database $vConceptObj = Model_Quiz_Concept::fromID($vConcept); if ($vConceptObj == null) { // Doesn't exist... we should make a record $vConceptObj = Model_Quiz_Concept::fromScratch($vConcept); } $notify($vConcept . "; "); // Now we need to make sure that this question has this concept associated with it $vQuestionBase->addConcept($vConceptObj); } // Update the questionBase's Difficulty & EstimatedTime (these are the things most likely to change) $vQuestionBase->setDifficulty($vQuestion->getDifficulty()); $vQuestionBase->setEstimated_time($vQuestion->getEstimatedTime()); $notify("<br/>Difficulty: " . $vQuestion->getDifficulty()); $notify("<br/>Estimated time to complete: " . $vQuestion->getEstimatedTime()); $notify("<br/><br/>\n"); }
/** * Generates a bank of questions for a question identifier provided * Expects parameters [question_id], [questions_to_generate_num], [max_errors_num] */ public function generatequestionbankAction() { // Check to see that all the parameters get passed $parameters = $this->_getAllParams(); $check_errors = array(); foreach (array("question_id" => "Question Identifier", "questions_to_generate_num" => "Number of Questions to Generate", "max_errors_num" => "Maximum number of Errors") as $check_key => $check_text) { if (!array_key_exists($check_key, $parameters) || !is_numeric($parameters[$check_key]) || $parameters[$check_key] < 0) { $check_errors[] = $check_text . " [" . $check_key . "] was not passed, or not a positive number."; } } if (sizeof($check_errors) > 0) { cronlog("The following validation errors occured:"); foreach ($check_errors as $ce) { cronlog($ce); } exit; } //cronlog('ok so far'); $question_base_id = intval($parameters['question_id']); $number_of_questions = intval($parameters['questions_to_generate_num']); $maximum_errors = intval($parameters['max_errors_num']); cronlog("Generating {$number_of_questions} questions from Question Base Identifier {$question_base_id} ; Maximum Error threshold is {$maximum_errors}"); $vQuestionBase = Model_Quiz_QuestionBase::fromID($question_base_id); if (is_null($vQuestionBase)) { throw new Exception("The question base identifier passed was invalid"); } $question_counter = 0; $error_counter = 0; My_Logger::log(__METHOD__ . " number_of_questions: {$number_of_questions}"); My_Logger::log(__METHOD__ . " maximum_errors: {$maximum_errors}"); while ($question_counter <= $number_of_questions && $error_counter <= $maximum_errors) { My_Logger::log(__METHOD__ . " question_counter: {$question_counter}"); My_Logger::log(__METHOD__ . " error_counter: {$error_counter}"); try { $vGeneratedQuestion = Model_Quiz_GeneratedQuestion::generateNewFromQuestionBase($vQuestionBase); } catch (Exception $e) { cronlog("Could not generate question. " . $e->getMessage()); echo Model_Shell_Debug::getInstance()->getLog(); $error_counter++; } } cronlog("Finished. Generated " . $question_counter . " questions; " . $error_counter . " errornous questions generated (but discarded)"); }
public static function getAll() { $db = Zend_Registry::get("db"); $vReturn = array(); $result = $db->query("SELECT * FROM question_base"); $rows = $result->fetchAll(); foreach ($rows as $row) { $vReturn[] = Model_Quiz_QuestionBase::fromID($row['question_id']); } return $vReturn; }
public static function select_next_question_2($vQuizAttempt, $vConcept, $vDifficulty) { //Firstly get ALL the questionBase's with this difficulty & concept $vPossibleQuestions = Model_Quiz_QuestionBase::getAllFromConceptAndDifficulty($vConcept, $vDifficulty); //Shuffle it to make it a little random shuffle($vPossibleQuestions); //print_r($vPossibleQuestions); //Now get all the questions the STUDENT has done... $vAttemptedQuestions = $vQuizAttempt->getAttemptedQuestionBases($vConcept, $vDifficulty); //print_r($vAttemptedQuestions); //There's the chance that we haven't had a questionbase asked. foreach ($vPossibleQuestions as $vPQ) { $vUsed = false; foreach ($vAttemptedQuestions as $vAQ) { if ($vPQ->getID() == $vAQ->getID()) { $vUsed = true; break; } } if (!$vUsed) { return $vPQ; } } //OK. So it turns out that we've used all questions. Pick a random one $vTemp = rand(0, sizeof($vPossibleQuestions) - 1); return $vPossibleQuestions[$vTemp]; }
/** * Shows the Question Analysis */ public function questionanalysisAction() { $file_id = $this->_getParam("file"); $this->view->file = $file_id; // Pointless line to load all the other functions in the GeneratedQuestion File // TODO: Fix this PLEASE $tmp = new Model_Quiz_GeneratedQuestion(); // Get All Question Bases $this->view->all_question_bases = Model_Quiz_QuestionBase::getAll(); if (is_null($file_id) || !isset($file_id)) { $default_question_base = current($this->view->all_question_bases); $file_id = $default_question_base->getID(); } if (!is_null($file_id) && isset($file_id)) { $question_base = Model_Quiz_QuestionBase::fromID($file_id); $attempts = Model_Quiz_QuestionAttempt::getAllFromQuestionBase($question_base); // Generate a sample question $config = new Zend_Config_Ini(APPLICATION_PATH . "/configs/application.ini", APPLICATION_ENV); $path = $config->xml->import_path; //$sample_question = new Model_Shell_GenericQuestion(APPLICATION_PATH . "/../xml/questions/" . $question_base->getXml()); $sample_question = new Model_Shell_GenericQuestion($path . '/' . $question_base->getXml()); $this->view->question_base = $question_base; $this->view->attempts = $attempts; $this->view->sample_question = $sample_question; } }
/** * Gets all Question attempts for a given question * * @param string $vQB * @return void * @author Ben Evans */ public static function getAllFromQuestionBase(Model_Quiz_QuestionBase $vQB) { $db = Zend_Registry::get("db"); $vReturn = array(); $sql = "SELECT attempt_id FROM question_attempt WHERE question_basequestion_id=" . $db->quote($vQB->getID()); //echo $sql; $result = $db->query($sql); $rows = $result->fetchAll(); foreach ($rows as $row) { $vReturn[] = Model_Quiz_QuestionAttempt::fromID($row['attempt_id']); } return $vReturn; }
/** * This will generate a brand new question from a question base. * Unlike fromQuestionBase(), this method will NOT consult the database for question first * @param Model_Quiz_QuestionBase $vQuestionBase * @return Model_Quiz_GeneratedQuestion */ public static function generateNewFromQuestionBase(Model_Quiz_QuestionBase $vQuestionBase, $path = false) { /* $path = "/../xml/questions/"; $path = "/../tests/fixtures/";*/ if (!$path) { $config = new Zend_Config_Ini(APPLICATION_PATH . "/configs/application.ini", APPLICATION_ENV); $path = $config->xml->import_path; } My_Logger::log(__METHOD__ . " Using path: {$path}"); $vGenerated = null; $error_threshold = 4; $error_counter = 0; while ($error_counter <= $error_threshold && is_null($vGenerated)) { // Start by ensuring the Question is has instructions outputs etc etc $vQuestion = new Model_Shell_GenericQuestion($path . '/' . $vQuestionBase->getXml()); $problem_string = $vQuestion->getProblem(); $question_output = $vQuestion->getCorrectOutput(); // We need to make sure that the question has valid output if (strlen(trim($question_output)) > 0) { // If the question is multiple choice, we need to ensure that all answers are different $alternate_answers = $vQuestion->getAnswers(); if (!is_null($alternate_answers) && sizeof($alternate_answers) > 0) { shuffle($alternate_answers); // Now, we need to ensure that we have 3 different answers that are ALL different to the actual answer $answer_set = array(trim($question_output)); // Value is the answer foreach ($alternate_answers as $aa_key => $alternate_answer) { if (is_array($alternate_answer)) { $alternate_answer = $alternate_answer[0]; } $alternate_answer = trim($alternate_answer); if (in_array($alternate_answer, $answer_set) || strlen(trim($alternate_answer)) == 0) { unset($alternate_answers[$aa_key]); // Answer already exists, or is blank (unusable) } else { $answer_set[] = $alternate_answer; } } if (sizeof($alternate_answers) >= 3) { // All is good. We can add this question, as well as all its alternate answers $vGenerated = Model_Quiz_GeneratedQuestion::fromScratch($vQuestion->getInstructions(), $vQuestion->getProblem(), $vQuestion->getCorrectOutput(), $vQuestionBase); $vNum = 1; foreach ($alternate_answers as $vAltAnswer) { if ($vNum > 3) { break; //Can't have more than 3 alternates } if (is_array($vAltAnswer)) { $vGenerated->addAlternateAnswer($vNum, $vAltAnswer[0], $vAltAnswer[1]); } else { $vGenerated->addAlternateAnswer($vNum, $vAltAnswer, ""); } $vNum++; } } else { $error_counter++; } } else { // Not a multiple choice question $vGenerated = Model_Quiz_GeneratedQuestion::fromScratch($vQuestion->getInstructions(), $vQuestion->getProblem(), $vQuestion->getCorrectOutput(), $vQuestionBase); } } else { $error_counter++; // The question didn't return a result } } if (is_null($vGenerated)) { throw new Exception("Attempted to generate a question " . $error_threshold . " times, but failed. Cannot continue"); } //If the question is a fill-in question, put the whole solution in the 1st alternate answer column if ($vQuestion->getFriendlyType() == "fill-in") { $vGenerated->setAlt_desc_1($vQuestion->getDebugProblem()); } return $vGenerated; }
public function getAttemptedQuestionBases($vConcept, $vDifficulty) { $db = Zend_Registry::get("db"); $vReturn = array(); $sql = "SELECT DISTINCT qb.question_id FROM question_attempt qa, question_base qb, question_concepts qc WHERE qc.conceptsconcept_name=" . $db->quote($vConcept->getID()) . " AND qb.difficulty=" . $db->quote($vDifficulty) . " AND qa.question_basequestion_id=qb.question_id AND qc.question_basequestion_id=qb.question_id AND qa.quiz_attemptquiz_attempt_id=" . $db->quote($this->quiz_attempt_id); //echo $sql; $result = $db->query($sql); $rows = $result->fetchAll(); foreach ($rows as $row) { $vReturn[] = Model_Quiz_QuestionBase::fromID($row['question_id']); } return $vReturn; }
/** * This function rebuilds XML files * In doing so, all pre-generated questions will be removed. */ public function rebuildxmlAction() { $process = $this->_getParam("process"); if (is_null($process) || $process !== "1") { // Get the amount of files in the Questions Dir $counter = 0; if ($handle = opendir(APPLICATION_PATH . '/../xml/questions')) { while (false !== ($file = readdir($handle))) { if (strtolower(substr($file, -3)) == "xml") { $counter = $counter + 1; } } closedir($handle); } $this->view->count = $counter; } else { // Process the XML Files if ($handle = opendir(APPLICATION_PATH . '/../xml/questions')) { while (false !== ($file = readdir($handle))) { if (strtolower(substr($file, -3)) == "xml") { echo "Parsing file: {$file} <br/>\nConcepts: "; //Begin Processing $vQuestion = new Model_Shell_GenericQuestion(APPLICATION_PATH . '/../xml/questions/' . $file); //Add to questionBase (if not already there) $vQuestionBase = Model_Quiz_QuestionBase::fromXml($file); if ($vQuestionBase == null) { $vQuestionBase = Model_Quiz_QuestionBase::fromScratch($file, $vQuestion->getDifficulty(), $vQuestion->getEstimatedTime(), $vQuestion->getFriendlyType(), strtotime("today")); } //Now look at the concepts $vConcepts = $vQuestion->getConcepts(); foreach ($vConcepts as $vConcept) { //Make sure this concept exists in the database $vConceptObj = Model_Quiz_Concept::fromID($vConcept); if ($vConceptObj == null) { //Doesn't exist... we should make a record $vConceptObj = Model_Quiz_Concept::fromScratch($vConcept); } echo $vConcept . "; "; //Now we need to make sure that this question has this concept associated with it $vQuestionBase->addConcept($vConceptObj); } //Update the questionBase's Difficulty & EstimatedTime (these are the things most likely to change) $vQuestionBase->setDifficulty($vQuestion->getDifficulty()); $vQuestionBase->setEstimated_time($vQuestion->getEstimatedTime()); echo "<br/>Difficulty: " . $vQuestion->getDifficulty(); echo "<br/>Estimated time to complete: " . $vQuestion->getEstimatedTime(); echo "<br/><br/>\n"; } } closedir($handle); Model_Quiz_GeneratedQuestion::removePregeneratedQuestions(); // Remove all Pre-Generated questions, so as to not cause any conficts } } }