1<?php
2/* Copyright (c) 1998-2013 ILIAS open source, Extended GPL, see docs/LICENSE */
3
4require_once 'Services/Xml/classes/class.ilSaxParser.php';
5
6/**
7 * @author        Björn Heyser <bheyser@databay.de>
8 * @version        $Id$
9 *
10 * @package     Modules/Test
11 */
12class ilObjTestXMLParser extends ilSaxParser
13{
14    /**
15     * @var ilObjTest
16     */
17    protected $testOBJ;
18
19    /**
20     * @var ilImportMapping
21     */
22    protected $importMapping;
23
24    /**
25     * @return ilObjTest
26     */
27    public function getTestOBJ()
28    {
29        return $this->testOBJ;
30    }
31
32    /**
33     * @param ilObjTest $testOBJ
34     */
35    public function setTestOBJ($testOBJ)
36    {
37        $this->testOBJ = $testOBJ;
38    }
39
40    /**
41     * @return ilImportMapping
42     */
43    public function getImportMapping()
44    {
45        return $this->importMapping;
46    }
47
48    /**
49     * @param ilImportMapping $importMapping
50     */
51    public function setImportMapping($importMapping)
52    {
53        $this->importMapping = $importMapping;
54    }
55
56    public function setHandlers($xmlParser)
57    {
58        xml_set_object($xmlParser, $this);
59        xml_set_element_handler($xmlParser, 'handlerBeginTag', 'handlerEndTag');
60        xml_set_character_data_handler($xmlParser, 'handlerCharacterData');
61    }
62
63    public function handlerBeginTag($xmlParser, $tagName, $tagAttributes)
64    {
65        switch ($tagName) {
66            case 'RandomQuestionSetConfig':
67                $this->inRandomQuestionSetConfig = true;
68                break;
69
70            case 'RandomQuestionSetSettings':
71                if ($this->inRandomQuestionSetConfig) {
72                    $this->inRandomQuestionSetSettings = true;
73                    $this->cdata = '';
74                    $this->attr = $tagAttributes;
75                }
76                break;
77
78            case 'RandomQuestionStage':
79                if ($this->inRandomQuestionSetConfig) {
80                    $this->inRandomQuestionStage = true;
81                }
82                break;
83
84            case 'RandomQuestionStagingPool':
85                if ($this->inRandomQuestionStage) {
86                    $this->cdata = '';
87                    $this->attr = $tagAttributes;
88                }
89                break;
90
91            case 'RandomQuestionSelectionDefinitions':
92                if ($this->inRandomQuestionSetConfig) {
93                    $this->inRandomQuestionSelectionDefinitions = true;
94                }
95                break;
96
97            case 'RandomQuestionSelectionDefinition':
98                if ($this->inRandomQuestionSelectionDefinitions) {
99                    $this->sourcePoolDefinition = $this->getRandomQuestionSourcePoolDefinitionInstance();
100                    $this->attr = $tagAttributes;
101                }
102                break;
103
104            case 'RandomQuestionSourcePoolTitle':
105            case 'RandomQuestionSourcePoolPath':
106                if ($this->sourcePoolDefinition instanceof ilTestRandomQuestionSetSourcePoolDefinition) {
107                    $this->cdata = '';
108                }
109                break;
110        }
111    }
112
113    public function handlerEndTag($xmlParser, $tagName)
114    {
115        switch ($tagName) {
116            case 'RandomQuestionSetConfig':
117                $this->inRandomQuestionSetConfig = false;
118                break;
119
120            case 'RandomQuestionSetSettings':
121                if ($this->inRandomQuestionSetConfig) {
122                    $this->importRandomQuestionSetSettings($this->attr);
123                    $this->attr = null;
124                }
125                break;
126
127            case 'RandomQuestionStage':
128                if ($this->inRandomQuestionSetConfig) {
129                    $this->inRandomQuestionStage = false;
130                }
131                break;
132
133            case 'RandomQuestionStagingPool':
134                if ($this->inRandomQuestionSetConfig && $this->inRandomQuestionStage) {
135                    $this->importRandomQuestionStagingPool($this->attr, $this->cdata);
136                    $this->attr = null;
137                    $this->cdata = '';
138                }
139                break;
140
141            case 'RandomQuestionSelectionDefinitions':
142                if ($this->inRandomQuestionSetConfig) {
143                    $this->inRandomQuestionSelectionDefinitions = false;
144                }
145                break;
146
147            case 'RandomQuestionSelectionDefinition':
148                if ($this->inRandomQuestionSetConfig && $this->inRandomQuestionSelectionDefinitions) {
149                    $this->importRandomQuestionSourcePoolDefinition($this->sourcePoolDefinition, $this->attr);
150                    $this->sourcePoolDefinition->saveToDb();
151
152                    $this->getImportMapping()->addMapping(
153                        'Modules/Test',
154                        'rnd_src_pool_def',
155                        $this->attr['id'],
156                        $this->sourcePoolDefinition->getId()
157                    );
158
159                    $this->sourcePoolDefinition = null;
160                    $this->attr = null;
161                }
162                break;
163
164            case 'RandomQuestionSourcePoolTitle':
165                if ($this->sourcePoolDefinition instanceof ilTestRandomQuestionSetSourcePoolDefinition) {
166                    $this->sourcePoolDefinition->setPoolTitle($this->cdata);
167                    $this->cdata = '';
168                }
169                break;
170
171            case 'RandomQuestionSourcePoolPath':
172                if ($this->sourcePoolDefinition instanceof ilTestRandomQuestionSetSourcePoolDefinition) {
173                    $this->sourcePoolDefinition->setPoolPath($this->cdata);
174                    $this->cdata = '';
175                }
176                break;
177        }
178    }
179
180    public function handlerCharacterData($xmlParser, $charData)
181    {
182        if ($charData != "\n") {
183            // Replace multiple tabs with one space
184            $charData = preg_replace("/\t+/", " ", $charData);
185
186            $this->cdata .= $charData;
187        }
188    }
189
190    protected function importRandomQuestionSetSettings($attr)
191    {
192        global $DIC;
193        $tree = $DIC['tree'];
194        $ilDB = $DIC['ilDB'];
195        $ilPluginAdmin = $DIC['ilPluginAdmin'];
196
197        require_once 'Modules/Test/classes/class.ilTestRandomQuestionSetConfig.php';
198        $questionSetConfig = new ilTestRandomQuestionSetConfig($tree, $ilDB, $ilPluginAdmin, $this->testOBJ);
199
200        if (!$questionSetConfig->isValidQuestionAmountConfigurationMode($attr['amountMode'])) {
201            require_once 'Modules/Test/exceptions/class.ilTestException.php';
202            throw new ilTestException(
203                'invalid random test question set config amount mode given: "' . $attr['amountMode'] . '"'
204            );
205        }
206
207        $questionSetConfig->setQuestionAmountConfigurationMode($attr['amountMode']);
208        $questionSetConfig->setQuestionAmountPerTest((int) $attr['questAmount']);
209        $questionSetConfig->setPoolsWithHomogeneousScoredQuestionsRequired((bool) $attr['homogeneous']);
210        $questionSetConfig->setLastQuestionSyncTimestamp((int) $attr['synctimestamp']);
211
212        $questionSetConfig->saveToDb();
213    }
214
215    protected function importRandomQuestionStagingPool($attr, $cdata)
216    {
217        global $DIC;
218        $ilDB = $DIC['ilDB'];
219
220        $oldPoolId = $attr['poolId'];
221        $newPoolId = $ilDB->nextId('object_data'); // yes !!
222
223        $this->getImportMapping()->addMapping(
224            'Modules/Test',
225            'pool',
226            $oldPoolId,
227            $newPoolId
228        );
229
230        $oldQuestionIds = explode(',', $cdata);
231
232        require_once 'Modules/Test/classes/class.ilTestRandomQuestionSetStagingPoolQuestion.php';
233
234        foreach ($oldQuestionIds as $oldQuestionId) {
235            $newQuestionId = $this->getImportMapping()->getMapping(
236                'Modules/Test',
237                'quest',
238                $oldQuestionId
239            );
240
241            $stagingQuestion = new ilTestRandomQuestionSetStagingPoolQuestion($ilDB);
242            $stagingQuestion->setTestId($this->testOBJ->getTestId());
243            $stagingQuestion->setPoolId($newPoolId);
244            $stagingQuestion->setQuestionId($newQuestionId);
245
246            $stagingQuestion->saveQuestionStaging();
247        }
248    }
249
250    protected function getRandomQuestionSourcePoolDefinitionInstance()
251    {
252        global $DIC;
253        $ilDB = $DIC['ilDB'];
254
255        require_once 'Modules/Test/classes/class.ilTestRandomQuestionSetSourcePoolDefinition.php';
256
257        return new ilTestRandomQuestionSetSourcePoolDefinition($ilDB, $this->testOBJ);
258    }
259
260    protected function importRandomQuestionSourcePoolDefinition(ilTestRandomQuestionSetSourcePoolDefinition $sourcePoolDefinition, $attr)
261    {
262        $source_pool_id = (int) $attr['poolId'];
263        $effective_pool_id = (int) $this->getImportMapping()->getMapping(
264            'Modules/Test',
265            'pool',
266            $source_pool_id
267        );
268        $sourcePoolDefinition->setPoolId($effective_pool_id);
269
270        $derive_from_obj_id = true;
271        // The ref_id might not be given in old export files, so we have to check for existence
272        if (isset($attr['ref_id']) && is_numeric($attr['ref_id'])) {
273            if ($source_pool_id === $effective_pool_id) {
274                $derive_from_obj_id = false;
275                $sourcePoolDefinition->setPoolRefId((int) $attr['ref_id']);
276            }
277        }
278
279        if ($derive_from_obj_id) {
280            $ref_ids = ilObject::_getAllReferences($effective_pool_id);
281            $ref_id = current($ref_ids);
282            $sourcePoolDefinition->setPoolRefId($ref_id ? (int) $ref_id : null);
283        }
284
285        $sourcePoolDefinition->setPoolQuestionCount((int) $attr['poolQuestCount']);
286        $sourcePoolDefinition->setQuestionAmount((int) $attr['questAmount']);
287        $sourcePoolDefinition->setSequencePosition((int) $attr['position']);
288
289        // #21330
290        if (isset($attr['tax']) && isset($attr['taxNode'])) {
291            $mappedTaxFilter = array(
292                (int) $attr['tax'] => array(
293                    (int) $attr['taxNode']
294                )
295            );
296            $sourcePoolDefinition->setMappedTaxonomyFilter($mappedTaxFilter);
297        } elseif (isset($attr['taxFilter']) && strlen($attr['taxFilter']) > 0) {
298            $mappedTaxFilter = unserialize($attr['taxFilter']);
299            $sourcePoolDefinition->setMappedTaxonomyFilter($mappedTaxFilter);
300        }
301    }
302}
303