lib.php 77.8 KB
Newer Older
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
<?php

// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.


/**
 * Functions used by gradebook plugins and reports.
 *
tjhunt's avatar
tjhunt committed
22
 * @package   moodlecore
23
24
25
 * @copyright 2009 Petr Skoda and Nicolas Connault
 * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
 */
nicolasconnault's avatar
nicolasconnault committed
26

27
28
require_once $CFG->libdir.'/gradelib.php';

29
30
/**
 * This class iterates over all users that are graded in a course.
31
 * Returns detailed info about users and their grades.
32
33
34
 *
 * @author Petr Skoda <skodak@moodle.org>
 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
35
36
 */
class graded_users_iterator {
37
38
39
40
41
42
43
44
45
46
    public $course;
    public $grade_items;
    public $groupid;
    public $users_rs;
    public $grades_rs;
    public $gradestack;
    public $sortfield1;
    public $sortorder1;
    public $sortfield2;
    public $sortorder2;
47
48
49

    /**
     * Constructor
50
51
52
53
     *
     * @param object $course A course object
     * @param array  $grade_items array of grade items, if not specified only user info returned
     * @param int    $groupid iterate only group users if present
54
55
56
57
     * @param string $sortfield1 The first field of the users table by which the array of users will be sorted
     * @param string $sortorder1 The order in which the first sorting field will be sorted (ASC or DESC)
     * @param string $sortfield2 The second field of the users table by which the array of users will be sorted
     * @param string $sortorder2 The order in which the second sorting field will be sorted (ASC or DESC)
58
     */
59
60
61
    public function graded_users_iterator($course, $grade_items=null, $groupid=0,
                                          $sortfield1='lastname', $sortorder1='ASC',
                                          $sortfield2='firstname', $sortorder2='ASC') {
62
63
64
        $this->course      = $course;
        $this->grade_items = $grade_items;
        $this->groupid     = $groupid;
65
66
67
68
        $this->sortfield1  = $sortfield1;
        $this->sortorder1  = $sortorder1;
        $this->sortfield2  = $sortfield2;
        $this->sortorder2  = $sortorder2;
69
70
71
72
73
74
75
76

        $this->gradestack  = array();
    }

    /**
     * Initialise the iterator
     * @return boolean success
     */
77
78
    public function init() {
        global $CFG, $DB;
79
80
81
82
83
84
85
86
87
88

        $this->close();

        grade_regrade_final_grades($this->course->id);
        $course_item = grade_item::fetch_course_item($this->course->id);
        if ($course_item->needsupdate) {
            // can not calculate all final grades - sorry
            return false;
        }

89
90
        list($gradebookroles_sql, $params) =
            $DB->get_in_or_equal(explode(',', $CFG->gradebookroles), SQL_PARAMS_NAMED, 'grbr0');
91
92
93
94

        $relatedcontexts = get_related_contexts_string(get_context_instance(CONTEXT_COURSE, $this->course->id));

        if ($this->groupid) {
95
            $groupsql = "INNER JOIN {groups_members} gm ON gm.userid = u.id";
96
            $groupwheresql = "AND gm.groupid = :groupid";
97
            // $params contents: gradebookroles
98
            $params['groupid'] = $this->groupid;
99
100
101
102
103
        } else {
            $groupsql = "";
            $groupwheresql = "";
        }

104
105
106
107
108
109
110
111
112
        if (empty($this->sortfield1)) {
            // we must do some sorting even if not specified
            $ofields = ", u.id AS usrt";
            $order   = "usrt ASC";

        } else {
            $ofields = ", u.$this->sortfield1 AS usrt1";
            $order   = "usrt1 $this->sortorder1";
            if (!empty($this->sortfield2)) {
113
                $ofields .= ", u.$this->sortfield2 AS usrt2";
114
115
116
                $order   .= ", usrt2 $this->sortorder2";
            }
            if ($this->sortfield1 != 'id' and $this->sortfield2 != 'id') {
117
118
                // user order MUST be the same in both queries,
                // must include the only unique user->id if not already present
119
120
121
122
123
                $ofields .= ", u.id AS usrt";
                $order   .= ", usrt ASC";
            }
        }

124
        // $params contents: gradebookroles and groupid (for $groupwheresql)
125
        $users_sql = "SELECT u.* $ofields
126
127
                        FROM {user} u
                             INNER JOIN {role_assignments} ra ON u.id = ra.userid
128
                             $groupsql
129
                       WHERE ra.roleid $gradebookroles_sql
130
                             AND ra.contextid $relatedcontexts
131
132
                             $groupwheresql
                    ORDER BY $order";
133

134
        $this->users_rs = $DB->get_recordset_sql($users_sql, $params);
135
136
137

        if (!empty($this->grade_items)) {
            $itemids = array_keys($this->grade_items);
138
            list($itemidsql, $grades_params) = $DB->get_in_or_equal($itemids, SQL_PARAMS_NAMED, 'items0');
139
            $params = array_merge($params, $grades_params);
140

141
            // $params contents: gradebookroles, groupid (for $groupwheresql) and itemids
142
            $grades_sql = "SELECT g.* $ofields
143
144
145
                             FROM {grade_grades} g
                                  INNER JOIN {user} u ON g.userid = u.id
                                  INNER JOIN {role_assignments} ra ON u.id = ra.userid
146
                                  $groupsql
147
                            WHERE ra.roleid $gradebookroles_sql
148
149
                                  AND ra.contextid $relatedcontexts
                                  $groupwheresql
150
                                  AND g.itemid $itemidsql
151
                         ORDER BY $order, g.itemid ASC";
152
            $this->grades_rs = $DB->get_recordset_sql($grades_sql, $params);
153
154
        } else {
            $this->grades_rs = false;
155
        }
156

157
158
159
160
161
162
163
164
        return true;
    }

