PageRenderTime 88ms CodeModel.GetById 4ms app.highlight 62ms RepoModel.GetById 1ms app.codeStats 1ms

/grade/lib.php

https://bitbucket.org/ngmares/moodle
PHP | 2668 lines | 1716 code | 311 blank | 641 comment | 355 complexity | cf90861941c649e1a2745322cd45c15f MD5 | raw file

Large files files are truncated, but you can click here to view the full file

   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 * Functions used by gradebook plugins and reports.
  19 *
  20 * @package   core_grades
  21 * @copyright 2009 Petr Skoda and Nicolas Connault
  22 * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  23 */
  24
  25require_once $CFG->libdir.'/gradelib.php';
  26
  27/**
  28 * This class iterates over all users that are graded in a course.
  29 * Returns detailed info about users and their grades.
  30 *
  31 * @author Petr Skoda <skodak@moodle.org>
  32 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  33 */
  34class graded_users_iterator {
  35
  36    /**
  37     * The couse whose users we are interested in
  38     */
  39    protected $course;
  40
  41    /**
  42     * An array of grade items or null if only user data was requested
  43     */
  44    protected $grade_items;
  45
  46    /**
  47     * The group ID we are interested in. 0 means all groups.
  48     */
  49    protected $groupid;
  50
  51    /**
  52     * A recordset of graded users
  53     */
  54    protected $users_rs;
  55
  56    /**
  57     * A recordset of user grades (grade_grade instances)
  58     */
  59    protected $grades_rs;
  60
  61    /**
  62     * Array used when moving to next user while iterating through the grades recordset
  63     */
  64    protected $gradestack;
  65
  66    /**
  67     * The first field of the users table by which the array of users will be sorted
  68     */
  69    protected $sortfield1;
  70
  71    /**
  72     * Should sortfield1 be ASC or DESC
  73     */
  74    protected $sortorder1;
  75
  76    /**
  77     * The second field of the users table by which the array of users will be sorted
  78     */
  79    protected $sortfield2;
  80
  81    /**
  82     * Should sortfield2 be ASC or DESC
  83     */
  84    protected $sortorder2;
  85
  86    /**
  87     * Should users whose enrolment has been suspended be ignored?
  88     */
  89    protected $onlyactive = false;
  90
  91    /**
  92     * Constructor
  93     *
  94     * @param object $course A course object
  95     * @param array  $grade_items array of grade items, if not specified only user info returned
  96     * @param int    $groupid iterate only group users if present
  97     * @param string $sortfield1 The first field of the users table by which the array of users will be sorted
  98     * @param string $sortorder1 The order in which the first sorting field will be sorted (ASC or DESC)
  99     * @param string $sortfield2 The second field of the users table by which the array of users will be sorted
 100     * @param string $sortorder2 The order in which the second sorting field will be sorted (ASC or DESC)
 101     */
 102    public function __construct($course, $grade_items=null, $groupid=0,
 103                                          $sortfield1='lastname', $sortorder1='ASC',
 104                                          $sortfield2='firstname', $sortorder2='ASC') {
 105        $this->course      = $course;
 106        $this->grade_items = $grade_items;
 107        $this->groupid     = $groupid;
 108        $this->sortfield1  = $sortfield1;
 109        $this->sortorder1  = $sortorder1;
 110        $this->sortfield2  = $sortfield2;
 111        $this->sortorder2  = $sortorder2;
 112
 113        $this->gradestack  = array();
 114    }
 115
 116    /**
 117     * Initialise the iterator
 118     *
 119     * @return boolean success
 120     */
 121    public function init() {
 122        global $CFG, $DB;
 123
 124        $this->close();
 125
 126        grade_regrade_final_grades($this->course->id);
 127        $course_item = grade_item::fetch_course_item($this->course->id);
 128        if ($course_item->needsupdate) {
 129            // can not calculate all final grades - sorry
 130            return false;
 131        }
 132
 133        $coursecontext = get_context_instance(CONTEXT_COURSE, $this->course->id);
 134        $relatedcontexts = get_related_contexts_string($coursecontext);
 135
 136        list($gradebookroles_sql, $params) =
 137            $DB->get_in_or_equal(explode(',', $CFG->gradebookroles), SQL_PARAMS_NAMED, 'grbr');
 138        list($enrolledsql, $enrolledparams) = get_enrolled_sql($coursecontext, '', 0, $this->onlyactive);
 139
 140        $params = array_merge($params, $enrolledparams);
 141
 142        if ($this->groupid) {
 143            $groupsql = "INNER JOIN {groups_members} gm ON gm.userid = u.id";
 144            $groupwheresql = "AND gm.groupid = :groupid";
 145            // $params contents: gradebookroles
 146            $params['groupid'] = $this->groupid;
 147        } else {
 148            $groupsql = "";
 149            $groupwheresql = "";
 150        }
 151
 152        if (empty($this->sortfield1)) {
 153            // we must do some sorting even if not specified
 154            $ofields = ", u.id AS usrt";
 155            $order   = "usrt ASC";
 156
 157        } else {
 158            $ofields = ", u.$this->sortfield1 AS usrt1";
 159            $order   = "usrt1 $this->sortorder1";
 160            if (!empty($this->sortfield2)) {
 161                $ofields .= ", u.$this->sortfield2 AS usrt2";
 162                $order   .= ", usrt2 $this->sortorder2";
 163            }
 164            if ($this->sortfield1 != 'id' and $this->sortfield2 != 'id') {
 165                // user order MUST be the same in both queries,
 166                // must include the only unique user->id if not already present
 167                $ofields .= ", u.id AS usrt";
 168                $order   .= ", usrt ASC";
 169            }
 170        }
 171
 172        // $params contents: gradebookroles and groupid (for $groupwheresql)
 173        $users_sql = "SELECT u.* $ofields
 174                        FROM {user} u
 175                        JOIN ($enrolledsql) je ON je.id = u.id
 176                             $groupsql
 177                        JOIN (
 178                                  SELECT DISTINCT ra.userid
 179                                    FROM {role_assignments} ra
 180                                   WHERE ra.roleid $gradebookroles_sql
 181                                     AND ra.contextid $relatedcontexts
 182                             ) rainner ON rainner.userid = u.id
 183                         WHERE u.deleted = 0
 184                             $groupwheresql
 185                    ORDER BY $order";
 186        $this->users_rs = $DB->get_recordset_sql($users_sql, $params);
 187
 188        if (!empty($this->grade_items)) {
 189            $itemids = array_keys($this->grade_items);
 190            list($itemidsql, $grades_params) = $DB->get_in_or_equal($itemids, SQL_PARAMS_NAMED, 'items');
 191            $params = array_merge($params, $grades_params);
 192            // $params contents: gradebookroles, enrolledparams, groupid (for $groupwheresql) and itemids
 193
 194            $grades_sql = "SELECT g.* $ofields
 195                             FROM {grade_grades} g
 196                             JOIN {user} u ON g.userid = u.id
 197                             JOIN ($enrolledsql) je ON je.id = u.id
 198                                  $groupsql
 199                             JOIN (
 200                                      SELECT DISTINCT ra.userid
 201                                        FROM {role_assignments} ra
 202                                       WHERE ra.roleid $gradebookroles_sql
 203                                         AND ra.contextid $relatedcontexts
 204                                  ) rainner ON rainner.userid = u.id
 205                              WHERE u.deleted = 0
 206                              AND g.itemid $itemidsql
 207                              $groupwheresql
 208                         ORDER BY $order, g.itemid ASC";
 209            $this->grades_rs = $DB->get_recordset_sql($grades_sql, $params);
 210        } else {
 211            $this->grades_rs = false;
 212        }
 213
 214        return true;
 215    }
 216
 217    /**
 218     * Returns information about the next user
 219     * @return mixed array of user info, all grades and feedback or null when no more users found
 220     */
 221    public function next_user() {
 222        if (!$this->users_rs) {
 223            return false; // no users present
 224        }
 225
 226        if (!$this->users_rs->valid()) {
 227            if ($current = $this->_pop()) {
 228                // this is not good - user or grades updated between the two reads above :-(
 229            }
 230
 231            return false; // no more users
 232        } else {
 233            $user = $this->users_rs->current();
 234            $this->users_rs->next();
 235        }
 236
 237        // find grades of this user
 238        $grade_records = array();
 239        while (true) {
 240            if (!$current = $this->_pop()) {
 241                break; // no more grades
 242            }
 243
 244            if (empty($current->userid)) {
 245                break;
 246            }
 247
 248            if ($current->userid != $user->id) {
 249                // grade of the next user, we have all for this user
 250                $this->_push($current);
 251                break;
 252            }
 253
 254            $grade_records[$current->itemid] = $current;
 255        }
 256
 257        $grades = array();
 258        $feedbacks = array();
 259
 260        if (!empty($this->grade_items)) {
 261            foreach ($this->grade_items as $grade_item) {
 262                if (!isset($feedbacks[$grade_item->id])) {
 263                    $feedbacks[$grade_item->id] = new stdClass();
 264                }
 265                if (array_key_exists($grade_item->id, $grade_records)) {
 266                    $feedbacks[$grade_item->id]->feedback       = $grade_records[$grade_item->id]->feedback;
 267                    $feedbacks[$grade_item->id]->feedbackformat = $grade_records[$grade_item->id]->feedbackformat;
 268                    unset($grade_records[$grade_item->id]->feedback);
 269                    unset($grade_records[$grade_item->id]->feedbackformat);
 270                    $grades[$grade_item->id] = new grade_grade($grade_records[$grade_item->id], false);
 271                } else {
 272                    $feedbacks[$grade_item->id]->feedback       = '';
 273                    $feedbacks[$grade_item->id]->feedbackformat = FORMAT_MOODLE;
 274                    $grades[$grade_item->id] =
 275                        new grade_grade(array('userid'=>$user->id, 'itemid'=>$grade_item->id), false);
 276                }
 277            }
 278        }
 279
 280        $result = new stdClass();
 281        $result->user      = $user;
 282        $result->grades    = $grades;
 283        $result->feedbacks = $feedbacks;
 284        return $result;
 285    }
 286
 287    /**
 288     * Close the iterator, do not forget to call this function
 289     */
 290    public function close() {
 291        if ($this->users_rs) {
 292            $this->users_rs->close();
 293            $this->users_rs = null;
 294        }
 295        if ($this->grades_rs) {
 296            $this->grades_rs->close();
 297            $this->grades_rs = null;
 298        }
 299        $this->gradestack = array();
 300    }
 301
 302    /**
 303     * Should all enrolled users be exported or just those with an active enrolment?
 304     *
 305     * @param bool $onlyactive True to limit the export to users with an active enrolment
 306     */
 307    public function require_active_enrolment($onlyactive = true) {
 308        if (!empty($this->users_rs)) {
 309            debugging('Calling require_active_enrolment() has no effect unless you call init() again', DEBUG_DEVELOPER);
 310        }
 311        $this->onlyactive  = $onlyactive;
 312    }
 313
 314
 315    /**
 316     * Add a grade_grade instance to the grade stack
 317     *
 318     * @param grade_grade $grade Grade object
 319     *
 320     * @return void
 321     */
 322    private function _push($grade) {
 323        array_push($this->gradestack, $grade);
 324    }
 325
 326
 327    /**
 328     * Remove a grade_grade instance from the grade stack
 329     *
 330     * @return grade_grade current grade object
 331     */
 332    private function _pop() {
 333        global $DB;
 334        if (empty($this->gradestack)) {
 335            if (empty($this->grades_rs) || !$this->grades_rs->valid()) {
 336                return null; // no grades present
 337            }
 338
 339            $current = $this->grades_rs->current();
 340
 341            $this->grades_rs->next();
 342
 343            return $current;
 344        } else {
 345            return array_pop($this->gradestack);
 346        }
 347    }
 348}
 349
 350/**
 351 * Print a selection popup form of the graded users in a course.
 352 *
 353 * @deprecated since 2.0
 354 *
 355 * @param int    $course id of the course
 356 * @param string $actionpage The page receiving the data from the popoup form
 357 * @param int    $userid   id of the currently selected user (or 'all' if they are all selected)
 358 * @param int    $groupid id of requested group, 0 means all
 359 * @param int    $includeall bool include all option
 360 * @param bool   $return If true, will return the HTML, otherwise, will print directly
 361 * @return null
 362 */
 363function print_graded_users_selector($course, $actionpage, $userid=0, $groupid=0, $includeall=true, $return=false) {
 364    global $CFG, $USER, $OUTPUT;
 365    return $OUTPUT->render(grade_get_graded_users_select(substr($actionpage, 0, strpos($actionpage, '/')), $course, $userid, $groupid, $includeall));
 366}
 367
 368function grade_get_graded_users_select($report, $course, $userid, $groupid, $includeall) {
 369    global $USER;
 370
 371    if (is_null($userid)) {
 372        $userid = $USER->id;
 373    }
 374
 375    $menu = array(); // Will be a list of userid => user name
 376    $gui = new graded_users_iterator($course, null, $groupid);
 377    $gui->init();
 378    $label = get_string('selectauser', 'grades');
 379    if ($includeall) {
 380        $menu[0] = get_string('allusers', 'grades');
 381        $label = get_string('selectalloroneuser', 'grades');
 382    }
 383    while ($userdata = $gui->next_user()) {
 384        $user = $userdata->user;
 385        $menu[$user->id] = fullname($user);
 386    }
 387    $gui->close();
 388
 389    if ($includeall) {
 390        $menu[0] .= " (" . (count($menu) - 1) . ")";
 391    }
 392    $select = new single_select(new moodle_url('/grade/report/'.$report.'/index.php', array('id'=>$course->id)), 'userid', $menu, $userid);
 393    $select->label = $label;
 394    $select->formid = 'choosegradeuser';
 395    return $select;
 396}
 397
 398/**
 399 * Print grading plugin selection popup form.
 400 *
 401 * @param array   $plugin_info An array of plugins containing information for the selector
 402 * @param boolean $return return as string
 403 *
 404 * @return nothing or string if $return true
 405 */
 406function print_grade_plugin_selector($plugin_info, $active_type, $active_plugin, $return=false) {
 407    global $CFG, $OUTPUT, $PAGE;
 408
 409    $menu = array();
 410    $count = 0;
 411    $active = '';
 412
 413    foreach ($plugin_info as $plugin_type => $plugins) {
 414        if ($plugin_type == 'strings') {
 415            continue;
 416        }
 417
 418        $first_plugin = reset($plugins);
 419
 420        $sectionname = $plugin_info['strings'][$plugin_type];
 421        $section = array();
 422
 423        foreach ($plugins as $plugin) {
 424            $link = $plugin->link->out(false);
 425            $section[$link] = $plugin->string;
 426            $count++;
 427            if ($plugin_type === $active_type and $plugin->id === $active_plugin) {
 428                $active = $link;
 429            }
 430        }
 431
 432        if ($section) {
 433            $menu[] = array($sectionname=>$section);
 434        }
 435    }
 436
 437    // finally print/return the popup form
 438    if ($count > 1) {
 439        $select = new url_select($menu, $active, null, 'choosepluginreport');
 440
 441        if ($return) {
 442            return $OUTPUT->render($select);
 443        } else {
 444            echo $OUTPUT->render($select);
 445        }
 446    } else {
 447        // only one option - no plugin selector needed
 448        return '';
 449    }
 450}
 451
 452/**
 453 * Print grading plugin selection tab-based navigation.
 454 *
 455 * @param string  $active_type type of plugin on current page - import, export, report or edit
 456 * @param string  $active_plugin active plugin type - grader, user, cvs, ...
 457 * @param array   $plugin_info Array of plugins
 458 * @param boolean $return return as string
 459 *
 460 * @return nothing or string if $return true
 461 */
 462function grade_print_tabs($active_type, $active_plugin, $plugin_info, $return=false) {
 463    global $CFG, $COURSE;
 464
 465    if (!isset($currenttab)) { //TODO: this is weird
 466        $currenttab = '';
 467    }
 468
 469    $tabs = array();
 470    $top_row  = array();
 471    $bottom_row = array();
 472    $inactive = array($active_plugin);
 473    $activated = array();
 474
 475    $count = 0;
 476    $active = '';
 477
 478    foreach ($plugin_info as $plugin_type => $plugins) {
 479        if ($plugin_type == 'strings') {
 480            continue;
 481        }
 482
 483        // If $plugins is actually the definition of a child-less parent link:
 484        if (!empty($plugins->id)) {
 485            $string = $plugins->string;
 486            if (!empty($plugin_info[$active_type]->parent)) {
 487                $string = $plugin_info[$active_type]->parent->string;
 488            }
 489
 490            $top_row[] = new tabobject($plugin_type, $plugins->link, $string);
 491            continue;
 492        }
 493
 494        $first_plugin = reset($plugins);
 495        $url = $first_plugin->link;
 496
 497        if ($plugin_type == 'report') {
 498            $url = $CFG->wwwroot.'/grade/report/index.php?id='.$COURSE->id;
 499        }
 500
 501        $top_row[] = new tabobject($plugin_type, $url, $plugin_info['strings'][$plugin_type]);
 502
 503        if ($active_type == $plugin_type) {
 504            foreach ($plugins as $plugin) {
 505                $bottom_row[] = new tabobject($plugin->id, $plugin->link, $plugin->string);
 506                if ($plugin->id == $active_plugin) {
 507                    $inactive = array($plugin->id);
 508                }
 509            }
 510        }
 511    }
 512
 513    $tabs[] = $top_row;
 514    $tabs[] = $bottom_row;
 515
 516    if ($return) {
 517        return print_tabs($tabs, $active_type, $inactive, $activated, true);
 518    } else {
 519        print_tabs($tabs, $active_type, $inactive, $activated);
 520    }
 521}
 522
 523/**
 524 * grade_get_plugin_info
 525 *
 526 * @param int    $courseid The course id
 527 * @param string $active_type type of plugin on current page - import, export, report or edit
 528 * @param string $active_plugin active plugin type - grader, user, cvs, ...
 529 *
 530 * @return array
 531 */
 532function grade_get_plugin_info($courseid, $active_type, $active_plugin) {
 533    global $CFG, $SITE;
 534
 535    $context = get_context_instance(CONTEXT_COURSE, $courseid);
 536
 537    $plugin_info = array();
 538    $count = 0;
 539    $active = '';
 540    $url_prefix = $CFG->wwwroot . '/grade/';
 541
 542    // Language strings
 543    $plugin_info['strings'] = grade_helper::get_plugin_strings();
 544
 545    if ($reports = grade_helper::get_plugins_reports($courseid)) {
 546        $plugin_info['report'] = $reports;
 547    }
 548
 549    //showing grade categories and items make no sense if we're not within a course
 550    if ($courseid!=$SITE->id) {
 551        if ($edittree = grade_helper::get_info_edit_structure($courseid)) {
 552            $plugin_info['edittree'] = $edittree;
 553        }
 554    }
 555
 556    if ($scale = grade_helper::get_info_scales($courseid)) {
 557        $plugin_info['scale'] = array('view'=>$scale);
 558    }
 559
 560    if ($outcomes = grade_helper::get_info_outcomes($courseid)) {
 561        $plugin_info['outcome'] = $outcomes;
 562    }
 563
 564    if ($letters = grade_helper::get_info_letters($courseid)) {
 565        $plugin_info['letter'] = $letters;
 566    }
 567
 568    if ($imports = grade_helper::get_plugins_import($courseid)) {
 569        $plugin_info['import'] = $imports;
 570    }
 571
 572    if ($exports = grade_helper::get_plugins_export($courseid)) {
 573        $plugin_info['export'] = $exports;
 574    }
 575
 576    foreach ($plugin_info as $plugin_type => $plugins) {
 577        if (!empty($plugins->id) && $active_plugin == $plugins->id) {
 578            $plugin_info['strings']['active_plugin_str'] = $plugins->string;
 579            break;
 580        }
 581        foreach ($plugins as $plugin) {
 582            if (is_a($plugin, 'grade_plugin_info')) {
 583                if ($active_plugin == $plugin->id) {
 584                    $plugin_info['strings']['active_plugin_str'] = $plugin->string;
 585                }
 586            }
 587        }
 588    }
 589
 590    //hide course settings if we're not in a course
 591    if ($courseid!=$SITE->id) {
 592        if ($setting = grade_helper::get_info_manage_settings($courseid)) {
 593            $plugin_info['settings'] = array('course'=>$setting);
 594        }
 595    }
 596
 597    // Put preferences last
 598    if ($preferences = grade_helper::get_plugins_report_preferences($courseid)) {
 599        $plugin_info['preferences'] = $preferences;
 600    }
 601
 602    foreach ($plugin_info as $plugin_type => $plugins) {
 603        if (!empty($plugins->id) && $active_plugin == $plugins->id) {
 604            $plugin_info['strings']['active_plugin_str'] = $plugins->string;
 605            break;
 606        }
 607        foreach ($plugins as $plugin) {
 608            if (is_a($plugin, 'grade_plugin_info')) {
 609                if ($active_plugin == $plugin->id) {
 610                    $plugin_info['strings']['active_plugin_str'] = $plugin->string;
 611                }
 612            }
 613        }
 614    }
 615
 616    return $plugin_info;
 617}
 618
 619/**
 620 * A simple class containing info about grade plugins.
 621 * Can be subclassed for special rules
 622 *
 623 * @package core_grades
 624 * @copyright 2009 Nicolas Connault
 625 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
 626 */
 627class grade_plugin_info {
 628    /**
 629     * A unique id for this plugin
 630     *
 631     * @var mixed
 632     */
 633    public $id;
 634    /**
 635     * A URL to access this plugin
 636     *
 637     * @var mixed
 638     */
 639    public $link;
 640    /**
 641     * The name of this plugin
 642     *
 643     * @var mixed
 644     */
 645    public $string;
 646    /**
 647     * Another grade_plugin_info object, parent of the current one
 648     *
 649     * @var mixed
 650     */
 651    public $parent;
 652
 653    /**
 654     * Constructor
 655     *
 656     * @param int $id A unique id for this plugin
 657     * @param string $link A URL to access this plugin
 658     * @param string $string The name of this plugin
 659     * @param object $parent Another grade_plugin_info object, parent of the current one
 660     *
 661     * @return void
 662     */
 663    public function __construct($id, $link, $string, $parent=null) {
 664        $this->id = $id;
 665        $this->link = $link;
 666        $this->string = $string;
 667        $this->parent = $parent;
 668    }
 669}
 670
 671/**
 672 * Prints the page headers, breadcrumb trail, page heading, (optional) dropdown navigation menu and
 673 * (optional) navigation tabs for any gradebook page. All gradebook pages MUST use these functions
 674 * in favour of the usual print_header(), print_header_simple(), print_heading() etc.
 675 * !IMPORTANT! Use of tabs.php file in gradebook pages is forbidden unless tabs are switched off at
 676 * the site level for the gradebook ($CFG->grade_navmethod = GRADE_NAVMETHOD_DROPDOWN).
 677 *
 678 * @param int     $courseid Course id
 679 * @param string  $active_type The type of the current page (report, settings,
 680 *                             import, export, scales, outcomes, letters)
 681 * @param string  $active_plugin The plugin of the current page (grader, fullview etc...)
 682 * @param string  $heading The heading of the page. Tries to guess if none is given
 683 * @param boolean $return Whether to return (true) or echo (false) the HTML generated by this function
 684 * @param string  $bodytags Additional attributes that will be added to the <body> tag
 685 * @param string  $buttons Additional buttons to display on the page
 686 * @param boolean $shownavigation should the gradebook navigation drop down (or tabs) be shown?
 687 *
 688 * @return string HTML code or nothing if $return == false
 689 */
 690function print_grade_page_head($courseid, $active_type, $active_plugin=null,
 691                               $heading = false, $return=false,
 692                               $buttons=false, $shownavigation=true) {
 693    global $CFG, $OUTPUT, $PAGE;
 694
 695    $plugin_info = grade_get_plugin_info($courseid, $active_type, $active_plugin);
 696
 697    // Determine the string of the active plugin
 698    $stractive_plugin = ($active_plugin) ? $plugin_info['strings']['active_plugin_str'] : $heading;
 699    $stractive_type = $plugin_info['strings'][$active_type];
 700
 701    if (empty($plugin_info[$active_type]->id) || !empty($plugin_info[$active_type]->parent)) {
 702        $title = $PAGE->course->fullname.': ' . $stractive_type . ': ' . $stractive_plugin;
 703    } else {
 704        $title = $PAGE->course->fullname.': ' . $stractive_plugin;
 705    }
 706
 707    if ($active_type == 'report') {
 708        $PAGE->set_pagelayout('report');
 709    } else {
 710        $PAGE->set_pagelayout('admin');
 711    }
 712    $PAGE->set_title(get_string('grades') . ': ' . $stractive_type);
 713    $PAGE->set_heading($title);
 714    if ($buttons instanceof single_button) {
 715        $buttons = $OUTPUT->render($buttons);
 716    }
 717    $PAGE->set_button($buttons);
 718    grade_extend_settings($plugin_info, $courseid);
 719
 720    $returnval = $OUTPUT->header();
 721    if (!$return) {
 722        echo $returnval;
 723    }
 724
 725    // Guess heading if not given explicitly
 726    if (!$heading) {
 727        $heading = $stractive_plugin;
 728    }
 729
 730    if ($shownavigation) {
 731        if ($CFG->grade_navmethod == GRADE_NAVMETHOD_COMBO || $CFG->grade_navmethod == GRADE_NAVMETHOD_DROPDOWN) {
 732            $returnval .= print_grade_plugin_selector($plugin_info, $active_type, $active_plugin, $return);
 733        }
 734
 735        if ($return) {
 736            $returnval .= $OUTPUT->heading($heading);
 737        } else {
 738            echo $OUTPUT->heading($heading);
 739        }
 740
 741        if ($CFG->grade_navmethod == GRADE_NAVMETHOD_COMBO || $CFG->grade_navmethod == GRADE_NAVMETHOD_TABS) {
 742            $returnval .= grade_print_tabs($active_type, $active_plugin, $plugin_info, $return);
 743        }
 744    }
 745
 746    if ($return) {
 747        return $returnval;
 748    }
 749}
 750
 751/**
 752 * Utility class used for return tracking when using edit and other forms in grade plugins
 753 *
 754 * @package core_grades
 755 * @copyright 2009 Nicolas Connault
 756 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
 757 */
 758class grade_plugin_return {
 759    public $type;
 760    public $plugin;
 761    public $courseid;
 762    public $userid;
 763    public $page;
 764
 765    /**
 766     * Constructor
 767     *
 768     * @param array $params - associative array with return parameters, if null parameter are taken from _GET or _POST
 769     */
 770    public function grade_plugin_return($params = null) {
 771        if (empty($params)) {
 772            $this->type     = optional_param('gpr_type', null, PARAM_SAFEDIR);
 773            $this->plugin   = optional_param('gpr_plugin', null, PARAM_PLUGIN);
 774            $this->courseid = optional_param('gpr_courseid', null, PARAM_INT);
 775            $this->userid   = optional_param('gpr_userid', null, PARAM_INT);
 776            $this->page     = optional_param('gpr_page', null, PARAM_INT);
 777
 778        } else {
 779            foreach ($params as $key=>$value) {
 780                if (property_exists($this, $key)) {
 781                    $this->$key = $value;
 782                }
 783            }
 784        }
 785    }
 786
 787    /**
 788     * Returns return parameters as options array suitable for buttons.
 789     * @return array options
 790     */
 791    public function get_options() {
 792        if (empty($this->type)) {
 793            return array();
 794        }
 795
 796        $params = array();
 797
 798        if (!empty($this->plugin)) {
 799            $params['plugin'] = $this->plugin;
 800        }
 801
 802        if (!empty($this->courseid)) {
 803            $params['id'] = $this->courseid;
 804        }
 805
 806        if (!empty($this->userid)) {
 807            $params['userid'] = $this->userid;
 808        }
 809
 810        if (!empty($this->page)) {
 811            $params['page'] = $this->page;
 812        }
 813
 814        return $params;
 815    }
 816
 817    /**
 818     * Returns return url
 819     *
 820     * @param string $default default url when params not set
 821     * @param array  $extras Extra URL parameters
 822     *
 823     * @return string url
 824     */
 825    public function get_return_url($default, $extras=null) {
 826        global $CFG;
 827
 828        if (empty($this->type) or empty($this->plugin)) {
 829            return $default;
 830        }
 831
 832        $url = $CFG->wwwroot.'/grade/'.$this->type.'/'.$this->plugin.'/index.php';
 833        $glue = '?';
 834
 835        if (!empty($this->courseid)) {
 836            $url .= $glue.'id='.$this->courseid;
 837            $glue = '&amp;';
 838        }
 839
 840        if (!empty($this->userid)) {
 841            $url .= $glue.'userid='.$this->userid;
 842            $glue = '&amp;';
 843        }
 844
 845        if (!empty($this->page)) {
 846            $url .= $glue.'page='.$this->page;
 847            $glue = '&amp;';
 848        }
 849
 850        if (!empty($extras)) {
 851            foreach ($extras as $key=>$value) {
 852                $url .= $glue.$key.'='.$value;
 853                $glue = '&amp;';
 854            }
 855        }
 856
 857        return $url;
 858    }
 859
 860    /**
 861     * Returns string with hidden return tracking form elements.
 862     * @return string
 863     */
 864    public function get_form_fields() {
 865        if (empty($this->type)) {
 866            return '';
 867        }
 868
 869        $result  = '<input type="hidden" name="gpr_type" value="'.$this->type.'" />';
 870
 871        if (!empty($this->plugin)) {
 872            $result .= '<input type="hidden" name="gpr_plugin" value="'.$this->plugin.'" />';
 873        }
 874
 875        if (!empty($this->courseid)) {
 876            $result .= '<input type="hidden" name="gpr_courseid" value="'.$this->courseid.'" />';
 877        }
 878
 879        if (!empty($this->userid)) {
 880            $result .= '<input type="hidden" name="gpr_userid" value="'.$this->userid.'" />';
 881        }
 882
 883        if (!empty($this->page)) {
 884            $result .= '<input type="hidden" name="gpr_page" value="'.$this->page.'" />';
 885        }
 886    }
 887
 888    /**
 889     * Add hidden elements into mform
 890     *
 891     * @param object &$mform moodle form object
 892     *
 893     * @return void
 894     */
 895    public function add_mform_elements(&$mform) {
 896        if (empty($this->type)) {
 897            return;
 898        }
 899
 900        $mform->addElement('hidden', 'gpr_type', $this->type);
 901        $mform->setType('gpr_type', PARAM_SAFEDIR);
 902
 903        if (!empty($this->plugin)) {
 904            $mform->addElement('hidden', 'gpr_plugin', $this->plugin);
 905            $mform->setType('gpr_plugin', PARAM_PLUGIN);
 906        }
 907
 908        if (!empty($this->courseid)) {
 909            $mform->addElement('hidden', 'gpr_courseid', $this->courseid);
 910            $mform->setType('gpr_courseid', PARAM_INT);
 911        }
 912
 913        if (!empty($this->userid)) {
 914            $mform->addElement('hidden', 'gpr_userid', $this->userid);
 915            $mform->setType('gpr_userid', PARAM_INT);
 916        }
 917
 918        if (!empty($this->page)) {
 919            $mform->addElement('hidden', 'gpr_page', $this->page);
 920            $mform->setType('gpr_page', PARAM_INT);
 921        }
 922    }
 923
 924    /**
 925     * Add return tracking params into url
 926     *
 927     * @param moodle_url $url A URL
 928     *
 929     * @return string $url with return tracking params
 930     */
 931    public function add_url_params(moodle_url $url) {
 932        if (empty($this->type)) {
 933            return $url;
 934        }
 935
 936        $url->param('gpr_type', $this->type);
 937
 938        if (!empty($this->plugin)) {
 939            $url->param('gpr_plugin', $this->plugin);
 940        }
 941
 942        if (!empty($this->courseid)) {
 943            $url->param('gpr_courseid' ,$this->courseid);
 944        }
 945
 946        if (!empty($this->userid)) {
 947            $url->param('gpr_userid', $this->userid);
 948        }
 949
 950        if (!empty($this->page)) {
 951            $url->param('gpr_page', $this->page);
 952        }
 953
 954        return $url;
 955    }
 956}
 957
 958/**
 959 * Function central to gradebook for building and printing the navigation (breadcrumb trail).
 960 *
 961 * @param string $path The path of the calling script (using __FILE__?)
 962 * @param string $pagename The language string to use as the last part of the navigation (non-link)
 963 * @param mixed  $id Either a plain integer (assuming the key is 'id') or
 964 *                   an array of keys and values (e.g courseid => $courseid, itemid...)
 965 *
 966 * @return string
 967 */
 968function grade_build_nav($path, $pagename=null, $id=null) {
 969    global $CFG, $COURSE, $PAGE;
 970
 971    $strgrades = get_string('grades', 'grades');
 972
 973    // Parse the path and build navlinks from its elements
 974    $dirroot_length = strlen($CFG->dirroot) + 1; // Add 1 for the first slash
 975    $path = substr($path, $dirroot_length);
 976    $path = str_replace('\\', '/', $path);
 977
 978    $path_elements = explode('/', $path);
 979
 980    $path_elements_count = count($path_elements);
 981
 982    // First link is always 'grade'
 983    $PAGE->navbar->add($strgrades, new moodle_url('/grade/index.php', array('id'=>$COURSE->id)));
 984
 985    $link = null;
 986    $numberofelements = 3;
 987
 988    // Prepare URL params string
 989    $linkparams = array();
 990    if (!is_null($id)) {
 991        if (is_array($id)) {
 992            foreach ($id as $idkey => $idvalue) {
 993                $linkparams[$idkey] = $idvalue;
 994            }
 995        } else {
 996            $linkparams['id'] = $id;
 997        }
 998    }
 999
1000    $navlink4 = null;
1001
1002    // Remove file extensions from filenames
1003    foreach ($path_elements as $key => $filename) {
1004        $path_elements[$key] = str_replace('.php', '', $filename);
1005    }
1006
1007    // Second level links
1008    switch ($path_elements[1]) {
1009        case 'edit': // No link
1010            if ($path_elements[3] != 'index.php') {
1011                $numberofelements = 4;
1012            }
1013            break;
1014        case 'import': // No link
1015            break;
1016        case 'export': // No link
1017            break;
1018        case 'report':
1019            // $id is required for this link. Do not print it if $id isn't given
1020            if (!is_null($id)) {
1021                $link = new moodle_url('/grade/report/index.php', $linkparams);
1022            }
1023
1024            if ($path_elements[2] == 'grader') {
1025                $numberofelements = 4;
1026            }
1027            break;
1028
1029        default:
1030            // If this element isn't among the ones already listed above, it isn't supported, throw an error.
1031            debugging("grade_build_nav() doesn't support ". $path_elements[1] .
1032                    " as the second path element after 'grade'.");
1033            return false;
1034    }
1035    $PAGE->navbar->add(get_string($path_elements[1], 'grades'), $link);
1036
1037    // Third level links
1038    if (empty($pagename)) {
1039        $pagename = get_string($path_elements[2], 'grades');
1040    }
1041
1042    switch ($numberofelements) {
1043        case 3:
1044            $PAGE->navbar->add($pagename, $link);
1045            break;
1046        case 4:
1047            if ($path_elements[2] == 'grader' AND $path_elements[3] != 'index.php') {
1048                $PAGE->navbar->add(get_string('pluginname', 'gradereport_grader'), new moodle_url('/grade/report/grader/index.php', $linkparams));
1049            }
1050            $PAGE->navbar->add($pagename);
1051            break;
1052    }
1053
1054    return '';
1055}
1056
1057/**
1058 * General structure representing grade items in course
1059 *
1060 * @package core_grades
1061 * @copyright 2009 Nicolas Connault
1062 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
1063 */
1064class grade_structure {
1065    public $context;
1066
1067    public $courseid;
1068
1069    /**
1070    * Reference to modinfo for current course (for performance, to save
1071    * retrieving it from courseid every time). Not actually set except for
1072    * the grade_tree type.
1073    * @var course_modinfo
1074    */
1075    public $modinfo;
1076
1077    /**
1078     * 1D array of grade items only
1079     */
1080    public $items;
1081
1082    /**
1083     * Returns icon of element
1084     *
1085     * @param array &$element An array representing an element in the grade_tree
1086     * @param bool  $spacerifnone return spacer if no icon found
1087     *
1088     * @return string icon or spacer
1089     */
1090    public function get_element_icon(&$element, $spacerifnone=false) {
1091        global $CFG, $OUTPUT;
1092        require_once $CFG->libdir.'/filelib.php';
1093
1094        switch ($element['type']) {
1095            case 'item':
1096            case 'courseitem':
1097            case 'categoryitem':
1098                $is_course   = $element['object']->is_course_item();
1099                $is_category = $element['object']->is_category_item();
1100                $is_scale    = $element['object']->gradetype == GRADE_TYPE_SCALE;
1101                $is_value    = $element['object']->gradetype == GRADE_TYPE_VALUE;
1102                $is_outcome  = !empty($element['object']->outcomeid);
1103
1104                if ($element['object']->is_calculated()) {
1105                    $strcalc = get_string('calculatedgrade', 'grades');
1106                    return '<img src="'.$OUTPUT->pix_url('i/calc') . '" class="icon itemicon" title="'.
1107                            s($strcalc).'" alt="'.s($strcalc).'"/>';
1108
1109                } else if (($is_course or $is_category) and ($is_scale or $is_value)) {
1110                    if ($category = $element['object']->get_item_category()) {
1111                        switch ($category->aggregation) {
1112                            case GRADE_AGGREGATE_MEAN:
1113                            case GRADE_AGGREGATE_MEDIAN:
1114                            case GRADE_AGGREGATE_WEIGHTED_MEAN:
1115                            case GRADE_AGGREGATE_WEIGHTED_MEAN2:
1116                            case GRADE_AGGREGATE_EXTRACREDIT_MEAN:
1117                                $stragg = get_string('aggregation', 'grades');
1118                                return '<img src="'.$OUTPUT->pix_url('i/agg_mean') . '" ' .
1119                                        'class="icon itemicon" title="'.s($stragg).'" alt="'.s($stragg).'"/>';
1120                            case GRADE_AGGREGATE_SUM:
1121                                $stragg = get_string('aggregation', 'grades');
1122                                return '<img src="'.$OUTPUT->pix_url('i/agg_sum') . '" ' .
1123                                        'class="icon itemicon" title="'.s($stragg).'" alt="'.s($stragg).'"/>';
1124                        }
1125                    }
1126
1127                } else if ($element['object']->itemtype == 'mod') {
1128                    //prevent outcomes being displaying the same icon as the activity they are attached to
1129                    if ($is_outcome) {
1130                        $stroutcome = s(get_string('outcome', 'grades'));
1131                        return '<img src="'.$OUTPUT->pix_url('i/outcomes') . '" ' .
1132                            'class="icon itemicon" title="'.$stroutcome.
1133                            '" alt="'.$stroutcome.'"/>';
1134                    } else {
1135                        $strmodname = get_string('modulename', $element['object']->itemmodule);
1136                        return '<img src="'.$OUTPUT->pix_url('icon',
1137                            $element['object']->itemmodule) . '" ' .
1138                            'class="icon itemicon" title="' .s($strmodname).
1139                            '" alt="' .s($strmodname).'"/>';
1140                    }
1141                } else if ($element['object']->itemtype == 'manual') {
1142                    if ($element['object']->is_outcome_item()) {
1143                        $stroutcome = get_string('outcome', 'grades');
1144                        return '<img src="'.$OUTPUT->pix_url('i/outcomes') . '" ' .
1145                                'class="icon itemicon" title="'.s($stroutcome).
1146                                '" alt="'.s($stroutcome).'"/>';
1147                    } else {
1148                        $strmanual = get_string('manualitem', 'grades');
1149                        return '<img src="'.$OUTPUT->pix_url('t/manual_item') . '" '.
1150                                'class="icon itemicon" title="'.s($strmanual).
1151                                '" alt="'.s($strmanual).'"/>';
1152                    }
1153                }
1154                break;
1155
1156            case 'category':
1157                $strcat = get_string('category', 'grades');
1158                return '<img src="'.$OUTPUT->pix_url(file_folder_icon()) . '" class="icon itemicon" ' .
1159                        'title="'.s($strcat).'" alt="'.s($strcat).'" />';
1160        }
1161
1162        if ($spacerifnone) {
1163            return $OUTPUT->spacer().' ';
1164        } else {
1165            return '';
1166        }
1167    }
1168
1169    /**
1170     * Returns name of element optionally with icon and link
1171     *
1172     * @param array &$element An array representing an element in the grade_tree
1173     * @param bool  $withlink Whether or not this header has a link
1174     * @param bool  $icon Whether or not to display an icon with this header
1175     * @param bool  $spacerifnone return spacer if no icon found
1176     *
1177     * @return string header
1178     */
1179    public function get_element_header(&$element, $withlink=false, $icon=true, $spacerifnone=false) {
1180        $header = '';
1181
1182        if ($icon) {
1183            $header .= $this->get_element_icon($element, $spacerifnone);
1184        }
1185
1186        $header .= $element['object']->get_name();
1187
1188        if ($element['type'] != 'item' and $element['type'] != 'categoryitem' and
1189            $element['type'] != 'courseitem') {
1190            return $header;
1191        }
1192
1193        if ($withlink) {
1194            $url = $this->get_activity_link($element);
1195            if ($url) {
1196                $a = new stdClass();
1197                $a->name = get_string('modulename', $element['object']->itemmodule);
1198                $title = get_string('linktoactivity', 'grades', $a);
1199
1200                $header = html_writer::link($url, $header, array('title' => $title));
1201            }
1202        }
1203
1204        return $header;
1205    }
1206
1207    private function get_activity_link($element) {
1208        global $CFG;
1209        /** @var array static cache of the grade.php file existence flags */
1210        static $hasgradephp = array();
1211
1212        $itemtype = $element['object']->itemtype;
1213        $itemmodule = $element['object']->itemmodule;
1214        $iteminstance = $element['object']->iteminstance;
1215        $itemnumber = $element['object']->itemnumber;
1216
1217        // Links only for module items that have valid instance, module and are
1218        // called from grade_tree with valid modinfo
1219        if ($itemtype != 'mod' || !$iteminstance || !$itemmodule || !$this->modinfo) {
1220            return null;
1221        }
1222
1223        // Get $cm efficiently and with visibility information using modinfo
1224        $instances = $this->modinfo->get_instances();
1225        if (empty($instances[$itemmodule][$iteminstance])) {
1226            return null;
1227        }
1228        $cm = $instances[$itemmodule][$iteminstance];
1229
1230        // Do not add link if activity is not visible to the current user
1231        if (!$cm->uservisible) {
1232            return null;
1233        }
1234
1235        if (!array_key_exists($itemmodule, $hasgradephp)) {
1236            if (file_exists($CFG->dirroot . '/mod/' . $itemmodule . '/grade.php')) {
1237                $hasgradephp[$itemmodule] = true;
1238            } else {
1239                $hasgradephp[$itemmodule] = false;
1240            }
1241        }
1242
1243        // If module has grade.php, link to that, otherwise view.php
1244        if ($hasgradephp[$itemmodule]) {
1245            $args = array('id' => $cm->id, 'itemnumber' => $itemnumber);
1246            if (isset($element['userid'])) {
1247                $args['userid'] = $element['userid'];
1248            }
1249            return new moodle_url('/mod/' . $itemmodule . '/grade.php', $args);
1250        } else {
1251            return new moodle_url('/mod/' . $itemmodule . '/view.php', array('id' => $cm->id));
1252        }
1253    }
1254
1255    /**
1256     * Returns URL of a page that is supposed to contain detailed grade analysis
1257     *
1258     * At the moment, only activity modules are supported. The method generates link
1259     * to the module's file grade.php with the parameters id (cmid), itemid, itemnumber,
1260     * gradeid and userid. If the grade.php does not exist, null is returned.
1261     *
1262     * @return moodle_url|null URL or null if unable to construct it
1263     */
1264    public function get_grade_analysis_url(grade_grade $grade) {
1265        global $CFG;
1266        /** @var array static cache of the grade.php file existence flags */
1267        static $hasgradephp = array();
1268
1269        if (empty($grade->grade_item) or !($grade->grade_item instanceof grade_item)) {
1270            throw new coding_exception('Passed grade without the associated grade item');
1271        }
1272        $item = $grade->grade_item;
1273
1274        if (!$item->is_external_item()) {
1275            // at the moment, only activity modules are supported
1276            return null;
1277        }
1278        if ($item->itemtype !== 'mod') {
1279            throw new coding_exception('Unknown external itemtype: '.$item->itemtype);
1280        }
1281        if (empty($item->iteminstance) or empty($item->itemmodule) or empty($this->modinfo)) {
1282            return null;
1283        }
1284
1285        if (!array_key_exists($item->itemmodule, $hasgradephp)) {
1286            if (file_exists($CFG->dirroot . '/mod/' . $item->itemmodule . '/grade.php')) {
1287                $hasgradephp[$item->itemmodule] = true;
1288            } else {
1289                $hasgradephp[$item->itemmodule] = false;
1290            }
1291        }
1292
1293        if (!$hasgradephp[$item->itemmodule]) {
1294            return null;
1295        }
1296
1297        $instances = $this->modinfo->get_instances();
1298        if (empty($instances[$item->itemmodule][$item->iteminstance])) {
1299            return null;
1300        }
1301        $cm = $instances[$item->itemmodule][$item->iteminstance];
1302        if (!$cm->uservisible) {
1303            return null;
1304        }
1305
1306        $url = new moodle_url('/mod/'.$item->itemmodule.'/grade.php', array(
1307            'id'         => $cm->id,
1308            'itemid'     => $item->id,
1309            'itemnumber' => $item->itemnumber,
1310            'gradeid'    => $grade->id,
1311            'userid'     => $grade->userid,
1312        ));
1313
1314        return $url;
1315    }
1316
1317    /**
1318     * Returns an action icon leading to the grade analysis page
1319     *
1320     * @param grade_grade $grade
1321     * @return string
1322     */
1323    public function get_grade_analysis_icon(grade_grade $grade) {
1324        global $OUTPUT;
1325
1326        $url = $this->get_grade_analysis_url($grade);
1327        if (is_null($url)) {
1328            return '';
1329        }
1330
1331        return $OUTPUT->action_icon($url, new pix_icon('t/preview',
1332            get_string('gradeanalysis', 'core_grades')));
1333    }
1334
1335    /**
1336     * Returns the grade eid - the grade may not exist yet.
1337     *
1338     * @param grade_grade $grade_grade A grade_grade object
1339     *
1340     * @return string eid
1341     */
1342    public function get_grade_eid($grade_grade) {
1343        if (empty($grade_grade->id)) {
1344            return 'n'.$grade_grade->itemid.'u'.$grade_grade->userid;
1345        } else {
1346            return 'g'.$grade_grade->id;
1347        }
1348    }
1349
1350    /**
1351     * Returns the grade_item eid
1352     * @param grade_item $grade_item A grade_item object
1353     * @return string eid
1354     */
1355    public function get_item_eid($grade_item) {
1356        return 'i'.$grade_item->id;
1357    }
1358
1359    /**
1360     * Given a grade_tree element, returns an array of parameters
1361     * used to build an icon for that element.
1362     *
1363     * @param array $element An array representing an element in the grade_tree
1364     *
1365     * @return array
1366     */
1367    public function get_params_for_iconstr($element) {
1368        $strparams = new stdClass();
1369        $strparams->category = '';
1370        $strparams->itemname = '';
1371        $strparams->itemmodule = '';
1372
1373        if (!method_exists($element['object'], 'get_name')) {
1374            return $strparams;
1375        }
1376
1377        $strparams->itemname = html_to_text($element['object']->get_name());
1378
1379        // If element name is categorytotal, get the name of the parent category
1380        if ($strparams->itemname == get_string('categorytotal', 'grades')) {
1381            $parent = $element['object']->get_parent_category();
1382            $strparams->category = $parent->get_name() . ' ';
1383        } else {
1384            $strparams->category = '';
1385        }
1386
1387        $strparams->itemmodule = null;
1388        if (isset($element['object']->itemmodule)) {
1389            $strparams->itemmodule = $element['object']->itemmodule;
1390        }
1391        return $strparams;
1392    }
1393
1394    /**
1395     * Return edit icon for give element
1396     *
1397     * @param array  $element An array representing an element in the grade_tree
1398     * @param object $gpr A grade_plugin_return object
1399     *
1400     * @return string
1401     */
1402    public function get_edit_icon($element, $gpr) {
1403        global $CFG, $OUTPUT;
1404
1405        if (!has_capability('moodle/grade:manage', $this->context)) {
1406            if ($element['type'] == 'grade' and has_capability('moodle/grade:edit', $this->context)) {
1407                // oki - let them override grade
1408            } else {
1409                return '';
1410            }
1411        }
1412
1413        static $strfeedback   = null;
1414        static $streditgrade = null;
1415        if (is_null($streditgrade)) {
1416            $streditgrade = get_string('editgrade', 'grades');
1417            $strfeedback  = get_string('feedback');
1418        }
1419
1420        $strparams = $this->get_params_for_iconstr($element);
1421
1422        $object = $element['object'];
1423
1424        switch ($element['type']) {
1425            case 'item':
1426            case 'categoryitem':
1427            case 'courseitem':
1428                $stredit = get_string('editverbose', 'grades', $strparams);
1429                if (empty($object->outcomeid) || empty($CFG->enableoutcomes)) {
1430                    $url = new moodle_url('/grade/edit/tree/item.php',
1431                            array('courseid' => $this->courseid, 'id' => $object->id));
1432                } else {
1433                    $url = new moodle_url('/grade/edit/tree/outcomeitem.php',
1434                            array('courseid' => $this->courseid, 'id' => $object->id));
1435                }
1436                break;
1437
1438            case 'category':
1439                $stredit = get_string('editverbose', 'grades', $strparams);
1440                $url = new moodle_url('/grade/edit/tree/category.php',
1441                        array('courseid' => $this->courseid, 'id' => $object->id));
1442                break;
1443
1444            case 'grade':
1445                $stredit = $streditgrade;
1446                if (empty($object->id)) {
1447                    $url = new moodle_url('/grade/edit/tree/grade.php',
1448                            array('courseid' => $this->courseid, 'itemid' => $object->itemid, 'userid' => $object->userid));
1449                } else {
1450                    $url = new moodle_url('/grade/edit/tree/grade.php',
1451                            array('courseid' => $this->courseid, 'id' => $object->id));
1452                }
1453                if (!empty($object->feedback)) {
1454                    $feedback = addslashes_js(trim(format_string($object->feedback, $object->feedbackformat)));
1455                }
1456                break;
1457
1458            default:
1459                $url = null;
1460        }
1461
1462        if ($url) {
1463            return $OUTPUT->action_icon($gpr->add_url_params($url), new pix_icon('t/edit', $stredit));
1464
1465        } else {
1466            return '';
1467        }
1468    }
1469
1470    /**
1471     * Return hiding icon for give element
1472     *
1473     * @param array  $element An array r…

Large files files are truncated, but you can click here to view the full file