1<?php
2/* Copyright (c) 1998-2013 ILIAS open source, Extended GPL, see docs/LICENSE */
3
4require_once 'Modules/TestQuestionPool/classes/class.ilAssQuestionList.php';
5
6/**
7 * Class manages access to the dynamic question set
8 * provided for the current test
9 *
10 * @author		Björn Heyser <bheyser@databay.de>
11 * @version		$Id$
12 *
13 * @package		Modules/Test
14 */
15class ilTestDynamicQuestionSet
16{
17    /**
18     * @var ilDBInterface
19     */
20    private $db = null;
21
22    /**
23     * @var ilLanguage
24     */
25    private $lng = null;
26
27    /**
28     * @var ilPluginAdmin
29     */
30    private $pluginAdmin = null;
31
32    /**
33     * @var ilObjTest
34     */
35    private $testOBJ = null;
36
37    /**
38     * @var ilAssQuestionList
39     */
40    private $completeQuestionList = null;
41
42    /**
43     * @var ilAssQuestionList
44     */
45    private $selectionQuestionList = null;
46
47    /**
48     * @var ilAssQuestionList
49     */
50    private $filteredQuestionList = null;
51
52    /**
53     * @var array
54     */
55    private $actualQuestionSequence = array();
56
57    /**
58     * Constructor
59     *
60     * @param ilObjTest $testOBJ
61     */
62    public function __construct(ilDBInterface $db, ilLanguage $lng, ilPluginAdmin $pluginAdmin, ilObjTest $testOBJ)
63    {
64        $this->db = $db;
65        $this->lng = $lng;
66        $this->pluginAdmin = $pluginAdmin;
67        $this->testOBJ = $testOBJ;
68    }
69
70    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
71
72    public function load(ilObjTestDynamicQuestionSetConfig $dynamicQuestionSetConfig, ilTestDynamicQuestionSetFilterSelection $filterSelection)
73    {
74        $this->completeQuestionList = $this->initCompleteQuestionList(
75            $dynamicQuestionSetConfig,
76            $filterSelection->getAnswerStatusActiveId()
77        );
78
79        $this->selectionQuestionList = $this->initSelectionQuestionList(
80            $dynamicQuestionSetConfig,
81            $filterSelection
82        );
83
84        $this->filteredQuestionList = $this->initFilteredQuestionList(
85            $dynamicQuestionSetConfig,
86            $filterSelection
87        );
88
89        $this->actualQuestionSequence = $this->initActualQuestionSequence(
90            $dynamicQuestionSetConfig,
91            $this->filteredQuestionList
92        );
93    }
94
95    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
96
97    private function initCompleteQuestionList(ilObjTestDynamicQuestionSetConfig $dynamicQuestionSetConfig, $answerStatusActiveId)
98    {
99        $questionList = $this->buildQuestionList(
100            $dynamicQuestionSetConfig->getSourceQuestionPoolId(),
101            $answerStatusActiveId
102        );
103
104        $questionList->load();
105
106        return $questionList;
107    }
108
109    private function initFilteredQuestionList(ilObjTestDynamicQuestionSetConfig $dynamicQuestionSetConfig, ilTestDynamicQuestionSetFilterSelection $filterSelection)
110    {
111        $questionList = $this->buildQuestionList(
112            $dynamicQuestionSetConfig->getSourceQuestionPoolId(),
113            $filterSelection->getAnswerStatusActiveId()
114        );
115
116        if ($dynamicQuestionSetConfig->isAnswerStatusFilterEnabled()) {
117            $questionList->setAnswerStatusFilter($filterSelection->getAnswerStatusSelection());
118        }
119
120        if ($dynamicQuestionSetConfig->isTaxonomyFilterEnabled()) {
121            require_once 'Services/Taxonomy/classes/class.ilObjTaxonomy.php';
122
123            $questionList->setAvailableTaxonomyIds(ilObjTaxonomy::getUsageOfObject(
124                $dynamicQuestionSetConfig->getSourceQuestionPoolId()
125            ));
126
127            foreach ($filterSelection->getTaxonomySelection() as $taxId => $taxNodes) {
128                $questionList->addTaxonomyFilter(
129                    $taxId,
130                    $taxNodes,
131                    $this->testOBJ->getId(),
132                    $this->testOBJ->getType()
133                );
134            }
135        } elseif ($dynamicQuestionSetConfig->getOrderingTaxonomyId()) {
136            $questionList->setAvailableTaxonomyIds(array(
137                $dynamicQuestionSetConfig->getOrderingTaxonomyId()
138            ));
139        }
140
141        $questionList->setForcedQuestionIds($filterSelection->getForcedQuestionIds());
142
143        $questionList->load();
144
145        return $questionList;
146    }
147
148    /**
149     * @param ilObjTestDynamicQuestionSetConfig $dynamicQuestionSetConfig
150     * @param ilTestDynamicQuestionSetFilterSelection $filterSelection
151     * @return ilAssQuestionList
152     */
153    public function initSelectionQuestionList(ilObjTestDynamicQuestionSetConfig $dynamicQuestionSetConfig, ilTestDynamicQuestionSetFilterSelection $filterSelection)
154    {
155        $questionList = $this->buildQuestionList(
156            $dynamicQuestionSetConfig->getSourceQuestionPoolId(),
157            $filterSelection->getAnswerStatusActiveId()
158        );
159
160        if ($dynamicQuestionSetConfig->isTaxonomyFilterEnabled()) {
161            require_once 'Services/Taxonomy/classes/class.ilObjTaxonomy.php';
162
163            $questionList->setAvailableTaxonomyIds(ilObjTaxonomy::getUsageOfObject(
164                $dynamicQuestionSetConfig->getSourceQuestionPoolId()
165            ));
166
167            foreach ($filterSelection->getTaxonomySelection() as $taxId => $taxNodes) {
168                $questionList->addTaxonomyFilter(
169                    $taxId,
170                    $taxNodes,
171                    $this->testOBJ->getId(),
172                    $this->testOBJ->getType()
173                );
174            }
175        }
176
177        $questionList->load();
178
179        return $questionList;
180    }
181
182    private function initActualQuestionSequence(ilObjTestDynamicQuestionSetConfig $dynamicQuestionSetConfig, ilAssQuestionList $questionList)
183    {
184        if ($dynamicQuestionSetConfig->getOrderingTaxonomyId()) {
185            return $this->getQuestionSequenceStructuredByTaxonomy(
186                $questionList,
187                $dynamicQuestionSetConfig->getOrderingTaxonomyId()
188            );
189        }
190
191        return $this->getQuestionSequenceStructuredByUpdateDate($questionList);
192    }
193
194    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
195
196    private function getQuestionSequenceStructuredByTaxonomy(ilAssQuestionList $questionList, $orderingTaxId)
197    {
198        require_once 'Services/Taxonomy/classes/class.ilObjTaxonomy.php';
199        $tax = new ilObjTaxonomy($orderingTaxId);
200
201        require_once 'Modules/Test/classes/class.ilTestTaxonomyTree.php';
202        $tree = new ilTestTaxonomyTree($orderingTaxId);
203        $tree->initOrderedTreeIndex($tax);
204
205        $questionsByNode = array();
206        $nodelessQuestions = array();
207
208        foreach ($questionList->getQuestionDataArray() as $qId => $qData) {
209            if (isset($qData['taxonomies'][$orderingTaxId]) && count($qData['taxonomies'][$orderingTaxId])) {
210                foreach ($qData['taxonomies'][$orderingTaxId] as $nodeId => $itemData) {
211                    $nodeOrderingPath = $tree->getNodeOrderingPathString($itemData['node_id']);
212
213                    if (!isset($questionsByNode[ $nodeOrderingPath ])) {
214                        $questionsByNode[ $nodeOrderingPath ] = array();
215                    }
216
217                    if ($tax->getItemSorting() == ilObjTaxonomy::SORT_MANUAL) {
218                        $questionsByNode[ $nodeOrderingPath ][$itemData['order_nr']] = $qId;
219                    } else {
220                        $questionsByNode[ $nodeOrderingPath ][$qData['title'] . '::' . $qId] = $qId;
221                    }
222                }
223            } else {
224                $nodelessQuestions[$qData['tstamp'] . '::' . $qId] = $qId;
225            }
226        }
227
228        foreach ($questionsByNode as $path => $questions) {
229            if ($tax->getItemSorting() == ilObjTaxonomy::SORT_MANUAL) {
230                ksort($questions, SORT_NUMERIC);
231            } else {
232                ksort($questions, SORT_STRING);
233            }
234
235            $questionsByNode[$path] = array_values($questions);
236        }
237
238        ksort($questionsByNode, SORT_STRING);
239        $sequence = array_values($questionsByNode);
240
241        ksort($nodelessQuestions);
242        $sequence[] = array_values($nodelessQuestions);
243
244        return $sequence;
245    }
246
247    private function getQuestionSequenceStructuredByUpdateDate(ilAssQuestionList $questionList)
248    {
249        $sequence = array();
250
251        foreach ($questionList->getQuestionDataArray() as $qId => $qData) {
252            $sequence[ $qData['tstamp'] . '::' . $qId ] = $qId;
253        }
254
255        ksort($sequence);
256        $sequence = array_values($sequence);
257
258        return array($sequence);
259    }
260
261    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
262
263    public function getActualQuestionSequence()
264    {
265        return $this->actualQuestionSequence;
266    }
267
268    public function questionExists($questionId)
269    {
270        $questionData = $this->completeQuestionList->getQuestionDataArray();
271        return isset($questionData[$questionId]);
272    }
273
274    public function getQuestionData($questionId)
275    {
276        $questionData = $this->completeQuestionList->getQuestionDataArray();
277        return $questionData[$questionId];
278    }
279
280    public function getAllQuestionsData()
281    {
282        return $this->completeQuestionList->getQuestionDataArray();
283    }
284
285    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
286
287    /**
288     * @return ilAssQuestionList
289     */
290    public function getCompleteQuestionList()
291    {
292        return $this->completeQuestionList;
293    }
294
295    /**
296     * @return ilAssQuestionList
297     */
298    public function getSelectionQuestionList()
299    {
300        return $this->selectionQuestionList;
301    }
302
303    /**
304     * @return ilAssQuestionList
305     */
306    public function getFilteredQuestionList()
307    {
308        return $this->filteredQuestionList;
309    }
310
311    /**
312     * @param integer $sourceQuestionPoolId
313     * @param string $answerStatusActiveId
314     * @return ilAssQuestionList
315     */
316    private function buildQuestionList($sourceQuestionPoolId, $answerStatusActiveId)
317    {
318        $questionList = new ilAssQuestionList($this->db, $this->lng, $this->pluginAdmin);
319        $questionList->setParentObjId($sourceQuestionPoolId);
320        $questionList->setAnswerStatusActiveId($answerStatusActiveId);
321        return $questionList;
322    }
323}
324