PageRenderTime 27ms CodeModel.GetById 15ms RepoModel.GetById 1ms app.codeStats 0ms

/grade/report/singleview/classes/local/screen/screen.php

https://github.com/mackensen/moodle
PHP | 460 lines | 287 code | 53 blank | 120 comment | 16 complexity | 876bad6d7905c45a4dda43258b36628a MD5 | raw 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. * Abstract class used as a base for the 3 screens.
  18. *
  19. * @package gradereport_singleview
  20. * @copyright 2014 Moodle Pty Ltd (http://moodle.com)
  21. * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  22. */
  23. namespace gradereport_singleview\local\screen;
  24. use context_course;
  25. use moodle_url;
  26. use html_writer;
  27. use grade_structure;
  28. use grade_grade;
  29. use grade_item;
  30. use stdClass;
  31. defined('MOODLE_INTERNAL') || die;
  32. /**
  33. * Abstract class used as a base for the 3 screens.
  34. *
  35. * @package gradereport_singleview
  36. * @copyright 2014 Moodle Pty Ltd (http://moodle.com)
  37. * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  38. */
  39. abstract class screen {
  40. /** @var int $courseid The id of the course */
  41. protected $courseid;
  42. /** @var int $itemid Either a user id or a grade_item id */
  43. protected $itemid;
  44. /** @var int $groupid The currently set groupid (if set) */
  45. protected $groupid;
  46. /** @var course_context $context The course context */
  47. protected $context;
  48. /** @var int $page The page number */
  49. protected $page;
  50. /** @var int $perpage Results per page */
  51. protected $perpage;
  52. /** @var array $items List of items on the page, they could be users or grade_items */
  53. protected $items;
  54. /** @var array $validperpage List of allowed values for 'perpage' setting */
  55. protected static $validperpage = [20, 50, 100, 200, 400, 1000, 5000];
  56. /**
  57. * Constructor
  58. *
  59. * @param int $courseid The course id
  60. * @param int $itemid The item id
  61. * @param int $groupid The group id
  62. */
  63. public function __construct($courseid, $itemid, $groupid = null) {
  64. global $DB;
  65. $this->courseid = $courseid;
  66. $this->itemid = $itemid;
  67. $this->groupid = $groupid;
  68. $this->context = context_course::instance($this->courseid);
  69. $this->course = $DB->get_record('course', array('id' => $courseid));
  70. $this->page = optional_param('page', 0, PARAM_INT);
  71. $cache = \cache::make_from_params(\cache_store::MODE_SESSION, 'gradereport_singleview', 'perpage');
  72. $perpage = optional_param('perpage', null, PARAM_INT);
  73. if (!in_array($perpage, self::$validperpage)) {
  74. // Get from cache.
  75. $perpage = $cache->get(get_class($this));
  76. } else {
  77. // Save to cache.
  78. $cache->set(get_class($this), $perpage);
  79. }
  80. if ($perpage) {
  81. $this->perpage = $perpage;
  82. } else {
  83. $this->perpage = 100;
  84. }
  85. $this->init(empty($itemid));
  86. }
  87. /**
  88. * Cache the grade_structure class
  89. */
  90. public function setup_structure() {
  91. $this->structure = new grade_structure();
  92. $this->structure->modinfo = get_fast_modinfo($this->course);
  93. }
  94. /**
  95. * Create a nice link from a thing (user or grade_item).
  96. *
  97. * @param string $screen
  98. * @param int $itemid
  99. * @param bool $display Should we wrap this in an anchor ?
  100. * @return string The link
  101. */
  102. public function format_link($screen, $itemid, $display = null) {
  103. $url = new moodle_url('/grade/report/singleview/index.php', array(
  104. 'id' => $this->courseid,
  105. 'item' => $screen,
  106. 'itemid' => $itemid,
  107. 'group' => $this->groupid,
  108. ));
  109. if ($display) {
  110. return html_writer::link($url, $display);
  111. } else {
  112. return $url;
  113. }
  114. }
  115. /**
  116. * Get the grade_grade
  117. *
  118. * @param grade_item $item The grade_item
  119. * @param int $userid The user id
  120. * @return grade_grade
  121. */
  122. public function fetch_grade_or_default($item, $userid) {
  123. $grade = grade_grade::fetch(array(
  124. 'itemid' => $item->id, 'userid' => $userid
  125. ));
  126. if (!$grade) {
  127. $default = new stdClass;
  128. $default->userid = $userid;
  129. $default->itemid = $item->id;
  130. $default->feedback = '';
  131. $grade = new grade_grade($default, false);
  132. }
  133. $grade->grade_item = $item;
  134. return $grade;
  135. }
  136. /**
  137. * Make the HTML element that toggles all the checkboxes on or off.
  138. *
  139. * @param string $key A unique key for this control - inserted in the classes.
  140. * @return string
  141. */
  142. public function make_toggle($key) {
  143. $attrs = array('href' => '#');
  144. // Do proper lang strings for title attributes exist for the given key?
  145. $strmanager = \get_string_manager();
  146. $titleall = get_string('all');
  147. $titlenone = get_string('none');
  148. if ($strmanager->string_exists(strtolower($key) . 'all', 'gradereport_singleview')) {
  149. $titleall = get_string(strtolower($key) . 'all', 'gradereport_singleview');
  150. }
  151. if ($strmanager->string_exists(strtolower($key) . 'none', 'gradereport_singleview')) {
  152. $titlenone = get_string(strtolower($key) . 'none', 'gradereport_singleview');
  153. }
  154. $all = html_writer::tag('a', get_string('all'), $attrs + array(
  155. 'class' => 'include all ' . $key,
  156. 'title' => $titleall
  157. ));
  158. $none = html_writer::tag('a', get_string('none'), $attrs + array(
  159. 'class' => 'include none ' . $key,
  160. 'title' => $titlenone
  161. ));
  162. return html_writer::tag('span', "$all / $none", array(
  163. 'class' => 'inclusion_links'
  164. ));
  165. }
  166. /**
  167. * Make a toggle link with some text before it.
  168. *
  169. * @param string $key A unique key for this control - inserted in the classes.
  170. * @return string
  171. */
  172. public function make_toggle_links($key) {
  173. return get_string($key, 'gradereport_singleview') . ' ' .
  174. $this->make_toggle($key);
  175. }
  176. /**
  177. * Get the default heading for the screen.
  178. *
  179. * @return string
  180. */
  181. public function heading() {
  182. return get_string('entrypage', 'gradereport_singleview');
  183. }
  184. /**
  185. * Override this to init the screen.
  186. *
  187. * @param boolean $selfitemisempty True if no item has been selected yet.
  188. */
  189. public abstract function init($selfitemisempty = false);
  190. /**
  191. * Get the type of items in the list.
  192. *
  193. * @return string
  194. */
  195. public abstract function item_type();
  196. /**
  197. * Get the entire screen as a string.
  198. *
  199. * @return string
  200. */
  201. public abstract function html();
  202. /**
  203. * Does this screen support paging?
  204. *
  205. * @return bool
  206. */
  207. public function supports_paging() {
  208. return true;
  209. }
  210. /**
  211. * Default pager
  212. *
  213. * @return string
  214. */
  215. public function pager() {
  216. return '';
  217. }
  218. /**
  219. * Initialise the js for this screen.
  220. */
  221. public function js() {
  222. global $PAGE;
  223. $module = array(
  224. 'name' => 'gradereport_singleview',
  225. 'fullpath' => '/grade/report/singleview/js/singleview.js',
  226. 'requires' => array('base', 'dom', 'event', 'event-simulate', 'io-base')
  227. );
  228. $PAGE->requires->string_for_js('overridenoneconfirm', 'gradereport_singleview');
  229. $PAGE->requires->js_init_call('M.gradereport_singleview.init', array(), false, $module);
  230. }
  231. /**
  232. * Process the data from a form submission.
  233. *
  234. * @param array $data
  235. * @return array of warnings
  236. */
  237. public function process($data) {
  238. $warnings = array();
  239. $fields = $this->definition();
  240. // Avoiding execution timeouts when updating
  241. // a large amount of grades.
  242. $progress = 0;
  243. $progressbar = new \core\progress\display_if_slow();
  244. $progressbar->start_html();
  245. $progressbar->start_progress(get_string('savegrades', 'gradereport_singleview'), count((array) $data) - 1);
  246. $changecount = array();
  247. // This array is used to determine if the override should be excluded from being counted as a change.
  248. $ignorevalues = [];
  249. foreach ($data as $varname => $throw) {
  250. $progressbar->progress($progress);
  251. $progress++;
  252. if (preg_match("/(\w+)_(\d+)_(\d+)/", $varname, $matches)) {
  253. $itemid = $matches[2];
  254. $userid = $matches[3];
  255. } else {
  256. continue;
  257. }
  258. $gradeitem = grade_item::fetch(array(
  259. 'id' => $itemid, 'courseid' => $this->courseid
  260. ));
  261. if (preg_match('/^old[oe]{1}/', $varname)) {
  262. $elementname = preg_replace('/^old/', '', $varname);
  263. if (!isset($data->$elementname)) {
  264. // Decrease the progress because we've increased the
  265. // size of the array we are iterating through.
  266. $progress--;
  267. $data->$elementname = false;
  268. }
  269. }
  270. if (!in_array($matches[1], $fields)) {
  271. continue;
  272. }
  273. if (!$gradeitem) {
  274. continue;
  275. }
  276. $grade = $this->fetch_grade_or_default($gradeitem, $userid);
  277. $classname = '\\gradereport_singleview\\local\\ui\\' . $matches[1];
  278. $element = new $classname($grade);
  279. $name = $element->get_name();
  280. $oldname = "old$name";
  281. $posted = $data->$name;
  282. $format = $element->determine_format();
  283. if ($format->is_textbox() and trim($data->$name) === '') {
  284. $data->$name = null;
  285. }
  286. // Same value; skip.
  287. if (isset($data->$oldname) && $data->$oldname == $posted) {
  288. continue;
  289. }
  290. // If the user submits Exclude grade elements without the proper.
  291. // permissions then we should refuse to update.
  292. if ($matches[1] === 'exclude' && !has_capability('moodle/grade:manage', $this->context)){
  293. $warnings[] = get_string('nopermissions', 'error', get_string('grade:manage', 'role'));
  294. continue;
  295. }
  296. $msg = $element->set($posted);
  297. // Value to check against our list of matchelements to ignore.
  298. $check = explode('_', $varname, 2);
  299. // Optional type.
  300. if (!empty($msg)) {
  301. $warnings[] = $msg;
  302. if ($element instanceof \gradereport_singleview\local\ui\finalgrade) {
  303. // Add this value to this list so that the override object that is coming next will also be skipped.
  304. $ignorevalues[$check[1]] = $check[1];
  305. // This item wasn't changed so don't add to the changecount.
  306. continue;
  307. }
  308. }
  309. // Check to see if this value has already been skipped.
  310. if (array_key_exists($check[1], $ignorevalues)) {
  311. continue;
  312. }
  313. if (preg_match('/_(\d+)_(\d+)/', $varname, $matchelement)) {
  314. $changecount[$matchelement[0]] = 1;
  315. }
  316. }
  317. // Some post-processing.
  318. $eventdata = new stdClass;
  319. $eventdata->warnings = $warnings;
  320. $eventdata->post_data = $data;
  321. $eventdata->instance = $this;
  322. $eventdata->changecount = $changecount;
  323. $progressbar->end_html();
  324. return $eventdata;
  325. }
  326. /**
  327. * By default there are no options.
  328. * @return array
  329. */
  330. public function options() {
  331. return array();
  332. }
  333. /**
  334. * Should we show the group selector?
  335. * @return bool
  336. */
  337. public function display_group_selector() {
  338. return true;
  339. }
  340. /**
  341. * Should we show the next prev selector?
  342. * @return bool
  343. */
  344. public function supports_next_prev() {
  345. return true;
  346. }
  347. /**
  348. * Load a valid list of users for this gradebook as the screen "items".
  349. * @return array $users A list of enroled users.
  350. */
  351. protected function load_users() {
  352. global $CFG;
  353. // Create a graded_users_iterator because it will properly check the groups etc.
  354. $defaultgradeshowactiveenrol = !empty($CFG->grade_report_showonlyactiveenrol);
  355. $showonlyactiveenrol = get_user_preferences('grade_report_showonlyactiveenrol', $defaultgradeshowactiveenrol);
  356. $showonlyactiveenrol = $showonlyactiveenrol || !has_capability('moodle/course:viewsuspendedusers', $this->context);
  357. require_once($CFG->dirroot.'/grade/lib.php');
  358. $gui = new \graded_users_iterator($this->course, null, $this->groupid);
  359. $gui->require_active_enrolment($showonlyactiveenrol);
  360. $gui->init();
  361. // Flatten the users.
  362. $users = array();
  363. while ($user = $gui->next_user()) {
  364. $users[$user->user->id] = $user->user;
  365. }
  366. $gui->close();
  367. return $users;
  368. }
  369. /**
  370. * Allow selection of number of items to display per page.
  371. * @return string
  372. */
  373. public function perpage_select() {
  374. global $PAGE, $OUTPUT;
  375. $options = array_combine(self::$validperpage, self::$validperpage);
  376. $url = new moodle_url($PAGE->url);
  377. $url->remove_params(['page', 'perpage']);
  378. $out = '';
  379. $select = new \single_select($url, 'perpage', $options, $this->perpage, null, 'perpagechanger');
  380. $select->label = get_string('itemsperpage', 'gradereport_singleview');
  381. $out .= $OUTPUT->render($select);
  382. return $out;
  383. }
  384. }