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
/**
18
 * Abstract class used as a base for the 3 screens.
19
 *
20
 * @package   gradereport_singleview
21
 * @copyright 2014 Moodle Pty Ltd (http://moodle.com)
22
 * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
23
 */
24
 
25
namespace gradereport_singleview\local\screen;
26
 
27
use context_course;
28
use grade_report;
29
use moodle_url;
30
use html_writer;
31
use grade_structure;
32
use grade_grade;
33
use grade_item;
34
use stdClass;
35
 
36
defined('MOODLE_INTERNAL') || die;
37
require_once($CFG->dirroot . '/grade/report/lib.php');
38
 
39
/**
40
 * Abstract class used as a base for the 3 screens.
41
 *
42
 * @package   gradereport_singleview
43
 * @copyright 2014 Moodle Pty Ltd (http://moodle.com)
44
 * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
45
 */
46
abstract class screen {
47
 
48
    /**
49
     * The id of the course
50
     * @var int $courseid
51
     */
52
    protected $courseid;
53
 
54
    /**
55
     * Either a user id or a grade_item id
56
     * @var int|null $itemid
57
     */
58
    protected $itemid;
59
 
60
    /**
61
     * The currently set groupid (if set)
62
     * @var int $groupid
63
     */
64
    protected $groupid;
65
 
66
    /**
67
     * The course context
68
     * @var context_course $context
69
     */
70
    protected $context;
71
 
72
    /**
73
     * The page number
74
     * @var int $page
75
     */
76
    protected $page;
77
 
78
    /**
79
     * Results per page
80
     * @var int $perpage
81
     */
82
    protected $perpage;
83
 
84
    /**
85
     * List of items on the page, they could be users or grade_items
86
     * @var array $items
87
     */
88
    protected $items;
89
 
90
    /** @var int Maximum number of students that can be shown on one page */
91
    protected static $maxperpage = 5000;
92
 
93
    /**
94
     * List of allowed values for 'perpage' setting
95
     * @var array $validperpage
96
     */
97
    protected static $validperpage = [20, 100];
98
 
99
    /**
100
     * To store course data
101
     * @var stdClass
102
     */
103
    protected $course;
104
 
105
    /**
106
     * General structure representing grade items in course
107
     * @var grade_structure
108
     */
109
    protected $structure;
110
 
111
    /**
112
     * Constructor
113
     *
114
     * @param int $courseid The course id
115
     * @param int|null $itemid The item id
116
     * @param int|null $groupid The group id
117
     */
118
    public function __construct(int $courseid, ?int $itemid, ?int $groupid = null) {
119
        global $DB;
120
 
121
        $this->courseid = $courseid;
122
        $this->itemid = $itemid;
123
        $this->groupid = $groupid;
124
 
125
        $this->context = context_course::instance($this->courseid);
126
        $this->course = $DB->get_record('course', ['id' => $courseid]);
127
 
128
        $this->page = optional_param('page', 0, PARAM_INT);
129
 
130
        $cache = \cache::make_from_params(\cache_store::MODE_SESSION, 'gradereport_singleview', 'perpage');
131
        $perpage = optional_param('perpage', null, PARAM_INT);
132
        if (!in_array($perpage, self::$validperpage) && ($perpage !== 0)) {
133
            // Get from cache.
134
            $perpage = $cache->get(get_class($this));
135
        } else {
136
            // Save to cache.
137
            $cache->set(get_class($this), $perpage);
138
        }
139
        if (isset($perpage) && $perpage) {
140
            $this->perpage = $perpage;
141
        } else {
142
            // Get from cache.
143
            $perpage = $cache->get(get_class($this));
144
            $this->perpage = ($perpage === 0) ? $perpage : min(self::$validperpage);
145
        }
146
 
147
        $this->init(empty($itemid));
148
    }
149
 
150
    /**
151
     * Cache the grade_structure class
152
     */
153
    public function setup_structure() {
154
        $this->structure = new grade_structure();
155
        $this->structure->modinfo = get_fast_modinfo($this->course);
156
    }
157
 
158
    /**
159
     * Create a nice link from a thing (user or grade_item).
160
     *
161
     * @param string $screen
162
     * @param int $itemid
163
     * @param bool|null $display Should we wrap this in an anchor ?
164
     * @return string The link
165
     */
166
    public function format_link(string $screen, int $itemid, bool $display = null): string {
167
        $url = new moodle_url('/grade/report/singleview/index.php', [
168
            'id' => $this->courseid,
169
            'item' => $screen,
170
            'itemid' => $itemid,
171
            'group' => $this->groupid,
172
        ]);
173
 
174
        if ($display) {
175
            return html_writer::link($url, $display);
176
        } else {
177
            return $url;
178
        }
179
    }
180
 
181
    /**
182
     * Get the grade_grade
183
     *
184
     * @param grade_item $item The grade_item
185
     * @param int $userid The user id
186
     * @return grade_grade
187
     */
188
    public function fetch_grade_or_default(grade_item $item, int $userid): grade_grade {
189
        $grade = grade_grade::fetch([
190
            'itemid' => $item->id, 'userid' => $userid
191
        ]);
192
 
193
        if (!$grade) {
194
            $default = new stdClass;
195
 
196
            $default->userid = $userid;
197
            $default->itemid = $item->id;
198
            $default->feedback = '';
199
 
200
            $grade = new grade_grade($default, false);
201
        }
202
 
203
        $grade->grade_item = $item;
204
 
205
        return $grade;
206
    }
207
 
208
    /**
209
     * Get the default heading for the screen.
210
     *
211
     * @return string
212
     */
213
    public function heading(): string {
214
        return get_string('entrypage', 'gradereport_singleview');
215
    }
216
 
217
    /**
218
     * Override this to init the screen.
219
     *
220
     * @param boolean $selfitemisempty True if no item has been selected yet.
221
     */
222
    abstract public function init(bool $selfitemisempty = false);
223
 
224
    /**
225
     * Get the type of items in the list.
226
     *
227
     * @return null|string
228
     */
229
    abstract public function item_type(): ?string;
230
 
231
    /**
232
     * Get the entire screen as a string.
233
     *
234
     * @return string
235
     */
236
    abstract public function html(): string;
237
 
238
    /**
239
     * Does this screen support paging?
240
     *
241
     * @return bool
242
     */
243
    public function supports_paging(): bool {
244
        return true;
245
    }
246
 
247
    /**
248
     * Default pager
249
     *
250
     * @return string
251
     */
252
    public function pager(): string {
253
        return '';
254
    }
255
 
256
    /**
257
     * Initialise the js for this screen.
258
     */
259
    public function js() {
260
        global $PAGE;
261
 
262
        $module = [
263
            'name' => 'gradereport_singleview',
264
            'fullpath' => '/grade/report/singleview/js/singleview.js',
265
            'requires' => ['base', 'dom', 'event', 'event-simulate', 'io-base']
266
        ];
267
 
268
        $PAGE->requires->strings_for_js(['overridenoneconfirm', 'removeoverride', 'removeoverridesave'],
269
            'gradereport_singleview');
270
        $PAGE->requires->js_init_call('M.gradereport_singleview.init', [], false, $module);
271
    }
272
 
273
    /**
274
     * Process the data from a form submission.
275
     *
276
     * @param array|object $data
277
     * @return stdClass of warnings
278
     */
279
    public function process($data): stdClass {
280
        $warnings = [];
281
 
282
        $fields = $this->definition();
283
 
284
        // Avoiding execution timeouts when updating
285
        // a large amount of grades.
286
        $progress = 0;
287
        $progressbar = new \core\progress\display_if_slow();
288
        $progressbar->start_html();
289
        $progressbar->start_progress(get_string('savegrades', 'gradereport_singleview'), count((array) $data) - 1);
290
        $changecount = [];
291
        // This array is used to determine if the override should be excluded from being counted as a change.
292
        $ignorevalues = [];
293
 
294
        foreach ($data as $varname => $throw) {
295
            $progressbar->progress($progress);
296
            $progress++;
297
            if (preg_match("/(\w+)_(\d+)_(\d+)/", $varname, $matches)) {
298
                $itemid = $matches[2];
299
                $userid = $matches[3];
300
            } else {
301
                continue;
302
            }
303
 
304
            $gradeitem = grade_item::fetch([
305
                'id' => $itemid, 'courseid' => $this->courseid
306
            ]);
307
 
308
            if (preg_match('/^old[oe]{1}/', $varname)) {
309
                $elementname = preg_replace('/^old/', '', $varname);
310
                if (!isset($data->$elementname)) {
311
                    // Decrease the progress because we've increased the
312
                    // size of the array we are iterating through.
313
                    $progress--;
314
                    $data->$elementname = false;
315
                }
316
            }
317
 
318
            if (!in_array($matches[1], $fields)) {
319
                continue;
320
            }
321
 
322
            if (!$gradeitem) {
323
                continue;
324
            }
325
 
326
            $grade = $this->fetch_grade_or_default($gradeitem, $userid);
327
 
328
            $classname = '\\gradereport_singleview\\local\\ui\\' . $matches[1];
329
            $element = new $classname($grade);
330
 
331
            $name = $element->get_name();
332
            $oldname = "old$name";
333
 
334
            $posted = $data->$name;
335
 
336
            $format = $element->determine_format();
337
 
338
            if ($format->is_textbox() and trim($data->$name) === '') {
339
                $data->$name = null;
340
            }
341
 
342
            // Same value; skip.
343
            if (isset($data->$oldname) && $data->$oldname == $posted) {
344
                continue;
345
            }
346
 
347
            // If the user submits Exclude grade elements without the proper.
348
            // permissions then we should refuse to update.
349
            if ($matches[1] === 'exclude' && !has_capability('moodle/grade:manage', $this->context)){
350
                $warnings[] = get_string('nopermissions', 'error', get_string('grade:manage', 'role'));
351
                continue;
352
            }
353
 
354
            $msg = $element->set($posted);
355
            // Value to check against our list of matchelements to ignore.
356
            $check = explode('_', $varname, 2);
357
 
358
            // Optional type.
359
            if (!empty($msg)) {
360
                $warnings[] = $msg;
361
                if ($element instanceof \gradereport_singleview\local\ui\finalgrade) {
362
                    // Add this value to this list so that the override object that is coming next will also be skipped.
363
                    $ignorevalues[$check[1]] = $check[1];
364
                    // This item wasn't changed so don't add to the changecount.
365
                    continue;
366
                }
367
            }
368
            // Check to see if this value has already been skipped.
369
            if (array_key_exists($check[1], $ignorevalues)) {
370
                continue;
371
            }
372
            if (preg_match('/_(\d+)_(\d+)/', $varname, $matchelement)) {
373
                $changecount[$matchelement[0]] = 1;
374
            }
375
        }
376
 
377
        // Some post-processing.
378
        $eventdata = new stdClass;
379
        $eventdata->warnings = $warnings;
380
        $eventdata->post_data = $data;
381
        $eventdata->instance = $this;
382
        $eventdata->changecount = $changecount;
383
 
384
        $progressbar->end_html();
385
 
386
        return $eventdata;
387
    }
388
 
389
    /**
390
     * By default, there are no options.
391
     * @return array
392
     */
393
    public function options(): array {
394
        return [];
395
    }
396
 
397
    /**
398
     * Should we show the group selector?
399
     * @return bool
400
     */
401
    public function display_group_selector(): bool {
402
        return true;
403
    }
404
 
405
    /**
406
     * Should we show the next prev selector?
407
     * @return bool
408
     */
409
    public function supports_next_prev(): bool {
410
        return true;
411
    }
412
 
413
    /**
414
     * Load a valid list of users for this gradebook as the screen "items".
415
     *
416
     * @deprecated since Moodle 4.3
417
     * @return array A list of enroled users.
418
     */
419
    protected function load_users(): array {
420
        debugging('The function ' . __FUNCTION__ . '() is deprecated. Please use grade_report::get_gradable_users() instead.',
421
            DEBUG_DEVELOPER);
422
 
423
        return grade_report::get_gradable_users($this->courseid, $this->groupid);
424
    }
425
 
426
    /**
427
     * Allow selection of number of items to display per page.
428
     * @return string
429
     */
430
    public function perpage_select(): string {
431
        global $PAGE, $OUTPUT;
432
 
433
        $url = new moodle_url($PAGE->url);
434
        $numusers = count($this->items);
435
        // Print per-page dropdown.
436
        $pagingoptions = self::$validperpage;
437
        if ($this->perpage) {
438
            $pagingoptions[] = $this->perpage; // To make sure the current preference is within the options.
439
        }
440
        $pagingoptions = array_unique($pagingoptions);
441
        sort($pagingoptions);
442
        $pagingoptions = array_combine($pagingoptions, $pagingoptions);
443
        if ($numusers > self::$maxperpage) {
444
            $pagingoptions['0'] = self::$maxperpage;
445
        } else {
446
            $pagingoptions['0'] = get_string('all');
447
        }
448
 
449
        $perpagedata = [
450
            'baseurl' => $url->out(false),
451
            'options' => []
452
        ];
453
        foreach ($pagingoptions as $key => $name) {
454
            $perpagedata['options'][] = [
455
                'name' => $name,
456
                'value' => $key,
457
                'selected' => $key == $this->perpage,
458
            ];
459
        }
460
 
461
        // The number of students per page is always limited even if it is claimed to be unlimited.
462
        $this->perpage = $this->perpage ?: self::$maxperpage;
463
        $perpagedata['pagingbar'] = $this->pager();
464
        return $OUTPUT->render_from_template('gradereport_singleview/perpage', $perpagedata);;
465
    }
466
}