1<?php
2/* Copyright (c) 1998-2013 ILIAS open source, Extended GPL, see docs/LICENSE */
3
4/**
5* Class ilTestEvaluationUserData
6*
7* @author		Helmut Schottmüller <helmut.schottmueller@mac.com>
8* @author		Björn Heyser <bheyser@databay.de>
9* @version		$Id$
10*
11* @defgroup ModulesTest Modules/Test
12* @extends ilObject
13*/
14
15include_once "./Services/Object/classes/class.ilObject.php";
16include_once "./Modules/Test/classes/inc.AssessmentConstants.php";
17
18class ilTestEvaluationUserData
19{
20    /**
21    * User name
22    *
23    * @var string
24    */
25    public $name;
26
27    /**
28    * Login
29    *
30    * @var string
31    */
32    public $login;
33
34    /**
35    * User ID
36    *
37    * @var integer
38    */
39    public $user_id;
40
41    /**
42     * @var bool
43     */
44    protected $submitted;
45
46    /**
47    * Reached points
48    *
49    * @var double
50    */
51    public $reached;
52
53    /**
54    * Maximum available points
55    *
56    * @var double
57    */
58    public $maxpoints;
59
60    /**
61    * Mark
62    *
63    * @var string
64    */
65    public $mark;
66
67    /**
68    * Mark (official description)
69    *
70    * @var string
71    */
72    public $mark_official;
73
74    /**
75    * ECTS Mark
76    *
77    * @var string
78    */
79    public $markECTS;
80
81    /**
82    * Questions worked through
83    *
84    * @var integer
85    */
86    public $questionsWorkedThrough;
87
88    /**
89    * Total number of questions
90    *
91    * @var integer
92    */
93    public $numberOfQuestions;
94
95    /**
96    * Working time
97    *
98    * @var string
99    */
100    public $timeOfWork;
101
102    /**
103    * First visit
104    *
105    * @var string
106    */
107    public $firstVisit;
108
109    /**
110    * Last visit
111    *
112    * @var string
113    */
114    public $lastVisit;
115
116    /**
117    * Is the test passed
118    *
119    * @var boolean
120    */
121    public $passed;
122
123    /**
124    * Test passes
125    *
126    * @var array<int, ilTestEvaluationPassData>
127    */
128    public $passes;
129
130    /**
131    * Questions
132    *
133    * @var array
134    */
135    public $questions;
136
137    /**
138    * Pass Scoring (Last pass = 0, Best pass = 1)
139    *
140    * @var array
141    */
142    private $passScoring;
143
144    public function __sleep()
145    {
146        return array('questions', 'passes', 'passed', 'lastVisit', 'firstVisit', 'timeOfWork', 'numberOfQuestions',
147        'questionsWorkedThrough', 'markECTS', 'mark_official', 'mark', 'maxpoints', 'reached', 'user_id', 'login',
148        'name', 'passScoring');
149    }
150
151    /**
152    * Constructor
153    *
154    * @access	public
155    */
156    public function __construct($passScoring)
157    {
158        $this->passes = array();
159        $this->questions = array();
160        $this->passed = false;
161        $this->passScoring = $passScoring;
162    }
163
164    public function getPassScoring()
165    {
166        return $this->passScoring;
167    }
168
169    public function setPassScoring($passScoring)
170    {
171        $this->passScoring = $passScoring;
172    }
173
174    public function getPassed()
175    {
176        return $this->passed;
177    }
178
179    public function setPassed($a_passed)
180    {
181        $this->passed = ($a_passed ? true : false);
182    }
183
184    public function getName()
185    {
186        return $this->name;
187    }
188
189    public function setName($a_name)
190    {
191        $this->name = $a_name;
192    }
193
194    public function getLogin()
195    {
196        return $this->login;
197    }
198
199    public function setLogin($a_login)
200    {
201        $this->login = $a_login;
202    }
203
204    /**
205     * @return bool
206     */
207    public function isSubmitted()
208    {
209        return $this->submitted;
210    }
211
212    /**
213     * @param bool $submitted
214     */
215    public function setSubmitted($submitted)
216    {
217        $this->submitted = $submitted;
218    }
219
220    public function getReached()
221    {
222        return $this->getReachedPoints($this->getScoredPass());
223    }
224
225    public function setReached($a_reached)
226    {
227        $this->reached = $a_reached;
228    }
229
230    public function getMaxpoints()
231    {
232        return $this->getAvailablePoints($this->getScoredPass());
233    }
234
235    public function setMaxpoints($a_max_points)
236    {
237        $this->maxpoints = $a_max_points;
238    }
239
240    public function getReachedPointsInPercent()
241    {
242        return $this->getMaxPoints() ? $this->getReached() / $this->getMaxPoints() * 100.0 : 0;
243    }
244
245    public function getMark()
246    {
247        return $this->mark;
248    }
249
250    public function setMark($a_mark)
251    {
252        $this->mark = $a_mark;
253    }
254
255    public function getECTSMark()
256    {
257        return $this->markECTS;
258    }
259
260    public function setECTSMark($a_mark_ects)
261    {
262        $this->markECTS = $a_mark_ects;
263    }
264
265    public function getQuestionsWorkedThrough()
266    {
267        $questionpass = $this->getScoredPass();
268        if (!is_object($this->passes[$questionpass])) {
269            $questionpass = 0;
270        }
271        if (is_object($this->passes[$questionpass])) {
272            return $this->passes[$questionpass]->getNrOfAnsweredQuestions();
273        }
274        return 0;
275    }
276
277    public function setQuestionsWorkedThrough($a_nr)
278    {
279        $this->questionsWorkedThrough = $a_nr;
280    }
281
282    public function getNumberOfQuestions()
283    {
284        $questionpass = $this->getScoredPass();
285        if (!is_object($this->passes[$questionpass])) {
286            $questionpass = 0;
287        }
288        if (is_object($this->passes[$questionpass])) {
289            return $this->passes[$questionpass]->getQuestionCount();
290        }
291        return 0;
292        //		return $this->numberOfQuestions;
293    }
294
295    public function setNumberOfQuestions($a_nr)
296    {
297        $this->numberOfQuestions = $a_nr;
298    }
299
300    public function getQuestionsWorkedThroughInPercent()
301    {
302        return $this->getNumberOfQuestions() ? $this->getQuestionsWorkedThrough() / $this->getNumberOfQuestions() * 100.0 : 0;
303    }
304
305    public function getTimeOfWork()
306    {
307        $time = 0;
308        foreach ($this->passes as $pass) {
309            $time += $pass->getWorkingTime();
310        }
311        return $time;
312    }
313
314    public function setTimeOfWork($a_time_of_work)
315    {
316        $this->timeOfWork = $a_time_of_work;
317    }
318
319    public function getFirstVisit()
320    {
321        return $this->firstVisit;
322    }
323
324    public function setFirstVisit($a_time)
325    {
326        $this->firstVisit = $a_time;
327    }
328
329    public function getLastVisit()
330    {
331        return $this->lastVisit;
332    }
333
334    public function setLastVisit($a_time)
335    {
336        $this->lastVisit = $a_time;
337    }
338
339    public function getPasses()
340    {
341        return $this->passes;
342    }
343
344    /**
345     * @param int $pass_nr
346     * @param ilTestEvaluationPassData $pass
347     */
348    public function addPass($pass_nr, $pass)
349    {
350        $this->passes[$pass_nr] = $pass;
351    }
352
353    /**
354     * @param $pass_nr
355     * @return ilTestEvaluationPassData|null
356     */
357    public function getPass($pass_nr)
358    {
359        if (array_key_exists($pass_nr, $this->passes)) {
360            return $this->passes[$pass_nr];
361        } else {
362            return null;
363        }
364    }
365
366    public function getPassCount()
367    {
368        return count($this->passes);
369    }
370
371    public function getScoredPass()
372    {
373        if ($this->getPassScoring() == 1) {
374            return $this->getBestPass();
375        } else {
376            return $this->getLastPass();
377        }
378    }
379
380    public function getBestPass()
381    {
382        $bestpoints = 0;
383        $bestpass = 0;
384
385        $obligationsAnsweredPassExists = $this->doesObligationsAnsweredPassExist();
386
387        foreach ($this->passes as $pass) {
388            $reached = $this->getReachedPointsInPercentForPass($pass->getPass());
389
390            if ($reached >= $bestpoints && ($pass->areObligationsAnswered() || !$obligationsAnsweredPassExists)) {
391                $bestpoints = $reached;
392                $bestpass = $pass->getPass();
393            }
394        }
395
396        return $bestpass;
397    }
398
399    public function getLastPass()
400    {
401        $lastpass = 0;
402        foreach (array_keys($this->passes) as $pass) {
403            if ($pass > $lastpass) {
404                $lastpass = $pass;
405            }
406        }
407        return $lastpass;
408    }
409
410    public function addQuestionTitle($question_id, $question_title)
411    {
412        $this->questionTitles[$question_id] = $question_title;
413    }
414
415    public function getQuestionTitles()
416    {
417        return $this->questionTitles;
418    }
419
420    public function getQuestions($pass = 0)
421    {
422        if (array_key_exists($pass, $this->questions)) {
423            return $this->questions[$pass];
424        } else {
425            return null;
426        }
427    }
428
429    public function addQuestion($original_id, $question_id, $max_points, $sequence = null, $pass = 0)
430    {
431        if (!isset($this->questions[$pass])) {
432            $this->questions[$pass] = array();
433        }
434
435        $this->questions[$pass][] = array(
436            "id" => $question_id, // the so called "aid" from any historical time
437            "o_id" => $original_id, // when the "aid" was valid this was the "id"
438            "points" => $max_points,
439            "sequence" => $sequence
440        );
441    }
442
443    public function getQuestion($index, $pass = 0)
444    {
445        if (array_key_exists($index, $this->questions[$pass])) {
446            return $this->questions[$pass][$index];
447        } else {
448            return null;
449        }
450    }
451
452    public function getQuestionCount($pass = 0)
453    {
454        $count = 0;
455        if (array_key_exists($pass, $this->passes)) {
456            $count = $this->passes[$pass]->getQuestionCount();
457        }
458        return $count;
459    }
460
461    public function getReachedPoints($pass = 0)
462    {
463        $reached = 0;
464        if (array_key_exists($pass, $this->passes)) {
465            $reached = $this->passes[$pass]->getReachedPoints();
466        }
467        $reached = ($reached < 0) ? 0 : $reached;
468        $reached = round($reached, 2);
469        return $reached;
470    }
471
472    public function getAvailablePoints($pass = 0)
473    {
474        $available = 0;
475        if (!is_object($this->passes[$pass])) {
476            $pass = 0;
477        }
478        if (!is_object($this->passes[$pass])) {
479            return 0;
480        }
481        $available = $this->passes[$pass]->getMaxPoints();
482        $available = round($available, 2);
483        return $available;
484    }
485
486    public function getReachedPointsInPercentForPass($pass = 0)
487    {
488        $reached = $this->getReachedPoints($pass);
489        $available = $this->getAvailablePoints($pass);
490        $percent = ($available > 0) ? $reached / $available : 0;
491        return $percent;
492    }
493
494    public function setUserID($a_usr_id)
495    {
496        $this->user_id = $a_usr_id;
497    }
498
499    public function getUserID()
500    {
501        return $this->user_id;
502    }
503
504    public function setMarkOfficial($a_mark_official)
505    {
506        $this->mark_official = $a_mark_official;
507    }
508
509    public function getMarkOfficial()
510    {
511        return $this->mark_official;
512    }
513
514    /**
515     * returns the object of class ilTestEvaluationPassData
516     * that relates to the the scored test pass (best pass / last pass)
517     *
518     * @return ilTestEvaluationPassData $passDataObject
519     */
520    public function getScoredPassObject()
521    {
522        if ($this->getPassScoring() == 1) {
523            return $this->getBestPassObject();
524        } else {
525            return $this->getLastPassObject();
526        }
527    }
528
529    /**
530     * returns the count of hints requested by participant for scored testpass
531     *
532     * @return integer $requestedHintsCount
533     */
534    public function getRequestedHintsCountFromScoredPass()
535    {
536        return $this->getRequestedHintsCount($this->getScoredPass());
537    }
538
539    /**
540     * @return string
541     */
542    public function getExamIdFromScoredPass() : string
543    {
544        $examId = '';
545        $scoredPass = $this->getScoredPass();
546
547        if (isset($this->passes[$scoredPass]) && $this->passes[$scoredPass] instanceof ilTestEvaluationPassData) {
548            $examId = $this->passes[$scoredPass]->getExamId();
549        }
550
551        return $examId;
552    }
553
554    /**
555     * returns the count of hints requested by participant for given testpass
556     *
557     * @param integer $pass
558     * @return integer $requestedHintsCount
559     * @throws ilTestException
560     */
561    public function getRequestedHintsCount($pass)
562    {
563        if (!isset($this->passes[$pass]) || !($this->passes[$pass] instanceof ilTestEvaluationPassData)) {
564            throw new ilTestException("invalid pass index given: $pass");
565        }
566
567        $requestedHintsCount = $this->passes[$pass]->getRequestedHintsCount();
568
569        return $requestedHintsCount;
570    }
571
572    /**
573     * returns the object of class ilTestEvaluationPassData
574     * that relates to the the best test pass
575     *
576     * @return ilTestEvaluationPassData $passDataObject
577     */
578    public function getBestPassObject()
579    {
580        $bestpoints = 0;
581        $bestpassObject = 0;
582
583        $obligationsAnsweredPassExists = $this->doesObligationsAnsweredPassExist();
584
585        foreach ($this->passes as $pass) {
586            $reached = $this->getReachedPointsInPercentForPass($pass->getPass());
587
588            if ($reached >= $bestpoints && ($pass->areObligationsAnswered() || !$obligationsAnsweredPassExists)) {
589                $bestpoints = $reached;
590                $bestpassObject = $pass;
591            }
592        }
593
594        return $bestpassObject;
595    }
596
597    /**
598     * returns the object of class ilTestEvaluationPassData
599     * that relates to the the last test pass
600     *
601     * @return ilTestEvaluationPassData $passDataObject
602     */
603    public function getLastPassObject()
604    {
605        $lastpassIndex = 0;
606
607        foreach (array_keys($this->passes) as $passIndex) {
608            if ($passIndex > $lastpassIndex) {
609                $lastpassIndex = $passIndex;
610            }
611        }
612
613        $lastpassObject = $this->passes[$lastpassIndex];
614
615        return $lastpassObject;
616    }
617
618    /**
619     * returns the fact wether a test pass
620     * with all obligations answered exists or not
621     *
622     * @return boolean
623     */
624    public function doesObligationsAnsweredPassExist()
625    {
626        foreach ($this->passes as $pass) {
627            if ($pass->areObligationsAnswered()) {
628                return true;
629            }
630        }
631
632        return false;
633    }
634
635    /**
636     * returns the fact wether all obligations
637     * in the scored test pass are answered or not
638     *
639     * @return boolean
640     */
641    public function areObligationsAnswered()
642    {
643        return $this->getScoredPassObject()->areObligationsAnswered();
644    }
645} // END ilTestEvaluationUserData
646