Proyectos de Subversion Moodle

Rev

| Ultima modificación | Ver Log |

Rev Autor Línea Nro. Línea
1 efrain 1
<?php
2
// This file is part of Moodle - http://moodle.org/
3
//
4
// Moodle is free software: you can redistribute it and/or modify
5
// it under the terms of the GNU General Public License as published by
6
// the Free Software Foundation, either version 3 of the License, or
7
// (at your option) any later version.
8
//
9
// Moodle 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 Moodle.  If not, see <http://www.gnu.org/licenses/>.
16
 
17
use mod_quiz\quiz_attempt;
18
use mod_quiz\quiz_settings;
19
 
20
defined('MOODLE_INTERNAL') || die();
21
 
22
/**
23
 * Quiz module test data generator class
24
 *
25
 * @package mod_quiz
26
 * @copyright 2012 The Open University
27
 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
28
 */
29
class mod_quiz_generator extends testing_module_generator {
30
 
31
    public function create_instance($record = null, array $options = null) {
32
        global $CFG;
33
 
34
        require_once($CFG->dirroot.'/mod/quiz/locallib.php');
35
        $record = (object)(array)$record;
36
 
37
        $defaultquizsettings = [
38
            'timeopen'               => 0,
39
            'timeclose'              => 0,
40
            'preferredbehaviour'     => 'deferredfeedback',
41
            'attempts'               => 0,
42
            'attemptonlast'          => 0,
43
            'grademethod'            => QUIZ_GRADEHIGHEST,
44
            'decimalpoints'          => 2,
45
            'questiondecimalpoints'  => -1,
46
            'attemptduring'          => 1,
47
            'correctnessduring'      => 1,
48
            'maxmarksduring'         => 1,
49
            'marksduring'            => 1,
50
            'specificfeedbackduring' => 1,
51
            'generalfeedbackduring'  => 1,
52
            'rightanswerduring'      => 1,
53
            'overallfeedbackduring'  => 0,
54
            'attemptimmediately'          => 1,
55
            'correctnessimmediately'      => 1,
56
            'maxmarksimmediately'         => 1,
57
            'marksimmediately'            => 1,
58
            'specificfeedbackimmediately' => 1,
59
            'generalfeedbackimmediately'  => 1,
60
            'rightanswerimmediately'      => 1,
61
            'overallfeedbackimmediately'  => 1,
62
            'attemptopen'            => 1,
63
            'correctnessopen'        => 1,
64
            'maxmarksopen'           => 1,
65
            'marksopen'              => 1,
66
            'specificfeedbackopen'   => 1,
67
            'generalfeedbackopen'    => 1,
68
            'rightansweropen'        => 1,
69
            'overallfeedbackopen'    => 1,
70
            'attemptclosed'          => 1,
71
            'correctnessclosed'      => 1,
72
            'maxmarksclosed'         => 1,
73
            'marksclosed'            => 1,
74
            'specificfeedbackclosed' => 1,
75
            'generalfeedbackclosed'  => 1,
76
            'rightanswerclosed'      => 1,
77
            'overallfeedbackclosed'  => 1,
78
            'questionsperpage'       => 1,
79
            'shuffleanswers'         => 1,
80
            'sumgrades'              => 0,
81
            'grade'                  => 100,
82
            'timecreated'            => time(),
83
            'timemodified'           => time(),
84
            'timelimit'              => 0,
85
            'overduehandling'        => 'autosubmit',
86
            'graceperiod'            => 86400,
87
            'quizpassword'           => '',
88
            'subnet'                 => '',
89
            'browsersecurity'        => '',
90
            'delay1'                 => 0,
91
            'delay2'                 => 0,
92
            'showuserpicture'        => 0,
93
            'showblocks'             => 0,
94
            'navmethod'              => QUIZ_NAVMETHOD_FREE,
95
        ];
96
 
97
        foreach ($defaultquizsettings as $name => $value) {
98
            if (!isset($record->{$name})) {
99
                $record->{$name} = $value;
100
            }
101
        }
102
 
103
        if (isset($record->gradepass)) {
104
            $record->gradepass = unformat_float($record->gradepass);
105
        }
106
 
107
        return parent::create_instance($record, (array)$options);
108
    }
109
 
110
    /**
111
     * Create a quiz attempt for a particular user at a particular course.
112
     *
113
     * @param int $quizid the quiz id (from the mdl_quit table, not cmid).
114
     * @param int $userid the user id.
115
     * @param array $forcedrandomquestions slot => questionid. Optional,
116
     *      used with random questions, to control which one is 'randomly' selected in that slot.
117
     * @param array $forcedvariants slot => variantno. Optional. Optional,
118
     *      used with question where get_num_variants is > 1, to control which
119
     *      variants is 'randomly' selected.
120
     * @return stdClass the new attempt.
121
     */
122
    public function create_attempt($quizid, $userid, array $forcedrandomquestions = [],
123
            array $forcedvariants = []) {
124
        // Build quiz object and load questions.
125
        $quizobj = quiz_settings::create($quizid, $userid);
126
 
127
        $attemptnumber = 1;
128
        $attempt = null;
129
 
130
        if ($attempts = quiz_get_user_attempts($quizid, $userid, 'all', true)) {
131
            // There is/are already an attempt/some attempts.
132
            // Take the last attempt.
133
            $attempt = end($attempts);
134
            // Take the attempt number of the last attempt and increase it.
135
            $attemptnumber = $attempt->attempt + 1;
136
        }
137
 
138
        return quiz_prepare_and_start_new_attempt($quizobj, $attemptnumber, $attempt, false,
139
                $forcedrandomquestions, $forcedvariants);
140
    }
141
 
142
    /**
143
     * Submit responses to a quiz attempt.
144
     *
145
     * To be realistic, you should ensure that $USER is set to the user whose attempt
146
     * it is before calling this.
147
     *
148
     * @param int $attemptid the id of the attempt which is being
149
     * @param array $responses array responses to submit. See description on
150
     *      {@link core_question_generator::get_simulated_post_data_for_questions_in_usage()}.
151
     * @param bool $checkbutton if simulate a click on the check button for each question, else simulate save.
152
     *      This should only be used with behaviours that have a check button.
153
     * @param bool $finishattempt if true, the attempt will be submitted.
154
     */
155
    public function submit_responses($attemptid, array $responses, $checkbutton, $finishattempt) {
156
        $questiongenerator = $this->datagenerator->get_plugin_generator('core_question');
157
 
158
        $attemptobj = quiz_attempt::create($attemptid);
159
 
160
        $postdata = $questiongenerator->get_simulated_post_data_for_questions_in_usage(
161
                $attemptobj->get_question_usage(), $responses, $checkbutton);
162
 
163
        $attemptobj->process_submitted_actions(time(), false, $postdata);
164
 
165
        // Bit if a hack for interactive behaviour.
166
        // TODO handle this in a more plugin-friendly way.
167
        if ($checkbutton) {
168
            $postdata = [];
169
            foreach ($responses as $slot => $notused) {
170
                $qa = $attemptobj->get_question_attempt($slot);
171
                if ($qa->get_behaviour() instanceof qbehaviour_interactive && $qa->get_behaviour()->is_try_again_state()) {
172
                    $postdata[$qa->get_control_field_name('sequencecheck')] = (string)$qa->get_sequence_check_count();
173
                    $postdata[$qa->get_flag_field_name()] = (string)(int)$qa->is_flagged();
174
                    $postdata[$qa->get_behaviour_field_name('tryagain')] = 1;
175
                }
176
            }
177
 
178
            if ($postdata) {
179
                $attemptobj->process_submitted_actions(time(), false, $postdata);
180
            }
181
        }
182
 
183
        if ($finishattempt) {
184
            $attemptobj->process_finish(time(), false);
185
        }
186
    }
187
 
188
    /**
189
     * Create a quiz override (either user or group).
190
     *
191
     * @param array $data must specify quizid, and one of userid or groupid.
192
     */
193
    public function create_override(array $data): void {
194
        global $DB;
195
 
196
        // Validate.
197
        if (!isset($data['quiz'])) {
198
            throw new coding_exception('Must specify quiz (id) when creating a quiz override.');
199
        }
200
 
201
        if (!isset($data['userid']) && !isset($data['groupid'])) {
202
            throw new coding_exception('Must specify one of userid or groupid when creating a quiz override.');
203
        }
204
 
205
        if (isset($data['userid']) && isset($data['groupid'])) {
206
            throw new coding_exception('Cannot specify both userid and groupid when creating a quiz override.');
207
        }
208
 
209
        // Create the override.
210
        $DB->insert_record('quiz_overrides', (object) $data);
211
 
212
        // Update any associated calendar events, if necessary.
213
        quiz_update_events($DB->get_record('quiz', ['id' => $data['quiz']], '*', MUST_EXIST));
214
    }
215
 
216
    /**
217
     * Create a quiz override (either user or group).
218
     *
219
     * @param array $data must specify quizid and a name.
220
     * @return stdClass the newly created quiz_grade_items row.
221
     */
222
    public function create_grade_item(array $data): stdClass {
223
        global $DB;
224
 
225
        // Validate.
226
        if (!isset($data['quizid'])) {
227
            throw new coding_exception('Must specify quizid when creating a quiz grade item.');
228
        }
229
 
230
        if (!isset($data['name'])) {
231
            throw new coding_exception('Must specify a name when creating a quiz grade item.');
232
        }
233
 
234
        if (clean_param($data['name'], PARAM_TEXT) !== $data['name']) {
235
            throw new coding_exception('Grade item name must be PARAM_TEXT.');
236
        }
237
 
238
        $data['sortorder'] = $DB->get_field('quiz_grade_items',
239
                'COALESCE(MAX(sortorder) + 1, 1)',
240
                ['quizid' => $data['quizid']]);
241
 
242
        // Create the grade item.
243
        $gradeitem = (object) $data;
244
        $gradeitem->id = $DB->insert_record('quiz_grade_items', $gradeitem);
245
        return $gradeitem;
246
    }
247
}