    /**
     * Returns information about the next user
     * @return mixed array of user info, all grades and feedback or null when no more users found
     */
    function next_user() {
165
        if (!$this->users_rs) {
166
167
168
            return false; // no users present
        }

169
        if (!$this->users_rs->valid()) {
170
171
172
173
            if ($current = $this->_pop()) {
                // this is not good - user or grades updated between the two reads above :-(
            }

174
            return false; // no more users
175
176
177
        } else {
            $user = $this->users_rs->current();
            $this->users_rs->next();
178
179
        }

180
        // find grades of this user
181
182
183
184
185
186
        $grade_records = array();
        while (true) {
            if (!$current = $this->_pop()) {
                break; // no more grades
            }

187
188
189
190
            if (empty($current->userid)) {
                break;
            }

191
192
            if ($current->userid != $user->id) {
                // grade of the next user, we have all for this user
193
194
195
196
197
198
199
200
201
202
                $this->_push($current);
                break;
            }

            $grade_records[$current->itemid] = $current;
        }

        $grades = array();
        $feedbacks = array();

203
        if (!empty($this->grade_items)) {
204
205
206
207
208
209
210
211
212
213
            foreach ($this->grade_items as $grade_item) {
                if (array_key_exists($grade_item->id, $grade_records)) {
                    $feedbacks[$grade_item->id]->feedback       = $grade_records[$grade_item->id]->feedback;
                    $feedbacks[$grade_item->id]->feedbackformat = $grade_records[$grade_item->id]->feedbackformat;
                    unset($grade_records[$grade_item->id]->feedback);
                    unset($grade_records[$grade_item->id]->feedbackformat);
                    $grades[$grade_item->id] = new grade_grade($grade_records[$grade_item->id], false);
                } else {
                    $feedbacks[$grade_item->id]->feedback       = '';
                    $feedbacks[$grade_item->id]->feedbackformat = FORMAT_MOODLE;
214
215
                    $grades[$grade_item->id] =
                        new grade_grade(array('userid'=>$user->id, 'itemid'=>$grade_item->id), false);
216
                }
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
            }
        }

        $result = new object();
        $result->user      = $user;
        $result->grades    = $grades;
        $result->feedbacks = $feedbacks;

        return $result;
    }

    /**
     * Close the iterator, do not forget to call this function.
     * @return void
     */
    function close() {
233
        if ($this->users_rs) {
234
            $this->users_rs->close();
235
            $this->users_rs = null;
236
        }
237
        if ($this->grades_rs) {
238
            $this->grades_rs->close();
239
            $this->grades_rs = null;
240
241
242
243
        }
        $this->gradestack = array();
    }

244

245
    /**
246
247
248
249
250
     * _push
     *
     * @param grade_grade $grade Grade object
     *
     * @return void
251
252
253
254
255
     */
    function _push($grade) {
        array_push($this->gradestack, $grade);
    }

256

257
    /**
258
259
260
     * _pop
     *
     * @return void
261
262
     */
    function _pop() {
263
        global $DB;
264
        if (empty($this->gradestack)) {
265
            if (!$this->grades_rs) {
266
                return null; // no grades present
267
268
            }

269
            if ($this->grades_rs->next()) {
270
                return null; // no more grades
271
272
            }

273
            return $this->grades_rs->current();
274
275
276
277
278
279
        } else {
            return array_pop($this->gradestack);
        }
    }
}

