1<?php
2/* Copyright (c) 1998-2013 ILIAS open source, Extended GPL, see docs/LICENSE */
3
4require_once 'Modules/Test/classes/class.ilTestRandomQuestionSetStagingPoolQuestionList.php';
5require_once 'Modules/TestQuestionPool/classes/class.ilQuestionPoolFactory.php';
6require_once 'Modules/TestQuestionPool/classes/class.assQuestion.php';
7
8/**
9 * @author        Björn Heyser <bheyser@databay.de>
10 * @version        $Id$
11 *
12 * @package     Modules/Test(QuestionPool)
13 */
14class ilTestRandomQuestionSetPoolDeriver
15{
16    /**
17     * @var ilDBInterface
18     */
19    protected $db;
20
21    /**
22     * @var ilPluginAdmin
23     */
24    protected $pluginAdmin;
25
26    /**
27     * @var ilObjTest
28     */
29    protected $testOBJ;
30
31    /**
32     * @var integer
33     */
34    protected $targetContainerRef;
35
36    /**
37     * @var integer
38     */
39    protected $ownerId;
40
41    /**
42     * @var ilQuestionPoolFactory
43     */
44    protected $poolFactory;
45
46    /**
47     * @var ilTestRandomQuestionSetSourcePoolDefinitionList
48     */
49    protected $sourcePoolDefinitionList;
50
51    public function __construct(ilDBInterface $ilDB, ilPluginAdmin $pluginAdmin, ilObjTest $testOBJ)
52    {
53        $this->db = $ilDB;
54        $this->pluginAdmin = $pluginAdmin;
55        $this->testOBJ = $testOBJ;
56        $this->poolFactory = new ilQuestionPoolFactory();
57    }
58
59    /**
60     * @return int
61     */
62    public function getTargetContainerRef()
63    {
64        return $this->targetContainerRef;
65    }
66
67    /**
68     * @param int $targetContainerRef
69     */
70    public function setTargetContainerRef($targetContainerRef)
71    {
72        $this->targetContainerRef = $targetContainerRef;
73    }
74
75    /**
76     * @return int
77     */
78    public function getOwnerId()
79    {
80        return $this->ownerId;
81    }
82
83    /**
84     * @param int $ownerId
85     */
86    public function setOwnerId($ownerId)
87    {
88        $this->ownerId = $ownerId;
89    }
90
91    /**
92     * @return ilTestRandomQuestionSetSourcePoolDefinitionList
93     */
94    public function getSourcePoolDefinitionList()
95    {
96        return $this->sourcePoolDefinitionList;
97    }
98
99    /**
100     * @param ilTestRandomQuestionSetSourcePoolDefinitionList $sourcePoolDefinitionList
101     */
102    public function setSourcePoolDefinitionList($sourcePoolDefinitionList)
103    {
104        $this->sourcePoolDefinitionList = $sourcePoolDefinitionList;
105    }
106
107    protected function getQuestionsForPool(ilTestRandomQuestionSetNonAvailablePool $nonAvailablePool)
108    {
109        $questionList = new ilTestRandomQuestionSetStagingPoolQuestionList(
110            $this->db,
111            $this->pluginAdmin
112        );
113
114        $questionList->setTestObjId($this->testOBJ->getId());
115        $questionList->setTestId($this->testOBJ->getTestId());
116        $questionList->setPoolId($nonAvailablePool->getId());
117
118        $questionList->loadQuestions();
119
120        $questions = array();
121
122        foreach ($questionList as $questionId) {
123            $questions[] = assQuestion::_instantiateQuestion($questionId);
124        }
125
126        return $questions;
127    }
128
129    protected function createNewPool(ilTestRandomQuestionSetNonAvailablePool $nonAvailablePool)
130    {
131        $pool = $this->poolFactory->createNewInstance($this->getTargetContainerRef());
132
133        if (strlen($nonAvailablePool->getTitle())) {
134            $pool->setTitle($nonAvailablePool->getTitle());
135            $pool->update();
136        }
137
138        return $pool;
139    }
140
141    protected function copyQuestionsToPool(ilObjQuestionPool $pool, $questions)
142    {
143        $poolQidByTestQidMap = array();
144
145        foreach ($questions as $questionOBJ) {
146            /* @var assQuestion $questionOBJ */
147
148            $testQuestionId = $questionOBJ->getId();
149            $poolQuestionId = $questionOBJ->duplicate(false, '', '', $this->getOwnerId(), $pool->getId());
150
151            $poolQidByTestQidMap[$testQuestionId] = $poolQuestionId;
152        }
153
154        return $poolQidByTestQidMap;
155    }
156
157    protected function updateTestQuestionStage($poolQidByTestQidMap)
158    {
159        foreach ($poolQidByTestQidMap as $testQid => $poolQid) {
160            assQuestion::resetOriginalId($poolQid);
161            assQuestion::saveOriginalId($testQid, $poolQid);
162        }
163    }
164
165    protected function filterForQuestionRelatedTaxonomies($taxonomyIds, $relatedQuestionIds)
166    {
167        require_once 'Services/Taxonomy/classes/class.ilTaxNodeAssignment.php';
168
169        $filteredTaxIds = array();
170
171        foreach ($taxonomyIds as $taxonomyId) {
172            $taxNodeAssignment = new ilTaxNodeAssignment(
173                $this->testOBJ->getType(),
174                $this->testOBJ->getId(),
175                'quest',
176                $taxonomyId
177            );
178
179            foreach ($relatedQuestionIds as $questionId) {
180                $assignedTaxNodes = $taxNodeAssignment->getAssignmentsOfItem($questionId);
181
182                if (count($assignedTaxNodes)) {
183                    $filteredTaxIds[] = $taxonomyId;
184                    break;
185                }
186            }
187        }
188
189        return $filteredTaxIds;
190    }
191
192    protected function duplicateTaxonomies($poolQidByTestQidMap, ilObjQuestionPool $pool)
193    {
194        require_once 'Modules/TestQuestionPool/classes/class.ilQuestionPoolTaxonomiesDuplicator.php';
195        $taxDuplicator = new ilQuestionPoolTaxonomiesDuplicator();
196        $taxDuplicator->setSourceObjId($this->testOBJ->getId());
197        $taxDuplicator->setSourceObjType($this->testOBJ->getType());
198        $taxDuplicator->setTargetObjId($pool->getId());
199        $taxDuplicator->setTargetObjType($pool->getType());
200        $taxDuplicator->setQuestionIdMapping($poolQidByTestQidMap);
201
202        $taxDuplicator->duplicate($this->filterForQuestionRelatedTaxonomies(
203            $taxDuplicator->getAllTaxonomiesForSourceObject(),
204            array_keys($poolQidByTestQidMap)
205        ));
206
207        return $taxDuplicator->getDuplicatedTaxonomiesKeysMap();
208    }
209
210    protected function buildOriginalTaxonomyFilterForDerivedPool(ilQuestionPoolDuplicatedTaxonomiesKeysMap $taxKeysMap, $mappedTaxonomyFilter)
211    {
212        $originalTaxonomyFilter = array();
213
214        foreach ($mappedTaxonomyFilter as $testTaxonomyId => $testTaxNodes) {
215            $poolTaxonomyId = $taxKeysMap->getMappedTaxonomyId($testTaxonomyId);
216            $originalTaxonomyFilter[$poolTaxonomyId] = array();
217
218            foreach ($testTaxNodes as $testTaxNode) {
219                $poolTaxNode = $taxKeysMap->getMappedTaxNodeId($testTaxNode);
220                $originalTaxonomyFilter[$poolTaxonomyId][] = $poolTaxNode;
221            }
222        }
223
224        return $originalTaxonomyFilter;
225    }
226
227    protected function updateRelatedSourcePoolDefinitions(ilQuestionPoolDuplicatedTaxonomiesKeysMap $taxKeysMap, $derivedPoolId, $nonAvailablePoolId)
228    {
229        foreach ($this->getSourcePoolDefinitionList() as $definition) {
230            if ($definition->getPoolId() != $nonAvailablePoolId) {
231                continue;
232            }
233
234            $definition->setPoolId($derivedPoolId);
235
236            $definition->setOriginalTaxonomyFilter($this->buildOriginalTaxonomyFilterForDerivedPool(
237                $taxKeysMap,
238                $definition->getMappedTaxonomyFilter()
239            ));
240
241            $definition->saveToDb();
242        }
243    }
244
245    /**
246     * @param ilTestRandomQuestionSetNonAvailablePool $nonAvailablePool
247     * @return ilObjQuestionPool
248     */
249    public function derive(ilTestRandomQuestionSetNonAvailablePool $nonAvailablePool)
250    {
251        $pool = $this->createNewPool($nonAvailablePool);
252        $questions = $this->getQuestionsForPool($nonAvailablePool);
253
254        $poolQidByTestQidMap = $this->copyQuestionsToPool($pool, $questions);
255
256        $this->updateTestQuestionStage($poolQidByTestQidMap);
257
258        $duplicatedTaxKeysMap = $this->duplicateTaxonomies($poolQidByTestQidMap, $pool);
259
260        $this->updateRelatedSourcePoolDefinitions($duplicatedTaxKeysMap, $pool->getId(), $nonAvailablePool->getId());
261
262        return $pool;
263    }
264}
265