[ Index ] |
PHP Cross Reference of Unnamed Project |
[Summary view] [Print] [Text view]
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 * This file contains the definition for the grading table which subclassses easy_table 19 * 20 * @package mod_assign 21 * @copyright 2012 NetSpot {@link http://www.netspot.com.au} 22 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 23 */ 24 25 defined('MOODLE_INTERNAL') || die(); 26 27 require_once($CFG->libdir.'/tablelib.php'); 28 require_once($CFG->libdir.'/gradelib.php'); 29 require_once($CFG->dirroot.'/mod/assign/locallib.php'); 30 31 /** 32 * Extends table_sql to provide a table of assignment submissions 33 * 34 * @package mod_assign 35 * @copyright 2012 NetSpot {@link http://www.netspot.com.au} 36 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 37 */ 38 class assign_grading_table extends table_sql implements renderable { 39 /** @var assign $assignment */ 40 private $assignment = null; 41 /** @var int $perpage */ 42 private $perpage = 10; 43 /** @var int $rownum (global index of current row in table) */ 44 private $rownum = -1; 45 /** @var renderer_base for getting output */ 46 private $output = null; 47 /** @var stdClass gradinginfo */ 48 private $gradinginfo = null; 49 /** @var int $tablemaxrows */ 50 private $tablemaxrows = 10000; 51 /** @var boolean $quickgrading */ 52 private $quickgrading = false; 53 /** @var boolean $hasgrantextension - Only do the capability check once for the entire table */ 54 private $hasgrantextension = false; 55 /** @var boolean $hasgrade - Only do the capability check once for the entire table */ 56 private $hasgrade = false; 57 /** @var array $groupsubmissions - A static cache of group submissions */ 58 private $groupsubmissions = array(); 59 /** @var array $submissiongroups - A static cache of submission groups */ 60 private $submissiongroups = array(); 61 /** @var string $plugingradingbatchoperations - List of plugin supported batch operations */ 62 public $plugingradingbatchoperations = array(); 63 /** @var array $plugincache - A cache of plugin lookups to match a column name to a plugin efficiently */ 64 private $plugincache = array(); 65 /** @var array $scale - A list of the keys and descriptions for the custom scale */ 66 private $scale = null; 67 68 /** 69 * overridden constructor keeps a reference to the assignment class that is displaying this table 70 * 71 * @param assign $assignment The assignment class 72 * @param int $perpage how many per page 73 * @param string $filter The current filter 74 * @param int $rowoffset For showing a subsequent page of results 75 * @param bool $quickgrading Is this table wrapped in a quickgrading form? 76 * @param string $downloadfilename 77 */ 78 public function __construct(assign $assignment, 79 $perpage, 80 $filter, 81 $rowoffset, 82 $quickgrading, 83 $downloadfilename = null) { 84 global $CFG, $PAGE, $DB, $USER; 85 parent::__construct('mod_assign_grading'); 86 $this->is_persistent(true); 87 $this->assignment = $assignment; 88 89 // Check permissions up front. 90 $this->hasgrantextension = has_capability('mod/assign:grantextension', 91 $this->assignment->get_context()); 92 $this->hasgrade = $this->assignment->can_grade(); 93 94 // Check if we have the elevated view capablities to see the blind details. 95 $this->hasviewblind = has_capability('mod/assign:viewblinddetails', 96 $this->assignment->get_context()); 97 98 foreach ($assignment->get_feedback_plugins() as $plugin) { 99 if ($plugin->is_visible() && $plugin->is_enabled()) { 100 foreach ($plugin->get_grading_batch_operations() as $action => $description) { 101 if (empty($this->plugingradingbatchoperations)) { 102 $this->plugingradingbatchoperations[$plugin->get_type()] = array(); 103 } 104 $this->plugingradingbatchoperations[$plugin->get_type()][$action] = $description; 105 } 106 } 107 } 108 $this->perpage = $perpage; 109 $this->quickgrading = $quickgrading && $this->hasgrade; 110 $this->output = $PAGE->get_renderer('mod_assign'); 111 112 $urlparams = array('action'=>'grading', 'id'=>$assignment->get_course_module()->id); 113 $url = new moodle_url($CFG->wwwroot . '/mod/assign/view.php', $urlparams); 114 $this->define_baseurl($url); 115 116 // Do some business - then set the sql. 117 $currentgroup = groups_get_activity_group($assignment->get_course_module(), true); 118 119 if ($rowoffset) { 120 $this->rownum = $rowoffset - 1; 121 } 122 123 $users = array_keys( $assignment->list_participants($currentgroup, true)); 124 if (count($users) == 0) { 125 // Insert a record that will never match to the sql is still valid. 126 $users[] = -1; 127 } 128 129 $params = array(); 130 $params['assignmentid1'] = (int)$this->assignment->get_instance()->id; 131 $params['assignmentid2'] = (int)$this->assignment->get_instance()->id; 132 $params['assignmentid3'] = (int)$this->assignment->get_instance()->id; 133 134 $extrauserfields = get_extra_user_fields($this->assignment->get_context()); 135 136 $fields = user_picture::fields('u', $extrauserfields) . ', '; 137 $fields .= 'u.id as userid, '; 138 $fields .= 's.status as status, '; 139 $fields .= 's.id as submissionid, '; 140 $fields .= 's.timecreated as firstsubmission, '; 141 $fields .= 's.timemodified as timesubmitted, '; 142 $fields .= 's.attemptnumber as attemptnumber, '; 143 $fields .= 'g.id as gradeid, '; 144 $fields .= 'g.grade as grade, '; 145 $fields .= 'g.timemodified as timemarked, '; 146 $fields .= 'g.timecreated as firstmarked, '; 147 $fields .= 'uf.mailed as mailed, '; 148 $fields .= 'uf.locked as locked, '; 149 $fields .= 'uf.extensionduedate as extensionduedate, '; 150 $fields .= 'uf.workflowstate as workflowstate, '; 151 $fields .= 'uf.allocatedmarker as allocatedmarker '; 152 153 $from = '{user} u 154 LEFT JOIN {assign_submission} s 155 ON u.id = s.userid 156 AND s.assignment = :assignmentid1 157 AND s.latest = 1 158 LEFT JOIN {assign_grades} g 159 ON u.id = g.userid 160 AND g.assignment = :assignmentid2 '; 161 162 // For group submissions we don't immediately create an entry in the assign_submission table for each user, 163 // instead the userid is set to 0. In this case we use a different query to retrieve the grade for the user. 164 if ($this->assignment->get_instance()->teamsubmission) { 165 $params['assignmentid4'] = (int) $this->assignment->get_instance()->id; 166 $grademaxattempt = 'SELECT mxg.userid, MAX(mxg.attemptnumber) AS maxattempt 167 FROM {assign_grades} mxg 168 WHERE mxg.assignment = :assignmentid4 169 GROUP BY mxg.userid'; 170 $from .= 'LEFT JOIN (' . $grademaxattempt . ') gmx 171 ON u.id = gmx.userid 172 AND g.attemptnumber = gmx.maxattempt '; 173 } else { 174 $from .= 'AND g.attemptnumber = s.attemptnumber '; 175 } 176 177 $from .= 'LEFT JOIN {assign_user_flags} uf 178 ON u.id = uf.userid 179 AND uf.assignment = :assignmentid3'; 180 181 $userparams = array(); 182 $userindex = 0; 183 184 list($userwhere, $userparams) = $DB->get_in_or_equal($users, SQL_PARAMS_NAMED, 'user'); 185 $where = 'u.id ' . $userwhere; 186 $params = array_merge($params, $userparams); 187 188 // The filters do not make sense when there are no submissions, so do not apply them. 189 if ($this->assignment->is_any_submission_plugin_enabled()) { 190 if ($filter == ASSIGN_FILTER_SUBMITTED) { 191 $where .= ' AND (s.timemodified IS NOT NULL AND 192 s.status = :submitted) '; 193 $params['submitted'] = ASSIGN_SUBMISSION_STATUS_SUBMITTED; 194 195 } else if ($filter == ASSIGN_FILTER_NOT_SUBMITTED) { 196 $where .= ' AND (s.timemodified IS NULL OR s.status != :submitted) '; 197 $params['submitted'] = ASSIGN_SUBMISSION_STATUS_SUBMITTED; 198 } else if ($filter == ASSIGN_FILTER_REQUIRE_GRADING) { 199 $where .= ' AND (s.timemodified IS NOT NULL AND 200 s.status = :submitted AND 201 (s.timemodified >= g.timemodified OR g.timemodified IS NULL OR g.grade IS NULL))'; 202 $params['submitted'] = ASSIGN_SUBMISSION_STATUS_SUBMITTED; 203 204 } else if (strpos($filter, ASSIGN_FILTER_SINGLE_USER) === 0) { 205 $userfilter = (int) array_pop(explode('=', $filter)); 206 $where .= ' AND (u.id = :userid)'; 207 $params['userid'] = $userfilter; 208 } 209 } 210 211 if ($this->assignment->get_instance()->markingworkflow && 212 $this->assignment->get_instance()->markingallocation) { 213 if (has_capability('mod/assign:manageallocations', $this->assignment->get_context())) { 214 // Check to see if marker filter is set. 215 $markerfilter = (int)get_user_preferences('assign_markerfilter', ''); 216 if (!empty($markerfilter)) { 217 if ($markerfilter == ASSIGN_MARKER_FILTER_NO_MARKER) { 218 $where .= ' AND (uf.allocatedmarker IS NULL OR uf.allocatedmarker = 0)'; 219 } else { 220 $where .= ' AND uf.allocatedmarker = :markerid'; 221 $params['markerid'] = $markerfilter; 222 } 223 } 224 } else { // Only show users allocated to this marker. 225 $where .= ' AND uf.allocatedmarker = :markerid'; 226 $params['markerid'] = $USER->id; 227 } 228 } 229 230 if ($this->assignment->get_instance()->markingworkflow) { 231 $workflowstates = $this->assignment->get_marking_workflow_states_for_current_user(); 232 if (!empty($workflowstates)) { 233 $workflowfilter = get_user_preferences('assign_workflowfilter', ''); 234 if ($workflowfilter == ASSIGN_MARKING_WORKFLOW_STATE_NOTMARKED) { 235 $where .= ' AND (uf.workflowstate = :workflowstate OR uf.workflowstate IS NULL OR '. 236 $DB->sql_isempty('assign_user_flags', 'workflowstate', true, true).')'; 237 $params['workflowstate'] = $workflowfilter; 238 } else if (array_key_exists($workflowfilter, $workflowstates)) { 239 $where .= ' AND uf.workflowstate = :workflowstate'; 240 $params['workflowstate'] = $workflowfilter; 241 } 242 } 243 } 244 245 $this->set_sql($fields, $from, $where, $params); 246 247 if ($downloadfilename) { 248 $this->is_downloading('csv', $downloadfilename); 249 } 250 251 $columns = array(); 252 $headers = array(); 253 254 // Select. 255 if (!$this->is_downloading() && $this->hasgrade) { 256 $columns[] = 'select'; 257 $headers[] = get_string('select') . 258 '<div class="selectall"><label class="accesshide" for="selectall">' . get_string('selectall') . '</label> 259 <input type="checkbox" id="selectall" name="selectall" title="' . get_string('selectall') . '"/></div>'; 260 } 261 262 // User picture. 263 if ($this->hasviewblind || !$this->assignment->is_blind_marking()) { 264 if (!$this->is_downloading()) { 265 $columns[] = 'picture'; 266 $headers[] = get_string('pictureofuser'); 267 } else { 268 $columns[] = 'recordid'; 269 $headers[] = get_string('recordid', 'assign'); 270 } 271 272 // Fullname. 273 $columns[] = 'fullname'; 274 $headers[] = get_string('fullname'); 275 276 // Participant # details if can view real identities. 277 if ($this->assignment->is_blind_marking()) { 278 if (!$this->is_downloading()) { 279 $columns[] = 'recordid'; 280 $headers[] = get_string('recordid', 'assign'); 281 } 282 } 283 284 foreach ($extrauserfields as $extrafield) { 285 $columns[] = $extrafield; 286 $headers[] = get_user_field_name($extrafield); 287 } 288 } else { 289 // Record ID. 290 $columns[] = 'recordid'; 291 $headers[] = get_string('recordid', 'assign'); 292 } 293 294 // Submission status. 295 $columns[] = 'status'; 296 $headers[] = get_string('status', 'assign'); 297 298 // Team submission columns. 299 if ($assignment->get_instance()->teamsubmission) { 300 $columns[] = 'team'; 301 $headers[] = get_string('submissionteam', 'assign'); 302 } 303 // Allocated marker. 304 if ($this->assignment->get_instance()->markingworkflow && 305 $this->assignment->get_instance()->markingallocation && 306 has_capability('mod/assign:manageallocations', $this->assignment->get_context())) { 307 // Add a column for the allocated marker. 308 $columns[] = 'allocatedmarker'; 309 $headers[] = get_string('marker', 'assign'); 310 } 311 // Grade. 312 $columns[] = 'grade'; 313 $headers[] = get_string('grade'); 314 if ($this->is_downloading()) { 315 if ($this->assignment->get_instance()->grade >= 0) { 316 $columns[] = 'grademax'; 317 $headers[] = get_string('maxgrade', 'assign'); 318 } else { 319 // This is a custom scale. 320 $columns[] = 'scale'; 321 $headers[] = get_string('scale', 'assign'); 322 } 323 324 if ($this->assignment->get_instance()->markingworkflow) { 325 // Add a column for the marking workflow state. 326 $columns[] = 'workflowstate'; 327 $headers[] = get_string('markingworkflowstate', 'assign'); 328 } 329 // Add a column for the list of valid marking workflow states. 330 $columns[] = 'gradecanbechanged'; 331 $headers[] = get_string('gradecanbechanged', 'assign'); 332 } 333 if (!$this->is_downloading() && $this->hasgrade) { 334 // We have to call this column userid so we can use userid as a default sortable column. 335 $columns[] = 'userid'; 336 $headers[] = get_string('edit'); 337 } 338 339 // Submission plugins. 340 if ($assignment->is_any_submission_plugin_enabled()) { 341 $columns[] = 'timesubmitted'; 342 $headers[] = get_string('lastmodifiedsubmission', 'assign'); 343 344 foreach ($this->assignment->get_submission_plugins() as $plugin) { 345 if ($this->is_downloading()) { 346 if ($plugin->is_visible() && $plugin->is_enabled()) { 347 foreach ($plugin->get_editor_fields() as $field => $description) { 348 $index = 'plugin' . count($this->plugincache); 349 $this->plugincache[$index] = array($plugin, $field); 350 $columns[] = $index; 351 $headers[] = $plugin->get_name(); 352 } 353 } 354 } else { 355 if ($plugin->is_visible() && $plugin->is_enabled() && $plugin->has_user_summary()) { 356 $index = 'plugin' . count($this->plugincache); 357 $this->plugincache[$index] = array($plugin); 358 $columns[] = $index; 359 $headers[] = $plugin->get_name(); 360 } 361 } 362 } 363 } 364 365 // Time marked. 366 $columns[] = 'timemarked'; 367 $headers[] = get_string('lastmodifiedgrade', 'assign'); 368 369 // Feedback plugins. 370 foreach ($this->assignment->get_feedback_plugins() as $plugin) { 371 if ($this->is_downloading()) { 372 if ($plugin->is_visible() && $plugin->is_enabled()) { 373 foreach ($plugin->get_editor_fields() as $field => $description) { 374 $index = 'plugin' . count($this->plugincache); 375 $this->plugincache[$index] = array($plugin, $field); 376 $columns[] = $index; 377 $headers[] = $description; 378 } 379 } 380 } else if ($plugin->is_visible() && $plugin->is_enabled() && $plugin->has_user_summary()) { 381 $index = 'plugin' . count($this->plugincache); 382 $this->plugincache[$index] = array($plugin); 383 $columns[] = $index; 384 $headers[] = $plugin->get_name(); 385 } 386 } 387 388 // Exclude 'Final grade' column in downloaded grading worksheets. 389 if (!$this->is_downloading()) { 390 // Final grade. 391 $columns[] = 'finalgrade'; 392 $headers[] = get_string('finalgrade', 'grades'); 393 } 394 395 // Load the grading info for all users. 396 $this->gradinginfo = grade_get_grades($this->assignment->get_course()->id, 397 'mod', 398 'assign', 399 $this->assignment->get_instance()->id, 400 $users); 401 402 if (!empty($CFG->enableoutcomes) && !empty($this->gradinginfo->outcomes)) { 403 $columns[] = 'outcomes'; 404 $headers[] = get_string('outcomes', 'grades'); 405 } 406 407 // Set the columns. 408 $this->define_columns($columns); 409 $this->define_headers($headers); 410 foreach ($extrauserfields as $extrafield) { 411 $this->column_class($extrafield, $extrafield); 412 } 413 $this->no_sorting('recordid'); 414 $this->no_sorting('finalgrade'); 415 $this->no_sorting('userid'); 416 $this->no_sorting('select'); 417 $this->no_sorting('outcomes'); 418 419 if ($assignment->get_instance()->teamsubmission) { 420 $this->no_sorting('team'); 421 } 422 423 $plugincolumnindex = 0; 424 foreach ($this->assignment->get_submission_plugins() as $plugin) { 425 if ($plugin->is_visible() && $plugin->is_enabled() && $plugin->has_user_summary()) { 426 $submissionpluginindex = 'plugin' . $plugincolumnindex++; 427 $this->no_sorting($submissionpluginindex); 428 } 429 } 430 foreach ($this->assignment->get_feedback_plugins() as $plugin) { 431 if ($plugin->is_visible() && $plugin->is_enabled() && $plugin->has_user_summary()) { 432 $feedbackpluginindex = 'plugin' . $plugincolumnindex++; 433 $this->no_sorting($feedbackpluginindex); 434 } 435 } 436 437 // When there is no data we still want the column headers printed in the csv file. 438 if ($this->is_downloading()) { 439 $this->start_output(); 440 } 441 } 442 443 /** 444 * Before adding each row to the table make sure rownum is incremented. 445 * 446 * @param array $row row of data from db used to make one row of the table. 447 * @return array one row for the table 448 */ 449 public function format_row($row) { 450 if ($this->rownum < 0) { 451 $this->rownum = $this->currpage * $this->pagesize; 452 } else { 453 $this->rownum += 1; 454 } 455 456 return parent::format_row($row); 457 } 458 459 /** 460 * Add a column with an ID that uniquely identifies this user in this assignment. 461 * 462 * @param stdClass $row 463 * @return string 464 */ 465 public function col_recordid(stdClass $row) { 466 return get_string('hiddenuser', 'assign') . 467 $this->assignment->get_uniqueid_for_user($row->userid); 468 } 469 470 471 /** 472 * Add the userid to the row class so it can be updated via ajax. 473 * 474 * @param stdClass $row The row of data 475 * @return string The row class 476 */ 477 public function get_row_class($row) { 478 return 'user' . $row->userid; 479 } 480 481 /** 482 * Return the number of rows to display on a single page. 483 * 484 * @return int The number of rows per page 485 */ 486 public function get_rows_per_page() { 487 return $this->perpage; 488 } 489 490 /** 491 * list current marking workflow state 492 * 493 * @param stdClass $row 494 * @return string 495 */ 496 public function col_workflowstatus(stdClass $row) { 497 $o = ''; 498 499 $gradingdisabled = $this->assignment->grading_disabled($row->id); 500 // The function in the assignment keeps a static cache of this list of states. 501 $workflowstates = $this->assignment->get_marking_workflow_states_for_current_user(); 502 $workflowstate = $row->workflowstate; 503 if (empty($workflowstate)) { 504 $workflowstate = ASSIGN_MARKING_WORKFLOW_STATE_NOTMARKED; 505 } 506 if ($this->quickgrading && !$gradingdisabled) { 507 $notmarked = get_string('markingworkflowstatenotmarked', 'assign'); 508 $name = 'quickgrade_' . $row->id . '_workflowstate'; 509 $o .= html_writer::select($workflowstates, $name, $workflowstate, array('' => $notmarked)); 510 // Check if this user is a marker that can't manage allocations and doesn't have the marker column added. 511 if ($this->assignment->get_instance()->markingworkflow && 512 $this->assignment->get_instance()->markingallocation && 513 !has_capability('mod/assign:manageallocations', $this->assignment->get_context())) { 514 515 $name = 'quickgrade_' . $row->id . '_allocatedmarker'; 516 $o .= html_writer::empty_tag('input', array('type' => 'hidden', 'name' => $name, 517 'value' => $row->allocatedmarker)); 518 } 519 } else { 520 $o .= $this->output->container(get_string('markingworkflowstate' . $workflowstate, 'assign'), $workflowstate); 521 } 522 return $o; 523 } 524 525 /** 526 * For download only - list current marking workflow state 527 * 528 * @param stdClass $row - The row of data 529 * @return string The current marking workflow state 530 */ 531 public function col_workflowstate($row) { 532 $state = $row->workflowstate; 533 if (empty($state)) { 534 $state = ASSIGN_MARKING_WORKFLOW_STATE_NOTMARKED; 535 } 536 537 return get_string('markingworkflowstate' . $state, 'assign'); 538 } 539 540 /** 541 * list current marker 542 * 543 * @param stdClass $row - The row of data 544 * @return id the user->id of the marker. 545 */ 546 public function col_allocatedmarker(stdClass $row) { 547 static $markers = null; 548 static $markerlist = array(); 549 if ($markers === null) { 550 list($sort, $params) = users_order_by_sql(); 551 $markers = get_users_by_capability($this->assignment->get_context(), 'mod/assign:grade', '', $sort); 552 $markerlist[0] = get_string('choosemarker', 'assign'); 553 foreach ($markers as $marker) { 554 $markerlist[$marker->id] = fullname($marker); 555 } 556 } 557 if (empty($markerlist)) { 558 // TODO: add some form of notification here that no markers are available. 559 return ''; 560 } 561 if ($this->is_downloading()) { 562 if (isset($markers[$row->allocatedmarker])) { 563 return fullname($markers[$row->allocatedmarker]); 564 } else { 565 return ''; 566 } 567 } 568 569 if ($this->quickgrading && has_capability('mod/assign:manageallocations', $this->assignment->get_context()) && 570 (empty($row->workflowstate) || 571 $row->workflowstate == ASSIGN_MARKING_WORKFLOW_STATE_INMARKING || 572 $row->workflowstate == ASSIGN_MARKING_WORKFLOW_STATE_NOTMARKED)) { 573 574 $name = 'quickgrade_' . $row->id . '_allocatedmarker'; 575 return html_writer::select($markerlist, $name, $row->allocatedmarker, false); 576 } else if (!empty($row->allocatedmarker)) { 577 $output = ''; 578 if ($this->quickgrading) { // Add hidden field for quickgrading page. 579 $name = 'quickgrade_' . $row->id . '_allocatedmarker'; 580 $output .= html_writer::empty_tag('input', array('type'=>'hidden', 'name'=>$name, 'value'=>$row->allocatedmarker)); 581 } 582 $output .= $markerlist[$row->allocatedmarker]; 583 return $output; 584 } 585 } 586 /** 587 * For download only - list all the valid options for this custom scale. 588 * 589 * @param stdClass $row - The row of data 590 * @return string A list of valid options for the current scale 591 */ 592 public function col_scale($row) { 593 global $DB; 594 595 if (empty($this->scale)) { 596 $dbparams = array('id'=>-($this->assignment->get_instance()->grade)); 597 $this->scale = $DB->get_record('scale', $dbparams); 598 } 599 600 if (!empty($this->scale->scale)) { 601 return implode("\n", explode(',', $this->scale->scale)); 602 } 603 return ''; 604 } 605 606 /** 607 * Display a grade with scales etc. 608 * 609 * @param string $grade 610 * @param boolean $editable 611 * @param int $userid The user id of the user this grade belongs to 612 * @param int $modified Timestamp showing when the grade was last modified 613 * @return string The formatted grade 614 */ 615 public function display_grade($grade, $editable, $userid, $modified) { 616 if ($this->is_downloading()) { 617 if ($this->assignment->get_instance()->grade >= 0) { 618 if ($grade == -1 || $grade === null) { 619 return ''; 620 } 621 return format_float($grade, 2); 622 } else { 623 // This is a custom scale. 624 $scale = $this->assignment->display_grade($grade, false); 625 if ($scale == '-') { 626 $scale = ''; 627 } 628 return $scale; 629 } 630 } 631 return $this->assignment->display_grade($grade, $editable, $userid, $modified); 632 } 633 634 /** 635 * Get the team info for this user. 636 * 637 * @param stdClass $row 638 * @return string The team name 639 */ 640 public function col_team(stdClass $row) { 641 $submission = false; 642 $group = false; 643 $this->get_group_and_submission($row->id, $group, $submission, -1); 644 if ($group) { 645 return $group->name; 646 } else if ($this->assignment->get_instance()->preventsubmissionnotingroup) { 647 $usergroups = $this->assignment->get_all_groups($row->id); 648 if (count($usergroups) > 1) { 649 return get_string('multipleteamsgrader', 'assign'); 650 } else { 651 return get_string('noteamgrader', 'assign'); 652 } 653 } 654 return get_string('defaultteam', 'assign'); 655 } 656 657 /** 658 * Use a static cache to try and reduce DB calls. 659 * 660 * @param int $userid The user id for this submission 661 * @param int $group The groupid (returned) 662 * @param stdClass|false $submission The stdClass submission or false (returned) 663 * @param int $attemptnumber Return a specific attempt number (-1 for latest) 664 */ 665 protected function get_group_and_submission($userid, &$group, &$submission, $attemptnumber) { 666 $group = false; 667 if (isset($this->submissiongroups[$userid])) { 668 $group = $this->submissiongroups[$userid]; 669 } else { 670 $group = $this->assignment->get_submission_group($userid, false); 671 $this->submissiongroups[$userid] = $group; 672 } 673 674 $groupid = 0; 675 if ($group) { 676 $groupid = $group->id; 677 } 678 679 // Static cache is keyed by groupid and attemptnumber. 680 // We may need both the latest and previous attempt in the same page. 681 if (isset($this->groupsubmissions[$groupid . ':' . $attemptnumber])) { 682 $submission = $this->groupsubmissions[$groupid . ':' . $attemptnumber]; 683 } else { 684 $submission = $this->assignment->get_group_submission($userid, $groupid, false, $attemptnumber); 685 $this->groupsubmissions[$groupid . ':' . $attemptnumber] = $submission; 686 } 687 } 688 689 /** 690 * Format a list of outcomes. 691 * 692 * @param stdClass $row 693 * @return string 694 */ 695 public function col_outcomes(stdClass $row) { 696 $outcomes = ''; 697 foreach ($this->gradinginfo->outcomes as $index => $outcome) { 698 $options = make_grades_menu(-$outcome->scaleid); 699 700 $options[0] = get_string('nooutcome', 'grades'); 701 if ($this->quickgrading && !($outcome->grades[$row->userid]->locked)) { 702 $select = '<select name="outcome_' . $index . '_' . $row->userid . '" class="quickgrade">'; 703 foreach ($options as $optionindex => $optionvalue) { 704 $selected = ''; 705 if ($outcome->grades[$row->userid]->grade == $optionindex) { 706 $selected = 'selected="selected"'; 707 } 708 $select .= '<option value="' . $optionindex . '"' . $selected . '>' . $optionvalue . '</option>'; 709 } 710 $select .= '</select>'; 711 $outcomes .= $this->output->container($outcome->name . ': ' . $select, 'outcome'); 712 } else { 713 $name = $outcome->name . ': ' . $options[$outcome->grades[$row->userid]->grade]; 714 if ($this->is_downloading()) { 715 $outcomes .= $name; 716 } else { 717 $outcomes .= $this->output->container($name, 'outcome'); 718 } 719 } 720 } 721 722 return $outcomes; 723 } 724 725 726 /** 727 * Format a user picture for display. 728 * 729 * @param stdClass $row 730 * @return string 731 */ 732 public function col_picture(stdClass $row) { 733 return $this->output->user_picture($row); 734 } 735 736 /** 737 * Format a user record for display (link to profile). 738 * 739 * @param stdClass $row 740 * @return string 741 */ 742 public function col_fullname($row) { 743 if (!$this->is_downloading()) { 744 $courseid = $this->assignment->get_course()->id; 745 $link= new moodle_url('/user/view.php', array('id' =>$row->id, 'course'=>$courseid)); 746 $fullname = $this->output->action_link($link, $this->assignment->fullname($row)); 747 } else { 748 $fullname = $this->assignment->fullname($row); 749 } 750 751 if (!$this->assignment->is_active_user($row->id)) { 752 $suspendedstring = get_string('userenrolmentsuspended', 'grades'); 753 $fullname .= ' ' . html_writer::empty_tag('img', array('src' => $this->output->pix_url('i/enrolmentsuspended'), 754 'title' => $suspendedstring, 'alt' => $suspendedstring, 'class' => 'usersuspendedicon')); 755 $fullname = html_writer::tag('span', $fullname, array('class' => 'usersuspended')); 756 } 757 return $fullname; 758 } 759 760 /** 761 * Insert a checkbox for selecting the current row for batch operations. 762 * 763 * @param stdClass $row 764 * @return string 765 */ 766 public function col_select(stdClass $row) { 767 $selectcol = '<label class="accesshide" for="selectuser_' . $row->userid . '">'; 768 $selectcol .= get_string('selectuser', 'assign', $this->assignment->fullname($row)); 769 $selectcol .= '</label>'; 770 $selectcol .= '<input type="checkbox" 771 id="selectuser_' . $row->userid . '" 772 name="selectedusers" 773 value="' . $row->userid . '"/>'; 774 $selectcol .= '<input type="hidden" 775 name="grademodified_' . $row->userid . '" 776 value="' . $row->timemarked . '"/>'; 777 $selectcol .= '<input type="hidden" 778 name="gradeattempt_' . $row->userid . '" 779 value="' . $row->attemptnumber . '"/>'; 780 return $selectcol; 781 } 782 783 /** 784 * Return a users grades from the listing of all grade data for this assignment. 785 * 786 * @param int $userid 787 * @return mixed stdClass or false 788 */ 789 private function get_gradebook_data_for_user($userid) { 790 if (isset($this->gradinginfo->items[0]) && $this->gradinginfo->items[0]->grades[$userid]) { 791 return $this->gradinginfo->items[0]->grades[$userid]; 792 } 793 return false; 794 } 795 796 /** 797 * Format a column of data for display. 798 * 799 * @param stdClass $row 800 * @return string 801 */ 802 public function col_gradecanbechanged(stdClass $row) { 803 $gradingdisabled = $this->assignment->grading_disabled($row->id); 804 if ($gradingdisabled) { 805 return get_string('no'); 806 } else { 807 return get_string('yes'); 808 } 809 } 810 811 /** 812 * Format a column of data for display 813 * 814 * @param stdClass $row 815 * @return string 816 */ 817 public function col_grademax(stdClass $row) { 818 return format_float($this->assignment->get_instance()->grade, 2); 819 } 820 821 /** 822 * Format a column of data for display. 823 * 824 * @param stdClass $row 825 * @return string 826 */ 827 public function col_grade(stdClass $row) { 828 $o = ''; 829 830 $link = ''; 831 $separator = $this->output->spacer(array(), true); 832 $grade = ''; 833 $gradingdisabled = $this->assignment->grading_disabled($row->id); 834 835 if (!$this->is_downloading() && $this->hasgrade) { 836 $urlparams = array('id' => $this->assignment->get_course_module()->id, 837 'rownum' => 0, 838 'action' => 'grader'); 839 840 if ($this->assignment->is_blind_marking()) { 841 $urlparams['blindid'] = $this->assignment->get_uniqueid_for_user($row->userid); 842 } else { 843 $urlparams['userid'] = $row->userid; 844 } 845 846 $url = new moodle_url('/mod/assign/view.php', $urlparams); 847 $link = '<a href="' . $url . '" class="btn btn-primary">' . get_string('grade') . '</a>'; 848 $grade .= $link . $separator; 849 } 850 851 $grade .= $this->display_grade($row->grade, 852 $this->quickgrading && !$gradingdisabled, 853 $row->userid, 854 $row->timemarked); 855 856 return $grade; 857 } 858 859 /** 860 * Format a column of data for display. 861 * 862 * @param stdClass $row 863 * @return string 864 */ 865 public function col_finalgrade(stdClass $row) { 866 $o = ''; 867 868 $grade = $this->get_gradebook_data_for_user($row->userid); 869 if ($grade) { 870 $o = $this->display_grade($grade->grade, false, $row->userid, $row->timemarked); 871 } 872 873 return $o; 874 } 875 876 /** 877 * Format a column of data for display. 878 * 879 * @param stdClass $row 880 * @return string 881 */ 882 public function col_timemarked(stdClass $row) { 883 $o = '-'; 884 885 if ($row->timemarked && $row->grade !== null && $row->grade >= 0) { 886 $o = userdate($row->timemarked); 887 } 888 if ($row->timemarked && $this->is_downloading()) { 889 // Force it for downloads as it affects import. 890 $o = userdate($row->timemarked); 891 } 892 893 return $o; 894 } 895 896 /** 897 * Format a column of data for display. 898 * 899 * @param stdClass $row 900 * @return string 901 */ 902 public function col_timesubmitted(stdClass $row) { 903 $o = '-'; 904 905 $group = false; 906 $submission = false; 907 $this->get_group_and_submission($row->id, $group, $submission, -1); 908 if ($submission && $submission->timemodified && $submission->status != ASSIGN_SUBMISSION_STATUS_NEW) { 909 $o = userdate($submission->timemodified); 910 } else if ($row->timesubmitted && $row->status != ASSIGN_SUBMISSION_STATUS_NEW) { 911 $o = userdate($row->timesubmitted); 912 } 913 914 return $o; 915 } 916 917 /** 918 * Format a column of data for display 919 * 920 * @param stdClass $row 921 * @return string 922 */ 923 public function col_status(stdClass $row) { 924 $o = ''; 925 926 $instance = $this->assignment->get_instance(); 927 928 $due = $instance->duedate; 929 if ($row->extensionduedate) { 930 $due = $row->extensionduedate; 931 } 932 933 $group = false; 934 $submission = false; 935 $this->get_group_and_submission($row->id, $group, $submission, -1); 936 937 if ($instance->teamsubmission && !$group && !$instance->preventsubmissionnotingroup) { 938 $group = true; 939 } 940 941 if ($group && $submission) { 942 $timesubmitted = $submission->timemodified; 943 $status = $submission->status; 944 } else { 945 $timesubmitted = $row->timesubmitted; 946 $status = $row->status; 947 } 948 949 $displaystatus = $status; 950 if ($displaystatus == 'new') { 951 $displaystatus = ''; 952 } 953 954 if ($this->assignment->is_any_submission_plugin_enabled()) { 955 956 $o .= $this->output->container(get_string('submissionstatus_' . $displaystatus, 'assign'), 957 array('class'=>'submissionstatus' .$displaystatus)); 958 if ($due && $timesubmitted > $due && $status != ASSIGN_SUBMISSION_STATUS_NEW) { 959 $usertime = format_time($timesubmitted - $due); 960 $latemessage = get_string('submittedlateshort', 961 'assign', 962 $usertime); 963 $o .= $this->output->container($latemessage, 'latesubmission'); 964 } 965 if ($row->locked) { 966 $lockedstr = get_string('submissionslockedshort', 'assign'); 967 $o .= $this->output->container($lockedstr, 'lockedsubmission'); 968 } 969 970 // Add status of "grading" if markflow is not enabled. 971 if (!$instance->markingworkflow) { 972 if ($row->grade !== null && $row->grade >= 0) { 973 $o .= $this->output->container(get_string('graded', 'assign'), 'submissiongraded'); 974 } else if (!$timesubmitted || $status == ASSIGN_SUBMISSION_STATUS_NEW) { 975 $now = time(); 976 if ($due && ($now > $due)) { 977 $overduestr = get_string('overdue', 'assign', format_time($now - $due)); 978 $o .= $this->output->container($overduestr, 'overduesubmission'); 979 } 980 } 981 } 982 } 983 984 if ($instance->markingworkflow) { 985 $o .= $this->col_workflowstatus($row); 986 } 987 if ($row->extensionduedate) { 988 $userdate = userdate($row->extensionduedate); 989 $extensionstr = get_string('userextensiondate', 'assign', $userdate); 990 $o .= $this->output->container($extensionstr, 'extensiondate'); 991 } 992 993 if ($this->is_downloading()) { 994 $o = strip_tags(rtrim(str_replace('</div>', ' - ', $o), '- ')); 995 } 996 997 return $o; 998 } 999 1000 /** 1001 * Format a column of data for display. 1002 * 1003 * @param stdClass $row 1004 * @return string 1005 */ 1006 public function col_userid(stdClass $row) { 1007 global $USER; 1008 1009 $edit = ''; 1010 1011 $actions = array(); 1012 1013 $urlparams = array('id' => $this->assignment->get_course_module()->id, 1014 'rownum' => 0, 1015 'action' => 'grader'); 1016 1017 if ($this->assignment->is_blind_marking()) { 1018 $urlparams['blindid'] = $this->assignment->get_uniqueid_for_user($row->userid); 1019 } else { 1020 $urlparams['userid'] = $row->userid; 1021 } 1022 $url = new moodle_url('/mod/assign/view.php', $urlparams); 1023 $noimage = null; 1024 1025 if (!$row->grade) { 1026 $description = get_string('grade'); 1027 } else { 1028 $description = get_string('updategrade', 'assign'); 1029 } 1030 $actions['grade'] = new action_menu_link_secondary( 1031 $url, 1032 $noimage, 1033 $description 1034 ); 1035 1036 // Everything we need is in the row. 1037 $submission = $row; 1038 $flags = $row; 1039 if ($this->assignment->get_instance()->teamsubmission) { 1040 // Use the cache for this. 1041 $submission = false; 1042 $group = false; 1043 $this->get_group_and_submission($row->id, $group, $submission, -1); 1044 } 1045 1046 $submissionsopen = $this->assignment->submissions_open($row->id, 1047 true, 1048 $submission, 1049 $flags, 1050 $this->gradinginfo); 1051 $caneditsubmission = $this->assignment->can_edit_submission($row->id, $USER->id); 1052 1053 // Hide for offline assignments. 1054 if ($this->assignment->is_any_submission_plugin_enabled()) { 1055 if (!$row->status || 1056 $row->status == ASSIGN_SUBMISSION_STATUS_DRAFT || 1057 !$this->assignment->get_instance()->submissiondrafts) { 1058 1059 if (!$row->locked) { 1060 $urlparams = array('id' => $this->assignment->get_course_module()->id, 1061 'userid'=>$row->id, 1062 'action'=>'lock', 1063 'sesskey'=>sesskey(), 1064 'page'=>$this->currpage); 1065 $url = new moodle_url('/mod/assign/view.php', $urlparams); 1066 1067 $description = get_string('preventsubmissionsshort', 'assign'); 1068 $actions['lock'] = new action_menu_link_secondary( 1069 $url, 1070 $noimage, 1071 $description 1072 ); 1073 } else { 1074 $urlparams = array('id' => $this->assignment->get_course_module()->id, 1075 'userid'=>$row->id, 1076 'action'=>'unlock', 1077 'sesskey'=>sesskey(), 1078 'page'=>$this->currpage); 1079 $url = new moodle_url('/mod/assign/view.php', $urlparams); 1080 $description = get_string('allowsubmissionsshort', 'assign'); 1081 $actions['unlock'] = new action_menu_link_secondary( 1082 $url, 1083 $noimage, 1084 $description 1085 ); 1086 } 1087 } 1088 1089 if ($submissionsopen && 1090 $USER->id != $row->id && 1091 $caneditsubmission) { 1092 $urlparams = array('id' => $this->assignment->get_course_module()->id, 1093 'userid'=>$row->id, 1094 'action'=>'editsubmission', 1095 'sesskey'=>sesskey(), 1096 'page'=>$this->currpage); 1097 $url = new moodle_url('/mod/assign/view.php', $urlparams); 1098 $description = get_string('editsubmission', 'assign'); 1099 $actions['editsubmission'] = new action_menu_link_secondary( 1100 $url, 1101 $noimage, 1102 $description 1103 ); 1104 } 1105 } 1106 if (($this->assignment->get_instance()->duedate || 1107 $this->assignment->get_instance()->cutoffdate) && 1108 $this->hasgrantextension) { 1109 $urlparams = array('id' => $this->assignment->get_course_module()->id, 1110 'userid' => $row->id, 1111 'action' => 'grantextension', 1112 'sesskey' => sesskey(), 1113 'page' => $this->currpage); 1114 $url = new moodle_url('/mod/assign/view.php', $urlparams); 1115 $description = get_string('grantextension', 'assign'); 1116 $actions['grantextension'] = new action_menu_link_secondary( 1117 $url, 1118 $noimage, 1119 $description 1120 ); 1121 } 1122 if ($row->status == ASSIGN_SUBMISSION_STATUS_SUBMITTED && 1123 $this->assignment->get_instance()->submissiondrafts) { 1124 $urlparams = array('id' => $this->assignment->get_course_module()->id, 1125 'userid'=>$row->id, 1126 'action'=>'reverttodraft', 1127 'sesskey'=>sesskey(), 1128 'page'=>$this->currpage); 1129 $url = new moodle_url('/mod/assign/view.php', $urlparams); 1130 $description = get_string('reverttodraftshort', 'assign'); 1131 $actions['reverttodraft'] = new action_menu_link_secondary( 1132 $url, 1133 $noimage, 1134 $description 1135 ); 1136 } 1137 if ($row->status == ASSIGN_SUBMISSION_STATUS_DRAFT && 1138 $this->assignment->get_instance()->submissiondrafts && 1139 $caneditsubmission && 1140 $submissionsopen && 1141 $row->id != $USER->id) { 1142 $urlparams = array('id' => $this->assignment->get_course_module()->id, 1143 'userid'=>$row->id, 1144 'action'=>'submitotherforgrading', 1145 'sesskey'=>sesskey(), 1146 'page'=>$this->currpage); 1147 $url = new moodle_url('/mod/assign/view.php', $urlparams); 1148 $description = get_string('submitforgrading', 'assign'); 1149 $actions['submitforgrading'] = new action_menu_link_secondary( 1150 $url, 1151 $noimage, 1152 $description 1153 ); 1154 } 1155 1156 $ismanual = $this->assignment->get_instance()->attemptreopenmethod == ASSIGN_ATTEMPT_REOPEN_METHOD_MANUAL; 1157 $hassubmission = !empty($row->status); 1158 $notreopened = $hassubmission && $row->status != ASSIGN_SUBMISSION_STATUS_REOPENED; 1159 $isunlimited = $this->assignment->get_instance()->maxattempts == ASSIGN_UNLIMITED_ATTEMPTS; 1160 $hasattempts = $isunlimited || $row->attemptnumber < $this->assignment->get_instance()->maxattempts - 1; 1161 1162 if ($ismanual && $hassubmission && $notreopened && $hasattempts) { 1163 $urlparams = array('id' => $this->assignment->get_course_module()->id, 1164 'userid'=>$row->id, 1165 'action'=>'addattempt', 1166 'sesskey'=>sesskey(), 1167 'page'=>$this->currpage); 1168 $url = new moodle_url('/mod/assign/view.php', $urlparams); 1169 $description = get_string('addattempt', 'assign'); 1170 $actions['addattempt'] = new action_menu_link_secondary( 1171 $url, 1172 $noimage, 1173 $description 1174 ); 1175 } 1176 1177 $menu = new action_menu(); 1178 $menu->set_owner_selector('.gradingtable-actionmenu'); 1179 $menu->set_alignment(action_menu::TL, action_menu::BL); 1180 $menu->set_constraint('.gradingtable > .no-overflow'); 1181 $menu->set_menu_trigger(get_string('edit')); 1182 foreach ($actions as $action) { 1183 $menu->add($action); 1184 } 1185 1186 // Prioritise the menu ahead of all other actions. 1187 $menu->prioritise = true; 1188 1189 $edit .= $this->output->render($menu); 1190 1191 return $edit; 1192 } 1193 1194 /** 1195 * Write the plugin summary with an optional link to view the full feedback/submission. 1196 * 1197 * @param assign_plugin $plugin Submission plugin or feedback plugin 1198 * @param stdClass $item Submission or grade 1199 * @param string $returnaction The return action to pass to the 1200 * view_submission page (the current page) 1201 * @param string $returnparams The return params to pass to the view_submission 1202 * page (the current page) 1203 * @return string The summary with an optional link 1204 */ 1205 private function format_plugin_summary_with_link(assign_plugin $plugin, 1206 stdClass $item, 1207 $returnaction, 1208 $returnparams) { 1209 $link = ''; 1210 $showviewlink = false; 1211 1212 $summary = $plugin->view_summary($item, $showviewlink); 1213 $separator = ''; 1214 if ($showviewlink) { 1215 $viewstr = get_string('view' . substr($plugin->get_subtype(), strlen('assign')), 'assign'); 1216 $icon = $this->output->pix_icon('t/preview', $viewstr); 1217 $urlparams = array('id' => $this->assignment->get_course_module()->id, 1218 'sid'=>$item->id, 1219 'gid'=>$item->id, 1220 'plugin'=>$plugin->get_type(), 1221 'action'=>'viewplugin' . $plugin->get_subtype(), 1222 'returnaction'=>$returnaction, 1223 'returnparams'=>http_build_query($returnparams)); 1224 $url = new moodle_url('/mod/assign/view.php', $urlparams); 1225 $link = $this->output->action_link($url, $icon); 1226 $separator = $this->output->spacer(array(), true); 1227 } 1228 1229 return $link . $separator . $summary; 1230 } 1231 1232 1233 /** 1234 * Format the submission and feedback columns. 1235 * 1236 * @param string $colname The column name 1237 * @param stdClass $row The submission row 1238 * @return mixed string or NULL 1239 */ 1240 public function other_cols($colname, $row) { 1241 // For extra user fields the result is already in $row. 1242 if (empty($this->plugincache[$colname])) { 1243 return $row->$colname; 1244 } 1245 1246 // This must be a plugin field. 1247 $plugincache = $this->plugincache[$colname]; 1248 1249 $plugin = $plugincache[0]; 1250 1251 $field = null; 1252 if (isset($plugincache[1])) { 1253 $field = $plugincache[1]; 1254 } 1255 1256 if ($plugin->is_visible() && $plugin->is_enabled()) { 1257 if ($plugin->get_subtype() == 'assignsubmission') { 1258 if ($this->assignment->get_instance()->teamsubmission) { 1259 $group = false; 1260 $submission = false; 1261 1262 $this->get_group_and_submission($row->id, $group, $submission, -1); 1263 if ($submission) { 1264 if ($submission->status == ASSIGN_SUBMISSION_STATUS_REOPENED) { 1265 // For a newly reopened submission - we want to show the previous submission in the table. 1266 $this->get_group_and_submission($row->id, $group, $submission, $submission->attemptnumber-1); 1267 } 1268 if (isset($field)) { 1269 return $plugin->get_editor_text($field, $submission->id); 1270 } 1271 return $this->format_plugin_summary_with_link($plugin, 1272 $submission, 1273 'grading', 1274 array()); 1275 } 1276 } else if ($row->submissionid) { 1277 if ($row->status == ASSIGN_SUBMISSION_STATUS_REOPENED) { 1278 // For a newly reopened submission - we want to show the previous submission in the table. 1279 $submission = $this->assignment->get_user_submission($row->userid, false, $row->attemptnumber - 1); 1280 } else { 1281 $submission = new stdClass(); 1282 $submission->id = $row->submissionid; 1283 $submission->timecreated = $row->firstsubmission; 1284 $submission->timemodified = $row->timesubmitted; 1285 $submission->assignment = $this->assignment->get_instance()->id; 1286 $submission->userid = $row->userid; 1287 $submission->attemptnumber = $row->attemptnumber; 1288 } 1289 // Field is used for only for import/export and refers the the fieldname for the text editor. 1290 if (isset($field)) { 1291 return $plugin->get_editor_text($field, $submission->id); 1292 } 1293 return $this->format_plugin_summary_with_link($plugin, 1294 $submission, 1295 'grading', 1296 array()); 1297 } 1298 } else { 1299 $grade = null; 1300 if (isset($field)) { 1301 return $plugin->get_editor_text($field, $row->gradeid); 1302 } 1303 1304 if ($row->gradeid) { 1305 $grade = new stdClass(); 1306 $grade->id = $row->gradeid; 1307 $grade->timecreated = $row->firstmarked; 1308 $grade->timemodified = $row->timemarked; 1309 $grade->assignment = $this->assignment->get_instance()->id; 1310 $grade->userid = $row->userid; 1311 $grade->grade = $row->grade; 1312 $grade->mailed = $row->mailed; 1313 $grade->attemptnumber = $row->attemptnumber; 1314 } 1315 if ($this->quickgrading && $plugin->supports_quickgrading()) { 1316 return $plugin->get_quickgrading_html($row->userid, $grade); 1317 } else if ($grade) { 1318 return $this->format_plugin_summary_with_link($plugin, 1319 $grade, 1320 'grading', 1321 array()); 1322 } 1323 } 1324 } 1325 return ''; 1326 } 1327 1328 /** 1329 * Using the current filtering and sorting - load all rows and return a single column from them. 1330 * 1331 * @param string $columnname The name of the raw column data 1332 * @return array of data 1333 */ 1334 public function get_column_data($columnname) { 1335 $this->setup(); 1336 $this->currpage = 0; 1337 $this->query_db($this->tablemaxrows); 1338 $result = array(); 1339 foreach ($this->rawdata as $row) { 1340 $result[] = $row->$columnname; 1341 } 1342 return $result; 1343 } 1344 1345 /** 1346 * Return things to the renderer. 1347 * 1348 * @return string the assignment name 1349 */ 1350 public function get_assignment_name() { 1351 return $this->assignment->get_instance()->name; 1352 } 1353 1354 /** 1355 * Return things to the renderer. 1356 * 1357 * @return int the course module id 1358 */ 1359 public function get_course_module_id() { 1360 return $this->assignment->get_course_module()->id; 1361 } 1362 1363 /** 1364 * Return things to the renderer. 1365 * 1366 * @return int the course id 1367 */ 1368 public function get_course_id() { 1369 return $this->assignment->get_course()->id; 1370 } 1371 1372 /** 1373 * Return things to the renderer. 1374 * 1375 * @return stdClass The course context 1376 */ 1377 public function get_course_context() { 1378 return $this->assignment->get_course_context(); 1379 } 1380 1381 /** 1382 * Return things to the renderer. 1383 * 1384 * @return bool Does this assignment accept submissions 1385 */ 1386 public function submissions_enabled() { 1387 return $this->assignment->is_any_submission_plugin_enabled(); 1388 } 1389 1390 /** 1391 * Return things to the renderer. 1392 * 1393 * @return bool Can this user view all grades (the gradebook) 1394 */ 1395 public function can_view_all_grades() { 1396 $context = $this->assignment->get_course_context(); 1397 return has_capability('gradereport/grader:view', $context) && 1398 has_capability('moodle/grade:viewall', $context); 1399 } 1400 1401 /** 1402 * Always return a valid sort - even if the userid column is missing. 1403 * @return array column name => SORT_... constant. 1404 */ 1405 public function get_sort_columns() { 1406 $result = parent::get_sort_columns(); 1407 $result = array_merge($result, array('userid' => SORT_ASC)); 1408 return $result; 1409 } 1410 1411 /** 1412 * Override the table show_hide_link to not show for select column. 1413 * 1414 * @param string $column the column name, index into various names. 1415 * @param int $index numerical index of the column. 1416 * @return string HTML fragment. 1417 */ 1418 protected function show_hide_link($column, $index) { 1419 if ($index > 0 || !$this->hasgrade) { 1420 return parent::show_hide_link($column, $index); 1421 } 1422 return ''; 1423 } 1424 1425 /** 1426 * Overides setup to ensure it will only run a single time. 1427 */ 1428 public function setup() { 1429 // Check if the setup function has been called before, we should not run it twice. 1430 // If we do the sortorder of the table will be broken. 1431 if (!empty($this->setup)) { 1432 return; 1433 } 1434 parent::setup(); 1435 } 1436 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
Generated: Thu Aug 11 10:00:09 2016 | Cross-referenced by PHPXref 0.7.1 |