280
281
282
/**
 * Print a selection popup form of the graded users in a course.
 *
283
 * @param int    $course id of the course
284
 * @param string $actionpage The page receiving the data from the popoup form
285
286
287
288
 * @param int    $userid   id of the currently selected user (or 'all' if they are all selected)
 * @param int    $groupid id of requested group, 0 means all
 * @param int    $includeall bool include all option
 * @param bool   $return If true, will return the HTML, otherwise, will print directly
289
290
 * @return null
 */
291
function print_graded_users_selector($course, $actionpage, $userid=0, $groupid=0, $includeall=true, $return=false) {
292
    global $CFG, $USER;
293

294
295
296
    if (is_null($userid)) {
        $userid = $USER->id;
    }
297
298
299
300
301

    $context = get_context_instance(CONTEXT_COURSE, $course->id);

    $menu = array(); // Will be a list of userid => user name

302
    $gui = new graded_users_iterator($course, null, $groupid);
303
    $gui->init();
304

305

306
    $label = get_string('selectauser', 'grades');
307
    if ($includeall) {
308
        $menu[0] = get_string('allusers', 'grades');
309
        $label = get_string('selectalloroneuser', 'grades');
310
    }
311

312
313
    $nextuser = $gui->next_user();

314
315
316
317
318
319
320
    while ($userdata = $gui->next_user()) {
        $user = $userdata->user;
        $menu[$user->id] = fullname($user);
    }

    $gui->close();

321
    if ($includeall) {
322
323
324
        $menu[0] .= " (" . (count($menu) - 1) . ")";
    }

325
326
327
    return popup_form($CFG->wwwroot.'/grade/' . $actionpage . '&amp;userid=',
                      $menu, 'choosegradeduser', $userid, null, '', '',
                      $return, 'self', $label);
328
329
}

skodak's avatar
skodak committed
330
331
332
/**
 * Print grading plugin selection popup form.
 *
333
 * @param array   $plugin_info An array of plugins containing information for the selector
skodak's avatar
skodak committed
334
 * @param boolean $return return as string
335
 *
skodak's avatar
skodak committed
336
337
 * @return nothing or string if $return true
 */
338
339
340
341
342
343
344
345
346
347
348
349
function print_grade_plugin_selector($plugin_info, $return=false) {
    global $CFG;

    $menu = array();
    $count = 0;
    $active = '';

    foreach ($plugin_info as $plugin_type => $plugins) {
        if ($plugin_type == 'strings') {
            continue;
        }

350
        $first_plugin = reset($plugins);
351

352
        $menu[$first_plugin->link.'&amp;'] = '--'.$plugin_info['strings'][$plugin_type];
353

354
        if (empty($plugins->id)) {
355
            foreach ($plugins as $plugin) {
356
                $menu[$plugin->link] = $plugin->string;
357
358
359
360
361
                $count++;
            }
        }
    }

362
    // finally print/return the popup form
363
    if ($count > 1) {
364
365
        $select = popup_form('', $menu, 'choosepluginreport', '',
                             get_string('chooseaction', 'grades'), '', '', true, 'self');
366
367
368
369
370
        if ($return) {
            return $select;
        } else {
            echo $select;
        }
371
372
373
374
375
376
377
378
379
    } else {
        // only one option - no plugin selector needed
        return '';
    }
}

/**
 * Print grading plugin selection tab-based navigation.
 *
380
381
382
 * @param string  $active_type type of plugin on current page - import, export, report or edit
 * @param string  $active_plugin active plugin type - grader, user, cvs, ...
 * @param array   $plugin_info Array of plugins
383
 * @param boolean $return return as string
384
 *
385
386
 * @return nothing or string if $return true
 */
387
function grade_print_tabs($active_type, $active_plugin, $plugin_info, $return=false) {
388
    global $CFG, $COURSE;
389
    
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
    if (!isset($currenttab)) {
        $currenttab = '';
    }

    $tabs = array();
    $top_row  = array();
    $bottom_row = array();
    $inactive = array($active_plugin);
    $activated = array();

    $count = 0;
    $active = '';

    foreach ($plugin_info as $plugin_type => $plugins) {
        if ($plugin_type == 'strings') {
            continue;
        }

        // If $plugins is actually the definition of a child-less parent link:
409
410
411
412
        if (!empty($plugins->id)) {
            $string = $plugins->string;
            if (!empty($plugin_info[$active_type]->parent)) {
                $string = $plugin_info[$active_type]->parent->string;
413
414
            }

415
            $top_row[] = new tabobject($plugin_type, $plugins->link, $string);
416
417
418
419
            continue;
        }

        $first_plugin = reset($plugins);
420
        $url = $first_plugin->link;
421
422
423
424
425
426
427
428
429

        if ($plugin_type == 'report') {
            $url = $CFG->wwwroot.'/grade/report/index.php?id='.$COURSE->id;
        }

        $top_row[] = new tabobject($plugin_type, $url, $plugin_info['strings'][$plugin_type]);

        if ($active_type == $plugin_type) {
            foreach ($plugins as $plugin) {
430
431
432
                $bottom_row[] = new tabobject($plugin->id, $plugin->link, $plugin->string);
                if ($plugin->id == $active_plugin) {
                    $inactive = array($plugin->id);
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
                }
            }
        }
    }

    $tabs[] = $top_row;
    $tabs[] = $bottom_row;

    if ($return) {
        return print_tabs($tabs, $active_type, $inactive, $activated, true);
    } else {
        print_tabs($tabs, $active_type, $inactive, $activated);
    }
}

