Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
0.00% covered (danger)
0.00%
0 / 164
0.00% covered (danger)
0.00%
0 / 23
CRAP
0.00% covered (danger)
0.00%
0 / 1
ResponseDeclaration
0.00% covered (danger)
0.00%
0 / 164
0.00% covered (danger)
0.00%
0 / 23
3192
0.00% covered (danger)
0.00%
0 / 1
 generateIdentifier
0.00% covered (danger)
0.00%
0 / 3
0.00% covered (danger)
0.00%
0 / 1
6
 toArray
0.00% covered (danger)
0.00%
0 / 39
0.00% covered (danger)
0.00%
0 / 1
90
 getTemplateQtiVariables
0.00% covered (danger)
0.00%
0 / 27
0.00% covered (danger)
0.00%
0 / 1
42
 getCorrectResponses
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 setCorrectResponses
0.00% covered (danger)
0.00%
0 / 3
0.00% covered (danger)
0.00%
0 / 1
6
 getMapping
0.00% covered (danger)
0.00%
0 / 5
0.00% covered (danger)
0.00%
0 / 1
6
 setMapping
0.00% covered (danger)
0.00%
0 / 3
0.00% covered (danger)
0.00%
0 / 1
6
 setMappingAttributes
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 getMappingDefaultValue
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 setMappingDefaultValue
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 correctToJSON
0.00% covered (danger)
0.00%
0 / 11
0.00% covered (danger)
0.00%
0 / 1
12
 areaMapToJson
0.00% covered (danger)
0.00%
0 / 18
0.00% covered (danger)
0.00%
0 / 1
30
 mapToJSON
0.00% covered (danger)
0.00%
0 / 21
0.00% covered (danger)
0.00%
0 / 1
30
 getBaseType
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 getHowMatch
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 setHowMatch
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 getAssociatedInteraction
0.00% covered (danger)
0.00%
0 / 9
0.00% covered (danger)
0.00%
0 / 1
20
 toForm
0.00% covered (danger)
0.00%
0 / 11
0.00% covered (danger)
0.00%
0 / 1
12
 addFeedbackRule
0.00% covered (danger)
0.00%
0 / 2
0.00% covered (danger)
0.00%
0 / 1
2
 getFeedbackRules
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 getFeedbackRule
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
6
 removeFeedbackRule
