From: Ben H. <bdv...@us...> - 2010-11-22 23:06:00
|
Update of /cvsroot/stack/stack-dev/lib/deployment In directory sfp-cvsdas-3.v30.ch3.sourceforge.com:/tmp/cvs-serv29766/lib/deployment Modified Files: Tag: question_reporting Deployment.php Log Message: Merging from the current HEAD into question_reporting. Apologies in advance if this all goes horribly wrong. Index: Deployment.php =================================================================== RCS file: /cvsroot/stack/stack-dev/lib/deployment/Deployment.php,v retrieving revision 1.8 retrieving revision 1.8.2.1 diff -C2 -d -r1.8 -r1.8.2.1 *** Deployment.php 6 Oct 2009 18:03:53 -0000 1.8 --- Deployment.php 22 Nov 2010 23:05:52 -0000 1.8.2.1 *************** *** 1,3 **** --- 1,4 ---- <?php + /** * *************** *** 17,128 **** */ ! require_once $root . '/lib/Logger.php'; /** * This class manages the deployment of question instances. ! * It ensures that singletons are deployed only once. */ ! class Deployment { ! private $cache; ! private $questionID; ! private $instances; ! public $autoDeployed; ! private $logger; ! public function __construct($questionID) { ! $this->logger = new Logger("Deployment"); ! // get connection to cache ! $this->cache = new StackDBCache(); ! $this->cache->connect(); ! // assign questionID ! $this->questionID = $questionID; ! // get deployed instances ! $this->instances = $this->cache->getInstances($this->questionID); ! // ensure one instance if a singleton ! $this->ensureSingletonDeployed(); ! } ! public function formXHTML() { ! $xhtml = "<form method='POST' action='?id=".$this->questionID."'> ! <input type='submit' name='add' value='add'> ! <input type='text' name='add' value='1' size='3' maxlength='3'/> ".get_string('FE_deployQuestion_newversions', 'stack')."</form>"; ! return $xhtml; ! } ! public function processOperations($param) { ! // add instances ! if(isset($param['add']) && is_numeric($param['add'])) { ! if (!$this->isSingleton()) { ! $msg = get_string('FE_deployQuestion_adding', 'stack', $param['add']); ! $this->cache->deployCache($this->questionID, $param['add']); ! } ! $this->refreshInstances(); ! } ! // drop requests ! if(isset($param['drop']) && is_numeric($param['drop'])) { ! $msg = get_string('FE_deployQuestion_dropping', 'stack').$_GET['drop'].'<br />'; ! $this->cache->dropState($param['drop']); ! $this->refreshInstances(); ! $this->ensureSingletonDeployed(); // redeploy if dropped a singleton } - return $msg; } ! // ensure singletons are always instantiated ! public function ensureSingletonDeployed() { ! if($this->size() === 0 && $this->isSingleton()) { ! $this->cache->deployCache($this->questionID, 1); ! $this->refreshInstances(); ! $this->autoDeployed = true; ! } else { ! $this->autoDeployed = false; } } ! private function refreshInstances() { ! $this->instances = $this->cache->getInstances($this->questionID); } ! public function listXHTML() { ! //$xhtml = ''; ! if($this->instances == NULL) $xhtml = '<i>'.get_string('FE_deployQuestion_noi', 'stack').'</i>'; ! else { ! if (1 == count($this->instances)) { ! echo '<p>'.get_string('FE_deployQuestion_version', 'stack').'</p>'; ! } else { ! echo '<p>'.count($this->instances).get_string('FE_deployQuestion_versions', 'stack').'</p>'; ! } ! $xhtml = '<table class="deploymentTable" border="1">'; ! $xhtml .= '<tr><th>'; ! $xhtml .= '</th><th>'; ! $xhtml .= get_string('stackQuestion_questionStem', 'stack'); ! $xhtml .= '</th><th>'; ! $xhtml .= get_string('stackQuestion_questionNote', 'stack'); ! $xhtml .= '</th><th>'; ! $xhtml .= '</th></tr>'; ! foreach($this->instances as $instance) { ! $item = $this->cache->getDisplayItem($instance['id']); ! $xhtml .= '<tr>'; ! $xhtml .= '<td>'. $instance['id'] .'</td>'; ! $xhtml .= '<td>'. $instance['xhtml'] .'</td>'; ! $xhtml .= '<td>'.$item->getQuestionNote().'</td>'; ! $xhtml .= '<td>'; ! $xhtml .= "<a href='questionDeploy.php?id=$_GET[id]&drop=$instance[id]'>drop</a> "; ! $xhtml .= "<a href='questionTest.php?id=".$item->getQuestionId()."&seed=".$item->getQuestionSeed()."'>try</a></td>"; ! $xhtml .= '</tr>'; ! } ! $xhtml .= '</table>'; } ! return $xhtml; } --- 18,175 ---- */ ! require_once $root . '/lib/Logger.php'; /** * This class manages the deployment of question instances. ! * It ensures that singletons are deployed only once and all instances are of the same version. */ ! class Deployment { ! private $cache; ! private $version; ! private $line; // lookup on demand ! private $instances; ! public $autoDeployed; ! private $engineID; ! private $logger; ! public function __construct($version, $engineid = NULL) { ! $this->logger = new Logger("Deployment"); ! // get connection to cache ! $this->cache = new StackDBCache(); ! $this->cache->connect(); ! // assign version ! $this->version = $version; ! // get deployed instances ! $this->instances = $this->cache->getInstances($this->version); ! // ensure one instance if a singleton ! $this->ensureSingletonDeployed(); ! $this->engineID = $engineid; ! $this->logger->debug("engine id in Deployment constructor: ".$this->engineID); ! } ! /* this should probably be elsewhere ~ sph 23/10/09 */ ! public function formXHTML() { ! //$xhtml = "<form method='POST' action='?id=".$this->version."'> ! $xhtml = "<input type='submit' name='submit' value='add'> ! <input type='text' name='add' value='1' size='3' maxlength='3'/> " . get_string('FE_deployQuestion_newRandomInstances', 'stack'); ! //" <input type='checkbox' name='autoprime' ".(isset($_POST['autoprime'])?'checked="checked"':"")."> ".get_string('FE_deployQuestion_autoprime', 'stack'); ! /*" <input type='submit' onclick='return confirm(\"" . ! get_string('FE_deployQuestion_confirmUndeployAll', 'stack')."\")' name='dropall' value='" . ! get_string('FE_deployQuestion_undeployAll', 'stack')."'>";*/ ! return $xhtml; ! } ! ! public function processOperations($param) { ! $this->logger->debug("here in processOperations, param = ".print_r($param, 1)." and engineid = ".$this->engineID); ! ! // add requests ! if (isset ($param['add']) && is_numeric($param['add'])) { ! if (!$this->isSingleton()) { ! $msg = get_string('FE_deployQuestion_attemptingDeploy', 'stack', $param['add']); ! $initialStates = $this->cache->deployCache($this->version, $param['add']); ! ! //if in Moodle, update ! //$engineID = $param['engineid']; ! if(!empty($this->engineID)) ! { ! $this->logger->debug('In moodle, checking your engine ids'); ! $db = new MoodleDB(); ! $db->connect(); ! $inMoodle = $db->inMoodleQuestionBank($this->version, $this->engineID); ! if($inMoodle == true) ! { ! /*update Moodle's database. ! $result = $db->updateQuestion($this->version, $this->getLine(), $this->authorId, $engineID, $post['category']); ! if($result == false) ! { ! $this->userMessage .= '<h3>'.get_string('stackAuthor_moodleUpdateFail','stack','').'</h3>'.get_string('stackAuthor_moodleQBFail','stack',''); ! } ! //*/ ! } ! } ! ! $msg .= ' '.get_string('FE_deployQuestion_deployedInstances', 'stack', sizeof($initialStates)); ! } ! $this->refreshInstances(); ! ! if ($param['autoprime']) { // i.e. it equals 1 rather than 0. ! $ids = array (); // get ids only of newly-deployed instances ! foreach ($initialStates as $initialState) { ! $ids[] = $initialState['id']; ! } ! ! $ids = $initialStates; ! //$this->logger->debug("in processOperations, ids = ".print_r($ids, 1)); ! $this->primeResponses($ids); } } ! // drop requests ! if (isset ($param['drop']) && is_numeric($param['drop'])) { ! $msg = get_string('FE_deployQuestion_dropInstance', 'stack', $param['drop']) . '<br />'; ! $this->cache->deinitialiseState($param['drop']);// students may have attempted ! $this->refreshInstances(); ! $this->ensureSingletonDeployed(); // redeploy if dropped a singleton ! } ! ! // undeploy request (version) ! if (isset($param['operation']) && $param['operation'] === 'undeploy' && is_numeric($param['version'])) { ! $toDrop = new Deployment($param['version']); ! $this->logger->debug('trying to drop version'.$param['version']); ! $toDrop->drop($param['engine']); ! } ! ! ! // update request (the caching part - Moddle Question Bank handled elsewhere) ! if (isset($param['operation']) && $param['operation'] == 'update' && is_numeric($param['prior'])) { ! // take id, prior, number, category and update ! ! // undeploy all old ! $toDrop = new Deployment($param['prior']); ! $this->logger->debug('trying to drop version'.$param['version'].' during update'); ! $toDrop->drop($param['engine']); ! ! // Do new deploy last in case of timeout? ! // create new deployment ! if (!$this->isSingleton()) { // should auto-deploy in constructor ! $msg = get_string('FE_deployQuestion_attemptingDeploy', 'stack', $param['number']); ! $initialStates = $this->cache->deployCache($this->version, $param['number']); } } ! // prime requests ! if (isset ($param['operation']) && $param['operation'] == 'prime' && is_numeric($param['instance'])) { ! //$msg = get_string('FE_deployQuestion_prime', 'stack').$param['prime'].'<br />'; ! $this->primeResponses(array($param['instance'])); } ! return $msg; ! } ! // ensure singletons are always instantiated ! public function ensureSingletonDeployed() { ! // check no earlier blocking instances ! if ($this->size() === 0 && $this->isSingleton() && $this->earliestDeployedVersion() === false) { ! $this->cache->deployCache($this->version, 1); ! $this->refreshInstances(); ! $this->autoDeployed = true; ! } else { ! $this->autoDeployed = false; } ! } ! ! private function refreshInstances() { ! $this->instances = $this->cache->getInstances($this->version); ! } *************** *** 132,136 **** // Are random versions of this item available? $options = NULL; ! $item = new Item($options, $this->questionID); return $item->questionVariables->contains_rand() == false; } --- 179,183 ---- // Are random versions of this item available? $options = NULL; ! $item = new Item($options, $this->version); return $item->questionVariables->contains_rand() == false; } *************** *** 144,185 **** } - // return cached responses from question tests - // post the inputs from the question tests to set up the cache - // Would be nice to report number of responses cached also, return this count - // note: need to apply QTs to *each* version of our question - could be heavy? /* ! * List primed responses here: ! for each QT ! look for response in cache for inputs ! display response ! big warning if does not pass test with link to edit. */ ! public function primeResponses() { ! ! // return if there are no QTs $options = NULL; ! $item = new Item($options, $this->questionID); ! $QTs = $item->itemTests->getTests(); ! if($QTs == NULL || empty($QTs)) return NULL; ! // we have tests ! foreach($QTs as $key => $QT) { // get all inputs for each test ! foreach($QT as $field => $value) { ! if(substr($field, 0, 3) == "IE_") $posts[$key]['sAns__'.substr($field, 3)] = $value; ! } } ! // get instances ! $event = 1; // TODO: replace this magic number (submit) ! $newInstances = array(); ! foreach($this->instances as $instance) { // for each instance ! foreach($posts as $post) { // submit each post ! $iid = $instance['id']; ! for($i = 0; $i < 2; $i++) { // submit before loopback $transition = $this->cache->nextTransition($iid, $post, $event); // TODO: bad magic number ! if(NULL == $transition) { // no prior transition $item = $this->cache->getDisplayItem($iid); $xhtml = $item->processQuestion($post, true, 1); --- 191,238 ---- } /* ! * Primes question instances ! * If none given then prime all instances of this question deployment. */ ! public function primeResponses($instanceIDs = NULL) { ! $this->logger->debug('in primeResponses with ids: ' . print_r($instanceIDs, 1)); $options = NULL; ! $item = new Item($options, $this->version); ! if($item->itemTests !== NULL) { // not guaranteed ! // return if there are no QTs ! $QTs = $item->itemTests->getTests(); ! if ($QTs == NULL || empty ($QTs)) ! return NULL; ! } else return true; ! ! // we have tests, let's use them to prime ! foreach ($QTs as $key => $QT) { // get all inputs for each test ! foreach ($QT as $field => $value) { ! if (substr($field, 0, 3) == "IE_") ! $posts[$key]['sAns__' . substr($field, 3)] = $value; ! } } ! //$this->logger->debug('in primeResponses, this = '.print_r($this, 1)); ! if (NULL == $instanceIDs) { ! if (isset ($this->instances)) { ! foreach ($this->instances as $index => $instance) ! $instanceIDs[] = $instance['id']; // id of ALL instances ! } else ! return NULL; ! } ! ! $event = 1; // TODO: replace this magic number (representing 'submit') ! $newStates = array (); ! foreach ($instanceIDs as $instanceID) { ! foreach ($posts as $post) { // take each response ! $iid = $instanceID; // go back to original instance ! for ($i = 0; $i < 2; $i++) { // submit before loopback $transition = $this->cache->nextTransition($iid, $post, $event); // TODO: bad magic number ! if (NULL == $transition) { // no prior transition $item = $this->cache->getDisplayItem($iid); $xhtml = $item->processQuestion($post, true, 1); *************** *** 196,209 **** 0, // expired false); // a little redundancy in this last param.. ! ! $newInstances[] = $this->cache->nextNode($transition); } $iid = $this->cache->nextNode($transition); } - $this->cache->addTransition($iid, $iid, $post, $event); } ! } ! // echo "<pre>".print_r($newInstances, true)."</pre>"; ! return $newInstances; } } --- 249,371 ---- 0, // expired false); // a little redundancy in this last param.. ! $newStates[$instanceID][] = $this->cache->nextNode($transition); } $iid = $this->cache->nextNode($transition); } } ! if ($this->cache->nextTransition($iid, $post, $event) == NULL) { // no prior transition ! $this->cache->addTransition($iid, $iid, $post, $event); // loop back ! } ! } ! $this->logger->debug("newStates in primeResponses() = " . print_r($newStates, 1)); ! return $newStates; ! } ! ! // returns true iff there's a cached response for all the question tests ! function isPrimed($instanceID) { ! ! $item = $this->cache->getDisplayItem($instanceID); ! ! if(NULL == $item) return NULL; // no such instance! ! ! $options = NULL; ! $item = new Item($options, $this->version); ! ! if($item->itemTests !== NULL) { // not guaranteed ! // return true if there are no QTs ! $QTs = $item->itemTests->getTests(); ! if ($QTs == NULL || empty ($QTs)) ! return true; ! } else return true; ! ! // we have tests, let's check them ! foreach ($QTs as $key => $QT) { ! // get all inputs for each test ! foreach ($QT as $field => $value) { ! if (substr($field, 0, 3) == "IE_") ! $posts[$key]['sAns__' . substr($field, 3)] = $value; ! } ! } ! ! $event = 1; // TODO: replace this magic number (representing 'submit') ! foreach ($posts as $post) { // take each response ! $iid = $instanceID; // go back to original instance ! for ($i = 0; $i < 2; $i++) { // submit through loopback ! $transition = $this->cache->nextTransition($iid, $post, $event); // TODO: bad magic number ! if (NULL == $transition) { // no prior transition, so false. ! return false; ! } ! ! $iid = $this->cache->nextNode($transition); ! } ! } ! //$this->logger->debug($instanceID." is primed and good to go!"); ! return true; ! } ! ! function getVersion() { ! return $this->version; ! } ! ! /* ! * Removes all instances from this deployment by deinitialising all the states. ! */ ! function drop($engineID = NULL) { ! if(!empty($this->instances)) { ! foreach($this->instances as $instance) { ! $this->cache->deinitialiseState($instance['id']); ! } ! $this->refreshInstances(); ! } ! ! //if in Moodle, update ! if(!empty($engineID)) ! { ! $db = new MoodleDB(); ! $db->connect(); ! $inMoodle = $db->inMoodleQuestionBank($this->version, $engineID); ! if($inMoodle == true) ! { ! //update Moodle's database. ! /*$result = $db->REMOVEQuestion($this->version, $this->authorId, $engineID, $post['category']); ! if($result == false) ! { ! $this->userMessage .= '<h3>'.get_string('stackAuthor_moodleUpdateFail','stack','').'</h3>'.get_string('stackAuthor_moodleQBFail','stack',''); ! } ! */ ! } ! } ! //*/ ! } ! ! function earliestDeployedVersion() { ! $itemDB = new StackDBItem(); ! $itemDB->connect(); ! $versions = $itemDB->getVersions($itemDB->getLine($this->version)); // returned in descending order ! $itemDB->disconnect(); ! ! $earliest = false; ! ! // requires versions ordered by descending id ! foreach($versions as $date => $id) { ! if($this->cache->instancesDeployed($id)) { ! $earliest = $id; ! } ! } ! return $earliest; ! } ! ! function getLine() { ! if(!isset($this->line)) { ! $itemDB = new StackDBItem(); ! $itemDB->connect(); ! $this->line = $itemDB->getLine($this->version); // returned in descending order ! $itemDB->disconnect(); ! } ! return $this->line; ! } ! ! function getEngineID() { ! return $this->engineID; } } |