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 namespace gradereport_summary\local\entities; 18 19 use core_reportbuilder\local\filters\select; 20 use grade_item; 21 use grade_plugin_return; 22 use grade_report_summary; 23 use lang_string; 24 use stdClass; 25 use core_reportbuilder\local\entities\base; 26 use core_reportbuilder\local\report\column; 27 use core_reportbuilder\local\report\filter; 28 29 defined('MOODLE_INTERNAL') || die; 30 31 require_once($CFG->dirroot . '/grade/report/summary/lib.php'); 32 require_once($CFG->dirroot . '/grade/lib.php'); 33 34 /** 35 * Grade summary entity class implementation 36 * 37 * @package gradereport_summary 38 * @copyright 2022 Ilya Tregubov <ilya@moodle.com> 39 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 40 */ 41 class grade_items extends base { 42 43 /** @var stdClass Course */ 44 public $course; 45 46 /** @var grade_report_summary Grade report. */ 47 public $report; 48 49 /** @var array Ungraded grade items counts with sql info. */ 50 public $ungradedcounts; 51 52 /** 53 * Entity constructor 54 * 55 * @param stdClass $course 56 */ 57 public function __construct(stdClass $course) { 58 $this->course = $course; 59 } 60 61 /** 62 * Database tables that this entity uses and their default aliases 63 * 64 * @return array 65 */ 66 protected function get_default_table_aliases(): array { 67 return ['grade_items' => 'gi']; 68 } 69 70 /** 71 * The default title for this entity in the list of columns/conditions/filters in the report builder 72 * 73 * @return lang_string 74 */ 75 protected function get_default_entity_title(): lang_string { 76 return new lang_string('gradeitem', 'grades'); 77 } 78 79 /** 80 * Initialise the entity 81 * 82 * @return base 83 */ 84 public function initialise(): base { 85 $context = \context_course::instance($this->course->id); 86 87 $gpr = new grade_plugin_return( 88 [ 89 'type' => 'report', 90 'plugin' => 'summary', 91 'course' => $this->course, 92 ] 93 ); 94 95 $this->report = new grade_report_summary($this->course->id, $gpr, $context); 96 $this->ungradedcounts = $this->report->ungraded_counts(); 97 98 $columns = $this->get_all_columns(); 99 foreach ($columns as $column) { 100 $this->add_column($column); 101 } 102 103 $filters = $this->get_all_filters(); 104 foreach ($filters as $filter) { 105 $this->add_filter($filter); 106 } 107 108 return $this; 109 } 110 111 /** 112 * Returns list of all available columns 113 * 114 * @return column[] 115 */ 116 protected function get_all_columns(): array { 117 118 $tablealias = $this->get_table_alias('grade_items'); 119 $selectsql = "$tablealias.id, $tablealias.itemname, $tablealias.iteminstance, $tablealias.calculation, 120 $tablealias.itemnumber, $tablealias.itemmodule, $tablealias.hidden, $tablealias.courseid"; 121 122 // Grade item name column. 123 $columns[] = (new column( 124 'name', 125 null, 126 $this->get_entity_name() 127 )) 128 ->add_joins($this->get_joins()) 129 ->set_type(column::TYPE_TEXT) 130 ->add_fields($selectsql) 131 ->add_callback(static function($value, $row): string { 132 global $PAGE, $CFG; 133 134 $renderer = new \core_renderer($PAGE, RENDERER_TARGET_GENERAL); 135 if ($row->itemmodule) { 136 $modinfo = get_fast_modinfo($row->courseid); 137 $instances = $modinfo->get_instances(); 138 $cm = $instances[$row->itemmodule][$row->iteminstance]; 139 140 if (file_exists($CFG->dirroot . '/mod/' . $row->itemmodule . '/grade.php')) { 141 $args = ['id' => $cm->id, 'itemnumber' => $row->itemnumber]; 142 $url = new \moodle_url('/mod/' . $row->itemmodule . '/grade.php', $args); 143 } else { 144 $url = new \moodle_url('/mod/' . $row->itemmodule . '/view.php', ['id' => $cm->id]); 145 } 146 147 $imagedata = $renderer->pix_icon('monologo', '', $row->itemmodule, ['class' => 'activityicon']); 148 $purposeclass = plugin_supports('mod', $row->itemmodule, FEATURE_MOD_PURPOSE); 149 $purposeclass .= ' activityiconcontainer'; 150 $purposeclass .= ' modicon_' . $row->itemmodule; 151 $imagedata = \html_writer::tag('div', $imagedata, ['class' => $purposeclass]); 152 153 $dimmed = ''; 154 if ($row->hidden) { 155 $dimmed = ' dimmed_text'; 156 } 157 $html = \html_writer::start_div('page-context-header' . $dimmed); 158 // Image data. 159 $html .= \html_writer::div($imagedata, 'page-header-image mr-2'); 160 $prefix = \html_writer::div(get_string('pluginname', "mod_{$row->itemmodule}"), 161 'text-muted text-uppercase small line-height-3'); 162 $name = $prefix . \html_writer::link($url, format_string($cm->name, true)); 163 $html .= \html_writer::tag('div', $name, ['class' => 'page-header-headings']); 164 } else { 165 // Manual grade item. 166 $gradeitem = grade_item::fetch(['id' => $row->id, 'courseid' => $row->courseid]); 167 if ($row->calculation) { 168 $imagedata = $renderer->pix_icon('i/agg_sum', ''); 169 } else { 170 $imagedata = $renderer->pix_icon('i/manual_item', ''); 171 } 172 $imagedata = \html_writer::tag('div', $imagedata); 173 174 $html = \html_writer::start_div('page-context-header'); 175 // Image data. 176 $html .= \html_writer::div($imagedata, 'page-header-image mr-2'); 177 $html .= \html_writer::tag('div', $gradeitem->get_name(), ['class' => 'page-header-headings']); 178 } 179 return $html; 180 181 }); 182 183 $report = [ 184 'report' => $this->report, 185 'ungradedcounts' => $this->ungradedcounts 186 ]; 187 188 // Average column. 189 $columns[] = (new column( 190 'average', 191 new lang_string('average', 'grades'), 192 $this->get_entity_name() 193 )) 194 ->add_joins($this->get_joins()) 195 ->set_type(column::TYPE_TEXT) 196 ->add_field("$tablealias.id") 197 ->add_callback(static function($value) use ($report): string { 198 199 $gradeitem = grade_item::fetch(['id' => $value]); 200 if (!empty($gradeitem->avg)) { 201 $averageformatted = '-'; 202 } 203 204 if ($gradeitem->needsupdate) { 205 $averageformatted = get_string('error'); 206 } 207 208 if (empty($averageformatted)) { 209 $ungradedcounts = $report['ungradedcounts']; 210 $aggr = $report['report']->calculate_average($gradeitem, $ungradedcounts); 211 212 if (empty($aggr['average'])) { 213 $averageformatted = '-'; 214 } else { 215 $averagesdisplaytype = $ungradedcounts['report']['averagesdisplaytype']; 216 $averagesdecimalpoints = $ungradedcounts['report']['averagesdecimalpoints']; 217 $shownumberofgrades = $ungradedcounts['report']['shownumberofgrades']; 218 219 // Determine which display type to use for this average. 220 // No ==0 here, please resave the report and user preferences. 221 if ($averagesdisplaytype == GRADE_REPORT_PREFERENCE_INHERIT) { 222 $displaytype = $gradeitem->get_displaytype(); 223 } else { 224 $displaytype = $averagesdisplaytype; 225 } 226 227 // Override grade_item setting if a display preference (not inherit) was set for the averages. 228 if ($averagesdecimalpoints == GRADE_REPORT_PREFERENCE_INHERIT) { 229 $decimalpoints = $gradeitem->get_decimals(); 230 } else { 231 $decimalpoints = $averagesdecimalpoints; 232 } 233 234 $gradehtml = grade_format_gradevalue($aggr['average'], 235 $gradeitem, true, $displaytype, $decimalpoints); 236 237 if ($shownumberofgrades) { 238 $numberofgrades = $aggr['meancount']; 239 $gradehtml .= " (" . $numberofgrades . ")"; 240 } 241 $averageformatted = $gradehtml; 242 243 } 244 } 245 return $averageformatted; 246 }); 247 248 return $columns; 249 } 250 251 /** 252 * Return list of all available filters 253 * 254 * @return filter[] 255 */ 256 protected function get_all_filters(): array { 257 $tablealias = $this->get_table_alias('grade_items'); 258 259 // Activity type filter (for performance only load options on demand). 260 $filters[] = (new filter( 261 select::class, 262 'name', 263 new lang_string('activitytype', 'format_singleactivity'), 264 $this->get_entity_name(), 265 "coalesce({$tablealias}.itemmodule,{$tablealias}.itemtype)" 266 )) 267 ->add_joins($this->get_joins()) 268 ->set_options_callback([$this->report, 'item_types']); 269 270 return $filters; 271 } 272 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body