• Main Page
  • Related Pages
  • Namespaces
  • Data Structures
  • Files
  • File List
  • Globals

assessment/classes/class.ilObjTest.php

Go to the documentation of this file.
00001 <?php
00002 /*
00003         +-----------------------------------------------------------------------------+
00004         | ILIAS open source                                                           |
00005         +-----------------------------------------------------------------------------+
00006         | Copyright (c) 1998-2001 ILIAS open source, University of Cologne            |
00007         |                                                                             |
00008         | This program is free software; you can redistribute it and/or               |
00009         | modify it under the terms of the GNU General Public License                 |
00010         | as published by the Free Software Foundation; either version 2              |
00011         | of the License, or (at your option) any later version.                      |
00012         |                                                                             |
00013         | This program is distributed in the hope that it will be useful,             |
00014         | but WITHOUT ANY WARRANTY; without even the implied warranty of              |
00015         | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the               |
00016         | GNU General Public License for more details.                                |
00017         |                                                                             |
00018         | You should have received a copy of the GNU General Public License           |
00019         | along with this program; if not, write to the Free Software                 |
00020         | Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA. |
00021         +-----------------------------------------------------------------------------+
00022 */
00023 
00035 require_once "./classes/class.ilObject.php";
00036 require_once "./assessment/classes/class.assMarkSchema.php";
00037 require_once "./classes/class.ilMetaData.php";
00038 require_once "./assessment/classes/class.assQuestion.php";
00039 require_once "./assessment/classes/class.assClozeTest.php";
00040 require_once "./assessment/classes/class.assImagemapQuestion.php";
00041 require_once "./assessment/classes/class.assJavaApplet.php";
00042 require_once "./assessment/classes/class.assMatchingQuestion.php";
00043 require_once "./assessment/classes/class.assMultipleChoice.php";
00044 require_once "./assessment/classes/class.assOrderingQuestion.php";
00045 require_once "./classes/class.ilObjAssessmentFolder.php";
00046 
00047 define("TEST_FIXED_SEQUENCE", 0);
00048 define("TEST_POSTPONE", 1);
00049 
00050 define("REPORT_AFTER_QUESTION", 0);
00051 define("REPORT_AFTER_TEST", 1);
00052 
00053 define("TYPE_ASSESSMENT", "1");
00054 define("TYPE_SELF_ASSESSMENT", "2");
00055 define("TYPE_NAVIGATION_CONTROLLING", "3");
00056 
00057 class ilObjTest extends ilObject
00058 {
00066   var $test_id;
00067 
00076   var $author;
00077 
00085   var $metadata;
00086 
00094   var $questions;
00095 
00104   var $introduction;
00105 
00113   var $mark_schema;
00114 
00124   var $sequence_settings;
00125   
00137   var $score_reporting;
00138 
00149   var $reporting_date;
00150 
00158   var $evaluation_data;
00159 
00167   var $test_type;
00168 
00177   var $nr_of_tries;
00178 
00186   var $processing_time;
00187         
00195         var $enable_processing_time;
00196 
00204   var $starting_time;
00205   
00213   var $ending_time;
00214 
00222   var $ects_output;
00223 
00231   var $ects_fx;
00232 
00243         var $test_types;
00244 
00252   var $ects_grades;
00253 
00263         var $random_test;
00264 
00272         var $random_question_count;
00273 
00280         function ilObjTest($a_id = 0,$a_call_by_reference = true)
00281         {
00282                 global $ilUser;
00283                 $this->type = "tst";
00284                 $this->mark_schema = new ASS_MarkSchema();
00285                 //$this->ilObject($a_id, $a_call_by_reference);
00286                 $this->retrieveTestTypes();
00287                 $this->test_id = -1;
00288                 $this->author = $ilUser->fullname;
00289                 $this->introduction = "";
00290                 $this->questions = array();
00291                 $this->sequence_settings = TEST_FIXED_SEQUENCE;
00292                 $this->score_reporting = REPORT_AFTER_TEST;
00293                 $this->reporting_date = "";
00294                 $this->nr_of_tries = 0;
00295                 $this->starting_time = "";
00296                 $this->ending_time = "";
00297                 $this->processing_time = "00:00:00";
00298                 $this->enable_processing_time = "0";
00299                 $this->test_type = TYPE_ASSESSMENT;
00300                 $this->ects_output = 0;
00301                 $this->ects_fx = "";
00302                 $this->random_test = 0;
00303                 $this->random_question_count = "";
00304                 global $lng;
00305                 $lng->loadLanguageModule("assessment");
00306                 $this->mark_schema->create_simple_schema($lng->txt("failed_short"), $lng->txt("failed_official"), 0, 0, $lng->txt("passed_short"), $lng->txt("passed_official"), 50, 1);
00307                 $this->ects_grades = array(
00308                         "A" => 90,
00309                         "B" => 65,
00310                         "C" => 35,
00311                         "D" => 10,
00312                         "E" => 0
00313                 );
00314                 if ($a_id == 0)
00315                 {
00316                         $new_meta =& new ilMetaData();
00317                         $this->assignMetaData($new_meta);
00318                 }
00319                 $this->ilObject($a_id, $a_call_by_reference);
00320         }
00321 
00325         function create($a_upload = false)
00326         {
00327                 parent::create();
00328                 if (!$a_upload)
00329                 {
00330                         $this->meta_data->setId($this->getId());
00331                         $this->meta_data->setType($this->getType());
00332                         $this->meta_data->setTitle($this->getTitle());
00333                         $this->meta_data->setDescription($this->getDescription());
00334                         $this->meta_data->setObject($this);
00335                         $this->meta_data->create();
00336                 }
00337         }
00338 
00345         function update()
00346         {
00347                 if (!parent::update())
00348                 {                       
00349                         return false;
00350                 }
00351 
00352                 // put here object specific stuff
00353                 
00354                 return true;
00355         }
00356         
00365         function createReference() {
00366                 $result = parent::createReference();
00367                 $this->saveToDb();
00368                 return $result;
00369         }
00370         
00376         function getCallingScript()
00377         {
00378                 return "test.php";
00379         }
00380         
00386         function read($a_force_db = false)
00387         {
00388                 parent::read($a_force_db);
00389                 $this->loadFromDb();
00390                 $this->meta_data =& new ilMetaData($this->getType(), $this->getId());
00391         }
00392         
00400         function ilClone($a_parent_ref)
00401         {               
00402                 global $rbacadmin;
00403 
00404                 // always call parent ilClone function first!!
00405                 $new_ref_id = parent::ilClone($a_parent_ref);
00406                 
00407                 // get object instance of ilCloned object
00408                 //$newObj =& $this->ilias->obj_factory->getInstanceByRefId($new_ref_id);
00409 
00410                 // create a local role folder & default roles
00411                 //$roles = $newObj->initDefaultRoles();
00412 
00413                 // ...finally assign role to creator of object
00414                 //$rbacadmin->assignUser($roles[0], $newObj->getOwner(), "n");          
00415 
00416                 // always destroy objects in ilClone method because ilClone() is recursive and creates instances for each object in subtree!
00417                 //unset($newObj);
00418 
00419                 // ... and finally always return new reference ID!!
00420                 return $new_ref_id;
00421         }
00422 
00429         function delete()
00430         {               
00431                 // always call parent delete function first!!
00432                 if (!parent::delete())
00433                 {
00434                         return false;
00435                 }
00436                 
00437                 //put here your module specific stuff
00438                 $this->deleteTest();
00439                 
00440                 return true;
00441         }
00442 
00450         function deleteTest()
00451         {
00452                 $query = sprintf("SELECT active_id FROM tst_active WHERE test_fi = %s",
00453                         $this->ilias->db->quote($this->getTestId())
00454                 );
00455                 $result = $this->ilias->db->query($query);
00456                 $active_array = array();
00457                 while ($row = $result->fetchRow(DB_FETCHMODE_ASSOC))
00458                 {
00459                         array_push($active_array, $row["active_id"]);
00460                 }
00461                 
00462                 $query = sprintf("DELETE FROM tst_active WHERE test_fi = %s",
00463                         $this->ilias->db->quote($this->getTestId())
00464                 );
00465                 $result = $this->ilias->db->query($query);
00466 
00467                 if (count($active_array))
00468                 {
00469                         foreach ($active_array as $active_id)
00470                         {
00471                                 $query = sprintf("DELETE FROM tst_times WHERE active_fi = %s",
00472                                         $this->ilias->db->quote($active_id)
00473                                 );
00474                                 $result = $this->ilias->db->query($query);
00475                         }
00476                 }
00477                 
00478                 $query = sprintf("DELETE FROM tst_mark WHERE test_fi = %s",
00479                         $this->ilias->db->quote($this->getTestId())
00480                 );
00481                 $result = $this->ilias->db->query($query);
00482                 
00483                 $query = sprintf("SELECT question_fi FROM tst_test_question WHERE test_fi = %s",
00484                         $this->ilias->db->quote($this->getTestId())
00485                 );
00486                 $result = $this->ilias->db->query($query);
00487                 while ($row = $result->fetchRow(DB_FETCHMODE_OBJECT))
00488                 {
00489                         $this->removeQuestion($row->question_fi);
00490                 }
00491                 
00492                 $query = sprintf("DELETE FROM tst_tests WHERE test_id = %s",
00493                         $this->ilias->db->quote($this->getTestId())
00494                 );
00495                 $result = $this->ilias->db->query($query);
00496                 
00497                 $query = sprintf("DELETE FROM tst_test_random WHERE test_fi = %s",
00498                         $this->ilias->db->quote($this->getTestId())
00499                 );
00500                 $result = $this->ilias->db->query($query);
00501                 
00502                 $query = sprintf("DELETE FROM tst_test_random_question WHERE test_fi = %s",
00503                         $this->ilias->db->quote($this->getTestId())
00504                 );
00505                 $result = $this->ilias->db->query($query);
00506                 
00507                 $this->removeAllTestEditings();
00508                 
00509                 $query = sprintf("DELETE FROM tst_test_question WHERE test_fi = %s",
00510                         $this->ilias->db->quote($this->getTestId())
00511                 );
00512                 $result = $this->ilias->db->query($query);
00513                 
00514                 // delete export files
00515                 $tst_data_dir = ilUtil::getDataDir()."/tst_data";
00516                 $directory = $tst_data_dir."/tst_".$this->getId();
00517                 if (is_dir($directory))
00518                 {
00519                         $directory = escapeshellarg($directory);
00520                         exec("rm -rf $directory");
00521                 }
00522         }
00523 
00533         function initDefaultRoles()
00534         {
00535                 global $rbacadmin;
00536                 
00537                 // create a local role folder
00538                 //$rfoldObj = $this->createRoleFolder("Local roles","Role Folder of forum obj_no.".$this->getId());
00539 
00540                 // create moderator role and assign role to rolefolder...
00541                 //$roleObj = $rfoldObj->createRole("Moderator","Moderator of forum obj_no.".$this->getId());
00542                 //$roles[] = $roleObj->getId();
00543 
00544                 //unset($rfoldObj);
00545                 //unset($roleObj);
00546 
00547                 return $roles ? $roles : array();
00548         }
00549 
00563         function notify($a_event,$a_ref_id,$a_parent_non_rbac_id,$a_node_id,$a_params = 0)
00564         {
00565                 global $tree;
00566                 
00567                 switch ($a_event)
00568                 {
00569                         case "link":
00570                                 
00571                                 //var_dump("<pre>",$a_params,"</pre>");
00572                                 //echo "Module name ".$this->getRefId()." triggered by link event. Objects linked into target object ref_id: ".$a_ref_id;
00573                                 //exit;
00574                                 break;
00575                         
00576                         case "cut":
00577                                 
00578                                 //echo "Module name ".$this->getRefId()." triggered by cut event. Objects are removed from target object ref_id: ".$a_ref_id;
00579                                 //exit;
00580                                 break;
00581                                 
00582                         case "copy":
00583                         
00584                                 //var_dump("<pre>",$a_params,"</pre>");
00585                                 //echo "Module name ".$this->getRefId()." triggered by copy event. Objects are copied into target object ref_id: ".$a_ref_id;
00586                                 //exit;
00587                                 break;
00588 
00589                         case "paste":
00590 
00591                                 //echo "Module name ".$this->getRefId()." triggered by paste (cut) event. Objects are pasted into target object ref_id: ".$a_ref_id;
00592                                 //exit;
00593                                 break;
00594                         
00595                         case "new":
00596                                 
00597                                 //echo "Module name ".$this->getRefId()." triggered by paste (new) event. Objects are applied to target object ref_id: ".$a_ref_id;
00598                                 //exit;
00599                                 break;
00600                 }
00601                 
00602                 // At the beginning of the recursive process it avoids second call of the notify function with the same parameter
00603                 if ($a_node_id==$_GET["ref_id"])
00604                 {       
00605                         $parent_obj =& $this->ilias->obj_factory->getInstanceByRefId($a_node_id);
00606                         $parent_type = $parent_obj->getType();
00607                         if($parent_type == $this->getType())
00608                         {
00609                                 $a_node_id = (int) $tree->getParentId($a_node_id);
00610                         }
00611                 }
00612                 
00613                 parent::notify($a_event,$a_ref_id,$a_parent_non_rbac_id,$a_node_id,$a_params);
00614         }
00615         
00621         function createExportDirectory()
00622         {
00623                 $tst_data_dir = ilUtil::getDataDir()."/tst_data";
00624                 ilUtil::makeDir($tst_data_dir);
00625                 if(!is_writable($tst_data_dir))
00626                 {
00627                         $this->ilias->raiseError("Test Data Directory (".$tst_data_dir
00628                                 .") not writeable.",$this->ilias->error_obj->MESSAGE);
00629                 }
00630                 
00631                 // create learning module directory (data_dir/lm_data/lm_<id>)
00632                 $tst_dir = $tst_data_dir."/tst_".$this->getId();
00633                 ilUtil::makeDir($tst_dir);
00634                 if(!@is_dir($tst_dir))
00635                 {
00636                         $this->ilias->raiseError("Creation of Test Directory failed.",$this->ilias->error_obj->MESSAGE);
00637                 }
00638                 // create Export subdirectory (data_dir/lm_data/lm_<id>/Export)
00639                 $export_dir = $tst_dir."/export";
00640                 ilUtil::makeDir($export_dir);
00641                 if(!@is_dir($export_dir))
00642                 {
00643                         $this->ilias->raiseError("Creation of Export Directory failed.",$this->ilias->error_obj->MESSAGE);
00644                 }
00645         }
00646 
00654         function getExportDirectory()
00655         {
00656                 $export_dir = ilUtil::getDataDir()."/tst_data"."/tst_".$this->getId()."/export";
00657 
00658                 return $export_dir;
00659         }
00660         
00669         function getExportFiles($dir)
00670         {
00671                 // quit if import dir not available
00672                 if (!@is_dir($dir) or
00673                         !is_writeable($dir))
00674                 {
00675                         return array();
00676                 }
00677 
00678                 // open directory
00679                 $dir = dir($dir);
00680 
00681                 // initialize array
00682                 $file = array();
00683 
00684                 // get files and save the in the array
00685                 while ($entry = $dir->read())
00686                 {
00687                         if ($entry != "." and
00688                                 $entry != ".." and
00689                                 substr($entry, -4) == ".zip" and
00690                                 ereg("^[0-9]{10}_{2}[0-9]+_{2}(test__)*[0-9]+\.zip\$", $entry))
00691                         {
00692                                 $file[] = $entry;
00693                         }
00694                 }
00695 
00696                 // close import directory
00697                 $dir->close();
00698 
00699                 // sort files
00700                 sort ($file);
00701                 reset ($file);
00702 
00703                 return $file;
00704         }
00705 
00711         function createImportDirectory()
00712         {
00713                 $tst_data_dir = ilUtil::getDataDir()."/tst_data";
00714                 ilUtil::makeDir($tst_data_dir);
00715                 
00716                 if(!is_writable($tst_data_dir))
00717                 {
00718                         $this->ilias->raiseError("Test Data Directory (".$tst_data_dir
00719                                 .") not writeable.",$this->ilias->error_obj->FATAL);
00720                 }
00721 
00722                 // create test directory (data_dir/tst_data/tst_<id>)
00723                 $tst_dir = $tst_data_dir."/tst_".$this->getId();
00724                 ilUtil::makeDir($tst_dir);
00725                 if(!@is_dir($tst_dir))
00726                 {
00727                         $this->ilias->raiseError("Creation of Test Directory failed.",$this->ilias->error_obj->FATAL);
00728                 }
00729 
00730                 // create import subdirectory (data_dir/tst_data/tst_<id>/import)
00731                 $import_dir = $tst_dir."/import";
00732                 ilUtil::makeDir($import_dir);
00733                 if(!@is_dir($import_dir))
00734                 {
00735                         $this->ilias->raiseError("Creation of Import Directory failed.",$this->ilias->error_obj->FATAL);
00736                 }
00737         }
00738 
00747         function getImportDirectory()
00748         {
00749                 $import_dir = ilUtil::getDataDir()."/tst_data".
00750                         "/tst_".$this->getId()."/import";
00751                 if(@is_dir($import_dir))
00752                 {
00753                         return $import_dir;
00754                 }
00755                 else
00756                 {
00757                         return false;
00758                 }
00759         }
00760 
00761         
00771         function retrieveTestTypes()
00772         {
00773                 global $ilDB;
00774 
00775                 $this->test_types = array();
00776                 $query = "SELECT * FROM tst_test_type ORDER BY test_type_id";
00777                 $result = $ilDB->query($query);
00778                 while ($row = $result->fetchRow(DB_FETCHMODE_OBJECT))
00779                 {
00780                         $this->test_types[$row->test_type_id] = $row->type_tag;
00781                 }
00782         }
00783         
00793   function testTitleExists($title) 
00794         {
00795     $query = sprintf("SELECT * FROM object_data WHERE title = %s AND type = %s",
00796       $this->ilias->db->quote($title),
00797                         $this->ilias->db->quote("tst")
00798     );
00799     $result = $this->ilias->db->query($query);
00800     if (strcmp(strtolower(get_class($result)), db_result) == 0) {
00801       if ($result->numRows() == 1) {
00802         return TRUE;
00803       }
00804     }
00805     return FALSE;
00806   }
00807   
00815   function duplicate() 
00816         {
00817     $clone = $this;
00818     $clone->set_id(-1);
00819     $counter = 2;
00820     while ($this->testTitleExists($this->get_title() . " ($counter)")) {
00821       $counter++;
00822     }
00823     $clone->set_title($this->get_title() . " ($counter)");
00824     $clone->set_owner($this->ilias->account->id);
00825     $clone->setAuthor($this->ilias->account->fullname);
00826     $clone->saveToDb($this->ilias->db);
00827     // Duplicate questions
00828     $query = sprintf("SELECT * FROM tst_test_question WHERE test_fi = %s",
00829       $this->ilias->db->quote($this->getId())
00830     );
00831     $result = $this->ilias->db->query($query);
00832     while ($data = $result->fetchRow(DB_FETCHMODE_OBJECT)) {
00833       $query = sprintf("INSERT INTO tst_test_question (test_question_id, test_fi, question_fi, sequence, TIMESTAMP) VALUES (NULL, %s, %s, %s, NULL)",
00834         $this->ilias->db->quote($clone->getId()),
00835         $this->ilias->db->quote($data->question_fi),
00836         $this->ilias->db->quote($data->sequence)
00837       );
00838       $insert_result = $this->ilias->db->query($query);
00839     }
00840   }
00841   
00850         function isComplete()
00851         {
00852                 if (($this->getTitle()) and ($this->author) and (count($this->mark_schema->mark_steps)) and (count($this->questions)))
00853                 {
00854                         return true;
00855                 } 
00856                         else 
00857                 {
00858                         if ($this->isRandomTest())
00859                         {
00860                                 $arr = $this->getRandomQuestionpools();
00861                                 if (count($arr) && ($this->getRandomQuestionCount() > 0))
00862                                 {
00863                                         return true;
00864                                 }
00865                                 $count = 0;
00866                                 foreach ($arr as $array)
00867                                 {
00868                                         $count += $array["count"];
00869                                 }
00870                                 if ($count)
00871                                 {
00872                                         return true;
00873                                 }
00874                         }
00875                         return false;
00876                 }
00877         }
00878 
00887         function _isComplete($obj_id)
00888         {
00889                 $test = new ilObjTest($obj_id, false);
00890                 $test->loadFromDb();
00891                 return $test->isComplete();
00892         }
00893 
00901         function saveECTSStatus($ects_output = 0, $fx_support = "", $ects_a = 90, $ects_b = 65, $ects_c = 35, $ects_d = 10, $ects_e = 0) 
00902         {
00903     global $ilDB;
00904     if ($this->test_id > 0) {
00905                         $fx_support = preg_replace("/,/", ".", $fx_support);
00906                         if (preg_match("/\d+/", $fx_support))
00907                         {
00908                                 $fx_support = $fx_support;
00909                         }
00910                         else
00911                         {
00912                                 $fx_support = "NULL";
00913                         }
00914       $query = sprintf("UPDATE tst_tests SET ects_output = %s, ects_a = %s, ects_b = %s, ects_c = %s, ects_d = %s, ects_e = %s, ects_fx = %s WHERE test_id = %s",
00915                                 $ilDB->quote("$ects_output"),
00916                                 $ilDB->quote($ects_a . ""),
00917                                 $ilDB->quote($ects_b . ""),
00918                                 $ilDB->quote($ects_c . ""),
00919                                 $ilDB->quote($ects_d . ""),
00920                                 $ilDB->quote($ects_e . ""),
00921         $fx_support,
00922                                 $this->getTestId()
00923       );
00924       $result = $ilDB->query($query);
00925                         $this->ects_output = $ects_output;
00926                         $this->ects_fx = $fx_support;
00927                 }
00928         }
00929 
00937         function saveCompleteStatus() 
00938         {
00939     global $ilias;
00940                 
00941     $db =& $ilias->db;
00942                 $complete = 0;
00943                 if ($this->isComplete()) {
00944                         $complete = 1;
00945                 }
00946     if ($this->test_id > 0) {
00947       $query = sprintf("UPDATE tst_tests SET complete = %s WHERE test_id = %s",
00948                                 $db->quote("$complete"),
00949         $db->quote($this->test_id)
00950       );
00951       $result = $db->query($query);
00952                 }
00953         }
00954 
00963   function saveToDb($properties_only = FALSE)
00964   {
00965     global $ilias;
00966     $db =& $ilias->db;
00967                 $complete = 0;
00968                 if ($this->isComplete()) {
00969                         $complete = 1;
00970                 }
00971                 $ects_fx = "NULL";
00972                 if (preg_match("/\d+/", $this->ects_fx))
00973                 {
00974                         $ects_fx = $this->ects_fx;
00975                 }
00976                 $random_question_count = "NULL";
00977                 if ($this->random_question_count > 0)
00978                 {
00979                         $random_question_count = $this->ilias->db->quote($this->random_question_count . "");
00980                 }
00981     if ($this->test_id == -1) {
00982       // Create new dataset
00983       $now = getdate();
00984       $created = sprintf("%04d%02d%02d%02d%02d%02d", $now['year'], $now['mon'], $now['mday'], $now['hours'], $now['minutes'], $now['seconds']);
00985       $query = sprintf("INSERT INTO tst_tests (test_id, obj_fi, author, test_type_fi, introduction, sequence_settings, score_reporting, nr_of_tries, processing_time, enable_processing_time, reporting_date, starting_time, ending_time, complete, ects_output, ects_a, ects_b, ects_c, ects_d, ects_e, ects_fx, random_test, random_question_count, created, TIMESTAMP) VALUES (NULL, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, NULL)",
00986                                 $db->quote($this->getId() . ""),
00987         $db->quote($this->author . ""),
00988         $db->quote($this->test_type . ""),
00989         $db->quote($this->introduction . ""), 
00990         $db->quote($this->sequence_settings . ""),
00991         $db->quote($this->score_reporting . ""),
00992         $db->quote(sprintf("%d", $this->nr_of_tries) . ""),
00993         $db->quote($this->processing_time . ""),
00994                                 $db->quote("$this->enable_processing_time"),
00995         $db->quote($this->reporting_date . ""),
00996         $db->quote($this->starting_time . ""),
00997         $db->quote($this->ending_time . ""),
00998                                 $db->quote("$complete"),
00999                                 $db->quote($this->ects_output . ""),
01000                                 $db->quote($this->ects_grades["A"] . ""),
01001                                 $db->quote($this->ects_grades["B"] . ""),
01002                                 $db->quote($this->ects_grades["C"] . ""),
01003                                 $db->quote($this->ects_grades["D"] . ""),
01004                                 $db->quote($this->ects_grades["E"] . ""),
01005                                 $ects_fx,
01006                                 $db->quote(sprintf("%d", $this->random_test) . ""),
01007                                 $random_question_count,
01008         $db->quote($created)
01009       );
01010                         if (ilObjAssessmentFolder::_enabledAssessmentLogging())
01011                         {
01012                                 $this->logAction($this->lng->txt("log_create_new_test"));
01013                         }
01014       $result = $db->query($query);
01015       if ($result == DB_OK) {
01016         $this->test_id = $this->ilias->db->getLastInsertId();
01017       }
01018     } else {
01019       // Modify existing dataset
01020                         $oldrow = array();
01021                         if (ilObjAssessmentFolder::_enabledAssessmentLogging())
01022                         {
01023                                 $query = sprintf("SELECT * FROM tst_tests WHERE test_id = %s",
01024                 $db->quote($this->test_id)
01025                                 );
01026                                 $result = $db->query($query);
01027                                 if ($result->numRows() == 1)
01028                                 {
01029                                         $oldrow = $result->fetchRow(DB_FETCHMODE_ASSOC);
01030                                 }
01031                         }
01032       $query = sprintf("UPDATE tst_tests SET author = %s, test_type_fi = %s, introduction = %s, sequence_settings = %s, score_reporting = %s, nr_of_tries = %s, processing_time = %s, enable_processing_time = %s, reporting_date = %s, starting_time = %s, ending_time = %s, ects_output = %s, ects_a = %s, ects_b = %s, ects_c = %s, ects_d = %s, ects_e = %s, ects_fx = %s, random_test = %s, complete = %s WHERE test_id = %s",
01033         $db->quote($this->author . ""), 
01034         $db->quote($this->test_type . ""), 
01035         $db->quote($this->introduction . ""), 
01036         $db->quote($this->sequence_settings . ""), 
01037         $db->quote($this->score_reporting . ""), 
01038         $db->quote(sprintf("%d", $this->nr_of_tries) . ""), 
01039         $db->quote($this->processing_time . ""),
01040                                 $db->quote("$this->enable_processing_time"),
01041         $db->quote($this->reporting_date . ""), 
01042         $db->quote($this->starting_time . ""), 
01043         $db->quote($this->ending_time . ""), 
01044                                 $db->quote($this->ects_output . ""),
01045                                 $db->quote($this->ects_grades["A"] . ""),
01046                                 $db->quote($this->ects_grades["B"] . ""),
01047                                 $db->quote($this->ects_grades["C"] . ""),
01048                                 $db->quote($this->ects_grades["D"] . ""),
01049                                 $db->quote($this->ects_grades["E"] . ""),
01050                                 $ects_fx,
01051                                 $db->quote(sprintf("%d", $this->random_test) . ""),
01052                                 $db->quote("$complete"),
01053         $db->quote($this->test_id)
01054       );
01055       $result = $db->query($query);
01056                         if (ilObjAssessmentFolder::_enabledAssessmentLogging())
01057                         {
01058                                 $query = sprintf("SELECT * FROM tst_tests WHERE test_id = %s",
01059                 $db->quote($this->test_id)
01060                                 );
01061                                 $logresult = $db->query($query);
01062                                 $newrow = array();
01063                                 if ($logresult->numRows() == 1)
01064                                 {
01065                                         $newrow = $logresult->fetchRow(DB_FETCHMODE_ASSOC);
01066                                 }
01067                                 $changed_fields = array();
01068                                 foreach ($oldrow as $key => $value)
01069                                 {
01070                                         if (strcmp($oldrow[$key], $newrow[$key]) != 0)
01071                                         {
01072                                                 array_push($changed_fields, "$key: " . $oldrow[$key] . " => " . $newrow[$key]);
01073                                         }
01074                                 }
01075                                 $changes = join($changed_fields, ", ");
01076                                 if (count($changed_fields) == 0)
01077                                 {
01078                                         $changes = $this->lng->txt("log_no_test_fields_changed");
01079                                 }
01080                                 $this->logAction($this->lng->txt("log_modified_test") . " [".$changes."]");
01081                         }
01082     }
01083                 if (!$properties_only)
01084                 {
01085                         if ($result == DB_OK) {
01086                                 if (!$this->isRandomTest())
01087                                 {
01088                                         $this->saveQuestionsToDb();
01089                                 }
01090                                 $this->mark_schema->saveToDb($this->test_id);
01091                         }
01092                 }
01093   }
01094 
01103         function saveQuestionsToDb() 
01104         {
01105                 $oldquestions = array();
01106                 if (ilObjAssessmentFolder::_enabledAssessmentLogging())
01107                 {
01108                         $query = sprintf("SELECT question_fi FROM tst_test_question WHERE test_fi = %s ORDER BY sequence",
01109                                 $this->ilias->db->quote($this->getTestId())
01110                         );
01111                         $result = $this->ilias->db->query($query);
01112                         if ($result->numRows() > 0)
01113                         {
01114                                 while ($row = $result->fetchRow(DB_FETCHMODE_ASSOC))
01115                                 {
01116                                         array_push($oldquestions, $row["question_fi"]);
01117                                 }
01118                         }
01119                 }
01120                 
01121                 // delete existing category relations
01122     $query = sprintf("DELETE FROM tst_test_question WHERE test_fi = %s",
01123                         $this->ilias->db->quote($this->getTestId())
01124                 );
01125                 $result = $this->ilias->db->query($query);
01126                 // create new category relations
01127                 foreach ($this->questions as $key => $value) {
01128                         $query = sprintf("INSERT INTO tst_test_question (test_question_id, test_fi, question_fi, sequence, TIMESTAMP) VALUES (NULL, %s, %s, %s, NULL)",
01129                                 $this->ilias->db->quote($this->getTestId() . ""),
01130                                 $this->ilias->db->quote($value . ""),
01131                                 $this->ilias->db->quote($key . "")
01132                         );
01133                         $result = $this->ilias->db->query($query);
01134                 }
01135                 if (ilObjAssessmentFolder::_enabledAssessmentLogging())
01136                 {
01137                         $query = sprintf("SELECT question_fi FROM tst_test_question WHERE test_fi = %s ORDER BY sequence",
01138                                 $this->ilias->db->quote($this->getTestId())
01139                         );
01140                         $result = $this->ilias->db->query($query);
01141                         $newquestions = array();
01142                         if ($result->numRows() > 0)
01143                         {
01144                                 while ($row = $result->fetchRow(DB_FETCHMODE_ASSOC))
01145                                 {
01146                                         array_push($newquestions, $row["question_fi"]);
01147                                 }
01148                         }
01149                         foreach ($oldquestions as $index => $question_id)
01150                         {
01151                                 if (strcmp($newquestions[$index], $question_id) != 0)
01152                                 {
01153                                         $pos = array_search($question_id, $newquestions);
01154                                         if ($pos === FALSE)
01155                                         {
01156                                                 $this->logAction($this->lng->txt("log_question_removed"), $question_id);                                                        
01157                                         }
01158                                         else
01159                                         {
01160                                                 $this->logAction($this->lng->txt("log_question_position_changed") . ": " . ($index+1) . " => " . ($pos+1), $question_id);
01161                                         }
01162                                 }
01163                         }
01164                         foreach ($newquestions as $index => $question_id)
01165                         {
01166                                 if (array_search($question_id, $oldquestions) === FALSE)
01167                                 {
01168                                         $this->logAction($this->lng->txt("log_question_added") . ": " . ($index+1), $question_id);                                                      
01169                                 }
01170                         }
01171                 }
01172         }
01173 
01182         function saveRandomQuestion($question_id) 
01183         {
01184                 global $ilUser;
01185                 
01186                 $query = sprintf("SELECT test_random_question_id FROM tst_test_random_question WHERE test_fi = %s AND user_fi = %s",
01187                         $this->ilias->db->quote($this->getTestId() . ""),
01188                         $this->ilias->db->quote($ilUser->id . "")
01189                 );
01190                 $result = $this->ilias->db->query($query);
01191                 
01192                 $query = sprintf("INSERT INTO tst_test_random_question (test_random_question_id, test_fi, user_fi, question_fi, sequence, TIMESTAMP) VALUES (NULL, %s, %s, %s, %s, NULL)",
01193                         $this->ilias->db->quote($this->getTestId() . ""),
01194                         $this->ilias->db->quote($ilUser->id . ""),
01195                         $this->ilias->db->quote($question_id . ""),
01196                         $this->ilias->db->quote(($result->numRows()+1) . "")
01197                 );
01198                 $result = $this->ilias->db->query($query);
01199         }
01200 
01209         function saveRandomQuestionCount($total_questions = "NULL")
01210         {
01211                 if (strcmp($total_questions, "NULL") != 0)
01212                 {
01213                         $this->setRandomQuestionCount($total_questions);
01214                         $total_questions = $this->ilias->db->quote($total_questions);
01215                 }
01216                 $query = sprintf("UPDATE tst_tests SET random_question_count = %s WHERE test_id = %s",
01217                         $total_questions,
01218                         $this->ilias->db->quote($this->getTestId() . "")
01219                 );
01220                 $result = $this->ilias->db->query($query);
01221         }
01222 
01232         function saveRandomQuestionpools($qpl_array) 
01233         {
01234                 // delete existing random questionpools
01235     $query = sprintf("DELETE FROM tst_test_random WHERE test_fi = %s",
01236                         $this->ilias->db->quote($this->getTestId())
01237                 );
01238                 $result = $this->ilias->db->query($query);
01239                 // create new random questionpools
01240                 foreach ($qpl_array as $key => $value) {
01241                         if ($value["qpl"] > -1)
01242                         {
01243                                 $count = ilObjQuestionPool::_getQuestionCount($value["qpl"]);
01244                                 if ($value["count"] > $count)
01245                                 {
01246                                         $value["count"] = $count;
01247                                 }
01248                                 $query = sprintf("INSERT INTO tst_test_random (test_random_id, test_fi, questionpool_fi, num_of_q, TIMESTAMP) VALUES (NULL, %s, %s, %s, NULL)",
01249                                         $this->ilias->db->quote($this->getTestId() . ""),
01250                                         $this->ilias->db->quote($value["qpl"] . ""),
01251                                         $this->ilias->db->quote(sprintf("%d", $value["count"]) . "")
01252                                 );
01253                                 $result = $this->ilias->db->query($query);
01254                         }
01255                 }
01256         }
01257 
01267         function &getRandomQuestionpools() 
01268         {
01269                 $qpls = array();
01270                 $counter = 0;
01271                 $query = sprintf("SELECT * FROM tst_test_random WHERE test_fi = %s ORDER BY test_random_id",
01272                         $this->ilias->db->quote($this->getTestId() . "")
01273                 );
01274                 $result = $this->ilias->db->query($query);
01275                 if ($result->numRows())
01276                 {
01277                         while ($row = $result->fetchRow(DB_FETCHMODE_ASSOC))
01278                         {
01279                                 $qpls[$counter] = array(
01280                                         "index" => $counter,
01281                                         "count" => $row["num_of_q"],
01282                                         "qpl"   => $row["questionpool_fi"]
01283                                 );
01284                                 $counter++;
01285                         }
01286                 }
01287                 return $qpls;
01288         }
01289 
01299         function loadFromDb()
01300         {
01301                 $db = $this->ilias->db;
01302 
01303                 $query = sprintf("SELECT * FROM tst_tests WHERE obj_fi = %s",
01304                 $db->quote($this->getId())
01305                         );
01306                 $result = $db->query($query);
01307                 if (strcmp(strtolower(get_class($result)), db_result) == 0)
01308                 {
01309                         if ($result->numRows() == 1)
01310                         {
01311                                 $data = $result->fetchRow(DB_FETCHMODE_OBJECT);
01312                                 $this->test_id = $data->test_id;
01313                                 $this->author = $data->author;
01314                                 $this->test_type = $data->test_type_fi;
01315                                 $this->introduction = $data->introduction;
01316                                 $this->sequence_settings = $data->sequence_settings;
01317                                 $this->score_reporting = $data->score_reporting;
01318                                 $this->nr_of_tries = $data->nr_of_tries;
01319                                 $this->processing_time = $data->processing_time;
01320                                 $this->enable_processing_time = $data->enable_processing_time;
01321                                 $this->reporting_date = $data->reporting_date;
01322                                 $this->starting_time = $data->starting_time;
01323                                 $this->ending_time = $data->ending_time;
01324                                 $this->ects_output = $data->ects_output;
01325                                 $this->ects_grades = array(
01326                                         "A" => $data->ects_a,
01327                                         "B" => $data->ects_b,
01328                                         "C" => $data->ects_c,
01329                                         "D" => $data->ects_d,
01330                                         "E" => $data->ects_e
01331                                 );
01332                                 $this->ects_fx = $data->ects_fx;
01333                                 $this->random_test = $data->random_test;
01334                                 $this->random_question_count = $data->random_question_count;
01335                                 $this->mark_schema->flush();
01336                                 $this->mark_schema->loadFromDb($this->test_id);
01337                                 $this->loadQuestions();
01338                         }
01339                 }
01340         }
01341 
01350         function loadQuestions($user_id = "") 
01351         {
01352                 global $ilUser;
01353                 
01354     $db = $this->ilias->db;
01355                 $this->questions = array();
01356                 if (strcmp($user_id, "") == 0)
01357                 {
01358                         $user_id = $ilUser->id;
01359                 }
01360                 if ($this->isRandomTest())
01361                 {
01362                         $query = sprintf("SELECT tst_test_random_question.* FROM tst_test_random_question, qpl_questions WHERE tst_test_random_question.test_fi = %s AND tst_test_random_question.user_fi = %s AND qpl_questions.question_id = tst_test_random_question.question_fi ORDER BY sequence",
01363                                 $db->quote($this->test_id . ""),
01364                                 $db->quote($user_id . "")
01365                         );
01366                 }
01367                 else
01368                 {
01369                         $query = sprintf("SELECT tst_test_question.* FROM tst_test_question, qpl_questions WHERE tst_test_question.test_fi = %s AND qpl_questions.question_id = tst_test_question.question_fi ORDER BY sequence",
01370                                 $db->quote($this->test_id . "")
01371                         );
01372                 }
01373                 $result = $db->query($query);
01374                 $index = 1;
01375                 while ($data = $result->fetchRow(DB_FETCHMODE_OBJECT)) {
01376                         $this->questions[$index++] = $data->question_fi;
01377                 }
01378         }
01379 
01389   function setAuthor($author = "") 
01390         {
01391     $this->author = $author;
01392   }
01393 
01403   function setIntroduction($introduction = "") 
01404         {
01405     $this->introduction = $introduction;
01406   }
01407 
01417   function getAuthor() 
01418         {
01419     return $this->author;
01420   }
01421 
01431   function isRandomTest() 
01432         {
01433     return $this->random_test;
01434   }
01435 
01445   function getRandomQuestionCount() 
01446         {
01447     return $this->random_question_count;
01448   }
01449 
01459   function getIntroduction() 
01460         {
01461     return $this->introduction;
01462   }
01463 
01473   function getTestId() 
01474         {
01475     return $this->test_id;
01476   }
01477 
01487   function setSequenceSettings($sequence_settings = 0) 
01488         {
01489     $this->sequence_settings = $sequence_settings;
01490   }
01491 
01501   function setTestType($type = TYPE_ASSESSMENT) 
01502         {
01503     $this->test_type = $type;
01504   }
01505 
01515   function setScoreReporting($score_reporting = 0) 
01516         {
01517     $this->score_reporting = $score_reporting;
01518   }
01519 
01529   function setRandomTest($a_random_test = 0) 
01530         {
01531     $this->random_test = $a_random_test;
01532   }
01533 
01543   function setRandomQuestionCount($a_random_question_count = "") 
01544         {
01545     $this->random_question_count = $a_random_question_count;
01546   }
01547 
01557   function setReportingDate($reporting_date) 
01558         {
01559     if (!$reporting_date) 
01560                 {
01561       $this->reporting_date = "";
01562                         $this->ects_output = 0;
01563     }
01564                         else 
01565                 {
01566       $this->reporting_date = $reporting_date;
01567       $this->score_reporting = REPORT_AFTER_TEST;
01568     }
01569   }
01570 
01580   function getSequenceSettings() 
01581         {
01582     return $this->sequence_settings;
01583   }
01584 
01594   function getScoreReporting() 
01595         {
01596     return $this->score_reporting;
01597   }
01598 
01608   function getTestType() 
01609         {
01610     return $this->test_type;
01611   }
01612 
01622   function getReportingDate() 
01623         {
01624     return $this->reporting_date;
01625   }
01626 
01636   function getNrOfTries() 
01637         {
01638     return $this->nr_of_tries;
01639   }
01640 
01650   function getProcessingTime() 
01651         {
01652     return $this->processing_time;
01653   }
01654         
01664         function getProcessingTimeInSeconds()
01665         {
01666                 if (preg_match("/(\d{2}):(\d{2}):(\d{2})/", $this->getProcessingTime(), $matches))
01667                 {
01668                         return ($matches[1] * 3600) + ($matches[2] * 60) + $matches[3];
01669                 }
01670                         else
01671                 {
01672                         return 0;
01673                 }
01674         }
01675 
01685   function getEnableProcessingTime() 
01686         {
01687     return $this->enable_processing_time;
01688   }
01689 
01699   function getStartingTime() 
01700         {
01701     return $this->starting_time;
01702   }
01703 
01713   function getEndingTime() 
01714         {
01715     return $this->ending_time;
01716   }
01717 
01727   function setNrOfTries($nr_of_tries = 0) 
01728         {
01729     $this->nr_of_tries = $nr_of_tries;
01730   }
01731 
01741   function setProcessingTime($processing_time = "00:00:00") 
01742         {
01743     $this->processing_time = $processing_time;
01744   }
01745         
01755         function setEnableProcessingTime($enable = 0) 
01756         {
01757                 if ($enable) {
01758                         $this->enable_processing_time = "1";
01759                 } else {
01760                         $this->enable_processing_time = "0";
01761                 }
01762         }
01763 
01773   function setStartingTime($starting_time = "") 
01774         {
01775     $this->starting_time = $starting_time;
01776   }
01777 
01787   function setEndingTime($ending_time = "") 
01788         {
01789     $this->ending_time = $ending_time;
01790   }
01791   
01801         function removeQuestion($question_id) 
01802         {
01803                 $question = new ASS_Question();
01804                 if (ilObjAssessmentFolder::_enabledAssessmentLogging())
01805                 {
01806                         $this->logAction($this->lng->txt("log_question_removed"), $question_id);
01807                 }
01808                 $question->delete($question_id);
01809                 $this->removeAllTestEditings($question_id);
01810                 $this->loadQuestions();
01811                 $this->saveQuestionsToDb();
01812         }
01813         
01821         function clearEvalSelectedUsers()
01822         {
01823                 $query = sprintf("DELETE FROM tst_eval_users WHERE test_fi = %s",
01824                         $this->ilias->db->quote($this->getTestId())
01825                 );
01826                 $result = $this->ilias->db->query($query);
01827         }
01828         
01836         function clearEvalSelectedGroups()
01837         {
01838                 $query = sprintf("DELETE FROM tst_eval_groups WHERE test_fi = %s",
01839                         $this->ilias->db->quote($this->getTestId())
01840                 );
01841                 $result = $this->ilias->db->query($query);
01842         }
01843 
01855         function removeAllTestEditings($question_id = "") 
01856         {
01857                 // remove test_active entries, because test has changed
01858                 $this->deleteActiveTests();
01859                 // remove selected users/groups
01860                 $this->clearEvalSelectedUsers();
01861                 $this->clearEvalSelectedGroups();
01862                 
01863                 // remove the question from tst_solutions
01864                 if ($question_id) {
01865                         $query = sprintf("DELETE FROM tst_solutions WHERE test_fi = %s AND question_fi = %s",
01866                                 $this->ilias->db->quote($this->getTestId()),
01867                                 $this->ilias->db->quote($question_id)
01868                         );
01869                 } else {
01870                         $query = sprintf("DELETE FROM tst_solutions WHERE test_fi = %s",
01871                                 $this->ilias->db->quote($this->getTestId())
01872                         );
01873                 }
01874                 $result = $this->ilias->db->query($query);
01875                 if ($this->isRandomTest())
01876                 {
01877                         $query = sprintf("DELETE FROM tst_test_random_question WHERE test_fi = %s",
01878                                 $this->ilias->db->quote($this->getTestId())
01879                         );
01880                         $result = $this->ilias->db->query($query);
01881                 }
01882                 if (ilObjAssessmentFolder::_enabledAssessmentLogging())
01883                 {
01884                         $this->logAction($this->lng->txt("log_user_data_removed"));
01885                 }
01886         }
01887         
01896         function deleteActiveTests() 
01897         {
01898                 $query = sprintf("DELETE FROM tst_active WHERE test_fi = %s",
01899                         $this->ilias->db->quote($this->getTestId())
01900                 );
01901                 $result = $this->ilias->db->query($query);
01902         }
01903         
01914         function deleteResults($user_id = "",$a_delete_active = false) 
01915         {
01916                 if ($user_id) {
01917                         $query = sprintf("DELETE FROM tst_solutions WHERE test_fi = %s AND user_fi = %s",
01918                                 $this->ilias->db->quote($this->getTestId()),
01919                                 $this->ilias->db->quote($user_id)
01920                         );
01921                         $result = $this->ilias->db->query($query);
01922                         $sequence_arr = array_flip($this->questions);
01923                         $sequence = join($sequence_arr, ",");
01924                         $query = sprintf("UPDATE tst_active SET sequence = %s, lastindex = %s WHERE test_fi = %s and user_fi = %s",
01925                                 $this->ilias->db->quote($sequence),
01926                                 $this->ilias->db->quote("1"),
01927                                 $this->ilias->db->quote($this->getTestId()),
01928                                 $this->ilias->db->quote($user_id)
01929                         );
01930                         $result = $this->ilias->db->query($query);
01931 
01932                         if($a_delete_active)
01933                         {
01934                                 $query = "DELETE FROM tst_active ".
01935                                         "WHERE user_fi = '".$user_id."' ".
01936                                         "AND test_fi = '".$this->getTestId()."'";
01937 
01938                                 $this->ilias->db->query($query);
01939                         }
01940                 }
01941         }
01942         
01952         function questionMoveUp($question_id) 
01953         {
01954                 // Move a question up in sequence
01955                 $query = sprintf("SELECT * FROM tst_test_question WHERE test_fi=%s AND question_fi=%s",
01956                         $this->ilias->db->quote($this->getTestId()),
01957                         $this->ilias->db->quote($question_id)
01958                 );
01959                 $result = $this->ilias->db->query($query);
01960                 $data = $result->fetchRow(DB_FETCHMODE_OBJECT);
01961                 if ($data->sequence > 1) {
01962                         // OK, it's not the top question, so move it up
01963                         $query = sprintf("SELECT * FROM tst_test_question WHERE test_fi=%s AND sequence=%s",
01964                                 $this->ilias->db->quote($this->getTestId()),
01965                                 $this->ilias->db->quote($data->sequence - 1)
01966                         );
01967                         $result = $this->ilias->db->query($query);
01968                         $data_previous = $result->fetchRow(DB_FETCHMODE_OBJECT);
01969                         // change previous dataset
01970                         $query = sprintf("UPDATE tst_test_question SET sequence=%s WHERE test_question_id=%s",
01971                                 $this->ilias->db->quote($data->sequence),
01972                                 $this->ilias->db->quote($data_previous->test_question_id)
01973                         );
01974                         $result = $this->ilias->db->query($query);
01975                         // move actual dataset up
01976                         $query = sprintf("UPDATE tst_test_question SET sequence=%s WHERE test_question_id=%s",
01977                                 $this->ilias->db->quote($data->sequence - 1),
01978                                 $this->ilias->db->quote($data->test_question_id)
01979                         );
01980                         $result = $this->ilias->db->query($query);
01981                         if (ilObjAssessmentFolder::_enabledAssessmentLogging())
01982                         {
01983                                 $this->logAction($this->lng->txt("log_question_position_changed") . ": " . ($data->sequence) . " => " . ($data->sequence-1), $question_id);
01984                         }
01985                 }
01986                 $this->loadQuestions();
01987         }
01988         
01998         function questionMoveDown($question_id) 
01999         {
02000                 // Move a question down in sequence
02001                 $query = sprintf("SELECT * FROM tst_test_question WHERE test_fi=%s AND question_fi=%s",
02002                         $this->ilias->db->quote($this->getTestId()),
02003                         $this->ilias->db->quote($question_id)
02004                 );
02005                 $result = $this->ilias->db->query($query);
02006                 $data = $result->fetchRow(DB_FETCHMODE_OBJECT);
02007                 $query = sprintf("SELECT * FROM tst_test_question WHERE test_fi=%s AND sequence=%s",
02008                         $this->ilias->db->quote($this->getTestId()),
02009                         $this->ilias->db->quote($data->sequence + 1)
02010                 );
02011                 $result = $this->ilias->db->query($query);
02012                 if ($result->numRows() == 1) 
02013                 {
02014                         // OK, it's not the last question, so move it down
02015                         $data_next = $result->fetchRow(DB_FETCHMODE_OBJECT);
02016                         // change next dataset
02017                         $query = sprintf("UPDATE tst_test_question SET sequence=%s WHERE test_question_id=%s",
02018                                 $this->ilias->db->quote($data->sequence),
02019                                 $this->ilias->db->quote($data_next->test_question_id)
02020                         );
02021                         $result = $this->ilias->db->query($query);
02022                         // move actual dataset down
02023                         $query = sprintf("UPDATE tst_test_question SET sequence=%s WHERE test_question_id=%s",
02024                                 $this->ilias->db->quote($data->sequence + 1),
02025                                 $this->ilias->db->quote($data->test_question_id)
02026                         );
02027                         $result = $this->ilias->db->query($query);
02028                         if (ilObjAssessmentFolder::_enabledAssessmentLogging())
02029                         {
02030                                 $this->logAction($this->lng->txt("log_question_position_changed") . ": " . ($data->sequence) . " => " . ($data->sequence+1), $question_id);
02031                         }
02032                 }
02033                 $this->loadQuestions();
02034         }
02035         
02045         function duplicateQuestionForTest($question_id)
02046         {
02047                 global $ilUser;
02048 
02049                 $question =& ilObjTest::_instanciateQuestion($question_id);
02050                 $duplicate_id = $question->duplicate(true);
02051 
02052                 return $duplicate_id;
02053         }
02054 
02063         function insertQuestion($question_id)
02064         {
02065                 $duplicate_id = $this->duplicateQuestionForTest($question_id);
02066 
02067                 // get maximum sequence index in test
02068                 $query = sprintf("SELECT MAX(sequence) AS seq FROM tst_test_question WHERE test_fi=%s",
02069                         $this->ilias->db->quote($this->getTestId())
02070                         );
02071                 $result = $this->ilias->db->query($query);
02072                 $sequence = 1;
02073 
02074                 if ($result->numRows() == 1)
02075                 {
02076                         $data = $result->fetchRow(DB_FETCHMODE_OBJECT);
02077                         $sequence = $data->seq + 1;
02078                 }
02079 
02080                 $query = sprintf("INSERT INTO tst_test_question (test_question_id, test_fi, question_fi, sequence, TIMESTAMP) VALUES (NULL, %s, %s, %s, NULL)",
02081                         $this->ilias->db->quote($this->getTestId()),
02082                         $this->ilias->db->quote($duplicate_id),
02083                         $this->ilias->db->quote($sequence)
02084                         );
02085                 $result = $this->ilias->db->query($query);
02086                 if ($result != DB_OK)
02087                 {
02088                         // Error
02089                 }
02090                 else
02091                 {
02092                         if (ilObjAssessmentFolder::_enabledAssessmentLogging())
02093                         {
02094                                 $this->logAction($this->lng->txt("log_question_added") . ": " . $sequence, $duplicate_id);
02095                         }
02096                 }
02097                 // remove test_active entries, because test has changed
02098                 $query = sprintf("DELETE FROM tst_active WHERE test_fi = %s",
02099                         $this->ilias->db->quote($this->getTestId())
02100                         );
02101                 $result = $this->ilias->db->query($query);
02102                 $this->loadQuestions();
02103                 $this->saveCompleteStatus();
02104         }
02105 
02115         function &getQuestionTitles() 
02116         {
02117                 $titles = array();
02118                 if (!$this->isRandomTest())
02119                 {
02120                         global $ilDB;
02121                         $query = sprintf("SELECT qpl_questions.title FROM tst_test_question, qpl_questions WHERE tst_test_question.test_fi = %s AND tst_test_question.question_fi = qpl_questions.question_id ORDER BY tst_test_question.sequence",
02122                                 $ilDB->quote($this->getTestId() . "")
02123                         );
02124                         $result = $ilDB->query($query);
02125                         while ($row = $result->fetchRow(DB_FETCHMODE_ASSOC))
02126                         {
02127                                 array_push($titles, $row["title"]);
02128                         }
02129                 }
02130                 return $titles;
02131         }
02132         
02142         function getQuestionTitle($sequence) 
02143         {
02144                 global $ilUser;
02145                 if ($ilUser->id > 0)
02146                 {
02147                         $active = $this->getActiveTestUser($ilUser->id);
02148                         $seq = split(",", $active->sequence);
02149                         $query = sprintf("SELECT title from qpl_questions WHERE question_id = %s",
02150                                 $this->ilias->db->quote($this->questions[$seq[$sequence-1]])
02151                         );
02152                 }
02153                 else
02154                 {
02155                         $query = sprintf("SELECT title from qpl_questions WHERE question_id = %s",
02156                                 $this->ilias->db->quote($this->questions[$sequence])
02157                         );
02158                 }
02159     $result = $this->ilias->db->query($query);
02160                 $row = $result->fetchRow(DB_FETCHMODE_OBJECT);
02161                 return $row->title;
02162         }
02163         
02174         function getQuestionDataset($question_id) 
02175         {
02176                 $query = sprintf("SELECT qpl_questions.*, qpl_question_type.type_tag FROM qpl_questions, qpl_question_type WHERE qpl_questions.question_id = %s AND qpl_questions.question_type_fi = qpl_question_type.question_type_id",
02177                         $this->ilias->db->quote("$question_id")
02178                 );
02179     $result = $this->ilias->db->query($query);
02180                 $row = $result->fetchRow(DB_FETCHMODE_OBJECT);
02181                 return $row;
02182         }
02183         
02192         function &get_qpl_titles() 
02193         {
02194                 global $rbacsystem;
02195                 
02196                 $qpl_titles = array();
02197                 // get all available questionpools and remove the trashed questionspools
02198                 $query = "SELECT object_data.*, object_data.obj_id, object_reference.ref_id FROM object_data, object_reference WHERE object_data.obj_id = object_reference.obj_id AND object_data.type = 'qpl' ORDER BY object_data.title";
02199                 $result = $this->ilias->db->query($query);
02200                 while ($row = $result->fetchRow(DB_FETCHMODE_OBJECT))
02201                 {               
02202                         if ($rbacsystem->checkAccess("write", $row->ref_id) && ($this->_hasUntrashedReference($row->obj_id)))
02203                         {
02204                                 $qpl_titles["$row->obj_id"] = $row->title;
02205                         }
02206                 }
02207                 return $qpl_titles;
02208         }
02209         
02218         function &getExistingQuestions() 
02219         {
02220                 global $ilUser;
02221                 $existing_questions = array();
02222                 if ($this->isRandomTest())
02223                 {
02224                         $query = sprintf("SELECT qpl_questions.original_id FROM qpl_questions, tst_test_random_question WHERE tst_test_random_question.test_fi = %s AND tst_test_random_question.user_fi = %s AND tst_test_random_question.question_fi = qpl_questions.question_id",
02225                                 $this->ilias->db->quote($this->getTestId() . ""),
02226                                 $this->ilias->db->quote($ilUser->id . "")
02227                         );
02228                 }
02229                 else
02230                 {
02231                         $query = sprintf("SELECT qpl_questions.original_id FROM qpl_questions, tst_test_question WHERE tst_test_question.test_fi = %s AND tst_test_question.question_fi = qpl_questions.question_id",
02232                                 $this->ilias->db->quote($this->getTestId())
02233                         );
02234                 }
02235                 $result = $this->ilias->db->query($query);
02236                 while ($data = $result->fetchRow(DB_FETCHMODE_OBJECT)) {
02237                         array_push($existing_questions, $data->original_id);
02238                 }
02239                 return $existing_questions;
02240         }
02241         
02251   function getQuestionType($question_id) 
02252         {
02253     if ($question_id < 1)
02254       return -1;
02255     $query = sprintf("SELECT type_tag FROM qpl_questions, qpl_question_type WHERE qpl_questions.question_id = %s AND qpl_questions.question_type_fi = qpl_question_type.question_type_id",
02256       $this->ilias->db->quote($question_id)
02257     );
02258     $result = $this->ilias->db->query($query);
02259     if ($result->numRows() == 1) {
02260       $data = $result->fetchRow(DB_FETCHMODE_OBJECT);
02261       return $data->type_tag;
02262     } else {
02263       return "";
02264     }
02265   }
02266         
02275         function startWorkingTime ($user_id) 
02276         {
02277                 $result = "";
02278                 if (!($result = $this->getActiveTestUser($user_id))) {
02279                         $this->setActiveTestUser();
02280                         $result = $this->getActiveTestUser($user_id);
02281                 }
02282                 $q = sprintf("INSERT INTO tst_times (times_id, active_fi, started, finished, TIMESTAMP) VALUES (NULL, %s, %s, %s, NULL)",
02283                         $this->ilias->db->quote($result->active_id),
02284                         $this->ilias->db->quote(strftime("%Y-%m-%d %H:%M:%S")),
02285                         $this->ilias->db->quote(strftime("%Y-%m-%d %H:%M:%S"))
02286                 );
02287                 $result = $this->ilias->db->query($q);
02288                 return $this->ilias->db->getLastInsertId();
02289         }
02290         
02299         function updateWorkingTime($times_id)
02300         {
02301                 $q = sprintf("UPDATE tst_times SET finished = %s WHERE times_id = %s",
02302                         $this->ilias->db->quote(strftime("%Y-%m-%d %H:%M:%S")),
02303                         $this->ilias->db->quote($times_id)
02304                 );
02305                 $result = $this->ilias->db->query($q);
02306         }
02307   
02317         function getQuestionIdFromActiveUserSequence($sequence) 
02318         {
02319                 global $ilUser;
02320 
02321                 $active = $this->getActiveTestUser();
02322                 $sequence_array = split(",", $active->sequence);
02323 
02324                 return $this->questions[$sequence_array[$sequence-1]];
02325         }
02326         
02335         function &getAllQuestionsForActiveUser() 
02336         {
02337                 $result_array = array();
02338                 $active = $this->getActiveTestUser();
02339                 $sequence_array = split(",", $active->sequence);
02340                 $all_questions = &$this->getAllQuestions();
02341                 $worked_questions = &$this->getWorkedQuestions();
02342                 foreach ($sequence_array as $sequence)
02343                 {
02344                         if (in_array($this->questions[$sequence], $worked_questions))
02345                         {
02346                                 $all_questions[$this->questions[$sequence]]["worked"] = 1;
02347                         }
02348                         else
02349                         {
02350                                 $all_questions[$this->questions[$sequence]]["worked"] = 0;
02351                         }
02352                         array_push($result_array, $all_questions[$this->questions[$sequence]]);
02353                 }
02354                 return $result_array;
02355         }
02356 
02357         function getWrongAnsweredQuestions()
02358         {
02359                 global $ilUser;
02360 
02361                 foreach($all_questions =& $this->getAllQuestionsForActiveUser() as $question)
02362                 {
02363                         foreach($this->getTestResult($ilUser->getId()) as $result)
02364                         {
02365                                 if($result['qid'] == $question['question_id'])
02366                                 {
02367                                         if($result['max'] != $result['reached'])
02368                                         {
02369                                                 $wrong[] = $question;
02370                                         }
02371                                 }
02372                         }
02373                 }
02374                 return $wrong ? $wrong : array();
02375         }
02383         function incrementSequenceByResult($a_sequence)
02384         {
02385                 global $ilUser;
02386 
02387                 for($i = $a_sequence+1; $i <= $this->getQuestionCount(); $i++)
02388                 {
02389                         $qid = $this->getQuestionIdFromActiveUserSequence($i);
02390 
02391                         foreach($this->getTestResult($ilUser->getId()) as $result)
02392                         {
02393                                 if($qid == $result['qid'])
02394                                 {
02395                                         if($result['max'] != $result['reached'])
02396                                         {
02397                                                 return $i;
02398                                         }
02399                                 }
02400                         }
02401                 }
02402                 return ($this->getQuestionCount()+1);
02403         }
02404 
02405 
02413         function decrementSequenceByResult($a_sequence)
02414         {
02415                 for($i = $a_sequence; $i > 0; $i--)
02416                 {
02417                         $qid = $this->getQuestionIdFromActiveUserSequence($i);
02418 
02419                         foreach($this->getTestResult($ilUser->getId()) as $result)
02420                         {
02421                                 if($qid == $result['qid'])
02422                                 {
02423                                         if($result['max'] != $result['reached'])
02424                                         {
02425                                                 return $i;
02426                                         }
02427                                 }
02428                         }
02429                 }
02430                 return 1;
02431         }
02432 
02433         function getFirstSequence()
02434         {
02435                 global $ilUser;
02436 
02437                 $results = $this->getTestResult($ilUser->getId());
02438 
02439                 for($i = 1; $i <= $this->getQuestionCount(); $i++)
02440                 {
02441                         $qid = $this->getQuestionIdFromActiveUserSequence($i);
02442 
02443                         foreach($results as $result)
02444                         {
02445                                 if($qid == $result['qid'])
02446                                 {
02447                                         if(!$result['max'] or $result['max'] != $result['reached'])
02448                                         {
02449                                                 return $i;
02450                                         }
02451                                 }
02452                         }
02453                 }
02454                 return 0;
02455         }
02456 
02457         
02466         function &getWorkedQuestions()
02467         {
02468                 global $ilUser;
02469                 $query = sprintf("SELECT * FROM tst_solutions WHERE user_fi = %s AND test_fi = %s GROUP BY question_fi",
02470                         $this->ilias->db->quote($ilUser->id),
02471                         $this->ilias->db->quote($this->getTestId())
02472                 );
02473                 $result = $this->ilias->db->query($query);
02474                 $result_array = array();
02475                 while ($row = $result->fetchRow(DB_FETCHMODE_OBJECT))
02476                 {
02477                         array_push($result_array, $row->question_fi);
02478                 }
02479                 return $result_array;
02480         }
02481         
02490         function &getAllQuestions()
02491         {
02492                 global $ilUser;
02493                 
02494                 if ($this->isRandomTest())
02495                 {
02496                         $query = sprintf("SELECT qpl_questions.* FROM qpl_questions, tst_test_random_question WHERE tst_test_random_question.question_fi = qpl_questions.question_id AND tst_test_random_question.user_fi = %s AND qpl_questions.question_id IN (" . join($this->questions, ",") . ")",
02497                                 $this->ilias->db->quote($ilUser->id . "")
02498                         );
02499                 }
02500                 else
02501                 {
02502                         $query = "SELECT qpl_questions.* FROM qpl_questions, tst_test_question WHERE tst_test_question.question_fi = qpl_questions.question_id AND qpl_questions.question_id IN (" . join($this->questions, ",") . ")";
02503                 }
02504                 $result = $this->ilias->db->query($query);
02505                 $result_array = array();
02506                 while ($row = $result->fetchRow(DB_FETCHMODE_ASSOC))
02507                 {
02508                         $result_array[$row["question_id"]] = $row;
02509                 }
02510                 return $result_array;
02511         }
02512         
02522         function getActiveTestUser($user_id = "") 
02523         {
02524                 global $ilDB;
02525                 global $ilUser;
02526                 
02527                 $db =& $ilDB->db;
02528                 if (!$user_id) {
02529                         $user_id = $ilUser->id;
02530                 }
02531                 $query = sprintf("SELECT * FROM tst_active WHERE user_fi = %s AND test_fi = %s",
02532                         $db->quote($user_id),
02533                         $db->quote($this->test_id)
02534                 );
02535                 
02536                 $result = $db->query($query);
02537                 if ($result->numRows()) {
02538                         return $result->fetchRow(DB_FETCHMODE_OBJECT);
02539                 } else {
02540                         return "";
02541                 }
02542         }
02543         
02554         function _getActiveTestUser($user_id = "", $test_id = "") {
02555                 global $ilDB;
02556                 global $ilUser;
02557                 
02558                 $db =& $ilDB->db;
02559                 if (!$user_id) {
02560                         $user_id = $ilUser->id;
02561                 }
02562                 if (!$test_id)
02563                 {
02564                         return "";
02565                 }
02566                 $query = sprintf("SELECT * FROM tst_active WHERE user_fi = %s AND test_fi = %s",
02567                         $db->quote($user_id),
02568                         $db->quote($test_id)
02569                 );
02570                 
02571                 $result = $db->query($query);
02572                 if ($result->numRows()) {
02573                         return $result->fetchRow(DB_FETCHMODE_OBJECT);
02574                 } else {
02575                         return "";
02576                 }
02577         }
02578         
02591         function setActiveTestUser($lastindex = 1, $postpone = "", $addTries = false) 
02592         {
02593                 global $ilDB;
02594                 global $ilUser;
02595                 
02596                 $db =& $ilDB->db;
02597                 $old_active = $this->getActiveTestUser();
02598                 if ($old_active) {
02599                         $sequence = $old_active->sequence;
02600                         $postponed = $old_active->postponed;
02601                         if ($postpone) {
02602                                 $sequence_array = split(",", $sequence);
02603                                 $postpone_sequence = $sequence_array[$postpone-1];
02604                                 $question_id = $this->questions[$postpone_sequence];
02605                                 unset($sequence_array[$postpone-1]);
02606                                 array_push($sequence_array, $postpone_sequence);
02607                                 $sequence = join(",", $sequence_array);
02608                                 $postponed .= ",$question_id";
02609                                 $postponed = preg_replace("/^,/", "", $postponed);
02610                         }
02611                         $tries = $old_active->tries;
02612                         if ($addTries) {
02613                                 $tries++;
02614                         }
02615                         $query = sprintf("UPDATE tst_active SET lastindex = %s, sequence = %s, postponed = %s, tries = %s WHERE user_fi = %s AND test_fi = %s",
02616                                 $db->quote($lastindex),
02617                                 $db->quote($sequence),
02618                                 $db->quote($postponed),
02619                                 $db->quote($tries),
02620                                 $db->quote($ilUser->id),
02621                                 $db->quote($this->test_id)
02622                         );
02623                 } else {
02624                         $sequence_arr = array_flip($this->questions);
02625                         $sequence = join($sequence_arr, ",");
02626                         $query = sprintf("INSERT INTO tst_active (active_id, user_fi, test_fi, sequence, postponed, lastindex, tries, TIMESTAMP) VALUES (NULL, %s, %s, %s, %s, %s, %s, NULL)",
02627                                 $db->quote($ilUser->id),
02628                                 $db->quote($this->test_id),
02629                                 $db->quote($sequence),
02630                                 $db->quote(""),
02631                                 $db->quote($lastindex),
02632                                 $db->quote(0)
02633                         );
02634                 }
02635                 $db->query($query);
02636         }
02637         
02647         function &getTestResult($user_id)
02648         {
02649                 //              global $ilBench;
02650                 if ($this->isRandomTest())
02651                 {
02652                         $this->loadQuestions($user_id);
02653                 }
02654                 $add_parameter = "?ref_id=$this->ref_id&cmd=run";
02655                 $total_max_points = 0;
02656                 $total_reached_points = 0;
02657                 
02658                 // retrieve the active test dataset for the user containing
02659                 // questions sequence and other information 
02660                 //$active = $this->getActiveTestUser($user_id);
02661                 //$sequence_array = array();
02662                 //if (strlen($active->sequence))
02663                 //{
02664                 //      $sequence_array = split(",", $active->sequence);
02665                 //      sort($sequence_array, SORT_NUMERIC);
02666                 //}
02667                 $key = 1;
02668                 $result_array = array();
02669                 foreach ($this->questions as $value)
02670                 {
02671                         //$value = $this->questions[$seq];
02672 //                      $ilBench->start("getTestResult","instanciate question"); 
02673                         $question =& ilObjTest::_instanciateQuestion($value);
02674 //                      $ilBench->stop("getTestResult","instanciate question"); 
02675                         if (is_object($question))
02676                         {
02677                                 $max_points = $question->getMaximumPoints();
02678                                 $total_max_points += $max_points;
02679                                 $reached_points = $question->getReachedPoints($user_id, $this->getTestId());
02680                                 $total_reached_points += $reached_points;
02681                                 if ($max_points > 0)
02682                                 {
02683                                         $percentvalue = $reached_points / $max_points;
02684                                 }
02685                                 else
02686                                 {
02687                                         $percentvalue = 0;
02688                                 }
02689                                 if (count($question->suggested_solutions) == 1)
02690                                 {
02691                                         $solution_array = $question->getSuggestedSolution(0);
02692                                         $href = ASS_Question::_getInternalLinkHref($solution_array["internal_link"]);
02693                                 }
02694                                 elseif (count($question->suggested_solutions) > 1)
02695                                 {
02696                                         $href = "see_details_for_further_information";
02697                                 }
02698                                 else
02699                                 {
02700                                         $href = "";
02701                                 }
02702                                 $row = array(
02703                                         "nr" => "$key",
02704                                         "title" => "<a href=\"" . $this->getCallingScript() . "$add_parameter&evaluation=" . $question->getId() . "\">" . $question->getTitle() . "</a>",
02705                                         "max" => sprintf("%d", $max_points),
02706                                         "reached" => sprintf("%d", $reached_points),
02707                                         "percent" => sprintf("%2.2f ", ($percentvalue) * 100) . "%",
02708                                         "solution" => $href,
02709                                         "type" => $question->getQuestionType(),
02710                                         "qid" => $question->getId()
02711                                 );
02712                                 array_push($result_array, $row);
02713                                 $key++;
02714                         }
02715                 }
02716                 $result_array["test"]["total_max_points"] = $total_max_points;
02717                 $result_array["test"]["total_reached_points"] = $total_reached_points;
02718                 if ((!$total_reached_points) or (!$total_max_points))
02719                 {
02720                         $percentage = 0.0;
02721                 }
02722                 else
02723                 {
02724                         $percentage = ($total_reached_points / $total_max_points) * 100.0;
02725                 }
02726                 $mark_obj = $this->mark_schema->get_matching_mark($percentage);
02727                 $passed = "";
02728                 if ($mark_obj)
02729                 {
02730                         if ($mark_obj->get_passed())
02731                         {
02732                                 $passed = 1;
02733                         }
02734                         else
02735                         {
02736                                 $passed = 0;
02737                         }
02738                 }
02739                 $result_array["test"]["passed"] = $passed;
02740                 return $result_array;
02741         }
02742         
02752         function &_getTestResult($user_id, $test_obj_id) 
02753         {
02754                 $test = new ilObjTest($test_obj_id, false);
02755                 $test->loadFromDb();
02756                 $result =& $test->getTestResult($user_id);
02757                 return $result;
02758         }
02759 
02772         function _checkCondition($a_exc_id,$a_operator,$a_value)
02773         {
02774                 global $ilias;
02775 
02776                 switch($a_operator)
02777                 {
02778                         case 'passed':
02779                                 $result = ilObjTest::_getTestResult($ilias->account->getId(), $a_exc_id);
02780                                 if ($result["test"]["passed"])
02781                                 {
02782                                         return true;
02783                                 }
02784                                 else
02785                                 {
02786                                         return false;
02787                                 }
02788                                 break;
02789 
02790                         case 'finished':
02791                                 return ilObjTest::_hasFinished($ilias->account->getId(),$a_exc_id);
02792                         case 'not_finished':
02793                                 return !ilObjTest::_hasFinished($ilias->account->getId(),$a_exc_id);
02794                         default:
02795                                 return true;
02796                 }
02797                 return true;
02798         }
02799         
02809         function _hasFinished($a_user_id,$a_test_id)
02810         {
02811                 global $ilDB;
02812 
02813                 $tmp_test =& new ilObjTest($a_test_id,false);
02814 
02815                 $query = "SELECT * FROM tst_active ".
02816                         "WHERE user_fi = '".$a_user_id."' ".
02817                         "AND test_fi = '".$tmp_test->getTestId()."' ".
02818                         "AND tries > '0'";
02819                 $res = $ilDB->query($query);
02820 
02821                 return $res->numRows() ? true : false;
02822         }
02823         
02834         function &_getMark($user_id, $test_obj_id) 
02835         {
02836                 $test = new ilObjTest($test_obj_id, false);
02837                 $test->loadFromDb();
02838                 $result =& $test->getTestResult($user_id);
02839                 if ($result["test"]["total_max_points"] == 0)
02840                 {
02841                         $pct = 0;
02842                 }
02843                         else
02844                 {
02845                         $pct = ($result["test"]["total_reached_points"] / $result["test"]["total_max_points"]) * 100.0;
02846                 }
02847                 $mark = $test->mark_schema->get_matching_mark($pct);
02848                 return $mark;
02849         }
02850 
02856         function assignMetaData(&$a_meta_data)
02857         {
02858                 $this->meta_data =& $a_meta_data;
02859         }
02860 
02866         function &getMetaData()
02867         {
02868                 return $this->meta_data;
02869         }
02870 
02874         function initMeta()
02875         {
02876                 if (!is_object($this->meta_data))
02877                 {
02878                         if ($this->getId())
02879                         {
02880                                 $new_meta =& new ilMetaData($this->getType(), $this->getId());
02881                         }       
02882                         else
02883                         {
02884                                 $new_meta =& new ilMetaData();
02885                         }
02886                         $this->assignMetaData($new_meta);
02887                 }
02888         }
02889 
02898         function evalTotalPersons()
02899         {
02900                 $q = sprintf("SELECT COUNT(*) as total FROM tst_active WHERE test_fi = %s",
02901                         $this->ilias->db->quote($this->getTestId())
02902                 );
02903                 $result = $this->ilias->db->query($q);
02904                 $row = $result->fetchRow(DB_FETCHMODE_OBJECT);
02905                 return $row->total;
02906         }
02907         
02916         function canViewResults()
02917         {
02918                 $result = true;
02919                 if ($this->getTestType() == TYPE_ASSESSMENT)
02920                 {
02921                         if ($this->getReportingDate())
02922                         {
02923                                 preg_match("/(\d{4})(\d{2})(\d{2})(\d{2})(\d{2})(\d{2})/", $this->getReportingDate(), $matches);
02924                                 $epoch_time = mktime($matches[4], $matches[5], $matches[6], $matches[2], $matches[3], $matches[1]);
02925                                 $now = mktime();
02926                                 if ($now < $epoch_time) 
02927                                 {
02928                                         $result = false;
02929                                 }
02930                         }
02931                 }
02932                 return $result;
02933         }
02934 
02943         function evalLoadStatisticalSettings($user_id)
02944         {
02945                 $q = sprintf("SELECT * FROM tst_eval_settings WHERE user_fi = %s",
02946                         $this->ilias->db->quote("$user_id")
02947                 );
02948                 $result = $this->ilias->db->query($q);
02949                 if (!$result->numRows()) 
02950                 {
02951                         $row = array(
02952                                 "qworkedthrough" => "1",
02953                                 "pworkedthrough" => "1",
02954                                 "timeofwork" => "1",
02955                                 "atimeofwork" => "1",
02956                                 "firstvisit" => "1",
02957                                 "lastvisit" => "1",
02958                                 "resultspoints" => "1",
02959                                 "resultsmarks" => "1",
02960                                 "distancemedian" => "1"
02961                         );
02962                 } 
02963                         else 
02964                 {
02965                         $row = $result->fetchRow(DB_FETCHMODE_ASSOC);
02966                         unset($row["eval_settings_id"]);
02967                 }
02968                 return $row;            
02969         }
02970         
02979         function evalSaveStatisticalSettings($settings_array, $user_id)
02980         {
02981                 $q = sprintf("SELECT * FROM tst_eval_settings WHERE user_fi = %s",
02982                         $this->ilias->db->quote("$user_id")
02983                 );
02984                 $result = $this->ilias->db->query($q);
02985                 if ($result->numRows() > 0)
02986                 {
02987                         $row = $result->fetchRow(DB_FETCHMODE_ASSOC);
02988                 }
02989                 $update = $row["eval_settings_id"];
02990                 if (!$update) {
02991                         $q = sprintf("INSERT INTO tst_eval_settings ".
02992                                          "(eval_settings_id, user_fi, qworkedthrough, pworkedthrough, timeofwork, atimeofwork, firstvisit, " .
02993                                          "lastvisit, resultspoints, resultsmarks, distancemedian, TIMESTAMP) VALUES " .
02994                                          "(NULL, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, NULL)",
02995                                 $this->ilias->db->quote("$user_id"),
02996                                 $this->ilias->db->quote(sprintf("%01d", $settings_array["qworkedthrough"])),
02997                                 $this->ilias->db->quote(sprintf("%01d", $settings_array["pworkedthrough"])),
02998                                 $this->ilias->db->quote(sprintf("%01d", $settings_array["timeofwork"])),
02999                                 $this->ilias->db->quote(sprintf("%01d", $settings_array["atimeofwork"])),
03000                                 $this->ilias->db->quote(sprintf("%01d", $settings_array["firstvisit"])),
03001                                 $this->ilias->db->quote(sprintf("%01d", $settings_array["lastvisit"])),
03002                                 $this->ilias->db->quote(sprintf("%01d", $settings_array["resultspoints"])),
03003                                 $this->ilias->db->quote(sprintf("%01d", $settings_array["resultsmarks"])),
03004                                 $this->ilias->db->quote(sprintf("%01d", $settings_array["distancemedian"]))
03005                         );
03006                 } 
03007                         else 
03008                 {
03009                         $q = sprintf("UPDATE tst_eval_settings SET ".
03010                                          "qworkedthrough = %s, pworkedthrough = %s, timeofwork = %s, atimeofwork = %s, firstvisit = %s, " .
03011                                          "lastvisit = %s, resultspoints = %s, resultsmarks = %s, distancemedian = %s " .
03012                                          "WHERE eval_settings_id = %s",
03013                                 $this->ilias->db->quote(sprintf("%01d", $settings_array["qworkedthrough"])),
03014                                 $this->ilias->db->quote(sprintf("%01d", $settings_array["pworkedthrough"])),
03015                                 $this->ilias->db->quote(sprintf("%01d", $settings_array["timeofwork"])),
03016                                 $this->ilias->db->quote(sprintf("%01d", $settings_array["atimeofwork"])),
03017                                 $this->ilias->db->quote(sprintf("%01d", $settings_array["firstvisit"])),
03018                                 $this->ilias->db->quote(sprintf("%01d", $settings_array["lastvisit"])),
03019                                 $this->ilias->db->quote(sprintf("%01d", $settings_array["resultspoints"])),
03020                                 $this->ilias->db->quote(sprintf("%01d", $settings_array["resultsmarks"])),
03021                                 $this->ilias->db->quote(sprintf("%01d", $settings_array["distancemedian"])),
03022                                 $this->ilias->db->quote("$update")
03023                         );
03024                 }
03025                 $result = $this->ilias->db->query($q);
03026         }
03027 
03036         function getCompleteWorkingTime($user_id)
03037         {
03038                 $q = sprintf("SELECT tst_times.* FROM tst_active, tst_times WHERE tst_active.test_fi = %s AND tst_active.active_id = tst_times.active_fi AND tst_active.user_fi = %s",
03039                         $this->ilias->db->quote($this->getTestId()),
03040                         $this->ilias->db->quote($user_id)
03041                 );
03042                 $result = $this->ilias->db->query($q);
03043                 $time = 0;
03044                 while ($row = $result->fetchRow(DB_FETCHMODE_OBJECT)) 
03045                 {
03046                         preg_match("/(\d{4})-(\d{2})-(\d{2}) (\d{2}):(\d{2}):(\d{2})/", $row->started, $matches);
03047                         $epoch_1 = mktime($matches[4], $matches[5], $matches[6], $matches[2], $matches[3], $matches[1]);
03048                         preg_match("/(\d{4})-(\d{2})-(\d{2}) (\d{2}):(\d{2}):(\d{2})/", $row->finished, $matches);
03049                         $epoch_2 = mktime($matches[4], $matches[5], $matches[6], $matches[2], $matches[3], $matches[1]);
03050                         $time += ($epoch_2 - $epoch_1);
03051                 }
03052                 return $time;
03053         }
03054         
03063         function &evalStatistical($user_id)
03064         {
03065 //              global $ilBench;
03066                 
03067                 $test_result =& $this->getTestResult($user_id);
03068                 $q = sprintf("SELECT tst_times.* FROM tst_active, tst_times WHERE tst_active.test_fi = %s AND tst_active.active_id = tst_times.active_fi AND tst_active.user_fi = %s",
03069                         $this->ilias->db->quote($this->getTestId()),
03070                         $this->ilias->db->quote($user_id)
03071                 );
03072                 $result = $this->ilias->db->query($q);
03073                 $times = array();
03074                 $first_visit = "";
03075                 $last_visit = "";
03076                 while ($row = $result->fetchRow(DB_FETCHMODE_OBJECT)) {
03077                         preg_match("/(\d{4})-(\d{2})-(\d{2}) (\d{2}):(\d{2}):(\d{2})/", $row->started, $matches);
03078                         $epoch_1 = mktime($matches[4], $matches[5], $matches[6], $matches[2], $matches[3], $matches[1]);
03079                         if (!$first_visit) {
03080                                 $first_visit = $epoch_1;
03081                         }
03082                         if ($epoch_1 < $first_visit) {
03083                                 $first_visit = $epoch_1;
03084                         }
03085                         preg_match("/(\d{4})-(\d{2})-(\d{2}) (\d{2}):(\d{2}):(\d{2})/", $row->finished, $matches);
03086                         $epoch_2 = mktime($matches[4], $matches[5], $matches[6], $matches[2], $matches[3], $matches[1]);
03087                         if (!$last_visit) {
03088                                 $last_visit = $epoch_2;
03089                         }
03090                         if ($epoch_2 > $last_visit) {
03091                                 $last_visit = $epoch_2;
03092                         }
03093                         $times[$row->active_fi] += ($epoch_2 - $epoch_1);
03094                 }
03095                 $max_time = 0;
03096                 foreach ($times as $key => $value) {
03097                         $max_time += $value;
03098                 }
03099                 if ((!$test_result["test"]["total_reached_points"]) or (!$test_result["test"]["total_max_points"])) {
03100                         $percentage = 0.0;
03101                 } else {
03102                         $percentage = ($test_result["test"]["total_reached_points"] / $test_result["test"]["total_max_points"]) * 100.0;
03103                 }
03104                 $mark_obj = $this->mark_schema->get_matching_mark($percentage);
03105                 $first_date = getdate($first_visit);
03106                 $last_date = getdate($last_visit);
03107                 $qworkedthrough = 0;
03108                 $query_worked_through = sprintf("SELECT DISTINCT(question_fi) FROM tst_solutions WHERE user_fi = %s AND test_fi = %s",
03109                         $this->ilias->db->quote("$user_id"),
03110                         $this->ilias->db->quote($this->getTestId())
03111                 );
03112                 $worked_through_result = $this->ilias->db->query($query_worked_through);
03113                 if (!$worked_through_result->numRows())
03114                 {
03115                         $atimeofwork = 0;
03116                 }
03117                 else
03118                 {
03119                         $atimeofwork = $max_time / $worked_through_result->numRows();
03120                 }
03121                 $result_mark = "";
03122                 $passed = "";
03123                 if ($mark_obj)
03124                 {
03125                         $result_mark = $mark_obj->get_short_name();
03126                         if ($mark_obj->get_passed())
03127                         {
03128                                 $passed = 1;
03129                         }
03130                         else
03131                         {
03132                                 $passed = 0;
03133                         }
03134                 }
03135                 $result_array = array(
03136                         "qworkedthrough" => $worked_through_result->numRows(),
03137                         "qmax" => count($this->questions),
03138                         "pworkedthrough" => ($worked_through_result->numRows()) / count($this->questions),
03139                         "timeofwork" => $max_time,
03140                         "atimeofwork" => $atimeofwork,
03141                         "firstvisit" => $first_date,
03142                         "lastvisit" => $last_date,
03143                         "resultspoints" => $test_result["test"]["total_reached_points"],
03144                         "maxpoints" => $test_result["test"]["total_max_points"],
03145                         "resultsmarks" => $result_mark,
03146                         "passed" => $passed,
03147                         "distancemedian" => "0"
03148                 );
03149                 foreach ($test_result as $key => $value)
03150                 {
03151                         if (preg_match("/\d+/", $key))
03152                         {
03153                                 $result_array[$key] = $value;
03154                         }
03155                 }
03156                 return $result_array;
03157         }
03158 
03168         function &getTotalPointsArray()
03169         {
03170                 $totalpoints_array = array();
03171                 $all_users =& $this->evalTotalPersonsArray();
03172                 foreach ($all_users as $user_id => $user_name)
03173                 {
03174                         $test_result =& $this->getTestResult($user_id);
03175                         array_push($totalpoints_array, $test_result["test"]["total_reached_points"]);
03176                 }
03177                 return $totalpoints_array;
03178         }
03179         
03189         function &getTotalPointsPassedArray()
03190         {
03191                 $totalpoints_array = array();
03192                 $all_users =& $this->evalTotalPersonsArray();
03193                 foreach ($all_users as $user_id => $user_name)
03194                 {
03195                         $test_result =& $this->getTestResult($user_id);
03196                         $reached = $test_result["test"]["total_reached_points"];
03197                         $total = $test_result["test"]["total_max_points"];
03198                         $percentage = $reached/$total;
03199                         $mark = $this->mark_schema->get_matching_mark($percentage*100.0);
03200                         if ($mark)
03201                         {
03202                                 if ($mark->get_passed())
03203                                 {
03204                                         array_push($totalpoints_array, $test_result["test"]["total_reached_points"]);
03205                                 }
03206                         }
03207                 }
03208                 return $totalpoints_array;
03209         }
03210 
03219         function &evalTotalPersonsArray()
03220         {
03221                 $q = sprintf("SELECT tst_active.user_fi, usr_data.firstname, usr_data.lastname, usr_data.title FROM tst_active LEFT JOIN usr_data ON tst_active.user_fi = usr_data.usr_id WHERE tst_active.test_fi = %s ORDER BY usr_data.lastname",
03222                         $this->ilias->db->quote($this->getTestId())
03223                 );
03224                 $result = $this->ilias->db->query($q);
03225                 $persons_array = array();
03226                 while ($row = $result->fetchRow(DB_FETCHMODE_OBJECT))
03227                 {
03228                         if (strlen($row->firstname.$row->lastname.$row->title) == 0)
03229                         {
03230                                 $persons_array[$row->user_fi] = $this->lng->txt("deleted_user");
03231                         }
03232                         else
03233                         {
03234                                 $persons_array[$row->user_fi] = trim("$row->lastname, $row->firstname $row->title");
03235                         }
03236                 }
03237                 return $persons_array;
03238         }
03239         
03248         function evalTotalFinished()
03249         {
03250                 $q = sprintf("SELECT COUNT(*) as total FROM tst_active WHERE test_fi = %s AND tries > 0",
03251                         $this->ilias->db->quote($this->getTestId())
03252                 );
03253                 $result = $this->ilias->db->query($q);
03254                 $row = $result->fetchRow(DB_FETCHMODE_OBJECT);
03255                 return $row->total;
03256         }
03257         
03267         function evalTotalFinishedPassed()
03268         {
03269                 $q = sprintf("SELECT * FROM tst_active WHERE test_fi = %s AND tries > 0",
03270                         $this->ilias->db->quote($this->getTestId())
03271                 );
03272                 $result = $this->ilias->db->query($q);
03273                 $points = array();
03274                 $passed_tests = 0;
03275                 $failed_tests = 0;
03276                 $maximum_points = 0;
03277                 while ($row = $result->fetchRow(DB_FETCHMODE_OBJECT)) 
03278                 {
03279                         $res =& $this->getTestResult($row->user_fi);
03280                         if ((!$res["test"]["total_reached_points"]) or (!$res["test"]["total_max_points"])) 
03281                         {
03282                                 $percentage = 0.0;
03283                         } 
03284                                 else 
03285                         {
03286                                 $percentage = ($res["test"]["total_reached_points"] / $res["test"]["total_max_points"]) * 100.0;
03287                         }
03288                         $mark_obj = $this->mark_schema->get_matching_mark($percentage);
03289                         $maximum_points = $res["test"]["total_max_points"];
03290                         if ($mark_obj)
03291                         {
03292                                 if ($mark_obj->get_passed()) {
03293                                         $passed_tests++;
03294                                         array_push($points, $res["test"]["total_reached_points"]);
03295                                 } 
03296                                         else 
03297                                 {
03298                                         $failed_tests++;
03299                                 }
03300                         }
03301                 }
03302                 $reached_points = 0;
03303                 $counter = 0;
03304                 foreach ($points as $key => $value) 
03305                 {
03306                         $reached_points += $value;
03307                         $counter++;
03308                 }
03309                 if ($counter) 
03310                 {
03311                         $average_points = round($reached_points / $counter);
03312                 } 
03313                         else 
03314                 {
03315                         $average_points = 0;
03316                 }
03317                 return array(
03318                         "total_passed" => $passed_tests,
03319                         "total_failed" => $failed_tests,
03320                         "average_points" => $average_points,
03321                         "maximum_points" => $maximum_points
03322                 );
03323         }
03324         
03333         function evalTotalFinishedAverageTime()
03334         {
03335                 $q = sprintf("SELECT tst_times.* FROM tst_active, tst_times WHERE tst_active.test_fi = %s AND tst_active.tries > 0 AND tst_active.active_id = tst_times.active_fi",
03336                         $this->ilias->db->quote($this->getTestId())
03337                 );
03338                 $result = $this->ilias->db->query($q);
03339                 $times = array();
03340                 while ($row = $result->fetchRow(DB_FETCHMODE_OBJECT)) 
03341                 {
03342                         preg_match("/(\d{4})-(\d{2})-(\d{2}) (\d{2}):(\d{2}):(\d{2})/", $row->started, $matches);
03343                         $epoch_1 = mktime($matches[4], $matches[5], $matches[6], $matches[2], $matches[3], $matches[1]);
03344                         preg_match("/(\d{4})-(\d{2})-(\d{2}) (\d{2}):(\d{2}):(\d{2})/", $row->finished, $matches);
03345                         $epoch_2 = mktime($matches[4], $matches[5], $matches[6], $matches[2], $matches[3], $matches[1]);
03346                         $times[$row->active_fi] += ($epoch_2 - $epoch_1);
03347                 }
03348                 $max_time = 0;
03349                 $counter = 0;
03350                 foreach ($times as $key => $value) 
03351                 {
03352                         $max_time += $value;
03353                         $counter++;
03354                 }
03355                 if ($counter) 
03356                 {
03357                         $average_time = round($max_time / $counter);
03358                 } 
03359                         else 
03360                 {
03361                         $average_time = 0;
03362                 }
03363                 return $average_time;
03364         }
03365         
03374         function &getForbiddenQuestionpools()
03375         {
03376                 global $rbacsystem;
03377                 
03378                 $forbidden_pools = array();
03379                 $query = "SELECT object_data.*, object_data.obj_id, object_reference.ref_id FROM object_data, object_reference WHERE object_data.obj_id = object_reference.obj_id AND object_data.type = 'qpl'";
03380                 $result = $this->ilias->db->query($query);
03381                 while ($row = $result->fetchRow(DB_FETCHMODE_OBJECT))
03382                 {               
03383                         if (!$rbacsystem->checkAccess("write", $row->ref_id) || (!$this->_hasUntrashedReference($row->obj_id)))
03384                         {
03385                                 array_push($forbidden_pools, $row->obj_id);
03386                         }
03387                 }
03388                 return $forbidden_pools;
03389         }
03390 
03399         function &getAvailableQuestionpoolIDs()
03400         {
03401                 global $rbacsystem;
03402                 
03403                 $result_array = array();
03404                 $query = "SELECT object_data.*, object_data.obj_id, object_reference.ref_id FROM object_data, object_reference WHERE object_data.obj_id = object_reference.obj_id AND object_data.type = 'qpl'";
03405                 $result = $this->ilias->db->query($query);
03406                 while ($row = $result->fetchRow(DB_FETCHMODE_OBJECT))
03407                 {               
03408                         if ($rbacsystem->checkAccess("write", $row->ref_id) && ($this->_hasUntrashedReference($row->obj_id)))
03409                         {
03410                                 array_push($result_array, $row->obj_id);
03411                         }
03412                 }
03413                 return $result_array;
03414         }
03415 
03424         function &getAvailableQuestionpools($use_object_id = false)
03425         {
03426                 global $rbacsystem;
03427                 
03428                 $result_array = array();
03429                 $query = "SELECT object_data.*, object_data.obj_id, object_reference.ref_id FROM object_data, object_reference WHERE object_data.obj_id = object_reference.obj_id AND object_data.type = 'qpl' ORDER BY object_data.title";
03430                 $result = $this->ilias->db->query($query);
03431                 while ($row = $result->fetchRow(DB_FETCHMODE_OBJECT))
03432                 {               
03433                         if ($rbacsystem->checkAccess("write", $row->ref_id) && ($this->_hasUntrashedReference($row->obj_id)))
03434                         {
03435                                 if ($use_object_id)
03436                                 {
03437                                         $result_array[$row->obj_id] = $row->title;
03438                                 }
03439                                 else
03440                                 {
03441                                         $result_array[$row->ref_id] = $row->title;
03442                                 }
03443                         }
03444                 }
03445                 return $result_array;
03446         }
03447 
03456         function getEstimatedWorkingTime() 
03457         {
03458                 $time_in_seconds = 0;
03459                 foreach ($this->questions as $question_id) {
03460                         $question =& ilObjTest::_instanciateQuestion($question_id);
03461                         $est_time = $question->getEstimatedWorkingTime();
03462                         $time_in_seconds += $est_time["h"] * 3600 + $est_time["m"] * 60 + $est_time["s"];
03463                 }
03464                 $hours = (int)($time_in_seconds / 3600) ;
03465                 $time_in_seconds = $time_in_seconds - ($hours * 3600);
03466                 $minutes = (int)($time_in_seconds / 60);
03467                 $time_in_seconds = $time_in_seconds - ($minutes * 60);
03468                 $result = array("h" => $hours, "m" => $minutes, "s" => $time_in_seconds);
03469                 return $result;
03470         }
03471         
03484         function randomSelectQuestions($nr_of_questions, $questionpool, $use_obj_id = 0, $qpls = "")
03485         {
03486                 global $rbacsystem;
03487                 // get the questionpool id if a questionpool ref id was entered
03488                 if ($questionpool != 0)
03489                 {
03490                         // retrieve object id
03491                         if (!$use_obj_id)
03492                         {
03493                                 $query = sprintf("SELECT obj_id FROM object_reference WHERE ref_id = %s",
03494                                         $this->ilias->db->quote("$questionpool")
03495                                 );
03496                                 $result = $this->ilias->db->query($query);
03497                                 $row = $result->fetchRow(DB_FETCHMODE_ARRAY);
03498                                 $questionpool = $row[0];
03499                         }
03500                 }
03501                 
03502                 // get all existing questions in the test
03503                 $query = sprintf("SELECT qpl_questions.original_id FROM qpl_questions, tst_test_question WHERE qpl_questions.question_id = tst_test_question.question_fi AND tst_test_question.test_fi = %s",
03504                         $this->ilias->db->quote($this->getTestId() . "")
03505                 );
03506                 $result = $this->ilias->db->query($query);
03507                 $original_ids = array();
03508                 while ($row = $result->fetchRow(DB_FETCHMODE_ARRAY))
03509                 {
03510                         if (strcmp($row[0], "") != 0)
03511                         {
03512                                 array_push($original_ids, $row[0]);
03513                         }
03514                 }
03515                 $original_clause = "";
03516                 if (count($original_ids))
03517                 {
03518                         $original_clause = " AND ISNULL(qpl_questions.original_id) AND qpl_questions.question_id NOT IN (" . join($original_ids, ",") . ")";
03519                 }
03520                 
03521                 // get a list of questionpools which are allowed for the test (only for random selection of questions in test questions editor)
03522                 if (($questionpool == 0) && (!is_array($qpls)))
03523                 {
03524                         $available_pools =& $this->getAvailableQuestionpoolIDs();
03525                         $available = "";
03526                         $constraint_qpls = "";
03527                         if (count($available_pools))
03528                         {
03529                                 $available = " AND qpl_questions.obj_fi IN (" . join($available_pools, ",") . ")";
03530                         }
03531                         else
03532                         {
03533                                 return array();
03534                         }
03535                 }
03536                 
03537                 $result_array = array();
03538                 if ($questionpool == 0)
03539                 {
03540                         if (is_array($qpls))
03541                         {
03542                                 if (count($qpls) > 0)
03543                                 {
03544                                         $qplidx = array();
03545                                         foreach ($qpls as $idx => $arr)
03546                                         {
03547                                                 array_push($qplidx, $arr["qpl"]);
03548                                         }
03549                                         $constraint_qpls = " AND qpl_questions.obj_fi IN (" . join($qplidx, ",") . ")";
03550                                 }
03551                         }
03552                         $query = "SELECT COUNT(question_id) FROM qpl_questions, object_data WHERE ISNULL(qpl_questions.original_id) AND object_data.type = 'qpl' AND object_data.obj_id = qpl_questions.obj_fi$available$constraint_qpls AND qpl_questions.complete = '1'$original_clause";
03553                 }
03554                         else
03555                 {
03556                         $query = sprintf("SELECT COUNT(question_id) FROM qpl_questions WHERE ISNULL(qpl_questions.original_id) AND obj_fi = %s$original_clause",
03557                                 $this->ilias->db->quote("$questionpool")
03558                         );
03559                 }
03560                 $result = $this->ilias->db->query($query);
03561                 $row = $result->fetchRow(DB_FETCHMODE_ARRAY);
03562                 if (($row[0]) <= $nr_of_questions)
03563                 {
03564                         // take all available questions
03565                         if ($questionpool == 0)
03566                         {
03567                                 $query = "SELECT question_id FROM qpl_questions, object_data WHERE ISNULL(qpl_questions.original_id) AND object_data.type = 'qpl' AND object_data.obj_id = qpl_questions.obj_fi$available$constraint_qpls AND qpl_questions.complete = '1'$original_clause";
03568                         }
03569                                 else
03570                         {
03571                                 $query = sprintf("SELECT question_id FROM qpl_questions WHERE ISNULL(qpl_questions.original_id) AND obj_fi = %s AND qpl_questions.complete = '1'$original_clause",
03572                                         $this->ilias->db->quote("$questionpool")
03573                                 );
03574                         }
03575                         $result = $this->ilias->db->query($query);
03576                         while ($row = $result->fetchRow(DB_FETCHMODE_ARRAY))
03577                         {
03578                                 if ((!in_array($row[0], $this->questions)) && (strcmp($row[0], "") != 0))
03579                                 {
03580                                         $result_array[$row[0]] = $row[0];
03581                                 }
03582                         }
03583                 }
03584                         else
03585                 {
03586                         // select a random number out of the maximum number of questions
03587                         mt_srand((double)microtime()*1000000);
03588                         $random_number = mt_rand(0, $row[0] - 1);
03589                         $securitycounter = 500;
03590                         while ((count($result_array) < $nr_of_questions) && ($securitycounter > 0))
03591                         {
03592                                 if ($questionpool == 0)
03593                                 {
03594                                         $query = "SELECT question_id FROM qpl_questions, object_data WHERE ISNULL(qpl_questions.original_id) AND object_data.type = 'qpl' AND object_data.obj_id = qpl_questions.obj_fi$available$constraint_qpls AND qpl_questions.complete = '1'$original_clause LIMIT $random_number, 1";
03595                                 }
03596                                         else
03597                                 {
03598                                         $query = sprintf("SELECT question_id FROM qpl_questions WHERE ISNULL(qpl_questions.original_id) AND obj_fi = %s AND qpl_questions.complete = '1'$original_clause LIMIT $random_number, 1",
03599                                                 $this->ilias->db->quote("$questionpool")
03600                                         );
03601                                 }
03602                                 $result = $this->ilias->db->query($query);
03603                                 $result_row = $result->fetchRow(DB_FETCHMODE_ARRAY);
03604                                 if ((!in_array($result_row[0], $this->questions)) && (strcmp($result_row[0], "") != 0))
03605                                 {
03606                                         $result_array[$result_row[0]] = $result_row[0];
03607                                 }
03608                                 $random_number = mt_rand(0, $row[0] - 1);
03609                                 $securitycounter--;
03610                         }
03611                 }
03612                 return $result_array;
03613         }
03614 
03623         function getImagePath() 
03624         {
03625                 return CLIENT_WEB_DIR . "/assessment/" . $this->getId() . "/images/";
03626         }
03627 
03636         function getImagePathWeb() 
03637         {
03638                 $webdir = ilUtil::removeTrailingPathSeparators(CLIENT_WEB_DIR) . "/assessment/" . $this->getId() . "/images/";
03639                 return str_replace(ilUtil::removeTrailingPathSeparators(ILIAS_ABSOLUTE_PATH), ilUtil::removeTrailingPathSeparators(ILIAS_HTTP_PATH), $webdir);
03640         }
03641 
03652   function &createQuestionGUI($question_type, $question_id = -1) 
03653         {
03654     if ((!$question_type) and ($question_id > 0)) 
03655                 {
03656                         $question_type = $this->getQuestionType($question_id);
03657     }
03658     switch ($question_type) 
03659                 {
03660       case "qt_multiple_choice_sr":
03661         $question =& new ASS_MultipleChoiceGUI();
03662         $question->object->set_response(RESPONSE_SINGLE);
03663         break;
03664       case "qt_multiple_choice_mr":
03665         $question =& new ASS_MultipleChoiceGUI();
03666         $question->object->set_response(RESPONSE_MULTIPLE);
03667         break;
03668       case "qt_cloze":
03669         $question =& new ASS_ClozeTestGUI();
03670         break;
03671       case "qt_matching":
03672         $question =& new ASS_MatchingQuestionGUI();
03673         break;
03674       case "qt_ordering":
03675         $question =& new ASS_OrderingQuestionGUI();
03676         break;
03677       case "qt_imagemap":
03678         $question =& new ASS_ImagemapQuestionGUI();
03679         break;
03680                         case "qt_javaapplet":
03681                                 $question =& new ASS_JavaAppletGUI();
03682                                 break;
03683                         case "qt_text":
03684                                 $question =& new ASS_TextQuestionGUI();
03685                                 break;
03686     }
03687                 if ($question_id > 0)
03688                 {
03689                         $question->object->loadFromDb($question_id);
03690                 }
03691                 return $question;
03692   }
03693 
03703   function &_instanciateQuestion($question_id) 
03704         {
03705                 if (strcmp($question_id, "") != 0)
03706                 {
03707                         $question_type = ASS_Question::_getQuestionType($question_id);
03708 
03709                         switch ($question_type) {
03710                                 case "qt_cloze":
03711                                         $question = new ASS_ClozeTest();
03712                                         break;
03713                                 case "qt_matching":
03714                                         $question = new ASS_MatchingQuestion();
03715                                         break;
03716                                 case "qt_ordering":
03717                                         $question = new ASS_OrderingQuestion();
03718                                         break;
03719                                 case "qt_imagemap":
03720                                         $question = new ASS_ImagemapQuestion();
03721                                         break;
03722                                 case "qt_multiple_choice_sr":
03723                                 case "qt_multiple_choice_mr":
03724                                         $question = new ASS_MultipleChoice();
03725                                         break;
03726                                 case "qt_javaapplet":
03727                                         $question = new ASS_JavaApplet();
03728                                         break;
03729                                 case "qt_text":
03730                                         $question = new ASS_TextQuestion();
03731                                         break;
03732 
03733                                 default:
03734                                         // Return false if question id does not exists or type is unknown
03735                                         return false;
03736                         }
03737 
03738                         $question->loadFromDb($question_id);
03739                         return $question;
03740                 }
03741   }
03742 
03753         function moveQuestions($move_questions, $target_index, $insert_mode)
03754         {
03755                 $this->questions = array_values($this->questions);
03756                 $array_pos = array_search($target_index, $this->questions);
03757                 if ($insert_mode == 0)
03758                 {
03759                         $part1 = array_slice($this->questions, 0, $array_pos);
03760                         $part2 = array_slice($this->questions, $array_pos);
03761                 }
03762                 else if ($insert_mode == 1)
03763                 {
03764                         $part1 = array_slice($this->questions, 0, $array_pos + 1);
03765                         $part2 = array_slice($this->questions, $array_pos + 1);
03766                 }
03767                 foreach ($move_questions as $question_id)
03768                 {
03769                         if (!(array_search($question_id, $part1) === FALSE))
03770                         {
03771                                 unset($part1[array_search($question_id, $part1)]);
03772                         }
03773                         if (!(array_search($question_id, $part2) === FALSE))
03774                         {
03775                                 unset($part2[array_search($question_id, $part2)]);
03776                         }
03777                 }
03778                 $part1 = array_values($part1);
03779                 $part2 = array_values($part2);
03780                 $new_array = array_values(array_merge($part1, $move_questions, $part2));
03781                 $this->questions = array();
03782                 $counter = 1;
03783                 foreach ($new_array as $question_id)
03784                 {
03785                         $this->questions[$counter] = $question_id;
03786                         $counter++;
03787                 }
03788                 $this->saveQuestionsToDb();
03789         }
03790 
03791         
03801         function startingTimeReached()
03802         {
03803                 if ($this->getTestType() == TYPE_ASSESSMENT) 
03804                 {
03805                         if ($this->getStartingTime()) 
03806                         {
03807                                 preg_match("/(\d{4})(\d{2})(\d{2})(\d{2})(\d{2})(\d{2})/", $this->getStartingTime(), $matches);
03808                                 $epoch_time = mktime($matches[4], $matches[5], $matches[6], $matches[2], $matches[3], $matches[1]);
03809                                 $now = mktime();
03810                                 if ($now < $epoch_time) 
03811                                 {
03812                                         // starting time not reached
03813                                         return false;
03814                                 }
03815                         }
03816                 }
03817                 return true;
03818         }               
03819         
03829         function endingTimeReached()
03830         {
03831                 if ($this->getTestType() == TYPE_ASSESSMENT) 
03832                 {
03833                         if ($this->getEndingTime()) 
03834                         {
03835                                 preg_match("/(\d{4})(\d{2})(\d{2})(\d{2})(\d{2})(\d{2})/", $this->getEndingTime(), $matches);
03836                                 $epoch_time = mktime($matches[4], $matches[5], $matches[6], $matches[2], $matches[3], $matches[1]);
03837                                 $now = mktime();
03838                                 if ($now > $epoch_time) 
03839                                 {
03840                                         // ending time reached
03841                                         return true;
03842                                 }
03843                         }
03844                 }
03845                 return false;
03846         }               
03847         
03855         function getQuestionsTable($sortoptions, $filter_text, $sel_filter_type, $startrow = 0, $completeonly = 0, $filter_question_type = "", $filter_questionpool = "")
03856         {
03857                 global $ilUser;
03858                 $where = "";
03859                 if (strlen($filter_text) > 0) {
03860                         switch($sel_filter_type) {
03861                                 case "title":
03862                                         $where = " AND qpl_questions.title LIKE " . $this->ilias->db->quote("%" . $filter_text . "%");
03863                                         break;
03864                                 case "comment":
03865                                         $where = " AND qpl_questions.comment LIKE " . $this->ilias->db->quote("%" . $filter_text . "%");
03866                                         break;
03867                                 case "author":
03868                                         $where = " AND qpl_questions.author LIKE " . $this->ilias->db->quote("%" . $filter_text . "%");
03869                                         break;
03870                         }
03871                 }
03872                 
03873                 if ($filter_question_type && (strcmp($filter_question_type, "all") != 0))
03874                 {
03875                         $where .= " AND qpl_question_type.type_tag = " . $this->ilias->db->quote($filter_question_type);
03876                 }
03877                 
03878                 if ($filter_questionpool && (strcmp($filter_questionpool, "all") != 0))
03879                 {
03880                         $where .= " AND qpl_questions.obj_fi = $filter_questionpool";
03881                 }
03882   
03883     // build sort order for sql query
03884                 $order = "";
03885                 $images = array();
03886     if (count($sortoptions)) {
03887       foreach ($sortoptions as $key => $value) {
03888         switch($key) {
03889           case "title":
03890             $order = " ORDER BY title $value";
03891             $images["title"] = " <img src=\"" . ilUtil::getImagePath(strtolower($value) . "_order.png", true) . "\" alt=\"" . strtolower($value) . "ending order\" />";
03892             break;
03893           case "comment":
03894             $order = " ORDER BY comment $value";
03895             $images["comment"] = " <img src=\"" . ilUtil::getImagePath(strtolower($value) . "_order.png", true) . "\" alt=\"" . strtolower($value) . "ending order\" />";
03896             break;
03897           case "type":
03898             $order = " ORDER BY question_type_id $value";
03899             $images["type"] = " <img src=\"" . ilUtil::getImagePath(strtolower($value) . "_order.png", true) . "\" alt=\"" . strtolower($value) . "ending order\" />";
03900             break;
03901           case "author":
03902             $order = " ORDER BY author $value";
03903             $images["author"] = " <img src=\"" . ilUtil::getImagePath(strtolower($value) . "_order.png", true) . "\" alt=\"" . strtolower($value) . "ending order\" />";
03904             break;
03905           case "created":
03906             $order = " ORDER BY created $value";
03907             $images["created"] = " <img src=\"" . ilUtil::getImagePath(strtolower($value) . "_order.png", true) . "\" alt=\"" . strtolower($value) . "ending order\" />";
03908             break;
03909           case "updated":
03910             $order = " ORDER BY TIMESTAMP14 $value";
03911             $images["updated"] = " <img src=\"" . ilUtil::getImagePath(strtolower($value) . "_order.png", true) . "\" alt=\"" . strtolower($value) . "ending order\" />";
03912             break;
03913           case "qpl":
03914             $order = " ORDER BY obj_fi $value";
03915             $images["qpl"] = " <img src=\"" . ilUtil::getImagePath(strtolower($value) . "_order.png", true) . "\" alt=\"" . strtolower($value) . "ending order\" />";
03916             break;
03917         }
03918       }
03919     }
03920                 $maxentries = $ilUser->prefs["hits_per_page"];
03921                 if ($maxentries < 1)
03922                 {
03923                         $maxentries = 9999;
03924                 }
03925                 $available_pools =& $this->getAvailableQuestionpoolIDs();
03926                 $available = "";
03927                 if (count($available_pools))
03928                 {
03929                         $available = " AND qpl_questions.obj_fi IN (" . join($available_pools, ",") . ")";
03930                 }
03931                 else
03932                 {
03933                         return array();
03934                 }
03935                 if ($completeonly)
03936                 {
03937                         $available .= " AND qpl_questions.complete = " . $this->ilias->db->quote("1");
03938                 }
03939 
03940                 // get all questions in the test
03941                 $query = sprintf("SELECT qpl_questions.original_id, qpl_questions.TIMESTAMP + 0 AS TIMESTAMP14 FROM qpl_questions, tst_test_question WHERE qpl_questions.question_id = tst_test_question.question_fi AND tst_test_question.test_fi = %s",
03942                         $this->ilias->db->quote($this->getTestId() . "")
03943                 );
03944                 $result = $this->ilias->db->query($query);
03945                 $original_ids = array();
03946                 while ($row = $result->fetchRow(DB_FETCHMODE_ARRAY))
03947                 {
03948                         if (strcmp($row[0], "") != 0)
03949                         {
03950                                 array_push($original_ids, $row[0]);
03951                         }
03952                 }
03953                 $original_clause = " ISNULL(qpl_questions.original_id)";
03954                 if (count($original_ids))
03955                 {
03956                         $original_clause = " ISNULL(qpl_questions.original_id) AND qpl_questions.question_id NOT IN (" . join($original_ids, ",") . ")";
03957                 }
03958 
03959                 $query = "SELECT qpl_questions.question_id, qpl_questions.TIMESTAMP + 0 AS TIMESTAMP14 FROM qpl_questions, qpl_question_type WHERE $original_clause$available AND qpl_questions.question_type_fi = qpl_question_type.question_type_id $where$order$limit";
03960     $query_result = $this->ilias->db->query($query);
03961                 $max = $query_result->numRows();
03962                 if ($startrow > $max -1)
03963                 {
03964                         $startrow = $max - ($max % $maxentries);
03965                 }
03966                 else if ($startrow < 0)
03967                 {
03968                         $startrow = 0;
03969                 }
03970                 $limit = " LIMIT $startrow, $maxentries";
03971                 $query = "SELECT qpl_questions.*, qpl_questions.TIMESTAMP + 0 AS TIMESTAMP14, qpl_question_type.type_tag FROM qpl_questions, qpl_question_type WHERE $original_clause $available AND qpl_questions.question_type_fi = qpl_question_type.question_type_id $where$order$limit";
03972     $query_result = $this->ilias->db->query($query);
03973                 $rows = array();
03974                 if ($query_result->numRows())
03975                 {
03976                         while ($row = $query_result->fetchRow(DB_FETCHMODE_ASSOC))
03977                         {
03978                                 array_push($rows, $row);
03979                         }
03980                 }
03981                 $nextrow = $startrow + $maxentries;
03982                 if ($nextrow > $max - 1)
03983                 {
03984                         $nextrow = $startrow;
03985                 }
03986                 $prevrow = $startrow - $maxentries;
03987                 if ($prevrow < 0)
03988                 {
03989                         $prevrow = 0;
03990                 }
03991                 return array(
03992                         "rows" => $rows,
03993                         "images" => $images,
03994                         "startrow" => $startrow,
03995                         "nextrow" => $nextrow,
03996                         "prevrow" => $prevrow,
03997                         "step" => $maxentries,
03998                         "rowcount" => $max
03999                 );
04000         }
04001         
04011         function _getTestType($test_id)
04012         {
04013                 global $ilDB;
04014                 
04015                 $result = "";
04016                 $query = sprintf("SELECT tst_test_type.type_tag FROM tst_test_type, tst_tests WHERE tst_test_type.test_type_id = tst_tests.test_type_fi AND tst_tests.test_id = %s",
04017                         $ilDB->quote($test_id)
04018                 );
04019                 $query_result = $ilDB->query($query);
04020                 if ($query_result->numRows())
04021                 {
04022                         $row = $query_result->fetchRow(DB_FETCHMODE_ASSOC);
04023                         $result = $row["type_tag"];
04024                 }
04025                 return $result;
04026         }
04027         
04036         function &_getQuestiontypes()
04037         {
04038                 global $ilDB;
04039                 
04040                 $questiontypes = array();
04041                 $query = "SELECT * FROM qpl_question_type ORDER BY type_tag";
04042                 $query_result = $ilDB->query($query);
04043                 while ($row = $query_result->fetchRow(DB_FETCHMODE_ASSOC))
04044                 {
04045                         array_push($questiontypes, $row["type_tag"]);
04046                 }
04047                 return $questiontypes;
04048         }
04049         
04058         function to_xml()
04059         {
04060                 $xml_header = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<questestinterop></questestinterop>\n";
04061                 $domxml = domxml_open_mem($xml_header);
04062                 $root = $domxml->document_element();
04063                 // qti assessment
04064                 $qtiAssessment = $domxml->create_element("assessment");
04065                 $qtiAssessment->set_attribute("ident", "il_".IL_INST_ID."_tst_".$this->getTestId());
04066                 $qtiAssessment->set_attribute("title", $this->getTitle());
04067                 
04068                 // add qti comment
04069                 $qtiComment = $domxml->create_element("qticomment");
04070                 $qtiCommentText = $domxml->create_text_node($this->getDescription());
04071                 $qtiComment->append_child($qtiCommentText);
04072                 $qtiAssessment->append_child($qtiComment);
04073 
04074                 // add qti duration
04075                 if ($this->enable_processing_time)
04076                 {
04077                         $qtiDuration = $domxml->create_element("duration");
04078                         preg_match("/(\d+):(\d+):(\d+)/", $this->processing_time, $matches);
04079                         $qtiDurationText = $domxml->create_text_node(sprintf("P0Y0M0DT%dH%dM%dS", $matches[1], $matches[2], $matches[3]));
04080                         $qtiDuration->append_child($qtiDurationText);
04081                         $qtiAssessment->append_child($qtiDuration);
04082                 }
04083 
04084                 // add the rest of the preferences in qtimetadata tags, because there is no correspondent definition in QTI
04085                 $qtiMetadata = $domxml->create_element("qtimetadata");
04086                 // ILIAS version
04087                 $qtiMetadatafield = $domxml->create_element("qtimetadatafield");
04088                 $qtiFieldLabel = $domxml->create_element("fieldlabel");
04089                 $qtiFieldLabelText = $domxml->create_text_node("ILIAS_VERSION");
04090                 $qtiFieldLabel->append_child($qtiFieldLabelText);
04091                 $qtiFieldEntry = $domxml->create_element("fieldentry");
04092                 $qtiFieldEntryText = $domxml->create_text_node($this->ilias->getSetting("ilias_version"));
04093                 $qtiFieldEntry->append_child($qtiFieldEntryText);
04094                 $qtiMetadatafield->append_child($qtiFieldLabel);
04095                 $qtiMetadatafield->append_child($qtiFieldEntry);
04096                 $qtiMetadata->append_child($qtiMetadatafield);
04097                 // test type
04098                 $qtiMetadatafield = $domxml->create_element("qtimetadatafield");
04099                 $qtiFieldLabel = $domxml->create_element("fieldlabel");
04100                 $qtiFieldLabelText = $domxml->create_text_node("test_type");
04101                 $qtiFieldLabel->append_child($qtiFieldLabelText);
04102                 $qtiFieldEntry = $domxml->create_element("fieldentry");
04103                 $qtiFieldEntryText = $domxml->create_text_node(sprintf("%d", $this->getTestType()));
04104                 $qtiFieldEntry->append_child($qtiFieldEntryText);
04105                 $qtiMetadatafield->append_child($qtiFieldLabel);
04106                 $qtiMetadatafield->append_child($qtiFieldEntry);
04107                 $qtiMetadata->append_child($qtiMetadatafield);
04108                 // sequence settings
04109                 $qtiMetadatafield = $domxml->create_element("qtimetadatafield");
04110                 $qtiFieldLabel = $domxml->create_element("fieldlabel");
04111                 $qtiFieldLabelText = $domxml->create_text_node("sequence_settings");
04112                 $qtiFieldLabel->append_child($qtiFieldLabelText);
04113                 $qtiFieldEntry = $domxml->create_element("fieldentry");
04114                 $qtiFieldEntryText = $domxml->create_text_node(sprintf("%d", $this->getSequenceSettings()));
04115                 $qtiFieldEntry->append_child($qtiFieldEntryText);
04116                 $qtiMetadatafield->append_child($qtiFieldLabel);
04117                 $qtiMetadatafield->append_child($qtiFieldEntry);
04118                 $qtiMetadata->append_child($qtiMetadatafield);
04119                 // author
04120                 $qtiMetadatafield = $domxml->create_element("qtimetadatafield");
04121                 $qtiFieldLabel = $domxml->create_element("fieldlabel");
04122                 $qtiFieldLabelText = $domxml->create_text_node("author");
04123                 $qtiFieldLabel->append_child($qtiFieldLabelText);
04124                 $qtiFieldEntry = $domxml->create_element("fieldentry");
04125                 $qtiFieldEntryText = $domxml->create_text_node($this->getAuthor());
04126                 $qtiFieldEntry->append_child($qtiFieldEntryText);
04127                 $qtiMetadatafield->append_child($qtiFieldLabel);
04128                 $qtiMetadatafield->append_child($qtiFieldEntry);
04129                 $qtiMetadata->append_child($qtiMetadatafield);
04130                 // score reporting date
04131                 if ($this->getReportingDate())
04132                 {
04133                         $qtiMetadatafield = $domxml->create_element("qtimetadatafield");
04134                         $qtiFieldLabel = $domxml->create_element("fieldlabel");
04135                         $qtiFieldLabelText = $domxml->create_text_node("reporting_date");
04136                         $qtiFieldLabel->append_child($qtiFieldLabelText);
04137                         $qtiFieldEntry = $domxml->create_element("fieldentry");
04138                         preg_match("/(\d{4})(\d{2})(\d{2})(\d{2})(\d{2})(\d{2})/", $this->reporting_date, $matches);
04139                         $qtiFieldEntryText = $domxml->create_text_node(sprintf("P%dY%dM%dDT%dH%dM%dS", $matches[1], $matches[2], $matches[3], $matches[4], $matches[5], $matches[6]));
04140                         $qtiFieldEntry->append_child($qtiFieldEntryText);
04141                         $qtiMetadatafield->append_child($qtiFieldLabel);
04142                         $qtiMetadatafield->append_child($qtiFieldEntry);
04143                         $qtiMetadata->append_child($qtiMetadatafield);
04144                 }
04145                 // number of tries
04146                 $qtiMetadatafield = $domxml->create_element("qtimetadatafield");
04147                 $qtiFieldLabel = $domxml->create_element("fieldlabel");
04148                 $qtiFieldLabelText = $domxml->create_text_node("nr_of_tries");
04149                 $qtiFieldLabel->append_child($qtiFieldLabelText);
04150                 $qtiFieldEntry = $domxml->create_element("fieldentry");
04151                 $qtiFieldEntryText = $domxml->create_text_node(sprintf("%d", $this->getNrOfTries()));
04152                 $qtiFieldEntry->append_child($qtiFieldEntryText);
04153                 $qtiMetadatafield->append_child($qtiFieldLabel);
04154                 $qtiMetadatafield->append_child($qtiFieldEntry);
04155                 $qtiMetadata->append_child($qtiMetadatafield);
04156                 // random test
04157                 $qtiMetadatafield = $domxml->create_element("qtimetadatafield");
04158                 $qtiFieldLabel = $domxml->create_element("fieldlabel");
04159                 $qtiFieldLabelText = $domxml->create_text_node("random_test");
04160                 $qtiFieldLabel->append_child($qtiFieldLabelText);
04161                 $qtiFieldEntry = $domxml->create_element("fieldentry");
04162                 $qtiFieldEntryText = $domxml->create_text_node(sprintf("%d", $this->isRandomTest()));
04163                 $qtiFieldEntry->append_child($qtiFieldEntryText);
04164                 $qtiMetadatafield->append_child($qtiFieldLabel);
04165                 $qtiMetadatafield->append_child($qtiFieldEntry);
04166                 $qtiMetadata->append_child($qtiMetadatafield);
04167                 // random question count
04168                 $qtiMetadatafield = $domxml->create_element("qtimetadatafield");
04169                 $qtiFieldLabel = $domxml->create_element("fieldlabel");
04170                 $qtiFieldLabelText = $domxml->create_text_node("random_question_count");
04171                 $qtiFieldLabel->append_child($qtiFieldLabelText);
04172                 $qtiFieldEntry = $domxml->create_element("fieldentry");
04173                 $qtiFieldEntryText = $domxml->create_text_node(sprintf("%d", $this->getRandomQuestionCount()));
04174                 $qtiFieldEntry->append_child($qtiFieldEntryText);
04175                 $qtiMetadatafield->append_child($qtiFieldLabel);
04176                 $qtiMetadatafield->append_child($qtiFieldEntry);
04177                 $qtiMetadata->append_child($qtiMetadatafield);
04178                 // starting time
04179                 if ($this->getStartingTime())
04180                 {
04181                         $qtiMetadatafield = $domxml->create_element("qtimetadatafield");
04182                         $qtiFieldLabel = $domxml->create_element("fieldlabel");
04183                         $qtiFieldLabelText = $domxml->create_text_node("starting_time");
04184                         $qtiFieldLabel->append_child($qtiFieldLabelText);
04185                         $qtiFieldEntry = $domxml->create_element("fieldentry");
04186                         preg_match("/(\d{4})(\d{2})(\d{2})(\d{2})(\d{2})(\d{2})/", $this->starting_time, $matches);
04187                         $qtiFieldEntryText = $domxml->create_text_node(sprintf("P%dY%dM%dDT%dH%dM%dS", $matches[1], $matches[2], $matches[3], $matches[4], $matches[5], $matches[6]));
04188                         $qtiFieldEntry->append_child($qtiFieldEntryText);
04189                         $qtiMetadatafield->append_child($qtiFieldLabel);
04190                         $qtiMetadatafield->append_child($qtiFieldEntry);
04191                         $qtiMetadata->append_child($qtiMetadatafield);
04192                 }
04193                 // ending time
04194                 if ($this->getEndingTime())
04195                 {
04196                         $qtiMetadatafield = $domxml->create_element("qtimetadatafield");
04197                         $qtiFieldLabel = $domxml->create_element("fieldlabel");
04198                         $qtiFieldLabelText = $domxml->create_text_node("ending_time");
04199                         $qtiFieldLabel->append_child($qtiFieldLabelText);
04200                         $qtiFieldEntry = $domxml->create_element("fieldentry");
04201                         preg_match("/(\d{4})(\d{2})(\d{2})(\d{2})(\d{2})(\d{2})/", $this->ending_time, $matches);
04202                         $qtiFieldEntryText = $domxml->create_text_node(sprintf("P%dY%dM%dDT%dH%dM%dS", $matches[1], $matches[2], $matches[3], $matches[4], $matches[5], $matches[6]));
04203                         $qtiFieldEntry->append_child($qtiFieldEntryText);
04204                         $qtiMetadatafield->append_child($qtiFieldLabel);
04205                         $qtiMetadatafield->append_child($qtiFieldEntry);
04206                         $qtiMetadata->append_child($qtiMetadatafield);
04207                 }
04208                 foreach ($this->mark_schema->mark_steps as $index => $mark)
04209                 {
04210                         // mark steps
04211                         $qtiMetadatafield = $domxml->create_element("qtimetadatafield");
04212                         $qtiFieldLabel = $domxml->create_element("fieldlabel");
04213                         $qtiFieldLabelText = $domxml->create_text_node("mark_step_$index");
04214                         $qtiFieldLabel->append_child($qtiFieldLabelText);
04215                         $qtiFieldEntry = $domxml->create_element("fieldentry");
04216                         $qtiFieldEntryText = $domxml->create_text_node(sprintf("<short>%s</short><official>%s</official><percentage>%.2f</percentage><passed>%d</passed>", $mark->get_short_name(), $mark->get_official_name(), $mark->get_minimum_level(), $mark->get_passed()));
04217                         $qtiFieldEntry->append_child($qtiFieldEntryText);
04218                         $qtiMetadatafield->append_child($qtiFieldLabel);
04219                         $qtiMetadatafield->append_child($qtiFieldEntry);
04220                         $qtiMetadata->append_child($qtiMetadatafield);
04221                 }
04222                 $qtiAssessment->append_child($qtiMetadata);
04223                 
04224                 // add qti objectives
04225                 $qtiObjectives = $domxml->create_element("objectives");
04226                 $qtiMaterial = $domxml->create_element("material");
04227                 $qtiMaterial->set_attribute("label", "introduction");
04228                 $qtiMatText = $domxml->create_element("mattext");
04229                 $qtiMatTextText = $domxml->create_text_node($this->getIntroduction());
04230                 $qtiMatText->append_child($qtiMatTextText);
04231                 $qtiMaterial->append_child($qtiMatText);
04232                 $qtiObjectives->append_child($qtiMaterial);
04233                 $qtiAssessment->append_child($qtiObjectives);
04234 
04235                 // add qti assessmentcontrol
04236                 $qtiAssessmentcontrol = $domxml->create_element("assessmentcontrol");
04237                 $score_reporting = "No";
04238                 switch ($this->getScoreReporting())
04239                 {
04240                         case "1":
04241                                 $score_reporting = "Yes";
04242                                 break;
04243                 }
04244                 $qtiAssessmentcontrol->set_attribute("solutionswitch", $score_reporting);
04245                 $qtiAssessment->append_child($qtiAssessmentcontrol);
04246                 
04247                 $qtiSection = $domxml->create_element("section");
04248                 $qtiSection->set_attribute("ident", "1");
04249                 $qtiAssessment->append_child($qtiSection);
04250                 
04251                 $root->append_child($qtiAssessment);
04252                 $xml = $domxml->dump_mem(true);
04253                 $domxml->free();
04254                 foreach ($this->questions as $question_id) {
04255                         $question =& ilObjTest::_instanciateQuestion($question_id);
04256                         $qti_question = $question->to_xml(false);
04257                         $qti_question = preg_replace("/<questestinterop>/", "", $qti_question);
04258                         $qti_question = preg_replace("/<\/questestinterop>/", "", $qti_question);
04259                         if (strpos($xml, "</section>") !== false)
04260                         {
04261                                 $xml = str_replace("</section>", "$qti_question</section>", $xml);
04262                         }
04263                         else
04264                         {
04265                                 $xml = str_replace("<section ident=\"1\"/>", "<section ident=\"1\">\n$qti_question</section>", $xml);
04266                         }
04267                 }
04268                 return $xml;
04269         }
04270         
04277         function exportPagesXML(&$a_xml_writer, $a_inst, $a_target_dir, &$expLog)
04278         {
04279                 global $ilBench;
04280                 
04281                 $this->mob_ids = array();
04282                 $this->file_ids = array();
04283 
04284                 $attrs = array();
04285                 $attrs["Type"] = "Test";
04286                 $a_xml_writer->xmlStartTag("ContentObject", $attrs);
04287 
04288                 // MetaData
04289                 $this->exportXMLMetaData($a_xml_writer);
04290 
04291                 // PageObjects
04292                 $expLog->write(date("[y-m-d H:i:s] ")."Start Export Page Objects");
04293                 $ilBench->start("ContentObjectExport", "exportPageObjects");
04294                 $this->exportXMLPageObjects($a_xml_writer, $a_inst, $expLog);
04295                 $ilBench->stop("ContentObjectExport", "exportPageObjects");
04296                 $expLog->write(date("[y-m-d H:i:s] ")."Finished Export Page Objects");
04297 
04298                 // MediaObjects
04299                 $expLog->write(date("[y-m-d H:i:s] ")."Start Export Media Objects");
04300                 $ilBench->start("ContentObjectExport", "exportMediaObjects");
04301                 $this->exportXMLMediaObjects($a_xml_writer, $a_inst, $a_target_dir, $expLog);
04302                 $ilBench->stop("ContentObjectExport", "exportMediaObjects");
04303                 $expLog->write(date("[y-m-d H:i:s] ")."Finished Export Media Objects");
04304 
04305                 // FileItems
04306                 $expLog->write(date("[y-m-d H:i:s] ")."Start Export File Items");
04307                 $ilBench->start("ContentObjectExport", "exportFileItems");
04308                 $this->exportFileItems($a_target_dir, $expLog);
04309                 $ilBench->stop("ContentObjectExport", "exportFileItems");
04310                 $expLog->write(date("[y-m-d H:i:s] ")."Finished Export File Items");
04311 
04312                 $a_xml_writer->xmlEndTag("ContentObject");
04313         }
04314 
04321         function exportXMLMetaData(&$a_xml_writer)
04322         {
04323                 $nested = new ilNestedSetXML();
04324                 $nested->setParameterModifier($this, "modifyExportIdentifier");
04325                 $a_xml_writer->appendXML($nested->export($this->getId(),
04326                         $this->getType()));
04327         }
04328 
04336         function modifyExportIdentifier($a_tag, $a_param, $a_value)
04337         {
04338                 if ($a_tag == "Identifier" && $a_param == "Entry")
04339                 {
04340                         $a_value = ilUtil::insertInstIntoID($a_value);
04341                 }
04342 
04343                 return $a_value;
04344         }
04345 
04346 
04353         function exportXMLPageObjects(&$a_xml_writer, $a_inst, &$expLog)
04354         {
04355                 global $ilBench;
04356 
04357                 include_once "./content/classes/class.ilLMPageObject.php";
04358 
04359                 foreach ($this->questions as $question_id)
04360                 {
04361                         $ilBench->start("ContentObjectExport", "exportPageObject");
04362                         $expLog->write(date("[y-m-d H:i:s] ")."Page Object ".$question_id);
04363 
04364                         $attrs = array();
04365                         $a_xml_writer->xmlStartTag("PageObject", $attrs);
04366 
04367                         
04368                         // export xml to writer object
04369                         $ilBench->start("ContentObjectExport", "exportPageObject_XML");
04370                         $page_object = new ilPageObject("qpl", $question_id);
04371                         $page_object->buildDom();
04372                         $page_object->insertInstIntoIDs($a_inst);
04373                         $mob_ids = $page_object->collectMediaObjects(false);
04374                         $file_ids = $page_object->collectFileItems();
04375                         $xml = $page_object->getXMLFromDom(false, false, false, "", true);
04376                         $xml = str_replace("&","&amp;", $xml);
04377                         $a_xml_writer->appendXML($xml);
04378                         $page_object->freeDom();
04379                         unset ($page_object);
04380                         
04381                         $ilBench->stop("ContentObjectExport", "exportPageObject_XML");
04382 
04383                         // collect media objects
04384                         $ilBench->start("ContentObjectExport", "exportPageObject_CollectMedia");
04385                         //$mob_ids = $page_obj->getMediaObjectIDs();
04386                         foreach($mob_ids as $mob_id)
04387                         {
04388                                 $this->mob_ids[$mob_id] = $mob_id;
04389                         }
04390                         $ilBench->stop("ContentObjectExport", "exportPageObject_CollectMedia");
04391 
04392                         // collect all file items
04393                         $ilBench->start("ContentObjectExport", "exportPageObject_CollectFileItems");
04394                         //$file_ids = $page_obj->getFileItemIds();
04395                         foreach($file_ids as $file_id)
04396                         {
04397                                 $this->file_ids[$file_id] = $file_id;
04398                         }
04399                         $ilBench->stop("ContentObjectExport", "exportPageObject_CollectFileItems");
04400                         
04401                         $a_xml_writer->xmlEndTag("PageObject");
04402                         //unset($page_obj);
04403 
04404                         $ilBench->stop("ContentObjectExport", "exportPageObject");
04405                         
04406 
04407                 }
04408         }
04409 
04416         function exportXMLMediaObjects(&$a_xml_writer, $a_inst, $a_target_dir, &$expLog)
04417         {
04418                 include_once("content/classes/Media/class.ilObjMediaObject.php");
04419 
04420                 foreach ($this->mob_ids as $mob_id)
04421                 {
04422                         $expLog->write(date("[y-m-d H:i:s] ")."Media Object ".$mob_id);
04423                         $media_obj = new ilObjMediaObject($mob_id);
04424                         $media_obj->exportXML($a_xml_writer, $a_inst);
04425                         $media_obj->exportFiles($a_target_dir);
04426                         unset($media_obj);
04427                 }
04428         }
04429 
04434         function exportFileItems($a_target_dir, &$expLog)
04435         {
04436                 include_once("classes/class.ilObjFile.php");
04437 
04438                 foreach ($this->file_ids as $file_id)
04439                 {
04440                         $expLog->write(date("[y-m-d H:i:s] ")."File Item ".$file_id);
04441                         $file_obj = new ilObjFile($file_id, false);
04442                         $file_obj->export($a_target_dir);
04443                         unset($file_obj);
04444                 }
04445         }
04446 
04455         function from_xml($xml_text)
04456         {
04457                 $result = false;
04458                 $this->mark_schema->flush();
04459                 $xml_text = preg_replace("/>\s*?</", "><", $xml_text);
04460                 $domxml = domxml_open_mem($xml_text);
04461                 if (!empty($domxml))
04462                 {
04463                         $root = $domxml->document_element();
04464                         $this->setTitle($root->get_attribute("title"));
04465                         $item = $root;
04466                         $itemnodes = $item->child_nodes();
04467                         foreach ($itemnodes as $index => $node)
04468                         {
04469                                 switch ($node->node_name())
04470                                 {
04471                                         case "qticomment":
04472                                                 $comment = $node->get_content();
04473                                                 if (strpos($comment, "Author=") !== false)
04474                                                 {
04475                                                         $comment = str_replace("Author=", "", $comment);
04476                                                         $this->setAuthor($comment);
04477                                                 }
04478                                                 elseif (strpos($comment, "ILIAS Version=") !== false)
04479                                                 {
04480                                                 }
04481                                                 else
04482                                                 {
04483                                                         $this->setDescription($comment);
04484                                                 }
04485                                                 break;
04486                                         case "duration":
04487                                                 $iso8601period = $node->get_content();
04488                                                 if (preg_match("/P(\d+)Y(\d+)M(\d+)DT(\d+)H(\d+)M(\d+)S/", $iso8601period, $matches))
04489                                                 {
04490                                                         $this->enable_processing_time = 1;
04491                                                         $this->setProcessingTime(sprintf("%02d:%02d:%02d", $matches[4], $matches[5], $matches[6]));
04492                                                 }
04493                                                 break;
04494                                         case "assessmentcontrol":
04495                                                 $score_reporting = $node->get_attribute("solutionswitch");
04496                                                 switch (strtolower($score_reporting))
04497                                                 {
04498                                                         case "1":
04499                                                         case "yes":
04500                                                                 $score_reporting = 1;
04501                                                                 break;
04502                                                         default:
04503                                                                 $score_reporting = 0;
04504                                                                 break;
04505                                                 }
04506                                                 $this->setScoreReporting($score_reporting);
04507                                                 break;
04508                                         case "objectives":
04509                                                 $material = $node->first_child();
04510                                                 if (strcmp($material->get_attribute("label"), "introduction") == 0)
04511                                                 {
04512                                                         $mattext = $material->first_child();
04513                                                         $this->setIntroduction($mattext->get_content());
04514                                                 }
04515                                                 break;
04516                                         case "qtimetadata":
04517                                                 $metadata_fields = $node->child_nodes();
04518                                                 foreach ($metadata_fields as $index => $metadata_field)
04519                                                 {
04520                                                         $fieldlabel = $metadata_field->first_child();
04521                                                         $fieldentry = $fieldlabel->next_sibling();
04522                                                         switch ($fieldlabel->get_content())
04523                                                         {
04524                                                                 case "sequence_settings":
04525                                                                         $this->setSequenceSettings($fieldentry->get_content());
04526                                                                         break;
04527                                                                 case "author":
04528                                                                         $this->setAuthor($fieldentry->get_content());
04529                                                                         break;
04530                                                                 case "test_type":
04531                                                                         $this->setTestType($fieldentry->get_content());
04532                                                                         break;
04533                                                                 case "reporting_date":
04534                                                                         $iso8601period = $fieldentry->get_content();
04535                                                                         if (preg_match("/P(\d+)Y(\d+)M(\d+)DT(\d+)H(\d+)M(\d+)S/", $iso8601period, $matches))
04536                                                                         {
04537                                                                                 $this->setReportingDate(sprintf("%02d%02d%02d%02d%02d%02d", $matches[1], $matches[2], $matches[3], $matches[4], $matches[5], $matches[6]));
04538                                                                         }
04539                                                                         break;
04540                                                                 case "nr_of_tries":
04541                                                                         $this->setNrOfTries($fieldentry->get_content());
04542                                                                         break;
04543                                                                 case "random_test":
04544                                                                         $this->setRandomTest($fieldentry->get_content());
04545                                                                         break;
04546                                                                 case "random_question_count":
04547                                                                         $this->setRandomQuestionCount($fieldentry->get_content());
04548                                                                         break;
04549                                                                 case "starting_time":
04550                                                                         $iso8601period = $fieldentry->get_content();
04551                                                                         if (preg_match("/P(\d+)Y(\d+)M(\d+)DT(\d+)H(\d+)M(\d+)S/", $iso8601period, $matches))
04552                                                                         {
04553                                                                                 $this->setStartingTime(sprintf("%02d%02d%02d%02d%02d%02d", $matches[1], $matches[2], $matches[3], $matches[4], $matches[5], $matches[6]));
04554                                                                         }
04555                                                                         break;
04556                                                                 case "ending_time":
04557                                                                         $iso8601period = $fieldentry->get_content();
04558                                                                         if (preg_match("/P(\d+)Y(\d+)M(\d+)DT(\d+)H(\d+)M(\d+)S/", $iso8601period, $matches))
04559                                                                         {
04560                                                                                 $this->setEndingTime(sprintf("%02d%02d%02d%02d%02d%02d", $matches[1], $matches[2], $matches[3], $matches[4], $matches[5], $matches[6]));
04561                                                                         }
04562                                                                         break;
04563                                                         }
04564                                                         if (preg_match("/mark_step_\d+/", $fieldlabel->get_content()))
04565                                                         {
04566                                                                 $xmlmark = $fieldentry->get_content();
04567                                                                 preg_match("/<short>(.*?)<\/short>/", $xmlmark, $matches);
04568                                                                 $mark_short = $matches[1];
04569                                                                 preg_match("/<official>(.*?)<\/official>/", $xmlmark, $matches);
04570                                                                 $mark_official = $matches[1];
04571                                                                 preg_match("/<percentage>(.*?)<\/percentage>/", $xmlmark, $matches);
04572                                                                 $mark_percentage = $matches[1];
04573                                                                 preg_match("/<passed>(.*?)<\/passed>/", $xmlmark, $matches);
04574                                                                 $mark_passed = $matches[1];
04575                                                                 $this->mark_schema->add_mark_step($mark_short, $mark_official, $mark_percentage, $mark_passed);
04576                                                         }
04577                                                 }
04578                                                 break;
04579                                 }
04580                         }
04581                         $result = true;
04582                 }
04583                 return $result;
04584         }
04585         
04594         function importObject($source, $questionpool_id)
04595         {
04596                 $ilias_version = "";
04597                 $error = 0;
04598                 if (($source == 'none') || (!$source) || $file_info["error"] > UPLOAD_ERR_OK)
04599                 {
04600                         $this->ilias->raiseError("No file selected!",$this->ilias->error_obj->FATAL);
04601                         $error = 1;
04602                 }
04603                 
04604 
04605                 if (!$error)
04606                 {
04607                         // import file as a test
04608                         $fh = fopen($source, "r");
04609                         if (!$fh)
04610                         {
04611                         $this->ilias->raiseError("Error opening the file!",$this->ilias->error_obj->FATAL);
04612                                 $error = 1;
04613                                 return $error;
04614                         }
04615 
04616                         $xml = fread($fh, filesize($source));
04617                         $result = fclose($fh);
04618                         if (!$result)
04619                         {
04620                                 $this->ilias->raiseError("Error closing the file!",$this->ilias->error_obj->FATAL);
04621                                 $error = 1;
04622                                 return $error;
04623                         }
04624 
04625                         $assessment_part = "";
04626                         if (preg_match("/ILIAS Version\=(\d+)\.(\d+)\.?(\d?)/", $xml, $matches))
04627                         {
04628                                 $major_version = $matches[1];
04629                                 unset($matches[0]);
04630                                 $ilias_version = join($matches, ".");
04631                                 if ($major_version == 2)
04632                                 {
04633                                         $this->setTestType(TYPE_SELF_ASSESSMENT);
04634                                         global $lng;
04635                                         $lng->loadLanguageModule("assessment");
04636                                         $this->setTitle($lng->txt("imported_test"));
04637                                         $assessment_part = $this->to_xml();
04638                                         if (preg_match("/(<assessment[^>]*>.*?<\/assessment>)/si", $assessment_part, $matches))
04639                                         {
04640                                                 $assessment_part = $matches[1];
04641                                         }
04642                                 }
04643                         }
04644 
04645                         $found_assessment = preg_match("/(<assessment[^>]*>.*?<\/assessment>)/si", $xml, $matches);
04646                         if ($found_assessment or $assessment_part)
04647                         {
04648                                 if ((!$found_assessment) and ($assessment_part))
04649                                 {
04650                                         $matches[1] = $assessment_part;
04651                                 }
04652                                 // read test properties
04653                                 $succeeded = $this->from_xml($matches[1]);
04654 
04655                                 if (!$succeeded)
04656                                 {
04657 //                      $this->ilias->raiseError("The test properties do not contain proper values!",$this->ilias->error_obj->MESSAGE);
04658                                         $error = 1;
04659                                         return $error;
04660                                 }
04661                         }
04662                         else
04663                         {
04664 //                      $this->ilias->raiseError("No test properties found. Cannot import test!",$this->ilias->error_obj->MESSAGE);
04665                                 $error = 1;
04666                                 return $error;
04667                         }
04668 
04669                         $question_counter = 1;
04670                         
04671                         $this->import_mapping = array();
04672                         
04673                         if (preg_match_all("/(<item[^>]*>.*?<\/item>)/si", $xml, $matches))
04674                         {
04675 
04676                                 foreach ($matches[1] as $index => $item)
04677                                 {
04678                                         // get identifier
04679                                         if (preg_match("/(<item[^>]*>)/is", $item, $start_tag))
04680                                         {
04681                                                 if (preg_match("/(ident=\"([^\"]*)\")/is", $start_tag[1], $ident))
04682                                                 {
04683                                                         $ident = $ident[2];
04684                                                 }
04685                                         }
04686                                         
04687                                         $question = "";
04688                                         $qt = "";
04689                                         if (preg_match("/<fieldlabel>QUESTIONTYPE<\/fieldlabel>\s*<fieldentry>(.*?)<\/fieldentry>/is", $item, $questiontype))
04690                                         {
04691                                                 $qt = $questiontype[1];
04692                                         }
04693                                         if (preg_match("/<qticomment>Questiontype\=(.*?)<\/qticomment>/is", $item, $questiontype))
04694                                         {
04695                                                 $qt = $questiontype[1];
04696                                         }
04697                                         if (strlen($qt))
04698                                         {
04699                                                 switch ($qt)
04700                                                 {
04701                                                         case CLOZE_TEST_IDENTIFIER:
04702                                                                 $question = new ASS_ClozeTest();
04703                                                                 break;
04704                                                         case IMAGEMAP_QUESTION_IDENTIFIER:
04705                                                                 $question = new ASS_ImagemapQuestion();
04706                                                                 break;
04707                                                         case MATCHING_QUESTION_IDENTIFIER:
04708                                                                 $question = new ASS_MatchingQuestion();
04709                                                                 break;
04710                                                         case MULTIPLE_CHOICE_QUESTION_IDENTIFIER:
04711                                                                 $question = new ASS_MultipleChoice();
04712                                                                 break;
04713                                                         case ORDERING_QUESTION_IDENTIFIER:
04714                                                                 $question = new ASS_OrderingQuestion();
04715                                                                 break;
04716                                                         case JAVAAPPLET_QUESTION_IDENTIFIER:
04717                                                                 $question = new ASS_JavaApplet();
04718                                                                 break;
04719                                                         case TEXT_QUESTION_IDENTIFIER:
04720                                                                 $question = new ASS_TextQuestion();
04721                                                                 break;
04722                                                 }
04723                                                 if ($question)
04724                                                 {
04725                                                         $question->setObjId($questionpool_id);
04726                                                         if ($question->from_xml("<questestinterop>$item</questestinterop>"))
04727                                                         {
04728                                                                 $question->saveToDb();
04729                                                                 $q_1_id = $question->getId();
04730                                                                 $question_id = $question->duplicate(true);
04731                                                                 $this->questions[$question_counter++] = $question_id;
04732                                                                 $this->import_mapping[$ident] = array(
04733                                                                         "pool" => $q_1_id, "test" => $question_id);
04734                                                         }
04735                                                         else
04736                                                         {
04737                                                                 $this->ilias->raiseError($this->lng->txt("error_importing_question"), $this->ilias->error_obj->MESSAGE);
04738                                                         }
04739                                                 }
04740                                         }
04741                                 }
04742                         }
04743                 }
04744 //echo "<br>"; var_dump($this->import_mapping);
04745                 $result = array(
04746                         "error" => $error,
04747                         "version" => $ilias_version
04748                 );
04749                 return $result;
04750         }
04751         
04756         function getImportMapping()
04757         {
04758                 if (!is_array($this->import_mapping))
04759                 {
04760                         return array();
04761                 }
04762                 else
04763                 {
04764                         return $this->import_mapping;
04765                 }
04766         }
04767         
04768         function getECTSGrade($reached_points, $max_points)
04769         {
04770                 require_once "./classes/class.ilStatistics.php";
04771                 // calculate the median
04772                 $passed_statistics = new ilStatistics();
04773                 $passed_array =& $this->getTotalPointsPassedArray();
04774                 $passed_statistics->setData($passed_array);
04775                 $ects_percentiles = array
04776                         (
04777                                 "A" => $passed_statistics->quantile($this->ects_grades["A"]),
04778                                 "B" => $passed_statistics->quantile($this->ects_grades["B"]),
04779                                 "C" => $passed_statistics->quantile($this->ects_grades["C"]),
04780                                 "D" => $passed_statistics->quantile($this->ects_grades["D"]),
04781                                 "E" => $passed_statistics->quantile($this->ects_grades["E"])
04782                         );
04783                         if (count($passed_array) && ($reached_points >= $ects_percentiles["A"]))
04784                         {
04785                                 return "A";
04786                         }
04787                         else if (count($passed_array) && ($reached_points >= $ects_percentiles["B"]))
04788                         {
04789                                 return "B";
04790                         }
04791                         else if (count($passed_array) && ($reached_points >= $ects_percentiles["C"]))
04792                         {
04793                                 return "C";
04794                         }
04795                         else if (count($passed_array) && ($reached_points >= $ects_percentiles["D"]))
04796                         {
04797                                 return "D";
04798                         }
04799                         else if (count($passed_array) && ($reached_points >= $ects_percentiles["E"]))
04800                         {
04801                                 return "E";
04802                         }
04803                         else if (strcmp($this->ects_fx, "") != 0)
04804                         {
04805                                 if ($max_points > 0)
04806                                 {
04807                                         $percentage = ($reached_points / $max_points) * 100.0;
04808                                 }
04809                                 else
04810                                 {
04811                                         $percentage = 0.0;
04812                                 }
04813                                 if ($percentage >= $this->ects_fx)
04814                                 {
04815                                         return "FX";
04816                                 }
04817                                 else
04818                                 {
04819                                         return "F";
04820                                 }
04821                         }
04822                         else
04823                         {
04824                                 return "F";
04825                         }
04826         }
04827         
04828         function checkMarks()
04829         {
04830                 return $this->mark_schema->checkMarks();
04831         }
04832         
04836         function updateTitleAndDescription()
04837         {
04838                 $this->initMeta();
04839                 $this->meta_data->updateTitleAndDescription($this->getTitle(), $this->getDescription());
04840         }
04841 
04845         function updateMetaData()
04846         {
04847                 $this->initMeta();
04848                 $this->meta_data->update();
04849                 if ($this->meta_data->section != "General")
04850                 {
04851                         $meta = $this->meta_data->getElement("Title", "General");
04852                         $this->meta_data->setTitle($meta[0]["value"]);
04853                         $meta = $this->meta_data->getElement("Description", "General");
04854                         $this->meta_data->setDescription($meta[0]["value"]);
04855                 }
04856                 else
04857                 {
04858                         $this->setTitle($this->meta_data->getTitle());
04859                         $this->setDescription($this->meta_data->getDescription());
04860                 }
04861                 parent::update();
04862         }
04863         
04872         function &_getAvailableTests($use_object_id = false)
04873         {
04874                 global $rbacsystem;
04875                 global $ilDB;
04876                 
04877                 $result_array = array();
04878                 $query = "SELECT object_data.*, object_data.obj_id, object_reference.ref_id FROM object_data, object_reference WHERE object_data.obj_id = object_reference.obj_id AND object_data.type = 'tst' ORDER BY object_data.title";
04879                 $result = $ilDB->query($query);
04880                 while ($row = $result->fetchRow(DB_FETCHMODE_OBJECT))
04881                 {               
04882                         if ($rbacsystem->checkAccess("write", $row->ref_id) && (ilObject::_hasUntrashedReference($row->obj_id)))
04883                         {
04884                                 if ($use_object_id)
04885                                 {
04886                                         $result_array[$row->obj_id] = $row->title;
04887                                 }
04888                                 else
04889                                 {
04890                                         $result_array[$row->ref_id] = $row->title;
04891                                 }
04892                         }
04893                 }
04894                 return $result_array;
04895         }
04896 
04905         function cloneRandomQuestions($new_id)
04906         {
04907                 if ($new_id > 0)
04908                 {
04909                         $query = sprintf("SELECT * FROM tst_test_random WHERE test_fi = %s",
04910                                 $this->ilias->db->quote($this->getTestId() . "")
04911                         );
04912                         $result = $this->ilias->db->query($query);
04913                         if ($result->numRows())
04914                         {
04915                                 while ($row = $result->fetchRow(DB_FETCHMODE_ASSOC))
04916                                 {
04917                                         $query = sprintf("INSERT INTO tst_test_random (test_random_id, test_fi, questionpool_fi, num_of_q, TIMESTAMP) VALUES (NULL, %s, %s, %s, NULL)",
04918                                                 $this->ilias->db->quote($new_id . ""),
04919                                                 $this->ilias->db->quote($row["questionpool_fi"] . ""),
04920                                                 $this->ilias->db->quote($row["num_of_q"] . "")
04921                                         );
04922                                         $insertresult = $this->ilias->db->query($query);
04923                                 }
04924                         }
04925                 }
04926         }
04927         
04928         
04936         function _clone($obj_id)
04937         {
04938                 $original = new ilObjTest($obj_id, false);
04939                 $original->loadFromDb();
04940                 
04941                 $newObj = new ilObjTest();
04942                 $newObj->setType("tst");
04943     $counter = 2;
04944     while ($newObj->testTitleExists($newObj->getTitle() . " ($counter)")) 
04945                 {
04946       $counter++;
04947     }
04948                 $newObj->setTitle($original->getTitle() . " ($counter)");
04949                 $newObj->setDescription($original->getDescription());
04950                 $newObj->create(true);
04951                 $newObj->createReference();
04952                 $newObj->putInTree($_GET["ref_id"]);
04953                 $newObj->setPermissions($_GET["ref_id"]);
04954 //              $newObj->notify("new",$_GET["ref_id"],$_GET["parent_non_rbac_id"],$_GET["ref_id"],$newObj->getRefId());
04955                 
04956                 $newObj->$author = $original->getAuthor();
04957                 $newObj->introduction = $original->getIntroduction();
04958                 $newObj->mark_schema = $original->mark_schema;
04959                 $newObj->sequence_settings = $original->getSequenceSettings();
04960                 $newObj->score_reporting = $original->getScoreReporting();
04961                 $newObj->reporting_date = $original->getReportingDate();
04962                 $newObj->test_type = $original->getTestType();
04963                 $newObj->nr_of_tries = $original->getNrOfTries();
04964                 $newObj->processing_time = $original->getProcessingTime();
04965                 $newObj->enable_processing_time = $original->getEnableProcessingTime();
04966                 $newObj->starting_time = $original->getStartingTime();
04967                 $newObj->ending_time = $original->getEndingTime();
04968                 $newObj->ects_output = $original->ects_output;
04969                 $newObj->ects_fx = $original->ects_fx;
04970                 $newObj->ects_grades = $original->ects_grades;
04971                 $newObj->random_test = $original->random_test;
04972                 $newObj->random_question_count = $original->random_question_count;
04973                 $newObj->saveToDb();            
04974                 if ($original->isRandomTest())
04975                 {
04976                         $newObj->saveRandomQuestionCount($newObj->random_question_count);
04977                         $original->cloneRandomQuestions($newObj->getTestId());
04978                 }
04979                 else
04980                 {
04981                         // clone the questions
04982                         foreach ($original->questions as $key => $question_id)
04983                         {
04984                                 $question = ilObjTest::_instanciateQuestion($question_id);
04985                                 $newObj->questions[$key] = $question->duplicate();
04986         //                      $question->id = -1;
04987                                 $original_id = ASS_Question::_getOriginalId($question_id);
04988                                 $question = ilObjTest::_instanciateQuestion($newObj->questions[$key]);
04989                                 $question->saveToDb($original_id);
04990                         }
04991                 }
04992                 
04993                 $newObj->saveToDb();            
04994                 // clone meta data
04995                 $meta_data =& new ilMetaData($original->getType(), $original->getId());
04996                 include_once("./classes/class.ilNestedSetXML.php");
04997                 $nested = new ilNestedSetXML();
04998                 $nested->dom = domxml_open_mem($meta_data->nested_obj->dom->dump_mem(0));
04999                 $nodes = $nested->getDomContent("//MetaData/General", "Identifier");
05000                 if (is_array($nodes))
05001                 {
05002                         $nodes[0]["Entry"] = "il__" . $newObj->getType() . "_" . $newObj->getId();
05003                         $nested->updateDomContent("//MetaData/General", "Identifier", 0, $nodes[0]);
05004                 }
05005                 $xml = $nested->dom->dump_mem(0);
05006                 $nested->import($xml, $newObj->getId(), $newObj->getType());
05007         }
05008 
05009         function _getRefIdFromObjId($obj_id)
05010         {
05011                 global $ilDB;
05012                 
05013                 $query = sprintf("SELECT ref_id FROM object_reference WHERE obj_id=%s",
05014                         $ilDB->quote($obj_id)
05015                         
05016                 );
05017                 $result = $ilDB->query($query);
05018                 if ($result->numRows())
05019                 {
05020                         $row = $result->fetchRow(DB_FETCHMODE_ASSOC);
05021                         return $row["ref_id"];
05022                 }
05023                 return 0;
05024         }
05025         
05026         function createRandomSolutionsForAllUsers()
05027         {
05028                 global $ilDB;
05029                 global $ilUser;
05030                 
05031                 $db =& $ilDB->db;
05032                 $sequence_arr = array_flip($this->questions);
05033                 $sequence = join($sequence_arr, ",");
05034                 require_once("./classes/class.ilObjUser.php");
05035                 $logins = ilObjUser::_getAllUserData(array("login"));
05036 
05037                 foreach ($logins as $login)
05038                 {
05039                         $user_id = $login["usr_id"];
05040                         $old_active = $this->getActiveTestUser($user_id);
05041                         if ($old_active) {
05042                                 $query = sprintf("UPDATE tst_active SET lastindex = %s, sequence = %s, postponed = %s, tries = %s WHERE user_fi = %s AND test_fi = %s",
05043                                         $db->quote("0"),
05044                                         $db->quote($sequence),
05045                                         $db->quote(""),
05046                                         $db->quote("1"),
05047                                         $db->quote($user_id),
05048                                         $db->quote($this->getTestId())
05049                                 );
05050                         } else {
05051                                 $sequence_arr = array_flip($this->questions);
05052                                 $sequence = join($sequence_arr, ",");
05053                                 $query = sprintf("INSERT INTO tst_active (active_id, user_fi, test_fi, sequence, postponed, lastindex, tries, TIMESTAMP) VALUES (NULL, %s, %s, %s, %s, %s, %s, NULL)",
05054                                         $db->quote($user_id),
05055                                         $db->quote($this->getTestId()),
05056                                         $db->quote($sequence),
05057                                         $db->quote(""),
05058                                         $db->quote("0"),
05059                                         $db->quote("1")
05060                                 );
05061                         }
05062                         $db->query($query);
05063                 }
05064                 foreach ($this->questions as $question_id) {
05065                         $question =& ilObjTest::_instanciateQuestion($question_id);
05066                         foreach ($logins as $login)
05067                         {
05068                                 $question->createRandomSolution($this->getTestId(), $login["usr_id"]);
05069                         }
05070                 }
05071         }
05072 
05080         function &getEvaluationUsers($user_id)
05081         {
05082                 $users = array();
05083                 $query = sprintf("SELECT tst_eval_users.user_fi, usr_data.firstname, usr_data.lastname FROM tst_eval_users, usr_data WHERE tst_eval_users.test_fi = %s AND tst_eval_users.evaluator_fi = %s AND tst_eval_users.user_fi = usr_data.usr_id",
05084                         $this->ilias->db->quote($this->getTestId() . ""),
05085                         $this->ilias->db->quote($user_id . "")
05086                 );
05087                 $result = $this->ilias->db->query($query);
05088                 if ($result->numRows())
05089                 {
05090                         while ($row = $result->fetchRow(DB_FETCHMODE_ASSOC))
05091                         {
05092                                 $users[$row["user_fi"]] = trim($row["firstname"] ." " . $row["lastname"]);
05093                         }
05094                 }
05095                 return $users;
05096         }
05097 
05105         function &getEvaluationGroups($user_id)
05106         {
05107                 $groups = array();
05108                 $query = sprintf("SELECT group_fi FROM tst_eval_groups WHERE test_fi = %s AND evaluator_fi = %s",
05109                         $this->ilias->db->quote($this->getTestId() . ""),
05110                         $this->ilias->db->quote($user_id . "")
05111                 );
05112                 $result = $this->ilias->db->query($query);
05113                 if ($result->numRows())
05114                 {
05115                         while ($row = $result->fetchRow(DB_FETCHMODE_ASSOC))
05116                         {
05117                                 $groups[$row["group_fi"]] = $row["group_fi"];
05118                         }
05119                 }
05120                 return $groups;
05121         }
05122         
05131         function removeSelectedUser($user_id, $evaluator_id)
05132         {
05133                 $query = sprintf("DELETE FROM tst_eval_users WHERE test_fi = %s AND user_fi = %s AND evaluator_fi = %s",
05134                         $this->ilias->db->quote($this->getTestId() . ""),
05135                         $this->ilias->db->quote($user_id . ""),
05136                         $this->ilias->db->quote($evaluator_id . "")
05137                 );
05138                 $result = $this->ilias->db->query($query);
05139         }
05140 
05149         function addSelectedUser($user_id, $evaluator_id)
05150         {
05151                 $query = sprintf("SELECT user_fi FROM tst_eval_users WHERE test_fi = %s AND evaluator_fi = %s AND user_fi = %s",
05152                         $this->ilias->db->quote($this->getTestId() . ""),
05153                         $this->ilias->db->quote($evaluator_id . ""),
05154                         $this->ilias->db->quote($user_id . "")
05155                 );
05156                 $result = $this->ilias->db->query($query);
05157                 if ($result->numRows() < 1)
05158                 {
05159                         $query = sprintf("INSERT INTO tst_eval_users (eval_users_id, test_fi, evaluator_fi, user_fi, TIMESTAMP) VALUES (NULL, %s, %s, %s, NULL)",
05160                                 $this->ilias->db->quote($this->getTestId() . ""),
05161                                 $this->ilias->db->quote($evaluator_id . ""),
05162                                 $this->ilias->db->quote($user_id . "")
05163                         );
05164                         $result = $this->ilias->db->query($query);
05165                 }
05166         }
05167 
05176         function removeSelectedGroup($group_id, $evaluator_id)
05177         {
05178                 $query = sprintf("DELETE FROM tst_eval_groups WHERE test_fi = %s AND group_fi = %s AND evaluator_fi = %s",
05179                         $this->ilias->db->quote($this->getTestId() . ""),
05180                         $this->ilias->db->quote($group_id . ""),
05181                         $this->ilias->db->quote($evaluator_id . "")
05182                 );
05183                 $result = $this->ilias->db->query($query);
05184         }
05185 
05194         function addSelectedGroup($group_id, $evaluator_id)
05195         {
05196                 $query = sprintf("SELECT group_fi FROM tst_eval_groups WHERE test_fi = %s AND evaluator_fi = %s AND group_fi = %s",
05197                         $this->ilias->db->quote($this->getTestId() . ""),
05198                         $this->ilias->db->quote($evaluator_id . ""),
05199                         $this->ilias->db->quote($group_id . "")
05200                 );
05201                 $result = $this->ilias->db->query($query);
05202                 if ($result->numRows() < 1)
05203                 {
05204                         $query = sprintf("INSERT INTO tst_eval_groups (eval_groups_id, test_fi, evaluator_fi, group_fi, TIMESTAMP) VALUES (NULL, %s, %s, %s, NULL)",
05205                                 $this->ilias->db->quote($this->getTestId() . ""),
05206                                 $this->ilias->db->quote($evaluator_id . ""),
05207                                 $this->ilias->db->quote($group_id . "")
05208                         );
05209                         $result = $this->ilias->db->query($query);
05210                 }
05211         }
05212         
05221         function getQuestionCount()
05222         {
05223                 $num = 0;
05224                 
05225                 if ($this->isRandomTest())
05226                 {
05227                         if ($this->getRandomQuestionCount())
05228                         {
05229                                 $num = $this->getRandomQuestionCount();
05230                         }
05231                                 else
05232                         {
05233                                 $qpls =& $this->getRandomQuestionpools();
05234                                 foreach ($qpls as $data)
05235                                 {
05236                                         $num += $data["count"];
05237                                 }
05238                         }
05239                 }
05240                         else
05241                 {
05242                         $num = count($this->questions);
05243                 }
05244                 return $num;
05245         }
05246         
05255         function _goto($a_target)
05256         {
05257                 global $rbacsystem, $ilErr, $lng;
05258 
05259                 include_once 'classes/class.ilSearch.php';
05260                         
05261                 // Added this additional check (ParentConditions) to avoid calls of objects inside e.g courses.
05262                 // Will be replaced in future releases by ilAccess::checkAccess()
05263                 if ($rbacsystem->checkAccess("read", $a_target) and ilSearch::_checkParentConditions($a_target))
05264                 {
05265                         ilUtil::redirect("assessment/test.php?cmd=run&ref_id=$a_target");
05266                 }
05267                 else
05268                 {
05269                         $ilErr->raiseError($lng->txt("msg_no_perm_read_lm"), $ilErr->FATAL);
05270                 }
05271         }       
05272 
05280         function removeNonRandomTestData()
05281         {
05282                 // delete eventually set questions of a previous non-random test
05283                 $this->removeAllTestEditings();
05284                 $query = sprintf("DELETE FROM tst_test_question WHERE test_fi = %s",
05285                         $this->ilias->db->quote($this->getTestId())
05286                 );
05287                 $result = $this->ilias->db->query($query);
05288                 $this->questions = array();
05289                 $this->saveCompleteStatus();
05290         }
05291         
05299         function removeRandomTestData()
05300         {
05301                 // delete eventually set random question pools of a previous random test
05302                 $this->removeAllTestEditings();
05303                 $query = sprintf("DELETE FROM tst_test_random WHERE test_fi = %s",
05304                         $this->ilias->db->quote($this->getTestId())
05305                 );
05306                 $result = $this->ilias->db->query($query);
05307                 $this->questions = array();
05308                 $this->saveCompleteStatus();
05309         }
05310         
05320         function logAction($logtext = "", $question_id = "")
05321         {
05322                 global $ilUser;
05323 
05324                 $original_id = "";
05325                 if (strcmp($question_id, "") == 0)
05326                 {
05327                         $question_id = "NULL";
05328                 }
05329                 else
05330                 {
05331                         $original_id = ASS_Question::_getOriginalId($question_id);
05332                         $question_id = $this->ilias->db->quote($question_id . "");
05333                 }
05334                 if (strcmp($original_id, "") == 0)
05335                 {
05336                         $original_id = "NULL";
05337                 }
05338                 else
05339                 {
05340                         $original_id = $this->ilias->db->quote($original_id . "");
05341                 }
05342                 $query = sprintf("INSERT INTO ass_log (ass_log_id, user_fi, obj_fi, logtext, question_fi, original_fi, TIMESTAMP) VALUES (NULL, %s, %s, %s, %s, %s, NULL)",
05343                         $this->ilias->db->quote($ilUser->id . ""),
05344                         $this->ilias->db->quote($this->getId() . ""),
05345                         $this->ilias->db->quote($logtext . ""),
05346                         $question_id,
05347                         $original_id
05348                 );
05349                 $result = $this->ilias->db->query($query);
05350         }
05351         
05361         function _getObjectIDFromTestID($test_id)
05362         {
05363                 global $ilDB;
05364                 $object_id = FALSE;
05365                 $query = sprintf("SELECT obj_fi FROM tst_tests WHERE test_id = %s",
05366                         $ilDB->quote($test_id . "")
05367                 );
05368                 $result = $ilDB->query($query);
05369                 if ($result->numRows())
05370                 {
05371                         $row = $result->fetchRow(DB_FETCHMODE_ASSOC);
05372                         $object_id = $row["obj_fi"];
05373                 }
05374                 return $object_id;
05375         }
05376 
05386         function _getTestIDFromObjectID($object_id)
05387         {
05388                 global $ilDB;
05389                 $test_id = FALSE;
05390                 $query = sprintf("SELECT test_id FROM tst_tests WHERE obj_fi = %s",
05391                         $ilDB->quote($object_id . "")
05392                 );
05393                 $result = $ilDB->query($query);
05394                 if ($result->numRows())
05395                 {
05396                         $row = $result->fetchRow(DB_FETCHMODE_ASSOC);
05397                         $test_id = $row["test_id"];
05398                 }
05399                 return $test_id;
05400         }
05401 
05412         function getTextAnswer($user_id, $question_id)
05413         {
05414                 $res = "";
05415                 if (($user_id) && ($question_id))
05416                 {
05417                         $query = sprintf("SELECT value1 FROM tst_solutions WHERE user_fi = %s AND test_fi = %s AND question_fi = %s",
05418                                 $this->ilias->db->quote($user_id . ""),
05419                                 $this->ilias->db->quote($this->getTestId() . ""),
05420                                 $this->ilias->db->quote($question_id . "")
05421                         );
05422                         $result = $this->ilias->db->query($query);
05423                         if ($result->numRows() == 1)
05424                         {
05425                                 $row = $result->fetchRow(DB_FETCHMODE_ASSOC);
05426                                 $res = $row["value1"];
05427                         }
05428                 }
05429                 return $res;
05430         }
05431         
05441         function getQuestiontext($question_id)
05442         {
05443                 $res = "";
05444                 if ($question_id)
05445                 {
05446                         $query = sprintf("SELECT question_text FROM qpl_questions WHERE question_id = %s",
05447                                 $this->ilias->db->quote($question_id . "")
05448                         );
05449                         $result = $this->ilias->db->query($query);
05450                         if ($result->numRows() == 1)
05451                         {
05452                                 $row = $result->fetchRow(DB_FETCHMODE_ASSOC);
05453                                 $res = $row["question_text"];
05454                         }
05455                 }
05456                 return $res;
05457         }
05458         
05471         function &processCSVRow($row, $quoteAll = FALSE, $separator = ";")
05472         {
05473                 $resultarray = array();
05474                 foreach ($row as $rowindex => $entry)
05475                 {
05476                         $surround = FALSE;
05477                         if ($quoteAll)
05478                         {
05479                                 $surround = TRUE;
05480                         }
05481                         if (strpos($entry, "\"") !== FALSE)
05482                         {
05483                                 $entry = str_replace("\"", "\"\"", $entry);
05484                                 $surround = TRUE;
05485                         }
05486                         if (strpos($entry, $separator) !== FALSE)
05487                         {
05488                                 $surround = TRUE;
05489                         }
05490                         // replace all CR LF with LF (for Excel for Windows compatibility
05491                         $entry = str_replace(chr(13).chr(10), chr(10), $entry);
05492                         if ($surround)
05493                         {
05494                                 $resultarray[$rowindex] = utf8_decode("\"" . $entry . "\"");
05495                         }
05496                         else
05497                         {
05498                                 $resultarray[$rowindex] = utf8_decode($entry);
05499                         }
05500                 }
05501                 return $resultarray;
05502         }
05503 
05504 } // END class.ilObjTest
05505 ?>

Generated on Fri Dec 13 2013 09:06:33 for ILIAS Release_3_4_x_branch .rev 46804 by  doxygen 1.7.1