1<?php
2
3/* Copyright (c) 1998-2013 ILIAS open source, Extended GPL, see docs/LICENSE */
4
5require_once 'Modules/Test/classes/class.ilTestParticipant.php';
6
7/**
8 * Class ilTestParticipantList
9 *
10 * @author    Björn Heyser <info@bjoernheyser.de>
11 * @version    $Id$
12 *
13 * @package    Modules/Test
14 */
15class ilTestParticipantList implements Iterator
16{
17    /**
18     * @var ilTestParticipant[]
19     */
20    protected $participants = array();
21
22    /**
23     * @var ilObjTest
24     */
25    protected $testObj;
26
27    /**
28     * @param ilObjTest $testObj
29     */
30    public function __construct(ilObjTest $testObj)
31    {
32        $this->testObj = $testObj;
33    }
34
35    /**
36     * @return ilObjTest
37     */
38    public function getTestObj()
39    {
40        return $this->testObj;
41    }
42
43    /**
44     * @param ilObjTest $testObj
45     */
46    public function setTestObj($testObj)
47    {
48        $this->testObj = $testObj;
49    }
50
51    /**
52     * @param ilTestParticipant $participant
53     */
54    public function addParticipant(ilTestParticipant $participant)
55    {
56        $this->participants[] = $participant;
57    }
58
59    public function getParticipantByUsrId($usrId)
60    {
61        foreach ($this as $participant) {
62            if ($participant->getUsrId() != $usrId) {
63                continue;
64            }
65
66            return $participant;
67        }
68    }
69
70    /**
71     * @param $activeId
72     * @return ilTestParticipant
73     */
74    public function getParticipantByActiveId($activeId)
75    {
76        foreach ($this as $participant) {
77            if ($participant->getActiveId() != $activeId) {
78                continue;
79            }
80
81            return $participant;
82        }
83    }
84
85    /**
86     * @return bool
87     */
88    public function hasUnfinishedPasses()
89    {
90        foreach ($this as $participant) {
91            if ($participant->hasUnfinishedPasses()) {
92                return true;
93            }
94        }
95
96        return false;
97    }
98
99    /**
100     * @return bool
101     */
102    public function hasScorings()
103    {
104        foreach ($this as $participant) {
105            if ($participant->getScoring() instanceof ilTestParticipantScoring) {
106                return true;
107            }
108        }
109
110        return false;
111    }
112
113    public function getAllUserIds()
114    {
115        $usrIds = array();
116
117        foreach ($this as $participant) {
118            $usrIds[] = $participant->getUsrId();
119        }
120
121        return $usrIds;
122    }
123
124    public function getAllActiveIds()
125    {
126        $activeIds = array();
127
128        foreach ($this as $participant) {
129            $activeIds[] = $participant->getActiveId();
130        }
131
132        return $activeIds;
133    }
134
135    public function isActiveIdInList($activeId)
136    {
137        foreach ($this as $participant) {
138            if ($participant->getActiveId() == $activeId) {
139                return true;
140            }
141        }
142
143        return false;
144    }
145
146    public function getAccessFilteredList(callable $userAccessFilter)
147    {
148        $usrIds = call_user_func_array($userAccessFilter, [$this->getAllUserIds()]);
149
150        $accessFilteredList = new self($this->getTestObj());
151
152        foreach ($this as $participant) {
153            if (in_array($participant->getUsrId(), $usrIds)) {
154                $participant = clone $participant;
155                $accessFilteredList->addParticipant($participant);
156            }
157        }
158
159        return $accessFilteredList;
160    }
161
162    public function current()
163    {
164        return current($this->participants);
165    }
166    public function next()
167    {
168        return next($this->participants);
169    }
170    public function key()
171    {
172        return key($this->participants);
173    }
174    public function valid()
175    {
176        return key($this->participants) !== null;
177    }
178    public function rewind()
179    {
180        return reset($this->participants);
181    }
182
183    /**
184     * @param array[] $dbRows
185     */
186    public function initializeFromDbRows($dbRows)
187    {
188        foreach ($dbRows as $rowKey => $rowData) {
189            $participant = new ilTestParticipant();
190
191            if ((int) $rowData['active_id']) {
192                $participant->setActiveId((int) $rowData['active_id']);
193            }
194
195            $participant->setUsrId((int) $rowData['usr_id']);
196
197            $participant->setLogin($rowData['login']);
198            $participant->setLastname($rowData['lastname']);
199            $participant->setFirstname($rowData['firstname']);
200            $participant->setMatriculation($rowData['matriculation']);
201
202            $participant->setActiveStatus((bool) $rowData['active']);
203
204            if (isset($rowData['clientip'])) {
205                $participant->setClientIp($rowData['clientip']);
206            }
207
208            $participant->setFinishedTries((int) $rowData['tries']);
209            $participant->setTestFinished((bool) $rowData['test_finished']);
210            $participant->setUnfinishedPasses((bool) $rowData['unfinished_passes']);
211
212            $this->addParticipant($participant);
213        }
214    }
215
216    /**
217     * @return ilTestParticipantList
218     */
219    public function getScoredParticipantList()
220    {
221        require_once 'Modules/Test/classes/class.ilTestParticipantScoring.php';
222
223        $scoredParticipantList = new self($this->getTestObj());
224
225        global $DIC; /* @var ILIAS\DI\Container $DIC */
226
227        $res = $DIC->database()->query($this->buildScoringsQuery());
228
229        while ($row = $DIC->database()->fetchAssoc($res)) {
230            $scoring = new ilTestParticipantScoring();
231
232            $scoring->setActiveId((int) $row['active_fi']);
233            $scoring->setScoredPass((int) $row['pass']);
234
235            $scoring->setAnsweredQuestions((int) $row['answeredquestions']);
236            $scoring->setTotalQuestions((int) $row['questioncount']);
237
238            $scoring->setReachedPoints((float) $row['reached_points']);
239            $scoring->setMaxPoints((float) $row['max_points']);
240
241            $scoring->setPassed((bool) $row['passed']);
242            $scoring->setFinalMark((string) $row['mark_official']);
243
244            $this->getParticipantByActiveId($row['active_fi'])->setScoring($scoring);
245
246            $scoredParticipantList->addParticipant(
247                $this->getParticipantByActiveId($row['active_fi'])
248            );
249        }
250
251        return $scoredParticipantList;
252    }
253
254    public function buildScoringsQuery()
255    {
256        global $DIC; /* @var ILIAS\DI\Container $DIC */
257
258        $IN_activeIds = $DIC->database()->in(
259            'tres.active_fi',
260            $this->getAllActiveIds(),
261            false,
262            'integer'
263        );
264
265        if (false && !$this->getTestObj()->isDynamicTest()) { // BH: keep for the moment
266            $closedScoringsOnly = "
267				INNER JOIN tst_active tact
268				ON tact.active_id = tres.active_fi
269				AND tact.last_finished_pass = tact.last_started_pass
270			";
271        } else {
272            $closedScoringsOnly = '';
273        }
274
275        $query = "
276			SELECT * FROM tst_result_cache tres
277
278			INNER JOIN tst_pass_result pres
279			ON pres.active_fi = tres.active_fi
280			AND pres.pass = tres.pass
281
282			$closedScoringsOnly
283
284			WHERE $IN_activeIds
285		";
286
287        return $query;
288    }
289
290    public function getParticipantsTableRows()
291    {
292        $rows = array();
293
294        foreach ($this as $participant) {
295            $row = array(
296                'usr_id' => $participant->getUsrId(),
297                'active_id' => $participant->getActiveId(),
298                'login' => $participant->getLogin(),
299                'clientip' => $participant->getClientIp(),
300                'firstname' => $participant->getFirstname(),
301                'lastname' => $participant->getLastname(),
302                'name' => $this->buildFullname($participant),
303                'started' => ($participant->getActiveId() > 0) ? 1 : 0,
304                'unfinished' => $participant->hasUnfinishedPasses() ? 1 : 0,
305                'finished' => $participant->isTestFinished() ? 1 : 0,
306                'access' => $this->lookupLastAccess($participant->getActiveId()),
307                'tries' => $this->lookupNrOfTries($participant->getActiveId())
308            );
309
310            $rows[] = $row;
311        }
312
313        return $rows;
314    }
315
316    public function getScoringsTableRows()
317    {
318        $rows = array();
319
320        foreach ($this as $participant) {
321            if (!$participant->hasScoring()) {
322                continue;
323            }
324
325            $row = array(
326                'usr_id' => $participant->getUsrId(),
327                'active_id' => $participant->getActiveId(),
328                'login' => $participant->getLogin(),
329                'firstname' => $participant->getFirstname(),
330                'lastname' => $participant->getLastname(),
331                'name' => $this->buildFullname($participant)
332            );
333
334            if ($participant->getScoring()) {
335                $row['scored_pass'] = $participant->getScoring()->getScoredPass();
336                $row['answered_questions'] = $participant->getScoring()->getAnsweredQuestions();
337                $row['total_questions'] = $participant->getScoring()->getTotalQuestions();
338                $row['reached_points'] = $participant->getScoring()->getReachedPoints();
339                $row['max_points'] = $participant->getScoring()->getMaxPoints();
340                $row['percent_result'] = $participant->getScoring()->getPercentResult();
341                $row['passed_status'] = $participant->getScoring()->isPassed();
342                $row['final_mark'] = $participant->getScoring()->getFinalMark();
343
344                $row['pass_finished'] = ilObjTest::lookupLastTestPassAccess(
345                    $participant->getActiveId(),
346                    $participant->getScoring()->getScoredPass()
347                );
348            }
349
350            $rows[] = $row;
351        }
352
353        return $rows;
354    }
355
356    /**
357     * @param integer $activeId
358     * @return int|null
359     */
360    public function lookupNrOfTries($activeId)
361    {
362        $maxPassIndex = ilObjTest::_getMaxPass($activeId);
363
364        if ($maxPassIndex !== null) {
365            $nrOfTries = $maxPassIndex + 1;
366            return $nrOfTries;
367        }
368
369        return null;
370    }
371
372    /**
373     * @param integer $activeId
374     * @return string
375     */
376    protected function lookupLastAccess($activeId)
377    {
378        if (!$activeId) {
379            return '';
380        }
381
382        return $this->getTestObj()->_getLastAccess($activeId);
383    }
384
385    /**
386     * @param ilTestParticipant $participant
387     * @return string
388     */
389    protected function buildFullname(ilTestParticipant $participant)
390    {
391        if ($this->getTestObj()->getFixedParticipants() && !$participant->getActiveId()) {
392            return $this->buildInviteeFullname($participant);
393        }
394
395        return $this->buildParticipantsFullname($participant);
396    }
397
398    /**
399     * @param ilTestParticipant $participant
400     * @return string
401     */
402    protected function buildInviteeFullname(ilTestParticipant $participant)
403    {
404        global $DIC; /* @var ILIAS\DI\Container $DIC */
405
406        if (strlen($participant->getFirstname() . $participant->getLastname()) == 0) {
407            return $DIC->language()->txt("deleted_user");
408        }
409
410        if ($this->getTestObj()->getAnonymity()) {
411            return $DIC->language()->txt('anonymous');
412        }
413
414        return trim($participant->getLastname() . ", " . $participant->getFirstname());
415    }
416
417    /**
418     * @param ilTestParticipant $participant
419     * @return string
420     */
421    protected function buildParticipantsFullname(ilTestParticipant $participant)
422    {
423        require_once 'Modules/Test/classes/class.ilObjTestAccess.php';
424        return ilObjTestAccess::_getParticipantData($participant->getActiveId());
425    }
426}
427