Passed
Push — master ( fc8817...f91339 )
by Angel Fernando Quiroz
10:10 queued 10s
created

QuestionOptionsEvaluationPlugin   A

Complexity

Total Complexity 36

Size/Duplication

Total Lines 268
Duplicated Lines 0 %

Importance

Changes 0
Metric Value
eloc 109
dl 0
loc 268
rs 9.52
c 0
b 0
f 0
wmc 36

14 Methods

Rating   Name   Duplication   Size   Complexity  
A filterModify() 0 17 2
A performActionsAfterConfigure() 0 3 1
B getResultWithFormula() 0 47 8
A saveFormulaForExercise() 0 10 1
A get_name() 0 3 1
A uninstall() 0 3 1
A getFormulaForExercise() 0 13 2
A createExtraField() 0 13 2
A getMaxScore() 0 9 2
A __construct() 0 11 1
A create() 0 5 2
A install() 0 3 1
B recalculateQuestionScore() 0 37 10
A removeExtraField() 0 7 2
1
<?php
2
/* For licensing terms, see /license.txt */
3
4
use Chamilo\CoreBundle\Entity\TrackEAttempt;
5
6
/**
7
 * Class QuestionOptionsEvaluationPlugin.
8
 */
9
class QuestionOptionsEvaluationPlugin extends Plugin
10
{
11
    public const SETTING_ENABLE = 'enable';
12
    public const SETTING_MAX_SCORE = 'exercise_max_score';
13
    public const EXTRAFIELD_FORMULA = 'quiz_evaluation_formula';
14
15
    /**
16
     * QuestionValuationPlugin constructor.
17
     */
18
    protected function __construct()
19
    {
20
        $version = '1.0';
21
        $author = 'Angel Fernando Quiroz Campos';
22
23
        parent::__construct(
24
            $version,
25
            $author,
26
            [
27
                self::SETTING_ENABLE => 'boolean',
28
                self::SETTING_MAX_SCORE => 'text',
29
            ]
30
        );
31
    }
32
33
    /**
34
     * @return QuestionOptionsEvaluationPlugin|null
35
     */
36
    public static function create()
37
    {
38
        static $result = null;
39
40
        return $result ? $result : $result = new self();
41
    }
42
43
    /**
44
     * @param int $exerciseId
45
     * @param int $iconSize
46
     *
47
     * @return string
48
     */
49
    public static function filterModify($exerciseId, $iconSize = ICON_SIZE_SMALL)
50
    {
51
        $directory = basename(__DIR__);
52
        $title = get_plugin_lang('plugin_title', self::class);
53
        $enabled = api_get_plugin_setting('questionoptionsevaluation', 'enable');
54
55
        if ('true' !== $enabled) {
56
            return '';
57
        }
58
59
        return Display::url(
60
            Display::return_icon('options_evaluation.png', $title, [], $iconSize),
61
            api_get_path(WEB_PATH)."plugin/$directory/evaluation.php?exercise=$exerciseId",
62
            [
63
                'class' => 'ajax',
64
                'data-size' => 'md',
65
                'data-title' => get_plugin_lang('plugin_title', self::class),
66
            ]
67
        );
68
    }
69
70
    public function install()
71
    {
72
        $this->createExtraField();
73
    }
74
75
    public function uninstall()
76
    {
77
        $this->removeExtraField();
78
    }
79
80
    /**
81
     * @return Plugin
82
     */
83
    public function performActionsAfterConfigure()
84
    {
85
        return $this;
86
    }
87
88
    /**
89
     * @param int $formula
90
     */
91
    public function saveFormulaForExercise($formula, Exercise $exercise)
92
    {
93
        $this->recalculateQuestionScore($formula, $exercise);
94
95
        $extraFieldValue = new ExtraFieldValue('quiz');
96
        $extraFieldValue->save(
97
            [
98
                'item_id' => $exercise->iid,
0 ignored issues
show
Bug introduced by
The property iid does not seem to exist on Exercise.
Loading history...
99
                'variable' => self::EXTRAFIELD_FORMULA,
100
                'value' => $formula,
101
            ]
102
        );
103
    }
104
105
    /**
106
     * @param int $exerciseId
107
     *
108
     * @return int
109
     */
110
    public function getFormulaForExercise($exerciseId)
111
    {
112
        $extraFieldValue = new ExtraFieldValue('quiz');
113
        $value = $extraFieldValue->get_values_by_handler_and_field_variable(
114
            $exerciseId,
115
            self::EXTRAFIELD_FORMULA
116
        );
117
118
        if (empty($value)) {
119
            return 0;
120
        }
121
122
        return (int) $value['value'];
123
    }
124
125
    /**
126
     * @return int
127
     */
128
    public function getMaxScore()
129
    {
130
        $max = $this->get(self::SETTING_MAX_SCORE);
131
132
        if (!empty($max)) {
133
            return (int) $max;
134
        }
135
136
        return 10;
137
    }
138
139
    /**
140
     * @param int $trackId
141
     * @param int $formula
142
     *
143
     * @throws \Doctrine\ORM\ORMException
144
     * @throws \Doctrine\ORM\OptimisticLockException
145
     * @throws \Doctrine\ORM\TransactionRequiredException
146
     *
147
     * @return float|int
148
     */
149
    public function getResultWithFormula($trackId, $formula)
150
    {
151
        $em = Database::getManager();
152
153
        $eTrack = $em->find('ChamiloCoreBundle:TrackEExercises', $trackId);
154
155
        $qTracks = $em
156
            ->createQuery(
157
                'SELECT a FROM ChamiloCoreBundle:TrackEAttempt a
158
                WHERE a.exeId = :id AND a.userId = :user AND a.cId = :course AND a.sessionId = :session'
159
            )
160
            ->setParameters(
161
                [
162
                    'id' => $eTrack->getExeId(),
163
                    'course' => $eTrack->getCId(),
164
                    'session' => $eTrack->getSessionId(),
165
                    'user' => $eTrack->getExeUserId(),
166
                ]
167
            )
168
            ->getResult();
169
170
        $counts = ['correct' => 0, 'incorrect' => 0];
171
172
        /** @var TrackEAttempt $qTrack */
173
        foreach ($qTracks as $qTrack) {
174
            if ($qTrack->getMarks() > 0) {
175
                $counts['correct']++;
176
            } elseif ($qTrack->getMarks() < 0) {
177
                $counts['incorrect']++;
178
            }
179
        }
180
181
        switch ($formula) {
182
            case 1:
183
                $result = $counts['correct'] - $counts['incorrect'];
184
                break;
185
            case 2:
186
                $result = $counts['correct'] - $counts['incorrect'] / 2;
187
                break;
188
            case 3:
189
                $result = $counts['correct'] - $counts['incorrect'] / 3;
190
                break;
191
        }
192
193
        $score = ($result / count($qTracks)) * $this->getMaxScore();
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $result does not seem to be defined for all execution paths leading up to this point.
Loading history...
194
195
        return $score >= 0 ? $score : 0;
196
    }
197
198
    public function get_name()
199
    {
200
        return 'QuestionOptionsEvaluation';
201
    }
202
203
    /**
204
     * @param int $formula
205
     */
206
    private function recalculateQuestionScore($formula, Exercise $exercise)
207
    {
208
        $tblQuestion = Database::get_course_table(TABLE_QUIZ_QUESTION);
209
        $tblAnswer = Database::get_course_table(TABLE_QUIZ_ANSWER);
210
211
        foreach ($exercise->questionList as $questionId) {
212
            $question = Question::read($questionId, $exercise->course, false);
213
            if (!in_array($question->selectType(), [UNIQUE_ANSWER, MULTIPLE_ANSWER])) {
214
                continue;
215
            }
216
217
            $questionAnswers = new Answer($questionId, $exercise->course_id, $exercise);
218
            $counts = array_count_values($questionAnswers->correct);
219
220
            $questionPonderation = 0;
221
222
            foreach ($questionAnswers->correct as $i => $isCorrect) {
223
                if (!isset($questionAnswers->iid[$i])) {
224
                    continue;
225
                }
226
227
                $iid = $questionAnswers->iid[$i];
228
229
                if ($question->selectType() == MULTIPLE_ANSWER || 0 === $formula) {
230
                    $ponderation = 1 == $isCorrect ? 1 / $counts[1] : -1 / $counts[0];
231
                } else {
232
                    $ponderation = 1 == $isCorrect ? 1 : -1 / $formula;
233
                }
234
235
                if ($ponderation > 0) {
236
                    $questionPonderation += $ponderation;
237
                }
238
239
                Database::query("UPDATE $tblAnswer SET ponderation = $ponderation WHERE iid = $iid");
240
            }
241
242
            Database::query("UPDATE $tblQuestion SET ponderation = $questionPonderation WHERE iid = {$question->iid}");
243
        }
244
    }
245
246
    /**
247
     * Creates an extrafield.
248
     */
249
    private function createExtraField()
250
    {
251
        $extraField = new ExtraField('quiz');
252
253
        if (false === $extraField->get_handler_field_info_by_field_variable(self::EXTRAFIELD_FORMULA)) {
254
            $extraField
255
                ->save(
256
                    [
257
                        'variable' => self::EXTRAFIELD_FORMULA,
258
                        'field_type' => ExtraField::FIELD_TYPE_TEXT,
259
                        'display_text' => $this->get_lang('EvaluationFormula'),
260
                        'visible_to_self' => false,
261
                        'changeable' => false,
262
                    ]
263
                );
264
        }
265
    }
266
267
    /**
268
     * Removes the extrafield .
269
     */
270
    private function removeExtraField()
271
    {
272
        $extraField = new ExtraField('quiz');
273
        $value = $extraField->get_handler_field_info_by_field_variable(self::EXTRAFIELD_FORMULA);
274
275
        if (false !== $value) {
276
            $extraField->delete($value['id']);
277
        }
278
    }
279
}
280