Completed
Push — master ( 067f55...e1cb48 )
by Julito
09:39
created

recalculateQuestionScore()   B

Complexity

Conditions 10
Paths 12

Size

Total Lines 38
Code Lines 21

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 10
eloc 21
c 1
b 0
f 0
nc 12
nop 2
dl 0
loc 38
rs 7.6666

How to fix   Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

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
    const SETTING_ENABLE = 'enable';
12
    const SETTING_MAX_SCORE = 'exercise_max_score';
13
14
    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
     * @param Exercise $exercise
92
     */
93
    public function saveFormulaForExercise($formula, Exercise $exercise)
94
    {
95
        $this->recalculateQuestionScore($formula, $exercise);
96
97
        $extraFieldValue = new ExtraFieldValue('quiz');
98
        $extraFieldValue->save(
99
            [
100
                'item_id' => $exercise->iId,
101
                'variable' => self::EXTRAFIELD_FORMULA,
102
                'value' => $formula,
103
            ]
104
        );
105
    }
106
107
    /**
108
     * @param int $exerciseId
109
     *
110
     * @return int
111
     */
112
    public function getFormulaForExercise($exerciseId)
113
    {
114
        $extraFieldValue = new ExtraFieldValue('quiz');
115
        $value = $extraFieldValue->get_values_by_handler_and_field_variable(
116
            $exerciseId,
117
            self::EXTRAFIELD_FORMULA
118
        );
119
120
        if (empty($value)) {
121
            return 0;
122
        }
123
124
        return (int) $value['value'];
125
    }
126
127
    /**
128
     * @return int
129
     */
130
    public function getMaxScore()
131
    {
132
        $max = $this->get(self::SETTING_MAX_SCORE);
133
134
        if (!empty($max)) {
135
            return (int) $max;
136
        }
137
138
        return 10;
139
    }
140
141
    /**
142
     * @param int $trackId
143
     * @param int $formula
144
     *
145
     * @throws \Doctrine\ORM\ORMException
146
     * @throws \Doctrine\ORM\OptimisticLockException
147
     * @throws \Doctrine\ORM\TransactionRequiredException
148
     *
149
     * @return float|int
150
     */
151
    public function getResultWithFormula($trackId, $formula)
152
    {
153
        $em = Database::getManager();
154
155
        $eTrack = $em->find('ChamiloCoreBundle:TrackEExercises', $trackId);
156
157
        $qTracks = $em
158
            ->createQuery(
159
                'SELECT a FROM ChamiloCoreBundle:TrackEAttempt a
160
                WHERE a.exeId = :id AND a.userId = :user AND a.cId = :course AND a.sessionId = :session'
161
            )
162
            ->setParameters(
163
                [
164
                    'id' => $eTrack->getExeId(),
165
                    'course' => $eTrack->getCId(),
166
                    'session' => $eTrack->getSessionId(),
167
                    'user' => $eTrack->getExeUserId(),
168
                ]
169
            )
170
            ->getResult();
171
172
        $counts = ['correct' => 0, 'incorrect' => 0];
173
174
        /** @var TrackEAttempt $qTrack */
175
        foreach ($qTracks as $qTrack) {
176
            if ($qTrack->getMarks() > 0) {
177
                $counts['correct']++;
178
            } elseif ($qTrack->getMarks() < 0) {
179
                $counts['incorrect']++;
180
            }
181
        }
182
183
        switch ($formula) {
184
            case 1:
185
                $result = $counts['correct'] - $counts['incorrect'];
186
                break;
187
            case 2:
188
                $result = $counts['correct'] - $counts['incorrect'] / 2;
189
                break;
190
            case 3:
191
                $result = $counts['correct'] - $counts['incorrect'] / 3;
192
                break;
193
        }
194
195
        $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...
196
197
        return $score >= 0 ? $score : 0;
198
    }
199
200
    /**
201
     * @param int      $formula
202
     * @param Exercise $exercise
203
     */
204
    private function recalculateQuestionScore($formula, Exercise $exercise)
205
    {
206
        $tblQuestion = Database::get_course_table(TABLE_QUIZ_QUESTION);
207
        $tblAnswer = Database::get_course_table(TABLE_QUIZ_ANSWER);
208
209
        foreach ($exercise->questionList as $questionId) {
210
            $question = Question::read($questionId, $exercise->course, false);
211
            if (!in_array($question->selectType(), [UNIQUE_ANSWER, MULTIPLE_ANSWER])) {
212
                continue;
213
            }
214
215
            $questionAnswers = new Answer($questionId, $exercise->course_id, $exercise);
216
            $counts = array_count_values($questionAnswers->correct);
217
218
            $questionPonderation = 0;
219
220
            foreach ($questionAnswers->correct as $i => $isCorrect) {
221
                if (!isset($questionAnswers->iid[$i])) {
222
                    continue;
223
                }
224
225
                $iid = $questionAnswers->iid[$i];
226
227
                if ($question->selectType() == MULTIPLE_ANSWER || 0 === $formula) {
228
                    $ponderation = 1 == $isCorrect ? 1 / $counts[1] : -1 / $counts[0];
229
                } else {
230
                    $ponderation = 1 == $isCorrect ? 1 : -1 / $formula;
231
                }
232
233
                if ($ponderation > 0) {
234
                    $questionPonderation += $ponderation;
235
                }
236
237
                //error_log("question: $questionId -- i: $i -- w: $ponderation");
238
                Database::query("UPDATE $tblAnswer SET ponderation = $ponderation WHERE iid = $iid");
239
            }
240
241
            Database::query("UPDATE $tblQuestion SET ponderation = $questionPonderation WHERE iid = {$question->iid}");
242
        }
243
    }
244
245
    /**
246
     * Creates an extrafield.
247
     */
248
    private function createExtraField()
249
    {
250
        $extraField = new ExtraField('quiz');
251
252
        if (false === $extraField->get_handler_field_info_by_field_variable(self::EXTRAFIELD_FORMULA)) {
253
            $extraField
254
                ->save(
255
                    [
256
                        'variable' => self::EXTRAFIELD_FORMULA,
257
                        'field_type' => ExtraField::FIELD_TYPE_TEXT,
258
                        'display_text' => $this->get_lang('EvaluationFormula'),
259
                        'visible_to_self' => false,
260
                        'changeable' => false,
261
                    ]
262
                );
263
        }
264
    }
265
266
    /**
267
     * Removes the extrafield .
268
     */
269
    private function removeExtraField()
270
    {
271
        $extraField = new ExtraField('quiz');
272
        $value = $extraField->get_handler_field_info_by_field_variable(self::EXTRAFIELD_FORMULA);
273
274
        if (false !== $value) {
275
            $extraField->delete($value['id']);
276
        }
277
    }
278
}
279