Esempio n. 1
0
 /**
  * Using this object's id field, fetches the matching record in the DB, and looks at
  * each variable in turn. If the DB has different data, the db's data is used to update
  * the object. This is different from the update() function, which acts on the DB record
  * based on the object.
  */
 public function update_from_db()
 {
     if (empty($this->id)) {
         debugging("The object could not be used in its state to retrieve a matching record from the DB, because its id field is not set.");
         return false;
     }
     global $DB;
     if (!($params = $DB->get_record($this->table, array('id' => $this->id)))) {
         debugging("Object with this id:{$this->id} does not exist in table:{$this->table}, can not update from db!");
         return false;
     }
     grade_object::set_properties($this, $params);
     return true;
 }
 /**
  * Static method - returns all outcomes available in course
  * @static
  * @param int $courseid
  * @return array
  */
 function fetch_all_available($courseid)
 {
     global $CFG;
     $result = array();
     $sql = "SELECT go.*\n                  FROM {$CFG->prefix}grade_outcomes go, {$CFG->prefix}grade_outcomes_courses goc\n                 WHERE go.id = goc.outcomeid AND goc.courseid = {$courseid}\n              ORDER BY go.id ASC";
     if ($datas = get_records_sql($sql)) {
         foreach ($datas as $data) {
             $instance = new grade_outcome();
             grade_object::set_properties($instance, $data);
             $result[$instance->id] = $instance;
         }
     }
     return $result;
 }
Esempio n. 3
0
 /**
  * Overrides grade_object::set_properties() to add special handling for changes to category aggregation types
  *
  * @param stdClass $instance the object to set the properties on
  * @param array|stdClass $params Either an associative array or an object containing property name, property value pairs
  */
 public static function set_properties(&$instance, $params)
 {
     global $DB;
     parent::set_properties($instance, $params);
     //if they've changed aggregation type we made need to do some fiddling to provide appropriate defaults
     if (!empty($params->aggregation)) {
         //weight and extra credit share a column :( Would like a default of 1 for weight and 0 for extra credit
         //Flip from the default of 0 to 1 (or vice versa) if ALL items in the category are still set to the old default.
         if ($params->aggregation == GRADE_AGGREGATE_WEIGHTED_MEAN || $params->aggregation == GRADE_AGGREGATE_EXTRACREDIT_MEAN) {
             $sql = $defaultaggregationcoef = null;
             if ($params->aggregation == GRADE_AGGREGATE_WEIGHTED_MEAN) {
                 //if all items in this category have aggregation coefficient of 0 we can change it to 1 ie evenly weighted
                 $sql = "select count(id) from {grade_items} where categoryid=:categoryid and aggregationcoef!=0";
                 $defaultaggregationcoef = 1;
             } else {
                 if ($params->aggregation == GRADE_AGGREGATE_EXTRACREDIT_MEAN) {
                     //if all items in this category have aggregation coefficient of 1 we can change it to 0 ie no extra credit
                     $sql = "select count(id) from {grade_items} where categoryid=:categoryid and aggregationcoef!=1";
                     $defaultaggregationcoef = 0;
                 }
             }
             $params = array('categoryid' => $instance->id);
             $count = $DB->count_records_sql($sql, $params);
             if ($count === 0) {
                 //category is either empty or all items are set to a default value so we can switch defaults
                 $params['aggregationcoef'] = $defaultaggregationcoef;
                 $DB->execute("update {grade_items} set aggregationcoef=:aggregationcoef where categoryid=:categoryid", $params);
             }
         }
     }
 }
Esempio n. 4
0
 /**
  * Static method that returns all outcomes available in course
  *
  * @static
  * @param int $courseid
  * @return array
  */
 public static function fetch_all_available($courseid)
 {
     global $CFG, $DB;
     $result = array();
     $params = array($courseid);
     $sql = "SELECT go.*\n                  FROM {grade_outcomes} go, {grade_outcomes_courses} goc\n                 WHERE go.id = goc.outcomeid AND goc.courseid = ?\n              ORDER BY go.id ASC";
     if ($datas = $DB->get_records_sql($sql, $params)) {
         foreach ($datas as $data) {
             $instance = new grade_outcome();
             grade_object::set_properties($instance, $data);
             $result[$instance->id] = $instance;
         }
     }
     return $result;
 }
