PageRenderTime 47ms CodeModel.GetById 19ms RepoModel.GetById 1ms app.codeStats 0ms

/grade/export/lib.php

https://github.com/nicolasconnault/moodle2.0
PHP | 394 lines | 232 code | 61 blank | 101 comment | 46 complexity | ab44d62d22fef51314602dd260d67fca MD5 | raw file
Possible License(s): LGPL-2.1, GPL-2.0, BSD-3-Clause
  1. <?php // $Id: lib.php,v 1.55 2009/04/29 20:58:07 skodak Exp $
  2. ///////////////////////////////////////////////////////////////////////////
  3. // //
  4. // NOTICE OF COPYRIGHT //
  5. // //
  6. // Moodle - Modular Object-Oriented Dynamic Learning Environment //
  7. // http://moodle.com //
  8. // //
  9. // Copyright (C) 1999 onwards Martin Dougiamas http://moodle.com //
  10. // //
  11. // This program is free software; you can redistribute it and/or modify //
  12. // it under the terms of the GNU General Public License as published by //
  13. // the Free Software Foundation; either version 2 of the License, or //
  14. // (at your option) any later version. //
  15. // //
  16. // This program is distributed in the hope that it will be useful, //
  17. // but WITHOUT ANY WARRANTY; without even the implied warranty of //
  18. // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the //
  19. // GNU General Public License for more details: //
  20. // //
  21. // http://www.gnu.org/copyleft/gpl.html //
  22. // //
  23. ///////////////////////////////////////////////////////////////////////////
  24. require_once($CFG->dirroot.'/lib/gradelib.php');
  25. require_once($CFG->dirroot.'/grade/lib.php');
  26. require_once($CFG->dirroot.'/grade/export/grade_export_form.php');
  27. /**
  28. * Base export class
  29. */
  30. abstract class grade_export {
  31. public $plugin; // plgin name - must be filled in subclasses!
  32. public $grade_items; // list of all course grade items
  33. public $groupid; // groupid, 0 means all groups
  34. public $course; // course object
  35. public $columns; // array of grade_items selected for export
  36. public $previewrows; // number of rows in preview
  37. public $export_letters; // export letters
  38. public $export_feedback; // export feedback
  39. public $userkey; // export using private user key
  40. public $updatedgradesonly; // only export updated grades
  41. public $displaytype; // display type (e.g. real, percentages, letter) for exports
  42. public $decimalpoints; // number of decimal points for exports
  43. /**
  44. * Constructor should set up all the private variables ready to be pulled
  45. * @access public
  46. * @param object $course
  47. * @param int $groupid id of selected group, 0 means all
  48. * @param string $itemlist comma separated list of item ids, empty means all
  49. * @param boolean $export_feedback
  50. * @param boolean $export_letters
  51. * @note Exporting as letters will lead to data loss if that exported set it re-imported.
  52. */
  53. public function grade_export($course, $groupid=0, $itemlist='', $export_feedback=false, $updatedgradesonly = false, $displaytype = GRADE_DISPLAY_TYPE_REAL, $decimalpoints = 2) {
  54. $this->course = $course;
  55. $this->groupid = $groupid;
  56. $this->grade_items = grade_item::fetch_all(array('courseid'=>$this->course->id));
  57. $this->columns = array();
  58. if (!empty($itemlist)) {
  59. $itemids = explode(',', $itemlist);
  60. // remove items that are not requested
  61. foreach ($itemids as $itemid) {
  62. if (array_key_exists($itemid, $this->grade_items)) {
  63. $this->columns[$itemid] =& $this->grade_items[$itemid];
  64. }
  65. }
  66. } else {
  67. foreach ($this->grade_items as $itemid=>$unused) {
  68. $this->columns[$itemid] =& $this->grade_items[$itemid];
  69. }
  70. }
  71. $this->export_feedback = $export_feedback;
  72. $this->userkey = '';
  73. $this->previewrows = false;
  74. $this->updatedgradesonly = $updatedgradesonly;
  75. $this->displaytype = $displaytype;
  76. $this->decimalpoints = $decimalpoints;
  77. }
  78. /**
  79. * Init object based using data from form
  80. * @param object $formdata
  81. */
  82. function process_form($formdata) {
  83. global $USER;
  84. $this->columns = array();
  85. if (!empty($formdata->itemids)) {
  86. foreach ($formdata->itemids as $itemid=>$selected) {
  87. if ($selected and array_key_exists($itemid, $this->grade_items)) {
  88. $this->columns[$itemid] =& $this->grade_items[$itemid];
  89. }
  90. }
  91. } else {
  92. foreach ($this->grade_items as $itemid=>$unused) {
  93. $this->columns[$itemid] =& $this->grade_items[$itemid];
  94. }
  95. }
  96. if (isset($formdata->key)) {
  97. if ($formdata->key == 1 && isset($formdata->iprestriction) && isset($formdata->validuntil)) {
  98. // Create a new key
  99. $formdata->key = create_user_key('grade/export', $USER->id, $this->course->id, $formdata->iprestriction, $formdata->validuntil);
  100. }
  101. $this->userkey = $formdata->key;
  102. }
  103. if (isset($formdata->export_letters)) {
  104. $this->export_letters = $formdata->export_letters;
  105. }
  106. if (isset($formdata->export_feedback)) {
  107. $this->export_feedback = $formdata->export_feedback;
  108. }
  109. if (isset($formdata->previewrows)) {
  110. $this->previewrows = $formdata->previewrows;
  111. }
  112. }
  113. /**
  114. * Update exported field in grade_grades table
  115. * @return boolean
  116. */
  117. public function track_exports() {
  118. global $CFG;
  119. /// Whether this plugin is entitled to update export time
  120. if ($expplugins = explode(",", $CFG->gradeexport)) {
  121. if (in_array($this->plugin, $expplugins)) {
  122. return true;
  123. } else {
  124. return false;
  125. }
  126. } else {
  127. return false;
  128. }
  129. }
  130. /**
  131. * Returns string representation of final grade
  132. * @param $object $grade instance of grade_grade class
  133. * @return string
  134. */
  135. public function format_grade($grade) {
  136. return grade_format_gradevalue($grade->finalgrade, $this->grade_items[$grade->itemid], false, $this->displaytype, $this->decimalpoints);
  137. }
  138. /**
  139. * Returns the name of column in export
  140. * @param object $grade_item
  141. * @param boolena $feedback feedback colum
  142. * &return string
  143. */
  144. public function format_column_name($grade_item, $feedback=false) {
  145. if ($grade_item->itemtype == 'mod') {
  146. $name = get_string('modulename', $grade_item->itemmodule).': '.$grade_item->get_name();
  147. } else {
  148. $name = $grade_item->get_name();
  149. }
  150. if ($feedback) {
  151. $name .= ' ('.get_string('feedback').')';
  152. }
  153. return strip_tags($name);
  154. }
  155. /**
  156. * Returns formatted grade feedback
  157. * @param object $feedback object with properties feedback and feedbackformat
  158. * @return string
  159. */
  160. public function format_feedback($feedback) {
  161. return strip_tags(format_text($feedback->feedback, $feedback->feedbackformat));
  162. }
  163. /**
  164. * Implemented by child class
  165. */
  166. public abstract function print_grades();
  167. /**
  168. * Prints preview of exported grades on screen as a feedback mechanism
  169. * @param bool $require_user_idnumber true means skip users without idnumber
  170. */
  171. public function display_preview($require_user_idnumber=false) {
  172. print_heading(get_string('previewrows', 'grades'));
  173. echo '<table>';
  174. echo '<tr>';
  175. echo '<th>'.get_string("firstname")."</th>".
  176. '<th>'.get_string("lastname")."</th>".
  177. '<th>'.get_string("idnumber")."</th>".
  178. '<th>'.get_string("institution")."</th>".
  179. '<th>'.get_string("department")."</th>".
  180. '<th>'.get_string("email")."</th>";
  181. foreach ($this->columns as $grade_item) {
  182. echo '<th>'.$this->format_column_name($grade_item).'</th>';
  183. /// add a column_feedback column
  184. if ($this->export_feedback) {
  185. echo '<th>'.$this->format_column_name($grade_item, true).'</th>';
  186. }
  187. }
  188. echo '</tr>';
  189. /// Print all the lines of data.
  190. $i = 0;
  191. $gui = new graded_users_iterator($this->course, $this->columns, $this->groupid);
  192. $gui->init();
  193. while ($userdata = $gui->next_user()) {
  194. // number of preview rows
  195. if ($this->previewrows and $this->previewrows <= $i) {
  196. break;
  197. }
  198. $user = $userdata->user;
  199. if ($require_user_idnumber and empty($user->idnumber)) {
  200. // some exports require user idnumber
  201. continue;
  202. }
  203. $gradeupdated = false; // if no grade is update at all for this user, do not display this row
  204. $rowstr = '';
  205. foreach ($this->columns as $itemid=>$unused) {
  206. $gradetxt = $this->format_grade($userdata->grades[$itemid]);
  207. // get the status of this grade, and put it through track to get the status
  208. $g = new grade_export_update_buffer();
  209. $grade_grade = new grade_grade(array('itemid'=>$itemid, 'userid'=>$user->id));
  210. $status = $g->track($grade_grade);
  211. if ($this->updatedgradesonly && ($status == 'nochange' || $status == 'unknown')) {
  212. $rowstr .= '<td>'.get_string('unchangedgrade', 'grades').'</td>';
  213. } else {
  214. $rowstr .= "<td>$gradetxt</td>";
  215. $gradeupdated = true;
  216. }
  217. if ($this->export_feedback) {
  218. $rowstr .= '<td>'.$this->format_feedback($userdata->feedbacks[$itemid]).'</td>';
  219. }
  220. }
  221. // if we are requesting updated grades only, we are not interested in this user at all
  222. if (!$gradeupdated && $this->updatedgradesonly) {
  223. continue;
  224. }
  225. echo '<tr>';
  226. echo "<td>$user->firstname</td><td>$user->lastname</td><td>$user->idnumber</td><td>$user->institution</td><td>$user->department</td><td>$user->email</td>";
  227. echo $rowstr;
  228. echo "</tr>";
  229. $i++; // increment the counter
  230. }
  231. echo '</table>';
  232. $gui->close();
  233. }
  234. /**
  235. * Returns array of parameters used by dump.php and export.php.
  236. * @return array
  237. */
  238. public function get_export_params() {
  239. $itemids = array_keys($this->columns);
  240. $params = array('id' =>$this->course->id,
  241. 'groupid' =>$this->groupid,
  242. 'itemids' =>implode(',', $itemids),
  243. 'export_letters' =>$this->export_letters,
  244. 'export_feedback' =>$this->export_feedback,
  245. 'updatedgradesonly' =>$this->updatedgradesonly,
  246. 'displaytype' =>$this->displaytype,
  247. 'decimalpoints' =>$this->decimalpoints);
  248. return $params;
  249. }
  250. /**
  251. * Either prints a "Export" box, which will redirect the user to the download page,
  252. * or prints the URL for the published data.
  253. * @return void
  254. */
  255. public function print_continue() {
  256. global $CFG;
  257. $params = $this->get_export_params();
  258. print_heading(get_string('export', 'grades'));
  259. echo '<div class="gradeexportlink">';
  260. if (!$this->userkey) { // this button should trigger a download prompt
  261. print_single_button($CFG->wwwroot.'/grade/export/'.$this->plugin.'/export.php',
  262. $params, get_string('download', 'admin'));
  263. } else {
  264. $paramstr = '';
  265. $sep = '?';
  266. foreach($params as $name=>$value) {
  267. $paramstr .= $sep.$name.'='.$value;
  268. $sep = '&amp;';
  269. }
  270. $link = $CFG->wwwroot.'/grade/export/'.$this->plugin.'/dump.php'.$paramstr.'&amp;key='.$this->userkey;
  271. echo get_string('download', 'admin').': <a href="'.$link.'">'.$link.'</a>';
  272. }
  273. echo '</div>';
  274. }
  275. }
  276. /**
  277. * This class is used to update the exported field in grade_grades.
  278. * It does internal buffering to speedup the db operations.
  279. */
  280. class grade_export_update_buffer {
  281. public $update_list;
  282. public $export_time;
  283. /**
  284. * Constructor - creates the buffer and initialises the time stamp
  285. */
  286. public function grade_export_update_buffer() {
  287. $this->update_list = array();
  288. $this->export_time = time();
  289. }
  290. public function flush($buffersize) {
  291. global $CFG, $DB;
  292. if (count($this->update_list) > $buffersize) {
  293. list($usql, $params) = $DB->get_in_or_equal($this->update_list);
  294. $params = array_merge(array($this->export_time), $params);
  295. $sql = "UPDATE {grade_grades} SET exported = ? WHERE id $usql";
  296. $DB->execute($sql, $params);
  297. $this->update_list = array();
  298. }
  299. }
  300. /**
  301. * Track grade export status
  302. * @param object $grade_grade
  303. * @return string $status (unknow, new, regrade, nochange)
  304. */
  305. public function track($grade_grade) {
  306. if (empty($grade_grade->exported) or empty($grade_grade->timemodified)) {
  307. if (is_null($grade_grade->finalgrade)) {
  308. // grade does not exist yet
  309. $status = 'unknown';
  310. } else {
  311. $status = 'new';
  312. $this->update_list[] = $grade_grade->id;
  313. }
  314. } else if ($grade_grade->exported < $grade_grade->timemodified) {
  315. $status = 'regrade';
  316. $this->update_list[] = $grade_grade->id;
  317. } else if ($grade_grade->exported >= $grade_grade->timemodified) {
  318. $status = 'nochange';
  319. } else {
  320. // something is wrong?
  321. $status = 'unknown';
  322. }
  323. $this->flush(100);
  324. return $status;
  325. }
  326. /**
  327. * Flush and close the buffer.
  328. */
  329. public function close() {
  330. $this->flush(0);
  331. }
  332. }
  333. ?>