function clearDir($dirPath) { My_Logger::log(__METHOD__ . " will clear {$dirPath}"); //return; foreach (new RecursiveIteratorIterator(new RecursiveDirectoryIterator($dirPath, FilesystemIterator::SKIP_DOTS), RecursiveIteratorIterator::CHILD_FIRST) as $path) { $path->isDir() && !$path->isLink() ? rmdir($path->getPathname()) : unlink($path->getPathname()); } }
function process($data) { My_Logger::log(__METHOD__ . ': ' . var_export($data, true)); try { $this->doProcess($data); $res = array('result' => 'ok', 'msg' => 'All changes saved.'); } catch (Exception $e) { $res = array('result' => 'error', 'message' => $e->getMessage()); } return $res; }
function testLoginSubmit() { $this->getRequest()->setMethod('POST')->setParams(array('rqz-username' => 'foo', 'rqz-password' => 'secret')); $this->assertTrue($this->getRequest()->isPost()); $this->dispatch('/auth/login'); //echo $this->getResponse()->getBody(); $this->assertController('auth'); $this->assertAction('login'); $this->assertResponseCode(302); My_Logger::log('Hello!'); }
/** * Add the text to the log * * @param string $text * @return void */ public function log($text, $pre = '') { My_Logger::log($pre . ": " . $text); $backtrace = debug_backtrace(); if (is_array($backtrace) && sizeof($backtrace > 1)) { if (array_key_exists("function", $backtrace[1])) { $text = $backtrace[1]['class'] . ":" . $backtrace[1]['function'] . ":" . $backtrace[0]['line'] . ": " . $text; } } $this->log_contents .= date("Y-m-d H:i:s") . " - " . $text . "\n"; }
function addQuiz(Model_Quiz_Quiz $quiz) { $db = Zend_Registry::get('db'); $current = $this->getQuizzes(); try { $db->insert("sequence_quiz", array('quiz_id' => $quiz->getID(), 'sequence_id' => $this->id, 'position' => count($current) + 1)); return true; } catch (Exception $e) { My_Logger::log($e->getMessage()); return false; } }
public static function fromScratch($lower_difficulty, $higher_difficulty, $number_tested, $vConcept, $vQuiz) { My_Logger::log(__METHOD__); $db = Zend_Registry::get("db"); $sql = "INSERT INTO concepts_tested(ctest_id,lower_difficulty,higher_difficulty,number_tested,conceptsconcept_name,quizquiz_id) VALUES(NULL, " . $db->quote($lower_difficulty) . "," . $db->quote($higher_difficulty) . "," . $db->quote($number_tested) . "," . $db->quote($vConcept->getID()) . "," . $db->quote($vQuiz->getID()) . ")"; $db->query($sql); //Now find the appropriate entry in the database // A safe (default) assumption for this is a query that looks for everything you just put in. //This query has errors. Apparently it is not used anywhere else, so disabling - Ivan /*$sql = "SELECT ctest_id FROM concepts_tested WHERE lower_difficulty=".$db->quote($lower_difficulty)." AND higher_difficulty=".$db->quote($higher_difficulty)." AND number_tested=".$db->quote($number_tested)." AND conceptsconcept_name=".$db->quote($conceptsconcept_name)." AND quizquiz_id=".$db->quote($quizquiz_id); $result = $db->query($sql); $row = $result->fetch(); if($row['ctest_id']!=null){ return Model_Quiz_TestedConcept::fromID($row['ctest_id']); }else{ return null; //Something didn't happen }*/ }
/** * 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)"); }
static function load($file_name) { //My_Logger::log(__METHOD__ . " loading:" . $file_name); $obj = new self(); if (!file_exists($file_name)) { return $obj; } $file_contents = Model_XML_Parser::xml2array($file_name); if (!is_array($file_contents) || sizeof($file_contents) == 0) { return $obj; } $obj->xml = simplexml_load_file($file_name); My_Logger::log(__METHOD__ . " contents:" . print_r($file_contents, true)); //My_Logger::log(__METHOD__ . " xml:" . print_r($obj->xml, true)); $obj->file_Contents = $file_contents; $obj->file_name = $file_name; $obj->substitutions = array(); $obj->valid = true; //print_r($obj->mFileContents); My_Logger::log(__METHOD__ . $obj->file_Contents['question']['problem']); return $obj; }
function testTwice() { $this->clearAll(); $this->clearTemp(); $importer = $this->createXmlImporter($this->path); $this->assertEquals(1, $importer->getTotalQuestions()); /** * First import: * Creates the a question_base row for each new xml file not registered previously * Extracts concept string from xml. Creates a new cocepts row if concept does not exist * Looks for concept-question association in question_concepts table, If it does not exist it creates it * Then it tries to "remove ALL pre-generated questions that haven't been used in a quiz". Nothing on our tables, though. */ $importer->processFiles(); My_Logger::log("******* SECOND IMPORT *******"); /** * Second import: * Apparently process is idempotent. It didn't create new concepts, question_concepts rows * Just tries to update the question_base difficulty and estimated_time. No inserts. * Therefore: IDEMPOTENT - SAFE */ $importer->processFiles(); }
public static function getAll($vOrder = false) { My_Logger::log("in getAll"); $db = Zend_Registry::get("db"); $vReturn = array(); //$sql = "SELECT * FROM quiz"; $sql = "SELECT quiz.*, position FROM quiz\n\t\t\tLEFT JOIN sequence_quiz ON quiz.quiz_id = sequence_quiz.quiz_id\n\t\t\tORDER BY\n\t\t\tsequence_quiz.position ASC"; if ($vOrder) { $sql .= ", quiz.close_date ASC"; } //echo "SQL: $sql<br/>"; $result = $db->query($sql); $rows = $result->fetchAll(); foreach ($rows as $row) { $vReturn[] = Model_Quiz_Quiz::fromID($row['quiz_id']); } return $vReturn; }
private function populateSubstitutions() { /* This essentially goes through and evaluates the data in the <substitutions> part of the XML file. It consists of 2 parts: - Firstly changing %value%'s that are present in <substitution> keys to previously computed values - Evaluating the PHP code inside the <substitution> keys and saving the results to $mSubstitutions */ //$total = max(1, sizeof($this->mFileContents['question']['substitutions']['substitution']/2)); //Apparently system was not designed to work with just 1 substitution (let alone 0) Model_Shell_Debug::getInstance()->log("Populating " . sizeof($this->mFileContents['question']['substitutions']['substitution']) . "/2 Substitutions", __METHOD__); //Model_Shell_Debug::getInstance()->log("Populating $total Substitutions"); //There's essentially 2x the amount of array keys in this array because the XML parser puts both the VALUE and ATTRIBUTE in for ($vCounter = 0; $vCounter < sizeof($this->mFileContents['question']['substitutions']['substitution']) / 2; $vCounter++) { //for($vCounter = 0; $vCounter<$total; $vCounter++ ){ $tag = $this->mFileContents['question']['substitutions']['substitution'][$vCounter . "_attr"]['val']; //Firstly we look at the XML value $toGen = $this->mFileContents['question']['substitutions']['substitution'][$vCounter]; My_Logger::log(__METHOD__ . " toGen: {$toGen}"); if (strstr($toGen, ";") == false) { //Assuming its just a function without ; and return $toGen = "return " . $toGen . ";"; } $toGen = $this->substitutePercentages($toGen); //Let's eval the code and capture any errors - Ivan if (!$this->phpCodeChecker($toGen)) { //code is going to fail, so report back to caller about problem with this substitution ob_start(); eval($toGen); if ('' !== ($error = ob_get_clean())) { throw new EvalException("Error evaluating substitution `{$tag}`" . "\n\nExpression:\n{$toGen}" . "\n\nError: {$error}"); } } $this->mSubstitutions[$tag] = eval($toGen); } //End FOR //print_r($this->mSubstitutions); }
function query($sql, $bind = array()) { My_Logger::log('QUERY: ' . $sql); return parent::query($sql, $bind); }
function clickContinue() { My_Logger::log(__METHOD__ . " >>>>> 3. Send Continue, new quesion is displayed"); $this->sys->resetRequest()->resetResponse(); $this->sys->setPost(array('quiz' => $this->quiz_id)); $this->sys->dispatch($this->url); }
/** * Function for logging cron operations. * Relies on the constant CLI_CURRENT_LOG_PATH to be defined * @param string $message * @param int $severity */ function cronlog($message, $severity = 0) { if (defined('STARTED')) { My_Logger::log($message); } //Use our logger only if application has been initialized (hardcoded define for now) $log_message = "[" . date("Y-m-d H:i:s") . "]\t" . $message . "\r\n"; if (defined("CLI_CURRENT_LOG_PATH")) { file_put_contents(CLI_CURRENT_LOG_PATH, $log_message, FILE_APPEND); echo "*" . $log_message; } else { echo $log_message; } }
/** * This action is the quiz shell. * It ensures permissions, creates new attempts etc etc. * * @author Ben Evans */ public function attemptAction() { Model_Shell_Debug::getInstance()->log("User Entered the Attempt Action"); $identity = Zend_Auth::getInstance()->getIdentity(); $username = $identity->username; $auth_model = Model_Auth_General::getAuthModel(); /* Before we do anything, test to make sure we've passed a VALID QUIZ which WE ARE ENTITLED to sit. */ $quiz = $this->findQuiz($this->_getParam("quiz")); $finished = false; $marking = false; $now = strtotime("now"); // Permissions $is_open = $quiz->getOpen_date() <= $now; if ($auth_model->userInGroup($username, $quiz->getPermissions_group()) && $is_open && !$quiz->hasPendingPrerequisite($username)) { // Have we run out of attempts? $quizAttempts = Model_Quiz_QuizAttempt::getAllFromUser($username, $quiz); if (sizeof($quizAttempts) >= $quiz->getMax_attempts()) { // It is possible that we're on our last attempt, and that it's "in progress"...check $quizAttempt = $this->findQuizAttemptInProgress($quizAttempts); if (!$quizAttempt) { throw new Exception("You've exceeded your maximum attempts for this quiz. Cannot continue"); } } } else { if (!$this->view->is_admin) { throw new Exception("Insufficient Permissions to take this quiz / Quiz not open yet / Prerequisites incomplete."); } $quizAttempts = Model_Quiz_QuizAttempt::getAllFromUser($username, $quiz); } /* Ok. We're allowed to TAKE the quiz. Are we resuming, or starting a new one? */ $quizAttempt = $this->findQuizAttemptInProgress($quizAttempts); if ($quizAttempt == null) { $quizAttempt = Model_Quiz_QuizAttempt::fromScratch($now, $quiz, $username); } $total_questions = $quiz->getTotalQuestions(); /* We have our quizAttempt ready to go. Now we look to see if we're resuming a question or not */ $questionAttempt = $quizAttempt->getLastIncompleteQuestion(); if (is_object($questionAttempt) && !$questionAttempt->isValid()) { $questionAttempt->destroy(); // Remove the Question attempt (Database was reinitialised or something) $questionAttempt = null; } if ($questionAttempt != null) { /* Are we getting an ANSWER for this question? */ //if (array_key_exists("marking", $_POST) && $_POST['marking'] == "1") { if (1 == $this->getRequest()->getPost('marking')) { /* Mark it */ $marking = true; } My_Logger::log("Marking is {$marking}"); /* If we reach here, the page has probably been refreshed. We just re-display the last question */ } else { /* Have we finished this quiz? */ if ($quizAttempt->getQuestionAttemptCount() >= $total_questions) { // Close this attempt and display a result later on down the page $quizAttempt->setDate_finished($now); // Calculate and store the final score $quizAttempt->setTotal_score($quizAttempt->getTotal_score()); $finished = true; } else { /* Make a QuestionAttempt */ $questionAttempt = $this->makeQuestionAttempt($quizAttempt, $now); } } // Pass all relevant information to the view $this->view->setEscape('htmlentities'); $this->view->quiz = $quiz; $this->view->question_attempt = $questionAttempt; $this->view->finished = $finished; $this->view->marking = $marking; $this->view->mQuizAttempt = $quizAttempt; $this->view->vTotalQuestions = $total_questions; $this->view->setEscape('htmlspecialchars_decode'); }
function qualityTest($data) { //Will try to generate n questions, and show a ratio of success/total compilations $total = 10; $success = $errors = 0; $config = new Zend_Config_Ini(APPLICATION_PATH . "/configs/application.ini", APPLICATION_ENV); $xml_path = $config->xml->import_path; $selected_xml = $this->get($data['file']); if (empty($selected_xml)) { throw new Exception("Please save file first."); } $full_filename = $xml_path . "/" . $selected_xml . ".xml"; My_Logger::log(__METHOD__ . " full_filename: " . $full_filename); if (!file_exists($full_filename)) { throw new Exception("File does not exist."); } for ($i = 1; $i <= $total; $i++) { try { $mQuestion = new Model_Shell_GenericQuestion($full_filename); $mQuestion->getProblemNoHiddenLines(); $mQuestion->getCorrectOutput(); $success++; } catch (Exception $e) { //throw $e; $errors++; } } My_Logger::log("total: {$total}, error: {$errors}, success: {$success}"); $ratio = round($success / $total * 100, 2); return array('result' => 'success', 'title' => 'Compilation results', 'msg' => 'Success Ratio:' . $ratio . '%'); }
/** * Inspect the contents of the error.txt file for any compilation errors. * If there were errors, throw and terminate * @param string $error_file * @throws CompilerException * @author Ivan */ protected static function proccessErrorFile($error_file) { if (file_exists($error_file)) { $compiler_errors = file_get_contents($error_file); if (strlen($compiler_errors) > 0) { $cex = new CompilerException("There were compiler errors."); $cex->compiler_output = $compiler_errors; $cex->error_file = $error_file; My_Logger::log(__METHOD__ . " win compiler errors:\n" . $compiler_errors); throw $cex; } } }
/** * @expectedException EvalException */ function testEvalError() { $this->clearAll(); $this->clearTemp(); $filename = 'evalerror.xml'; $filepath = $this->config->xml->import_path . "/" . $filename; $xml = simplexml_load_file($filepath); $concept = (string) $xml->concepts->concept; //from source $importer = $this->createXmlImporter($this->path); $importer->parseFile($filename); //Create the quiz $qz = $this->createQuiz("Some Quiz", 'comp115-students'); //Add tested concept to quiz $this->addTestedConcept($qz, $concept, 3); My_Logger::clearLog(); $this->clearMysqlLog(); My_Logger::log('**** BEGIN ******'); // Get the Question XML $mQuestion = new Model_Shell_GenericQuestion($filepath); $this->assertEquals('output', $mQuestion->getFriendlyType()); $this->assertTrue(in_array($concept, $mQuestion->getConcepts())); $this->assertEquals('1', $mQuestion->getDifficulty()); //Here comes the compilation. After this single call, all the artifacts are produced //ini_set("display_errors", 0); $this->assertEquals(trim((string) $xml->instructions), $mQuestion->getInstructions()); //ini_set("display_errors", 0); }
/** * Allows Adding and Editing a TestedConcept to a quiz * Expects [quiz_id] as a parameter if no [tested_concept] (id) is passed */ public function addconceptAction() { $form = new Form_AddQuizConcept(); $quiz_id = $this->_getParam("quiz_id"); //part of the url $tested_concept = $this->_getParam("tested_concept"); if (is_numeric($tested_concept)) { $tested_concept_ob = Model_Quiz_TestedConcept::fromID(intval($tested_concept)); if (is_null($tested_concept_ob)) { throw new Exception("Invalid Tested Concept Identifier"); } $form->getElement("submit")->setLabel("Edit Tested Concept"); $this->view->action_text = "Edit"; $form->populateFromConcept($tested_concept_ob); } elseif (is_numeric($quiz_id)) { $quiz_ob = Model_Quiz_Quiz::fromID(intval($quiz_id)); if (is_null($quiz_ob)) { throw new Exception("Invalid Quiz Identifier"); } $this->view->action_text = "Add"; } else { throw new Exception("No quiz identifier or tested concept identifier passed"); } if ($this->getRequest()->isPost()) { $formdata = $this->getRequest()->getPost(); My_Logger::log(var_export($formdata, true)); if ($form->isValid($formdata)) { // Either update the existing tested concept or add a new one if (isset($tested_concept_ob)) { $vConcept = Model_Quiz_Concept::fromID($formdata['concept_id']); $tested_concept_ob->updateConcept($vConcept); $tested_concept_ob->updateLowerDifficulty($formdata['difficulty_from']); $tested_concept_ob->updateHigherDifficulty($formdata['difficulty_to']); $tested_concept_ob->updateNumberTested($formdata['number_of_questions']); $params = array('id' => $tested_concept_ob->getQuiz()->getID()); } else { $vConcept = Model_Quiz_Concept::fromID($formdata['concept_id']); $vTestedConcept = Model_Quiz_TestedConcept::fromScratch($formdata['difficulty_from'], $formdata['difficulty_to'], $formdata['number_of_questions'], $vConcept, $quiz_ob); $params = array('id' => $quiz_ob->getID()); } $this->_helper->redirector("showconcepts", "admin", null, $params); } else { $form->populate($formdata); } } $this->view->form = $form; }
public function hasPassedQuiz() { //if(($vHighest->getTotal_score()/$vQuiz->getTotalQuestions())*100 >= $vQuiz->getPercentage_pass()){ if (isset($this->date_finished)) { $min_score = $this->getQuiz()->getPercentage_pass(); $score = 100 * $this->getTotal_score() / $this->getQuiz()->getTotalQuestions(); My_Logger::log("Minimum score is " . $min_score); My_Logger::log("Score is " . $score); if ($score >= $min_score) { return true; } } return false; }
/** * 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; }
/** * An Administrative function that tests Question Generation * * @return void * @author Ben Evans */ public function testquestiongenerationAction() { if (!$this->view->is_admin) { throw new Exception("Access Denied"); } $this->_helper->layout->disableLayout(); //$xml_path = APPLICATION_PATH . '/../xml/questions'; $config = new Zend_Config_Ini(APPLICATION_PATH . "/configs/application.ini", APPLICATION_ENV); $xml_path = $config->xml->import_path; My_Logger::log($xml_path); $this->view->available_files = $this->getAvailableFiles($xml_path); // See what Question we're looking at... $this->view->selected_xml = $selected_xml = $this->_getParam("q"); if (isset($selected_xml) && !is_null($selected_xml)) { // Get the Question XML try { $mQuestion = new Model_Shell_GenericQuestion($xml_path . "/" . $selected_xml . ".xml"); $this->view->question = $mQuestion; } catch (Exception $e) { //throw $e; } // Just make a new random question, so we get access to functions like Randset $temp = new Model_Quiz_GeneratedQuestion(); } //added by Ivan. Force for now, comment out in release Model_Shell_Debug::getInstance()->saveToDisk(); }