0.00% covered (danger)
0.00%
0 / 2
0.00% covered (danger)
0.00%
0 / 1
2
 toFilteredArray
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
1<?php
2
3/*
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License
6 * as published by the Free Software Foundation; under version 2
7 * of the License (non-upgradable).
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
17 *
18 * Copyright (c) 2013 (original work) Open Assessment Technologies SA (under the project TAO-PRODUCT);
19 *
20 *
21 */
22
23namespace oat\taoQtiItem\model\qti;
24
25use oat\taoQtiItem\model\qti\VariableDeclaration;
26use oat\taoQtiItem\model\qti\response\Template;
27use oat\taoQtiItem\model\qti\interaction\Interaction;
28use oat\taoQtiItem\model\qti\response\SimpleFeedbackRule;
29use Exception;
30use oat\taoQtiItem\model\qti\ContentVariable;
31
32/**
33 * A response is on object associated to an interactino containing which are the
34 * response into the interaction choices and the score regarding the answers
35 *
36 * @access public
37 * @author Joel Bout, <joel.bout@tudor.lu>
38 * @package taoQTI
39 * @see http://www.imsglobal.org/question/qtiv2p1/imsqti_infov2p1.html#element10073
40
41 */
42class ResponseDeclaration extends VariableDeclaration implements ContentVariable
43{
44    /**
45     * the QTI tag name as defined in QTI standard
46     *
47     * @access protected
48     * @var string
49     */
50    protected static $qtiTagName = 'responseDeclaration';
51
52    /**
53     * Short description of attribute correctResponses
54     *
55     * @access protected
56     * @var array
57     */
58    protected $correctResponses = [];
59
60    /**
61     * Short description of attribute mapping
62     *
63     * @access protected
64     * @var array
65     */
66    protected $mapping = [];
67
68    /**
69     * Short description of attribute areaMapping
70     *
71     * @access protected
72     * @var array
73     */
74    protected $areaMapping = [];
75
76    /**
77     * Short description of attribute mappingDefaultValue
78     *
79     * @access protected
80     * @var double
81     */
82    protected $mappingDefaultValue = 0.0;
83
84    /**
85     * Short description of attribute howMatch
86     *
87     * @access protected
88     * @var String
89     */
90    protected $howMatch = null;
91    protected $simpleFeedbackRules = [];
92
93    protected function generateIdentifier($prefix = '')
94    {
95
96        if (empty($prefix)) {
97            $prefix = 'RESPONSE'; //QTI standard default value
98        }
99
100        return parent::generateIdentifier($prefix);
101    }
102
103    public function toArray($filterVariableContent = false, &$filtered = [])
104    {
105
106        $data = parent::toArray($filterVariableContent, $filtered);
107        //@todo : clean this please: do not use a class attributes to store childdren's ones.
108        unset($data['attributes']['mapping']);
109        unset($data['attributes']['areaMapping']);
110
111        //prepare the protected data:
112        $protectedData = [
113            'mapping' => $this->mapping,
114            'areaMapping' => $this->areaMapping,
115            'howMatch' => $this->howMatch
116        ];
117
118        $correct = [];
119        $correctResponses = $this->getCorrectResponses();
120        if (is_array($correctResponses)) {
121            foreach ($correctResponses as $correctResponseKey => $value) {
122                //if correct response has cardinality record:
123                if ($this->getAttribute('cardinality') == 'record') {
124                    $valueData = $value->toArray();
125                    $correct[$valueData['fieldIdentifier']] = $valueData;
126                } else {
127                    $correct[$correctResponseKey] = (string) $value;
128                }
129            }
130        }
131        $protectedData['correctResponses'] = $correct;
132
133        $defaultValues = $this->getDefaultValue();
134        if (is_array($defaultValues)) {
135            foreach ($defaultValues as $defaultValuesKey => $defaultValue) {
136                $defaultValues[$defaultValuesKey] = (string) $defaultValue;
137            }
138        }
139        $protectedData['defaultValue'] = $defaultValues;
140        $data['defaultValue'] = $defaultValues;
141
142        //add mapping attributes
143        $mappingAttributes = ['defaultValue' => $this->mappingDefaultValue];
144        if (is_array($this->getAttributeValue('mapping'))) {
145            $mappingAttributes = array_merge($mappingAttributes, $this->getAttributeValue('mapping'));
146        } elseif (is_array($this->getAttributeValue('areaMapping'))) {
147            $mappingAttributes = array_merge($mappingAttributes, $this->getAttributeValue('areaMapping'));
148        }
149        $protectedData['mappingAttributes'] = $mappingAttributes;
150
151        //add simple feedbacks
152        $protectedData['feedbackRules'] = $this->getArraySerializedElementCollection(
153            $this->getFeedbackRules(),
154            $filterVariableContent,
155            $filtered
156        );
157
158        if ($filterVariableContent) {
159            $filtered[$this->getSerial()] = $protectedData;
160        } else {
161            $data = array_merge($data, $protectedData);
162        }
163
164        return $data;
165    }
166
167    protected function getTemplateQtiVariables()
168    {
169
170        $variables = parent::getTemplateQtiVariables();
171        $variables['correctResponses'] = $this->getCorrectResponses();
172        $variables['defaultValue'] = $this->getDefaultValue();
173
174        $variables['mapping'] = $this->mapping;
175        $variables['areaMapping'] = $this->areaMapping;
176
177        //@todo : clean this please: do not use a class attributes to store childdren's ones!
178        unset($variables['attributes']['mapping']);
179        unset($variables['attributes']['areaMapping']);
180
181        $mappingAttributes = ['defaultValue' => $this->mappingDefaultValue];
182        if (is_array($this->getAttributeValue('mapping'))) {
183            $mappingAttributes = array_merge($mappingAttributes, $this->getAttributeValue('mapping'));
184        } elseif (is_array($this->getAttributeValue('areaMapping'))) {
185            $mappingAttributes = array_merge($mappingAttributes, $this->getAttributeValue('areaMapping'));
186        }
187
188        $variables['mappingAttributes'] = $this->xmlizeOptions($mappingAttributes, true);
189
190        $rpTemplate = '';
191        switch ($this->howMatch) {
192            case Template::MATCH_CORRECT:
193                $rpTemplate = 'match_correct';
194                break;
195
196            case Template::MAP_RESPONSE:
197                $rpTemplate = 'map_response';
198                break;
199
200            case Template::MAP_RESPONSE_POINT:
201                $rpTemplate = 'map_response_point';
202                break;
203        }
204        $variables['howMatch'] = $this->howMatch; //the template
205        $variables['rpTemplate'] = $rpTemplate; //the template
206
207        return $variables;
208    }
209
210    /**
211     * Short description of method getCorrectResponses
212     *
213     * @access public
214     * @author Joel Bout, <joel.bout@tudor.lu>
215     * @return array
216     */
217    public function getCorrectResponses()
218    {
219        return (array) $this->correctResponses;
220    }
221
222    /**
223     * Short description of method setCorrectResponses
224     *
225     * @access public
226     * @author Joel Bout, <joel.bout@tudor.lu>
227     * @param  array responses
228     * @return mixed
229     */
230    public function setCorrectResponses($responses)
231    {
232        if (!is_array($responses)) {
233            $responses = [$responses];
234        }
235        $this->correctResponses = $responses;
236    }
237
238    /**
239     * Short description of method getMapping
240     *
241     * @access public
242     * @author Joel Bout, <joel.bout@tudor.lu>
243     * @param  string type
244     * @return array
245     */
246    public function getMapping($type = '')
247    {
248        $returnValue = [];
249
250        if ($type == 'area') {
251            $returnValue = $this->areaMapping;
252        } else {
253            $returnValue = $this->mapping;
254        }
255
256        return (array) $returnValue;
257    }
258
259    /**
260     * Short description of method setMapping
261     *
262     * @access public
263     * @author Joel Bout, <joel.bout@tudor.lu>
264     * @param  array map
265     * @param  type
266     * @return mixed
267     */
268    public function setMapping($map, $type = '')
269    {
270        if ($type == 'area') {
271            $this->areaMapping = $map;
272        } else {
273            $this->mapping = $map;
274        }
275    }
276
277    public function setMappingAttributes($attributes)
278    {
279        $this->setAttribute('mapping', $attributes);
280    }
281
282    /**
283     * Short description of method getMappingDefaultValue
284     *
285     * @access public
286     * @author Joel Bout, <joel.bout@tudor.lu>
287     * @return double
288     */
289    public function getMappingDefaultValue()
290    {
291        return $this->mappingDefaultValue;
292    }
293
294    /**
295     * Short description of method setMappingDefaultValue
296     *
297     * @access public
298     * @author Joel Bout, <joel.bout@tudor.lu>
299     * @param  double value
300     * @return mixed
301     */
302    public function setMappingDefaultValue($value)
303    {
304        $this->mappingDefaultValue = floatval($value);
305    }
306
307    /**
308     * get the correct response in JSON format. If no correct response defined
309     * null.
310     *
311     * @deprecated now use the new qtism lib for response evaluation
312     * @access public
313     * @author Joel Bout, <joel.bout@tudor.lu>
314     */
315    public function correctToJSON()
316    {
317        $returnValue = null;
318
319        try {
320            $correctResponses = $this->getCorrectResponses();
321            if (count($correctResponses)) {
322                $returnValue = taoQTI_models_classes_Matching_VariableFactory::createJSONVariableFromQTIData(
323                    $this->getIdentifier(),
324                    $this->getAttributeValue('cardinality'),
325                    $this->getAttributeValue('baseType'),
326                    $this->correctResponses
327                );
328            }
329        } catch (Exception $e) {
330        }
331
332        return $returnValue;
333    }
334
335    /**
336     * Short description of method areaMapToJson
337     *
338     * @deprecated now use the new qtism lib for response evaluation
339     * @access public
340     * @author Joel Bout, <joel.bout@tudor.lu>
341     */
342    public function areaMapToJson()
343    {
344        $returnValue = null;
345
346        // Get the stored area mapping
347        $mapping = $this->getMapping('area');
348
349        if (count($mapping)) {
350            $returnValue = [];
351            $returnValue['identifier'] = $this->getIdentifier();
352            $returnValue['defaultValue'] = $this->mappingDefaultValue;
353            if ($this->hasAttribute('areaMapping')) {
354                $returnValue = array_merge($returnValue, $this->getAttributeValue('areaMapping'));
355            }
356            $mappingValue = [];
357
358            // If a mapping has been defined
359            if (!empty($mapping)) {
360                foreach ($mapping as $mapKey => $mappedValue) {
361                    $areaMapEntryJSON = [];
362                    $areaMapEntryJSON['value'] = (float) $mappedValue["mappedValue"];
363                    // phpcs:disable Generic.Files.LineLength
364                    $areaMapEntryJSON['key'] = taoQTI_models_classes_Matching_VariableFactory::createJSONShapeFromQTIData($mappedValue);
365                    // phpcs:enable Generic.Files.LineLength
366                    array_push($mappingValue, (object) $areaMapEntryJSON);
367                }
368                $returnValue['value'] = $mappingValue;
369            }
370
371            $returnValue = (object) $returnValue;
372        }
373
374        return $returnValue;
375    }
376
377    /**
378     * get the mapping in JSON format. If no mapping defined return null.
379     *
380     * @deprecated now use the new qtism lib for response evaluation
381     * @access public
382     * @author Joel Bout, <joel.bout@tudor.lu>
383     */
384    public function mapToJSON()
385    {
386        $returnValue = null;
387
388        $mapping = $this->getMapping();
389        if (count($mapping)) {
390            $returnValue = [];
391            $returnValue['identifier'] = $this->getIdentifier();
392            $returnValue['defaultValue'] = $this->mappingDefaultValue;
393            if ($this->hasAttribute('areaMapping')) {
394                $returnValue = array_merge($returnValue, $this->getAttributeValue('areaMapping'));
395            }
396            $mappingValue = [];
397
398            // If a mapping has been defined
399            if (!empty($mapping)) {
400                foreach ($mapping as $mapKey => $mappedValue) {
401                    $mapEntryJSON = [];
402                    $mapEntryJSON['value'] = (float) $mappedValue;
403                    $mapEntryJSON['key'] = taoQTI_models_classes_Matching_VariableFactory::createJSONValueFromQTIData(
404                        $mapKey,
405                        $this->getAttributeValue('baseType')
406                    );
407                    array_push($mappingValue, (object) $mapEntryJSON);
408                }
409
410                $returnValue['value'] = $mappingValue;
411            }
412
413            $returnValue = (object) $returnValue;
414        }
415
416        return $returnValue;
417    }
418
419    /**
420     * get the base type of the response declaration
421     *
422     * @access public
423     * @author Joel Bout, <joel.bout@tudor.lu>
424     * @return string
425     */
426    public function getBaseType()
427    {
428        return (string) $this->getAttributeValue('baseType');
429    }
430
431    /**
432     * Short description of method getHowMatch
433     *
434     * @access public
435     * @author Joel Bout, <joel.bout@tudor.lu>
436     * @return string
437     */
438    public function getHowMatch()
439    {
440        return (string) $this->howMatch;
441    }
442
443    /**
444     * Short description of method setHowMatch
445     *
446     * @access public
447     * @author Joel Bout, <joel.bout@tudor.lu>
448     * @param  string howMatch
449     * @return mixed
450     */
451    public function setHowMatch($howMatch)
452    {
453        $this->howMatch = $howMatch;
454    }
455
456    public function getAssociatedInteraction()
457    {
458        $returnValue = null;
459        $item = $this->getRelatedItem();
460        if (!is_null($item)) {
461            $interactions = $item->getInteractions();
462            foreach ($interactions as $interaction) {
463                if ($interaction->getAttributeValue('responseIdentifier') == $this->getIdentifier()) {
464                    $returnValue = $interaction;
465                    break;
466                }
467            }
468        }
469        return $returnValue;
470    }
471
472    /**
473     * Short description of method toForm
474     *
475     * @access public
476     * @author Joel Bout, <joel.bout@tudor.lu>
477     * @return tao_helpers_form_xhtml_Form
478     */
479    public function toForm()
480    {
481        $returnValue = null;
482
483        $interaction = $this->getAssociatedInteraction();
484        if ($interaction instanceof Interaction) {
485            $responseFormClass = '\\oat\\taoQtiItem\\controller\\QTIform\\response\\'
486                . ucfirst(strtolower($interaction->getType())) . 'Interaction';
487
488            if (class_exists($responseFormClass)) {
489                $formContainer = new $responseFormClass($this);
490                $myForm = $formContainer->getForm();
491                $returnValue = $myForm;
492            }
493        } else {
494            throw new Exception('cannot find the parent interaction of the current response');
495        }
496
497        return $returnValue;
498    }
499
500    public function addFeedbackRule(SimpleFeedbackRule $simpleFeedbackRule)
501    {
502        $this->simpleFeedbackRules[$simpleFeedbackRule->getSerial()] = $simpleFeedbackRule;
503        $simpleFeedbackRule->setRelatedItem($this->getRelatedItem());
504    }
505
506    public function getFeedbackRules()
507    {
508        return $this->simpleFeedbackRules;
509    }
510
511    public function getFeedbackRule($serial)
512    {
513        return isset($this->simpleFeedbackRules[$serial]) ? $this->simpleFeedbackRules[$serial] : null;
514    }
515
516    public function removeFeedbackRule($serial)
517    {
518        unset($this->simpleFeedbackRules[$serial]);
519        return true;
520    }
521
522    public function toFilteredArray()
523    {
524        return $this->toArray(true);
525    }
526}