Esempio n. 5
0
 /**
  * Obtains the name of a grade item.
  *
  * @global object
  * @param object $gradeitemobj Object from get_record on grade_items table,
  *     (can be empty if you want to just get !missing)
  * @return string Name of item of !missing if it didn't exist
  */
 private static function get_grade_name($gradeitemobj)
 {
     global $CFG;
     if (isset($gradeitemobj->id)) {
         require_once $CFG->libdir . '/gradelib.php';
         $item = new grade_item();
         grade_object::set_properties($item, $gradeitemobj);
         return $item->get_name();
     } else {
         return '!missing';
         // Ooops, missing grade
     }
 }
 /**
  * Obtains the name of a grade item, also checking that it exists. Uses a
  * cache. The name returned is suitable for display.
  *
  * @param int $courseid Course id
  * @param int $gradeitemid Grade item id
  * @return string Grade name or empty string if no grade with that id
  */
 private static function get_cached_grade_name($courseid, $gradeitemid)
 {
     global $DB, $CFG;
     require_once $CFG->libdir . '/gradelib.php';
     // Get all grade item names from cache, or using db query.
     $cache = \cache::make('availability_grade', 'items');
     if (($cacheditems = $cache->get($courseid)) === false) {
         // We cache the whole items table not the name; the format_string
         // call for the name might depend on current user (e.g. multilang)
         // and this is a shared cache.
         $cacheditems = $DB->get_records('grade_items', array('courseid' => $courseid));
         $cache->set($courseid, $cacheditems);
     }
     // Return name from cached item or a lang string.
     if (!array_key_exists($gradeitemid, $cacheditems)) {
         return get_string('missing', 'availability_grade');
     }
     $gradeitemobj = $cacheditems[$gradeitemid];
     $item = new \grade_item();
     \grade_object::set_properties($item, $gradeitemobj);
     return $item->get_name();
 }
Esempio n. 7
0
 /**
  * Overrides grade_object::set_properties() to add special handling for changes to category aggregation types
  *
  * @param stdClass $instance the object to set the properties on
  * @param array|stdClass $params Either an associative array or an object containing property name, property value pairs
  */
 public static function set_properties(&$instance, $params)
 {
     global $DB;
     $fromaggregation = $instance->aggregation;
     parent::set_properties($instance, $params);
     // The aggregation method is changing and this category has already been saved.
     if (isset($params->aggregation) && !empty($instance->id)) {
         $achildwasdupdated = false;
         // Get all its children.
         $children = $instance->get_children();
         foreach ($children as $child) {
             $item = $child['object'];
             if ($child['type'] == 'category') {
                 $item = $item->load_grade_item();
             }
             // Set the new aggregation fields.
             if ($item->set_aggregation_fields_for_aggregation($fromaggregation, $params->aggregation)) {
                 $item->update();
                 $achildwasdupdated = true;
             }
         }
         // If this is the course category, it is possible that its grade item was set as needsupdate
         // by one of its children. If we keep a reference to that stale object we might cause the
         // needsupdate flag to be lost. It's safer to just reload the grade_item from the database.
         if ($achildwasdupdated && !empty($instance->grade_item) && $instance->is_course_category()) {
             $instance->grade_item = null;
             $instance->load_grade_item();
         }
     }
 }
