Passed
Push — master ( 621302...15a517 )
by Angel Fernando Quiroz
16:26 queued 07:49
created

QuestionOptionsEvaluationPlugin   A

Complexity

Total Complexity 35

Size/Duplication

Total Lines 263
Duplicated Lines 0 %

Importance

Changes 0
Metric Value
eloc 108
dl 0
loc 263
rs 9.6
c 0
b 0
f 0
wmc 35

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