Search moodle.org's
Developer Documentation

See Release Notes

  • Bug fixes for general core bugs in 4.2.x will end 22 April 2024 (12 months).
  • Bug fixes for security issues in 4.2.x will end 7 October 2024 (18 months).
  • PHP version: minimum PHP 8.0.0 Note: minimum PHP version has increased since Moodle 4.1. PHP 8.1.x is supported too.

Differences Between: [Versions 311 and 402] [Versions 400 and 402] [Versions 401 and 402]

   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 core\event;
  18  
  19  defined('MOODLE_INTERNAL') || die();
  20  
  21  global $CFG;
  22  
  23  require_once($CFG->libdir . '/mathslib.php');
  24  
  25  /**
  26   * Tests for event \core\event\user_graded
  27   *
  28   * @package    core
  29   * @category   test
  30   * @copyright  2014 Petr Skoda
  31   * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  32   */
  33  class user_graded_test extends \advanced_testcase {
  34  
  35      /**
  36       * Tests set up.
  37       */
  38      public function setUp(): void {
  39          $this->resetAfterTest();
  40      }
  41  
  42      /**
  43       * Tests the event details.
  44       */
  45      public function test_event() {
  46          global $CFG;
  47          require_once("$CFG->libdir/gradelib.php");
  48  
  49          $course = $this->getDataGenerator()->create_course();
  50          $user = $this->getDataGenerator()->create_user();
  51          $this->getDataGenerator()->enrol_user($user->id, $course->id);
  52  
  53          $grade_category = \grade_category::fetch_course_category($course->id);
  54          $grade_category->load_grade_item();
  55          $grade_item = $grade_category->grade_item;
  56  
  57          $grade_item->update_final_grade($user->id, 10, 'gradebook');
  58  
  59          $grade_grade = new \grade_grade(array('userid' => $user->id, 'itemid' => $grade_item->id), true);
  60          $grade_grade->grade_item = $grade_item;
  61  
  62          $event = \core\event\user_graded::create_from_grade($grade_grade);
  63  
  64          $this->assertEquals(\context_course::instance($course->id), $event->get_context());
  65          $this->assertSame($event->objecttable, 'grade_grades');
  66          $this->assertEquals($event->objectid, $grade_grade->id);
  67          $this->assertEquals($event->other['itemid'], $grade_item->id);
  68          $this->assertTrue($event->other['overridden']);
  69          $this->assertEquals(10, $event->other['finalgrade']);
  70  
  71          // Trigger the events.
  72          $sink = $this->redirectEvents();
  73          $event->trigger();
  74          $result = $sink->get_events();
  75          $sink->close();
  76  
  77          $this->assertCount(1, $result);
  78  
  79          $event = reset($result);
  80          $this->assertEventContextNotUsed($event);
  81  
  82          $grade = $event->get_grade();
  83          $this->assertInstanceOf('grade_grade', $grade);
  84          $this->assertEquals($grade_grade->id, $grade->id);
  85      }
  86  
  87      /**
  88       * Tests that the event is fired in the correct locations in core.
  89       */
  90      public function test_event_is_triggered() {
  91          global $DB;
  92  
  93          // Create the items we need to test with.
  94          $course = $this->getDataGenerator()->create_course();
  95          $user = $this->getDataGenerator()->create_user();
  96          $this->getDataGenerator()->enrol_user($user->id, $course->id);
  97          $quiz = $this->getDataGenerator()->create_module('quiz', array('course' => $course->id));
  98          $quizitemparams = array('itemtype' => 'mod', 'itemmodule' => 'quiz', 'iteminstance' => $quiz->id,
  99              'courseid' => $course->id);
 100          $gradeitem = \grade_item::fetch($quizitemparams);
 101          $courseitem = \grade_item::fetch_course_item($course->id);
 102  
 103          // Now mark the quiz using grade_update as this is the function that modules use.
 104          $grade = array();
 105          $grade['userid'] = $user->id;
 106          $grade['rawgrade'] = 60;
 107  
 108          $sink = $this->redirectEvents();
 109          grade_update('mod/quiz', $course->id, 'mod', 'quiz', $quiz->id, 0, $grade);
 110          $events = $sink->get_events();
 111          $sink->close();
 112  
 113          // Ensure we have two user_graded events, one for the item, one for the course.
 114          $this->assertEquals(2, count($events));
 115          $this->assertInstanceOf('\core\event\user_graded', $events[0]);
 116          $this->assertEquals($gradeitem->id, $events[0]->other['itemid']);
 117          $this->assertInstanceOf('\core\event\user_graded', $events[1]);
 118          $this->assertEquals($courseitem->id, $events[1]->other['itemid']);
 119  
 120          // Remove the grades, force the regrading and re-fetch the item. This is needed because the item
 121          // will be set as needing an update when the grades are deleted.
 122          $gradeitem->delete_all_grades();
 123          grade_regrade_final_grades($course->id);
 124          $gradeitem = \grade_item::fetch($quizitemparams);
 125  
 126          // Now, create a grade using \grade_item::update_final_grade().
 127          $sink = $this->redirectEvents();
 128          $gradeitem->update_raw_grade($user->id, 10);
 129          $events = $sink->get_events();
 130          $sink->close();
 131  
 132          // Ensure we have two user_graded events, one for the item, one for the course.
 133          $this->assertEquals(2, count($events));
 134          $this->assertInstanceOf('\core\event\user_graded', $events[0]);
 135          $this->assertEquals($gradeitem->id, $events[0]->other['itemid']);
 136          $this->assertInstanceOf('\core\event\user_graded', $events[1]);
 137          $this->assertEquals($courseitem->id, $events[1]->other['itemid']);
 138  
 139          // Now, update this grade using \grade_item::update_raw_grade().
 140          $sink = $this->redirectEvents();
 141          $gradeitem->update_raw_grade($user->id, 20);
 142          $events = $sink->get_events();
 143          $sink->close();
 144  
 145          // Ensure we have two user_graded events, one for the item, one for the course.
 146          $this->assertEquals(2, count($events));
 147          $this->assertInstanceOf('\core\event\user_graded', $events[0]);
 148          $this->assertEquals($gradeitem->id, $events[0]->other['itemid']);
 149          $this->assertInstanceOf('\core\event\user_graded', $events[1]);
 150          $this->assertEquals($courseitem->id, $events[1]->other['itemid']);
 151  
 152          // Remove the grades, force the regrading and re-fetch the item. This is needed because the item
 153          // will be set as needing an update when the grades are deleted.
 154          $gradeitem->delete_all_grades();
 155          grade_regrade_final_grades($course->id);
 156          $gradeitem = \grade_item::fetch($quizitemparams);
 157  
 158          // Now, create a grade using \grade_item::update_final_grade().
 159          $sink = $this->redirectEvents();
 160          $gradeitem->update_final_grade($user->id, 30);
 161          $events = $sink->get_events();
 162          $sink->close();
 163  
 164          // Ensure we have two user_graded events, one for the item, one for the course.
 165          $this->assertEquals(2, count($events));
 166          $this->assertInstanceOf('\core\event\user_graded', $events[0]);
 167          $this->assertEquals($gradeitem->id, $events[0]->other['itemid']);
 168          $this->assertInstanceOf('\core\event\user_graded', $events[1]);
 169          $this->assertEquals($courseitem->id, $events[1]->other['itemid']);
 170  
 171          // Now, update this grade using \grade_item::update_final_grade().
 172          $sink = $this->redirectEvents();
 173          $gradeitem->update_final_grade($user->id, 40);
 174          $events = $sink->get_events();
 175          $sink->close();
 176  
 177          // Ensure we have two user_graded events, one for the item, one for the course.
 178          $this->assertEquals(2, count($events));
 179          $this->assertInstanceOf('\core\event\user_graded', $events[0]);
 180          $this->assertEquals($gradeitem->id, $events[0]->other['itemid']);
 181          $this->assertInstanceOf('\core\event\user_graded', $events[1]);
 182          $this->assertEquals($courseitem->id, $events[1]->other['itemid']);
 183  
 184          // Remove the overridden flag from the grade, this was set by \grade_item::update_final_grade().
 185          $gradegrade = \grade_grade::fetch(array('itemid' => $gradeitem->id, 'userid' => $user->id));
 186          $gradegrade->set_overridden(false, false);
 187  
 188          // Let's change the calculation to anything that won't cause an error.
 189          $calculation = \calc_formula::unlocalize("=3");
 190          $gradeitem->set_calculation($calculation);
 191  
 192          // Now force the computation of the grade.
 193          $sink = $this->redirectEvents();
 194          grade_regrade_final_grades($course->id);
 195          $events = $sink->get_events();
 196          $sink->close();
 197  
 198          // Ensure we have two user_graded events, one for the item, one for the course.
 199          $this->assertEquals(2, count($events));
 200          $this->assertInstanceOf('\core\event\user_graded', $events[0]);
 201          $this->assertEquals($gradeitem->id, $events[0]->other['itemid']);
 202          $this->assertInstanceOf('\core\event\user_graded', $events[1]);
 203          $this->assertEquals($courseitem->id, $events[1]->other['itemid']);
 204  
 205          // Now, let's trick the gradebook, we manually update a grade, and flag the grade item as
 206          // needing a regrading, so we can trigger the event in \grade_item::regrade_final_grades().
 207          $gradeitem = \grade_item::fetch($quizitemparams);
 208          $gradeitem->set_calculation('');
 209          $gradegrade = \grade_grade::fetch(array('itemid' => $gradeitem->id, 'userid' => $user->id));
 210          $gradegrade->rawgrade = 50;
 211          $gradegrade->update();
 212  
 213          $sink = $this->redirectEvents();
 214          grade_regrade_final_grades($course->id);
 215          $events = $sink->get_events();
 216          $sink->close();
 217  
 218          // Ensure we have two user_graded events, one for the item, one for the course.
 219          $this->assertEquals(2, count($events));
 220          $this->assertInstanceOf('\core\event\user_graded', $events[0]);
 221          $this->assertEquals($gradeitem->id, $events[0]->other['itemid']);
 222          $this->assertInstanceOf('\core\event\user_graded', $events[1]);
 223          $this->assertEquals($courseitem->id, $events[1]->other['itemid']);
 224      }
 225  }