Esempio n. 8
0
 /**
  * Tests the is_available and get_description functions.
  */
 public function test_usage()
 {
     global $CFG, $DB;
     require_once $CFG->dirroot . '/mod/assign/locallib.php';
     $this->resetAfterTest();
     // Create course with completion turned on.
     $CFG->enablecompletion = true;
     $CFG->enableavailability = true;
     $generator = $this->getDataGenerator();
     $course = $generator->create_course(array('enablecompletion' => 1));
     $user = $generator->create_user();
     $generator->enrol_user($user->id, $course->id);
     $this->setUser($user);
     // Create a Page with manual completion for basic checks.
     $page = $generator->get_plugin_generator('mod_page')->create_instance(array('course' => $course->id, 'name' => 'Page!', 'completion' => COMPLETION_TRACKING_MANUAL));
     // Create an assignment - we need to have something that can be graded
     // so as to test the PASS/FAIL states. Set it up to be completed based
     // on its grade item.
     $assignrow = $this->getDataGenerator()->create_module('assign', array('course' => $course->id, 'name' => 'Assign!', 'completion' => COMPLETION_TRACKING_AUTOMATIC));
     $DB->set_field('course_modules', 'completiongradeitemnumber', 0, array('id' => $assignrow->cmid));
     $assign = new assign(context_module::instance($assignrow->cmid), false, false);
     // Get basic details.
     $modinfo = get_fast_modinfo($course);
     $pagecm = $modinfo->get_cm($page->cmid);
     $assigncm = $assign->get_course_module();
     $info = new \core_availability\mock_info($course, $user->id);
     // COMPLETE state (false), positive and NOT.
     $cond = new condition((object) array('cm' => (int) $pagecm->id, 'e' => COMPLETION_COMPLETE));
     $this->assertFalse($cond->is_available(false, $info, true, $user->id));
     $information = $cond->get_description(false, false, $info);
     $information = \core_availability\info::format_info($information, $course);
     $this->assertRegExp('~Page!.*is marked complete~', $information);
     $this->assertTrue($cond->is_available(true, $info, true, $user->id));
     // INCOMPLETE state (true).
     $cond = new condition((object) array('cm' => (int) $pagecm->id, 'e' => COMPLETION_INCOMPLETE));
     $this->assertTrue($cond->is_available(false, $info, true, $user->id));
     $this->assertFalse($cond->is_available(true, $info, true, $user->id));
     $information = $cond->get_description(false, true, $info);
     $information = \core_availability\info::format_info($information, $course);
     $this->assertRegExp('~Page!.*is marked complete~', $information);
     // Mark page complete.
     $completion = new completion_info($course);
     $completion->update_state($pagecm, COMPLETION_COMPLETE);
     // COMPLETE state (true).
     $cond = new condition((object) array('cm' => (int) $pagecm->id, 'e' => COMPLETION_COMPLETE));
     $this->assertTrue($cond->is_available(false, $info, true, $user->id));
     $this->assertFalse($cond->is_available(true, $info, true, $user->id));
     $information = $cond->get_description(false, true, $info);
     $information = \core_availability\info::format_info($information, $course);
     $this->assertRegExp('~Page!.*is incomplete~', $information);
     // INCOMPLETE state (false).
     $cond = new condition((object) array('cm' => (int) $pagecm->id, 'e' => COMPLETION_INCOMPLETE));
     $this->assertFalse($cond->is_available(false, $info, true, $user->id));
     $information = $cond->get_description(false, false, $info);
     $information = \core_availability\info::format_info($information, $course);
     $this->assertRegExp('~Page!.*is incomplete~', $information);
     $this->assertTrue($cond->is_available(true, $info, true, $user->id));
     // We are going to need the grade item so that we can get pass/fails.
     $gradeitem = $assign->get_grade_item();
     grade_object::set_properties($gradeitem, array('gradepass' => 50.0));
     $gradeitem->update();
     // With no grade, it should return true for INCOMPLETE and false for
     // the other three.
     $cond = new condition((object) array('cm' => (int) $assigncm->id, 'e' => COMPLETION_INCOMPLETE));
     $this->assertTrue($cond->is_available(false, $info, true, $user->id));
     $this->assertFalse($cond->is_available(true, $info, true, $user->id));
     $cond = new condition((object) array('cm' => (int) $assigncm->id, 'e' => COMPLETION_COMPLETE));
     $this->assertFalse($cond->is_available(false, $info, true, $user->id));
     $this->assertTrue($cond->is_available(true, $info, true, $user->id));
     // Check $information for COMPLETE_PASS and _FAIL as we haven't yet.
     $cond = new condition((object) array('cm' => (int) $assigncm->id, 'e' => COMPLETION_COMPLETE_PASS));
     $this->assertFalse($cond->is_available(false, $info, true, $user->id));
     $information = $cond->get_description(false, false, $info);
     $information = \core_availability\info::format_info($information, $course);
     $this->assertRegExp('~Assign!.*is complete and passed~', $information);
     $this->assertTrue($cond->is_available(true, $info, true, $user->id));
     $cond = new condition((object) array('cm' => (int) $assigncm->id, 'e' => COMPLETION_COMPLETE_FAIL));
     $this->assertFalse($cond->is_available(false, $info, true, $user->id));
     $information = $cond->get_description(false, false, $info);
     $information = \core_availability\info::format_info($information, $course);
     $this->assertRegExp('~Assign!.*is complete and failed~', $information);
     $this->assertTrue($cond->is_available(true, $info, true, $user->id));
     // Change the grade to be complete and failed.
     self::set_grade($assignrow, $user->id, 40);
     $cond = new condition((object) array('cm' => (int) $assigncm->id, 'e' => COMPLETION_INCOMPLETE));
     $this->assertFalse($cond->is_available(false, $info, true, $user->id));
     $this->assertTrue($cond->is_available(true, $info, true, $user->id));
     $cond = new condition((object) array('cm' => (int) $assigncm->id, 'e' => COMPLETION_COMPLETE));
     $this->assertTrue($cond->is_available(false, $info, true, $user->id));
     $this->assertFalse($cond->is_available(true, $info, true, $user->id));
     $cond = new condition((object) array('cm' => (int) $assigncm->id, 'e' => COMPLETION_COMPLETE_PASS));
     $this->assertFalse($cond->is_available(false, $info, true, $user->id));
     $information = $cond->get_description(false, false, $info);
     $information = \core_availability\info::format_info($information, $course);
     $this->assertRegExp('~Assign!.*is complete and passed~', $information);
     $this->assertTrue($cond->is_available(true, $info, true, $user->id));
     $cond = new condition((object) array('cm' => (int) $assigncm->id, 'e' => COMPLETION_COMPLETE_FAIL));
     $this->assertTrue($cond->is_available(false, $info, true, $user->id));
     $this->assertFalse($cond->is_available(true, $info, true, $user->id));
     $information = $cond->get_description(false, true, $info);
     $information = \core_availability\info::format_info($information, $course);
     $this->assertRegExp('~Assign!.*is not complete and failed~', $information);
     // Now change it to pass.
     self::set_grade($assignrow, $user->id, 60);
     $cond = new condition((object) array('cm' => (int) $assigncm->id, 'e' => COMPLETION_INCOMPLETE));
     $this->assertFalse($cond->is_available(false, $info, true, $user->id));
     $this->assertTrue($cond->is_available(true, $info, true, $user->id));
     $cond = new condition((object) array('cm' => (int) $assigncm->id, 'e' => COMPLETION_COMPLETE));
     $this->assertTrue($cond->is_available(false, $info, true, $user->id));
     $this->assertFalse($cond->is_available(true, $info, true, $user->id));
     $cond = new condition((object) array('cm' => (int) $assigncm->id, 'e' => COMPLETION_COMPLETE_PASS));
     $this->assertTrue($cond->is_available(false, $info, true, $user->id));
     $this->assertFalse($cond->is_available(true, $info, true, $user->id));
     $information = $cond->get_description(false, true, $info);
     $information = \core_availability\info::format_info($information, $course);
     $this->assertRegExp('~Assign!.*is not complete and passed~', $information);
     $cond = new condition((object) array('cm' => (int) $assigncm->id, 'e' => COMPLETION_COMPLETE_FAIL));
     $this->assertFalse($cond->is_available(false, $info, true, $user->id));
     $information = $cond->get_description(false, false, $info);
     $information = \core_availability\info::format_info($information, $course);
     $this->assertRegExp('~Assign!.*is complete and failed~', $information);
     $this->assertTrue($cond->is_available(true, $info, true, $user->id));
     // Simulate deletion of an activity by using an invalid cmid. These
     // conditions always fail, regardless of NOT flag or INCOMPLETE.
     $cond = new condition((object) array('cm' => $assigncm->id + 100, 'e' => COMPLETION_COMPLETE));
     $this->assertFalse($cond->is_available(false, $info, true, $user->id));
     $information = $cond->get_description(false, false, $info);
     $information = \core_availability\info::format_info($information, $course);
     $this->assertRegExp('~(Missing activity).*is marked complete~', $information);
     $this->assertFalse($cond->is_available(true, $info, true, $user->id));
     $cond = new condition((object) array('cm' => $assigncm->id + 100, 'e' => COMPLETION_INCOMPLETE));
     $this->assertFalse($cond->is_available(false, $info, true, $user->id));
 }
 public function test_course_completion_progress()
 {
     global $CFG, $DB;
     $CFG->enablecompletion = true;
     $DB->update_record('course', (object) ['id' => $this->course->id, 'enablecompletion' => 1]);
     $this->course = $DB->get_record('course', ['id' => $this->course->id]);
     $actual = local::course_completion_progress($this->course);
     $this->assertNull($actual);
     $this->create_extra_users();
     $this->setUser($this->extrasuspendedstudents[0]);
     $actual = local::course_completion_progress($this->course);
     $this->assertNull($actual);
     $this->setUser($this->students[0]);
     $actual = local::course_completion_progress($this->course);
     $this->assertNull($actual);
     // Create an assignment that is enabled for completion.
     $this->setUSer($this->teachers[0]);
     $assign = $this->create_instance(['course' => $this->course->id, 'name' => 'Assign!', 'completion' => COMPLETION_TRACKING_AUTOMATIC]);
     // Should now have something that can be tracked for progress.
     $this->setUser($this->students[0]);
     $actual = local::course_completion_progress($this->course);
     $this->assertInstanceOf('stdClass', $actual);
     $this->assertEquals(0, $actual->complete);
     $this->assertEquals(1, $actual->total);
     $this->assertEquals(0, $actual->progress);
     // Make sure completion updates on grading.
     $DB->set_field('course_modules', 'completiongradeitemnumber', 0, ['id' => $assign->get_course_module()->id]);
     $gradeitem = $assign->get_grade_item();
     grade_object::set_properties($gradeitem, array('gradepass' => 50.0));
     $gradeitem->update();
     $assignrow = $assign->get_instance();
     $grades = array();
     $grades[$this->students[0]->id] = (object) ['rawgrade' => 60, 'userid' => $this->students[0]->id];
     $assignrow->cmidnumber = null;
     assign_grade_item_update($assignrow, $grades);
     $actual = local::course_completion_progress($this->course);
     $this->assertInstanceOf('stdClass', $actual);
     $this->assertEquals(1, $actual->complete);
     $this->assertEquals(1, $actual->total);
     $this->assertEquals(100, $actual->progress);
     // Make sure course completion returns null when disabled at site level.
     $CFG->enablecompletion = false;
     $actual = local::course_completion_progress($this->course);
     $this->assertNull($actual);
     // Make sure course completion returns null when disabled at course level.
     $CFG->enablecompletion = true;
     $DB->update_record('course', (object) ['id' => $this->course->id, 'enablecompletion' => 0]);
     $this->course = $DB->get_record('course', ['id' => $this->course->id]);
     $actual = local::course_completion_progress($this->course);
     $this->assertNull($actual);
 }