448
449
450
451
452
453
454
455
456
/**
 * grade_get_plugin_info
 *
 * @param int    $courseid The course id
 * @param string $active_type type of plugin on current page - import, export, report or edit
 * @param string $active_plugin active plugin type - grader, user, cvs, ...
 *
 * @return array
 */
457
function grade_get_plugin_info($courseid, $active_type, $active_plugin) {
458
459
    global $CFG;

460
    $context = get_context_instance(CONTEXT_COURSE, $courseid);
461

462
    $plugin_info = array();
463
    $count = 0;
464
    $active = '';
465
466
467
468
469
470
471
472
473
474
    $url_prefix = $CFG->wwwroot . '/grade/';

    // Language strings
    $plugin_info['strings'] = array(
        'report' => get_string('view'),
        'edittree' => get_string('edittree', 'grades'),
        'scale' => get_string('scales'),
        'outcome' => get_string('outcomes', 'grades'),
        'letter' => get_string('letters', 'grades'),
        'export' => get_string('export', 'grades'),
475
        'import' => get_string('import'),
476
        'preferences' => get_string('mypreferences', 'grades'),
477
478
479
480
481
482
483
484
485
486
        'settings' => get_string('settings'));

    // Settings tab first
    if (has_capability('moodle/course:update', $context)) {
        $url = $url_prefix.'edit/settings/index.php?id='.$courseid;

        if ($active_type == 'settings' and $active_plugin == 'course') {
            $active = $url;
        }

487
        $plugin_info['settings'] = array();
488
489
        $plugin_info['settings']['course'] =
                new grade_plugin_info('coursesettings', $url, get_string('course'));
490
491
492
        $count++;
    }

493

494
495
496
    // report plugins with its special structure

    // Get all installed reports
497
    if ($reports = get_plugin_list('gradereport')) {
498
499

        // Remove ones we can't see
500
        foreach ($reports as $plugin => $unused) {
501
502
            if (!has_capability('gradereport/'.$plugin.':view', $context)) {
                unset($reports[$key]);
503
504
            }
        }
505
    }
506

507
    $reportnames = array();
508

509
    if (!empty($reports)) {
510
        foreach ($reports as $plugin => $plugindir) {
511
            $pluginstr = get_string('modulename', 'gradereport_'.$plugin);
512
            $url = $url_prefix.'report/'.$plugin.'/index.php?id='.$courseid;
513
514
            if ($active_type == 'report' and $active_plugin == $plugin ) {
                $active = $url;
515
            }
516
            $reportnames[$plugin] = new grade_plugin_info($plugin, $url, $pluginstr);
517
518

            // Add link to preferences tab if such a page exists
519
            if (file_exists($plugindir.'/preferences.php')) {
520
                $pref_url = $url_prefix.'report/'.$plugin.'/preferences.php?id='.$courseid;
521
                $plugin_info['preferences'][$plugin] = new grade_plugin_info($plugin, $pref_url, $pluginstr);
522
523
            }

524
            $count++;
525
        }
526
        asort($reportnames);
527
    }
528
    if (!empty($reportnames)) {
529
530
531
        $plugin_info['report']=$reportnames;
    }

532
    // editing scripts - not real plugins
533
534
535
536
537
538
    if (has_capability('moodle/grade:manage', $context)
      or has_capability('moodle/grade:manageletters', $context)
      or has_capability('moodle/course:managescales', $context)
      or has_capability('moodle/course:update', $context)) {

        if (has_capability('moodle/grade:manage', $context)) {
539
540
541
542
            $url = $url_prefix.'edit/tree/index.php?sesskey='.sesskey().
                    '&amp;showadvanced=0&amp;id='.$courseid;
            $url_adv = $url_prefix.'edit/tree/index.php?sesskey='.sesskey().
                    '&amp;showadvanced=1&amp;id='.$courseid;
543
544
545

            if ($active_type == 'edittree' and $active_plugin == 'simpleview') {
                $active = $url;
546
            } else if ($active_type == 'edittree' and $active_plugin == 'fullview') {
547
548
549
550
                $active = $url_adv;
            }

            $plugin_info['edittree'] = array();
551
552
553
            $plugin_info['edittree']['simpleview'] =
                    new grade_plugin_info('simpleview', $url, get_string('simpleview', 'grades'));
            $plugin_info['edittree']['fullview'] =
554
                    new grade_plugin_info('fullview', $url_adv, get_string('fullview', 'grades'));
555
556
557
558
559
            $count++;
        }

        if (has_capability('moodle/course:managescales', $context)) {
            $url = $url_prefix.'edit/scale/index.php?id='.$courseid;
560

561
562
563
            if ($active_type == 'scale' and is_null($active_plugin)) {
                $active = $url;
            }
564

565
566
            $plugin_info['scale'] = array();

567
            if ($active_type == 'scale' and $active_plugin == 'edit') {
568
569
                $edit_url = $url_prefix.'edit/scale/edit.php?courseid='.$courseid.
                        '&amp;id='.optional_param('id', 0, PARAM_INT);
570
                $active = $edit_url;
571
572
573
                $parent = new grade_plugin_info('scale', $url, get_string('scales'));
                $plugin_info['scale']['view'] =
                        new grade_plugin_info('edit', $edit_url, get_string('edit'), $parent);
574
            } else {
575
576
                $plugin_info['scale']['view'] =
                        new grade_plugin_info('scale', $url, get_string('view'));
577
578
            }

579
580
581
582
583
584
585
586
587
588
589
590
            $count++;
        }

        if (!empty($CFG->enableoutcomes) && (has_capability('moodle/grade:manage', $context) or
                                             has_capability('moodle/course:update', $context))) {

            $url_course = $url_prefix.'edit/outcome/course.php?id='.$courseid;
            $url_edit = $url_prefix.'edit/outcome/index.php?id='.$courseid;

            $plugin_info['outcome'] = array();

            if (has_capability('moodle/course:update', $context)) {  // Default to course assignment
591
592
593
594
                $plugin_info['outcome']['course'] =
                        new grade_plugin_info('course', $url_course, get_string('outcomescourse', 'grades'));
                $plugin_info['outcome']['edit'] =
                        new grade_plugin_info('edit', $url_edit, get_string('editoutcomes', 'grades'));
595
            } else {
596
597
                $plugin_info['outcome'] =
                        new grade_plugin_info('edit', $url_course, get_string('outcomescourse', 'grades'));
598
599
600
601
            }

            if ($active_type == 'outcome' and is_null($active_plugin)) {
                $active = $url_edit;
602
            } else if ($active_type == 'outcome' and $active_plugin == 'course' ) {
603
                $active = $url_course;
604
            } else if ($active_type == 'outcome' and $active_plugin == 'edit' ) {
605
                $active = $url_edit;
606
607
608
            } else if ($active_type == 'outcome' and $active_plugin == 'import') {
                $plugin_info['outcome']['import'] =
                        new grade_plugin_info('import', null, get_string('importoutcomes', 'grades'));
609
610
611
612
613
            }

            $count++;
        }

614
615
        if (has_capability('moodle/grade:manage', $context) or
                    has_capability('moodle/grade:manageletters', $context)) {
616
617
618
619
620
621
            $course_context = get_context_instance(CONTEXT_COURSE, $courseid);
            $url = $url_prefix.'edit/letter/index.php?id='.$courseid;
            $url_edit = $url_prefix.'edit/letter/edit.php?id='.$course_context->id;

            if ($active_type == 'letter' and $active_plugin == 'view' ) {
                $active = $url;
622
            } else if ($active_type == 'letter' and $active_plugin == 'edit' ) {
623
624
625
626
                $active = $url_edit;
            }

            $plugin_info['letter'] = array();
627
628
            $plugin_info['letter']['view'] = new grade_plugin_info('view', $url, get_string('view'));
            $plugin_info['letter']['edit'] = new grade_plugin_info('edit', $url_edit, get_string('edit'));
629
630
            $count++;
        }
631
632
    }

633
    // standard import plugins
634
635
    if ($imports = get_plugin_list('gradeimport')) { // Get all installed import plugins
        foreach ($imports as $plugin => $plugindir) { // Remove ones we can't see
636
637
            if (!has_capability('gradeimport/'.$plugin.':view', $context)) {
                unset($imports[$key]);
638
639
640
            }
        }
    }
641
642
643
    $importnames = array();
    if (!empty($imports)) {
        foreach ($imports as $plugin) {
644
            $pluginstr = get_string('modulename', 'gradeimport_'.$plugin);
645
            $url = $url_prefix.'import/'.$plugin.'/index.php?id='.$courseid;
646
            if ($active_type == 'import' and $active_plugin == $plugin ) {
647
648
                $active = $url;
            }
649
            $importnames[$plugin] = new grade_plugin_info($plugin, $url, $pluginstr);
650
            $count++;
651
        }
652
        asort($importnames);
653
    }
654
    if (!empty($importnames)) {
655
        $plugin_info['import']=$importnames;
656
657
    }

658
    // standard export plugins
659
    if ($exports = get_plugin_list('gradeexport')) { // Get all installed export plugins
660
        foreach ($exports as $key => $plugin) { // Remove ones we can't see
661
662
            if (!has_capability('gradeexport/'.$plugin.':view', $context)) {
                unset($exports[$key]);
663
664
            }
        }
665
    }
666
667
    $exportnames = array();
    if (!empty($exports)) {
668
        foreach ($exports as $plugin => $plugindir) {
669
            $pluginstr = get_string('modulename', 'gradeexport_'.$plugin);
670
            $url = $url_prefix.'export/'.$plugin.'/index.php?id='.$courseid;
671
            if ($active_type == 'export' and $active_plugin == $plugin ) {
672
673
                $active = $url;
            }
674
            $exportnames[$plugin] = new grade_plugin_info($plugin, $url, $pluginstr);
675
            $count++;
676
        }
677
        asort($exportnames);
678
    }
679

680
    if (!empty($exportnames)) {
681
        $plugin_info['export']=$exportnames;
682
    }
683

684
685
686
    // Key managers
    if ($CFG->gradepublishing) {
        $keymanager_url = $url_prefix.'export/keymanager.php?id='.$courseid;
687
688
        $plugin_info['export']['keymanager'] =
                new grade_plugin_info('keymanager', $keymanager_url, get_string('keymanager', 'grades'));
689
690
691
692
693
694
        if ($active_type == 'export' and $active_plugin == 'keymanager' ) {
            $active = $keymanager_url;
        }
        $count++;

        $keymanager_url = $url_prefix.'import/keymanager.php?id='.$courseid;
695
696
        $plugin_info['import']['keymanager'] =
                new grade_plugin_info('keymanager', $keymanager_url, get_string('keymanager', 'grades'));
697
698
699
700
701
702
703
        if ($active_type == 'import' and $active_plugin == 'keymanager' ) {
            $active = $keymanager_url;
        }
        $count++;
    }


704
    foreach ($plugin_info as $plugin_type => $plugins) {
705
706
        if (!empty($plugins->id) && $active_plugin == $plugins->id) {
            $plugin_info['strings']['active_plugin_str'] = $plugins->string;
707
            break;
708
        }
709
        foreach ($plugins as $plugin) {
710
711
712
713
            if (is_a($plugin, 'grade_plugin_info')) {
                if ($active_plugin == $plugin->id) {
                    $plugin_info['strings']['active_plugin_str'] = $plugin->string;
                }
714
715
            }
        }
716
    }
717

718
    // Put settings last
719
720
721
722
723
724
725
726
727
728
729
730
731
    if (!empty($plugin_info['settings'])) {
        $settings = $plugin_info['settings'];
        unset($plugin_info['settings']);
        $plugin_info['settings'] = $settings;
    }

    // Put preferences last
    if (!empty($plugin_info['preferences'])) {
        $prefs = $plugin_info['preferences'];
        unset($plugin_info['preferences']);
        $plugin_info['preferences'] = $prefs;
    }

732
733
734
735
736
737
738
    // Check import and export caps
    if (!has_capability('moodle/grade:export', $context)) {
        unset($plugin_info['export']);
    }
    if (!has_capability('moodle/grade:import', $context)) {
        unset($plugin_info['import']);
    }
739
740
    return $plugin_info;
}
741