Esempio n. 10
0
 /**
  * Returns the grade items associated with the courses.
  *
  * @param array $courseids Array of course ids.
  * @return array Array of grade_items for each course level grade item.
  */
 public static function fetch_course_items(array $courseids)
 {
     global $DB;
     $courseitems = array();
     if (!empty($courseids)) {
         list($courseidssql, $courseidsparams) = $DB->get_in_or_equal($courseids);
         $select = 'courseid ' . $courseidssql . ' AND itemtype = ?';
         $params = array_merge($courseidsparams, array('course'));
         $rs = $DB->get_recordset_select('grade_items', $select, $params);
         $courseitems = array();
         foreach ($rs as $data) {
             $instance = new \grade_item();
             \grade_object::set_properties($instance, $data);
             $courseitems[$instance->id] = $instance;
         }
         $rs->close();
     }
     // Determine if any courses were missing.
     $receivedids = array();
     foreach ($courseitems as $item) {
         $receivedids[] = $item->courseid;
     }
     $missingids = array_diff($courseids, $receivedids);
     // Create grade items for any courses that didn't have one.
     if (!empty($missingids)) {
         foreach ($missingids as $courseid) {
             // First get category - it creates the associated grade item.
             $coursecategory = \grade_category::fetch_course_category($courseid);
             $gradeitem = $coursecategory->get_grade_item();
             $courseitems[$gradeitem->id] = $gradeitem;
         }
     }
     return $courseitems;
 }