742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
/**
 * A simple class containing info about grade plugins.
 * Can be subclassed for special rules
 *
 * @package moodlecore
 * @copyright 2009 Nicolas Connault
 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
 */
class grade_plugin_info {
    /**
     * A unique id for this plugin
     *
     * @var mixed
     */
    public $id;
    /**
     * A URL to access this plugin
     *
     * @var mixed
     */
    public $link;
    /**
     * The name of this plugin
     *
     * @var mixed
     */
    public $string;
    /**
     * Another grade_plugin_info object, parent of the current one
     *
     * @var mixed
     */
    public $parent;

    /**
     * Constructor
     *
     * @param int $id A unique id for this plugin
     * @param string $link A URL to access this plugin
     * @param string $string The name of this plugin
     * @param object $parent Another grade_plugin_info object, parent of the current one
     *
     * @return void
     */
    public function __construct($id, $link, $string, $parent=null) {
        $this->id = $id;
        $this->link = $link;
        $this->string = $string;
        $this->parent = $parent;
    }
}

nicolasconnault's avatar
nicolasconnault committed
794
795
796
797
798
799
800
/**
 * Prints the page headers, breadcrumb trail, page heading, (optional) dropdown navigation menu and
 * (optional) navigation tabs for any gradebook page. All gradebook pages MUST use these functions
 * in favour of the usual print_header(), print_header_simple(), print_heading() etc.
 * !IMPORTANT! Use of tabs.php file in gradebook pages is forbidden unless tabs are switched off at
 * the site level for the gradebook ($CFG->grade_navmethod = GRADE_NAVMETHOD_DROPDOWN).
 *
801
802
803
804
805
 * @param int     $courseid Course id
 * @param string  $active_type The type of the current page (report, settings,
 *                             import, export, scales, outcomes, letters)
 * @param string  $active_plugin The plugin of the current page (grader, fullview etc...)
 * @param string  $heading The heading of the page. Tries to guess if none is given
nicolasconnault's avatar
nicolasconnault committed
806
 * @param boolean $return Whether to return (true) or echo (false) the HTML generated by this function
807
808
809
 * @param string  $bodytags Additional attributes that will be added to the <body> tag
 * @param string  $buttons Additional buttons to display on the page
 * @param array   $extracss An array of additional stylesheets to load (relative paths)
nicolasconnault's avatar
nicolasconnault committed
810
811
812
 *
 * @return string HTML code or nothing if $return == false
 */
813
function print_grade_page_head($courseid, $active_type, $active_plugin=null,
814
                               $heading = false, $return=false,
815
                               $buttons=false, $extracss=array()) {
816
817
818
    global $CFG, $COURSE;
    $strgrades = get_string('grades');
    $plugin_info = grade_get_plugin_info($courseid, $active_type, $active_plugin);
819
    
820
821
822
    // Determine the string of the active plugin
    $stractive_plugin = ($active_plugin) ? $plugin_info['strings']['active_plugin_str'] : $heading;
    $stractive_type = $plugin_info['strings'][$active_type];
skodak's avatar
skodak committed
823

824
    $navlinks = array();
nicolasconnault's avatar
nicolasconnault committed
825
826
    $first_link = '';

nicolasconnault's avatar
nicolasconnault committed
827
    if ($active_type == 'settings' && $active_plugin != 'coursesettings') {
828
829
        $first_link = $plugin_info['report'][$active_plugin]->link;
    } else if ($active_type != 'report') {
nicolasconnault's avatar
nicolasconnault committed
830
831
832
        $first_link = $CFG->wwwroot.'/grade/index.php?id='.$COURSE->id;
    }

833
834
835
836
    if ($active_type == 'preferences') {
        $CFG->stylesheets[] = $CFG->wwwroot . '/grade/report/styles.css';
    }

837
838
839
840
    foreach ($extracss as $css_url) {
        $CFG->stylesheets[] = $css_url;
    }

841
    $navlinks[] = array('name' => $strgrades,
nicolasconnault's avatar
nicolasconnault committed
842
                        'link' => $first_link,
843
844
845
846
                        'type' => 'misc');

    $active_type_link = '';

847
848
    if (!empty($plugin_info[$active_type]->link) && $plugin_info[$active_type]->link != qualified_me()) {
        $active_type_link = $plugin_info[$active_type]->link;
849
850
    }

851
852
    if (!empty($plugin_info[$active_type]->parent->link)) {
        $active_type_link = $plugin_info[$active_type]->parent->link;
853
854
855
        $navlinks[] = array('name' => $stractive_type, 'link' => $active_type_link, 'type' => 'misc');
    }

856
    if (empty($plugin_info[$active_type]->id)) {
nicolasconnault's avatar
nicolasconnault committed
857
858
859
        $navlinks[] = array('name' => $stractive_type, 'link' => $active_type_link, 'type' => 'misc');
    }

nicolasconnault's avatar
nicolasconnault committed
860
    $navlinks[] = array('name' => $stractive_plugin, 'link' => null, 'type' => 'misc');
861
862
863

    $navigation = build_navigation($navlinks);

nicolasconnault's avatar
nicolasconnault committed
864
    $title = ': ' . $stractive_plugin;
865
    if (empty($plugin_info[$active_type]->id) || !empty($plugin_info[$active_type]->parent)) {
nicolasconnault's avatar
nicolasconnault committed
866
867
868
869
        $title = ': ' . $stractive_type . ': ' . $stractive_plugin;
    }

    $returnval = print_header_simple($strgrades . ': ' . $stractive_type, $title, $navigation, '',
870
            '', true, $buttons, navmenu($COURSE), false, '', $return);
871
872
873
874
875
876

    // Guess heading if not given explicitly
    if (!$heading) {
        $heading = $stractive_plugin;
    }

nicolasconnault's avatar
nicolasconnault committed
877
    if ($CFG->grade_navmethod == GRADE_NAVMETHOD_COMBO || $CFG->grade_navmethod == GRADE_NAVMETHOD_DROPDOWN) {
878
879
        $returnval .= print_grade_plugin_selector($plugin_info, $return);
    }
880
    $returnval .= print_heading($heading);
881

nicolasconnault's avatar
nicolasconnault committed
882
    if ($CFG->grade_navmethod == GRADE_NAVMETHOD_COMBO || $CFG->grade_navmethod == GRADE_NAVMETHOD_TABS) {
nicolasconnault's avatar
nicolasconnault committed
883
        $returnval .= grade_print_tabs($active_type, $active_plugin, $plugin_info, $return);
884
    }
885
886
887

    if ($return) {
        return $returnval;
888
    }
889
890
}

skodak's avatar
skodak committed
891
/**
892
 * Utility class used for return tracking when using edit and other forms in grade plugins
893
894
895
896
 *
 * @package moodlecore
 * @copyright 2009 Nicolas Connault
 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
skodak's avatar
skodak committed
897
 */
898
class grade_plugin_return {
899
900
901
902
903
    public $type;
    public $plugin;
    public $courseid;
    public $userid;
    public $page;
904

skodak's avatar
skodak committed
905
906
    /**
     * Constructor
907
     *
skodak's avatar
skodak committed
908
909
     * @param array $params - associative array with return parameters, if null parameter are taken from _GET or _POST
     */
910
    public function grade_plugin_return($params = null) {
911
912
913
914
915
916
        if (empty($params)) {
            $this->type     = optional_param('gpr_type', null, PARAM_SAFEDIR);
            $this->plugin   = optional_param('gpr_plugin', null, PARAM_SAFEDIR);
            $this->courseid = optional_param('gpr_courseid', null, PARAM_INT);
            $this->userid   = optional_param('gpr_userid', null, PARAM_INT);
            $this->page     = optional_param('gpr_page', null, PARAM_INT);
917
918

        } else {
919
920
921
922
            foreach ($params as $key=>$value) {
                if (array_key_exists($key, $this)) {
                    $this->$key = $value;
                }
923
924
            }
        }
925
926
    }

skodak's avatar
skodak committed
927
928
929
930
    /**
     * Returns return parameters as options array suitable for buttons.
     * @return array options
     */
931
    public function get_options() {
932
        if (empty($this->type)) {
933
            return array();
934
        }
935

936
        $params = array();
937

938
939
940
        if (!empty($this->plugin)) {
            $params['plugin'] = $this->plugin;
        }
941

942
943
        if (!empty($this->courseid)) {
            $params['id'] = $this->courseid;
944
        }
skodak's avatar
skodak committed
945

946
947
        if (!empty($this->userid)) {
            $params['userid'] = $this->userid;
skodak's avatar
skodak committed
948
949
        }

950
951
        if (!empty($this->page)) {
            $params['page'] = $this->page;
952
        }
953

954
        return $params;
955
956
    }

skodak's avatar
skodak committed
957
958
    /**
     * Returns return url
959
     *
skodak's avatar
skodak committed
960
     * @param string $default default url when params not set
961
962
     * @param array  $extras Extra URL parameters
     *
skodak's avatar
skodak committed
963
964
     * @return string url
     */
965
    public function get_return_url($default, $extras=null) {
966
        global $CFG;
967

968
969
        if (empty($this->type) or empty($this->plugin)) {
            return $default;
970
971
        }

972
973
        $url = $CFG->wwwroot.'/grade/'.$this->type.'/'.$this->plugin.'/index.php';
        $glue = '?';
974

975
976
977
        if (!empty($this->courseid)) {
            $url .= $glue.'id='.$this->courseid;
            $glue = '&amp;';
978
979
        }

980
981
982
        if (!empty($this->userid)) {
            $url .= $glue.'userid='.$this->userid;
            $glue = '&amp;';
983
        }
toyomoyo's avatar
toyomoyo committed
984

985
986
        if (!empty($this->page)) {
            $url .= $glue.'page='.$this->page;
987
988
989
990
            $glue = '&amp;';
        }

        if (!empty($extras)) {
991
            foreach ($extras as $key=>$value) {
992
993
                $url .= $glue.$key.'='.$value;
                $glue = '&amp;';
994
            }
995
996
        }

997
        return $url;
998
999
    }

skodak's avatar
skodak committed
1000
    /**
For faster browsing, not all history is shown. View entire blame