MDL-10233 fixed grade_*::fetch() - does not modify $this anymore, we can now use it from normal methods to fetch other objects of the same class.
fwrite ($bf,full_tag("ITEMNUMBER",5,false,$grade_item->itemnumber));
fwrite ($bf,full_tag("ITEMINFO",5,false,$grade_item->iteminfo));
fwrite ($bf,full_tag("IDNUMBER",5,false,$grade_item->idnumber));
+ // use [idnumber] in calculation instead of [#giXXX#]
+ fwrite ($bf,full_tag("CALCULATION",5,false,$grade_item->get_caclulation()));
fwrite ($bf,full_tag("GRADEMAX",5,false,$grade_item->grademax));
fwrite ($bf,full_tag("GRADEMIN",5,false,$grade_item->grademin));
fwrite ($bf,full_tag("SCALEID",5,false,$grade_item->scaleid));
fwrite ($bf,full_tag("LOCKTIME",5,false,$grade_item->locktime));
// back up the other stuff here
- $status = backup_gradebook_calculations_info($bf,$preferences,$grade_item->id);
$status = backup_gradebook_grades_info($bf,$preferences,$grade_item->id);
$status = backup_gradebook_grades_history_info($bf,$preferences,$grade_item->id);
$status = backup_gradebook_grades_text_info($bf,$preferences,$grade_item->id);
return $status;
}
- //Backup gradebook_calculations(called from backup_gradebook_item_info
- function backup_gradebook_calculations_info($bf,$preferences, $itemid) {
-
- global $CFG;
-
- $status = true;
-
- // find all calculations belonging to this item
- if ($calculations = get_records('grade_calculations', 'itemid', $itemid)) {
- fwrite ($bf,start_tag("GRADE_CALCULATIONS",5,true));
- foreach ($calculations as $calculation) {
- fwrite ($bf,start_tag("GRADE_CALCULATION",6,true));
- fwrite ($bf,full_tag("ID",7,false,$calculation->id));
- fwrite ($bf,full_tag("CALCULATION",7,false,$calculation->calculation));
- fwrite ($bf,full_tag("USERMODIFIED",7,false,$calculation->usermodified));
- fwrite ($bf,end_tag("GRADE_CALCULATION",6,true));
- }
- $status = fwrite ($bf,end_tag("GRADE_CALCULATIONS",5,true));
- }
- return $status;
- }
function backup_gradebook_grades_info($bf,$preferences, $itemid) {
$status = true;
- // find all calculations belonging to this item
- if ($raws = get_records('grade_grades', 'itemid', $itemid)) {
+ // find all grades belonging to this item
+ if ($grades = get_records('grade_grades', 'itemid', $itemid)) {
fwrite ($bf,start_tag("GRADE_GRADES",5,true));
- foreach ($raws as $raw) {
+ foreach ($grades as $grade) {
fwrite ($bf,start_tag("GRADE",6,true));
- fwrite ($bf,full_tag("ID",7,false,$raw->id));
- fwrite ($bf,full_tag("USERID",7,false,$raw->userid));
- fwrite ($bf,full_tag("RAWGRADE",7,false,$raw->rawgrade));
- fwrite ($bf,full_tag("RAWGRADEMAX",7,false,$raw->rawgrademax));
- fwrite ($bf,full_tag("RAWGRADEMIN",7,false,$raw->rawgrademin));
- fwrite ($bf,full_tag("RAWSCALEID",7,false,$raw->rawscaleid));
- fwrite ($bf,full_tag("USERMODIFIED",7,false,$raw->usermodified));
- fwrite ($bf,full_tag("FINALGRADE",7,false,$raw->finalgrade));
+ fwrite ($bf,full_tag("ID",7,false,$grade->id));
+ fwrite ($bf,full_tag("USERID",7,false,$grade->userid));
+ fwrite ($bf,full_tag("RAWGRADE",7,false,$grade->rawgrade));
+ fwrite ($bf,full_tag("RAWGRADEMAX",7,false,$grade->rawgrademax));
+ fwrite ($bf,full_tag("RAWGRADEMIN",7,false,$grade->rawgrademin));
+ fwrite ($bf,full_tag("RAWSCALEID",7,false,$grade->rawscaleid));
+ fwrite ($bf,full_tag("USERMODIFIED",7,false,$grade->usermodified));
+ fwrite ($bf,full_tag("FINALGRADE",7,false,$grade->finalgrade));
fwrite ($bf,full_tag("HIDDEN",7,false,$final->hidden));
fwrite ($bf,full_tag("LOCKED",7,false,$final->locked));
fwrite ($bf,full_tag("LOCKTIME",7,false,$final->locktime));
$status = true;
- // find all calculations belonging to this item
+ // find all grade texts belonging to this item
if ($texts = get_records('grade_grades_text', 'itemid', $itemid)) {
fwrite ($bf,start_tag("GRADE_GRADES_TEXT",5,true));
foreach ($texts as $text) {
$status = true;
- // find all calculations belonging to this item
+ // find all grade history belonging to this item
if ($histories = get_records('grade_history', 'itemid', $itemid)) {
fwrite ($bf,start_tag("GRADE_GRADES_HISTORY",5,true));
foreach ($histories as $history) {
$dbrec->itemnumber = backup_todb($info['GRADE_ITEM']['#']['ITEMNUMBER']['0']['#']);
$dbrec->iteminfo = backup_todb($info['GRADE_ITEM']['#']['ITEMINFO']['0']['#']);
$dbrec->idnumber = backup_todb($info['GRADE_ITEM']['#']['IDNUMBER']['0']['#']);
+ $dbrec->calculation = backup_todb($info['GRADE_ITEM']['#']['CALCULATION']['0']['#']);
$dbrec->grademax = backup_todb($info['GRADE_ITEM']['#']['GRADEMAX']['0']['#']);
$dbrec->grademin = backup_todb($info['GRADE_ITEM']['#']['GRADEMIN']['0']['#']);
/// needs to be restored first
$itemid = insert_record('grade_items',$dbrec);
- /// now, restore grade_calculations, grade_raw, grade_final, grade_text, and grade_history
+ /// now, restore grade_grades, grade_text, and grade_history
if (!empty($info['GRADE_ITEM']['#']['GRADE_GRADES']['0']['#']) && ($grades = $info['GRADE_ITEM']['#']['GRADE_GRADES']['0']['#']['GRADE'])) {
//Iterate over items
for($i = 0; $i < sizeof($grades); $i++) {
}
}
- /// processing grade_calculations
- if (!empty($info['GRADE_ITEM']['#']['GRADE_CALCULATIONS']['0']['#']) && ($calcs = $info['GRADE_ITEM']['#']['GRADE_CALCULATIONS']['0']['#']['GRADE_CALCULATION'])) {
- //Iterate over items
- for($i = 0; $i < sizeof($calcs); $i++) {
- $ite_info = $calcs[$i];
- //traverse_xmlize($ite_info);
-//Debug
- //print_object ($GLOBALS['traverse_array']);
-//Debug
- //$GLOBALS['traverse_array']=""; //Debug
- $calc->itemid = $itemid;
-
- $calc->calculation = backup_todb($ite_info['#']['CALCULATION']['0']['#']);
-
- $modifier = backup_getid($restore->backup_unique_code,"user", backup_todb($ite_info['#']['USERMODIFIED']['0']['#']));
- $calc->usermodified = $modifier->new_id;
-
- insert_record('grade_calculations', $calc);
-
- $counter++;
- if ($counter % 20 == 0) {
- if (!defined('RESTORE_SILENTLY')) {
- echo ".";
- if ($counter % 400 == 0) {
- echo "<br />";
- }
- }
- backup_flush(300);
- }
- }
- }
/// processing grade_grades_text
if (!empty($info['GRADE_ITEM']['#']['GRADE_GRADES_TEXT']['0']['#']) && ($texts = $info['GRADE_ITEM']['#']['GRADE_GRADES_TEXT']['0']['#']['GRADE_TEXT'])) {
<?xml version="1.0" encoding="UTF-8" ?>
-<XMLDB PATH="lib/db" VERSION="20070619" COMMENT="XMLDB file for core Moodle tables"
+<XMLDB PATH="lib/db" VERSION="20070623" COMMENT="XMLDB file for core Moodle tables"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="../../lib/xmldb/xmldb.xsd"
>
<FIELD NAME="iteminstance" TYPE="int" LENGTH="10" NOTNULL="false" UNSIGNED="true" SEQUENCE="false" ENUM="false" COMMENT="id of the item module" PREVIOUS="itemmodule" NEXT="itemnumber"/>
<FIELD NAME="itemnumber" TYPE="int" LENGTH="10" NOTNULL="false" UNSIGNED="true" SEQUENCE="false" ENUM="false" COMMENT="Can be used to distinguish multiple grades for an activity" PREVIOUS="iteminstance" NEXT="iteminfo"/>
<FIELD NAME="iteminfo" TYPE="text" LENGTH="medium" NOTNULL="true" SEQUENCE="false" ENUM="false" COMMENT="Info and notes about this item XXX" PREVIOUS="itemnumber" NEXT="idnumber"/>
- <FIELD NAME="idnumber" TYPE="char" LENGTH="255" NOTNULL="false" SEQUENCE="false" ENUM="false" COMMENT="Arbitrary idnumber provided by the module responsible" PREVIOUS="iteminfo" NEXT="gradetype"/>
- <FIELD NAME="gradetype" TYPE="int" LENGTH="4" NOTNULL="true" UNSIGNED="false" DEFAULT="1" SEQUENCE="false" ENUM="false" COMMENT="0 = none, 1 = value, 2 = scale, 3 = text" PREVIOUS="idnumber" NEXT="grademax"/>
+ <FIELD NAME="idnumber" TYPE="char" LENGTH="255" NOTNULL="false" SEQUENCE="false" ENUM="false" COMMENT="Arbitrary idnumber provided by the module responsible" PREVIOUS="iteminfo" NEXT="calculation"/>
+ <FIELD NAME="calculation" TYPE="text" LENGTH="medium" NOTNULL="false" SEQUENCE="false" ENUM="false" COMMENT="Formula describing how to derive this grade from other items, referring to them using giXXX where XXX is grade item id ... eg something like: =sin(square([#gi20#])) + [#gi30#]" PREVIOUS="idnumber" NEXT="gradetype"/>
+ <FIELD NAME="gradetype" TYPE="int" LENGTH="4" NOTNULL="true" UNSIGNED="false" DEFAULT="1" SEQUENCE="false" ENUM="false" COMMENT="0 = none, 1 = value, 2 = scale, 3 = text" PREVIOUS="calculation" NEXT="grademax"/>
<FIELD NAME="grademax" TYPE="number" LENGTH="10" NOTNULL="true" UNSIGNED="false" DEFAULT="100" SEQUENCE="false" ENUM="false" DECIMALS="5" COMMENT="What is the maximum allowable grade?" PREVIOUS="gradetype" NEXT="grademin"/>
<FIELD NAME="grademin" TYPE="number" LENGTH="10" NOTNULL="true" UNSIGNED="false" DEFAULT="0" SEQUENCE="false" ENUM="false" DECIMALS="5" COMMENT="What is the minimum allowable grade?" PREVIOUS="grademax" NEXT="scaleid"/>
<FIELD NAME="scaleid" TYPE="int" LENGTH="10" NOTNULL="false" UNSIGNED="true" SEQUENCE="false" ENUM="false" COMMENT="If this grade is based on a scale, which one is it?" PREVIOUS="grademin" NEXT="outcomeid"/>
<KEY NAME="outcomeid" TYPE="foreign" FIELDS="outcomeid" REFTABLE="grade_outcomes" REFFIELDS="id" PREVIOUS="scaleid"/>
</KEYS>
</TABLE>
- <TABLE NAME="grade_categories" COMMENT="This table keeps information about categories, used for grouping items." PREVIOUS="grade_items" NEXT="grade_calculations">
+ <TABLE NAME="grade_categories" COMMENT="This table keeps information about categories, used for grouping items." PREVIOUS="grade_items" NEXT="grade_grades">
<FIELDS>
<FIELD NAME="id" TYPE="int" LENGTH="10" NOTNULL="true" UNSIGNED="false" SEQUENCE="true" ENUM="false" COMMENT="id of the table, please edit me" NEXT="courseid"/>
<FIELD NAME="courseid" TYPE="int" LENGTH="10" NOTNULL="true" UNSIGNED="true" SEQUENCE="false" ENUM="false" COMMENT="The course this grade category is part of" PREVIOUS="id" NEXT="parent"/>
<KEY NAME="parent" TYPE="foreign" FIELDS="parent" REFTABLE="grade_categories" REFFIELDS="id" PREVIOUS="courseid"/>
</KEYS>
</TABLE>
- <TABLE NAME="grade_calculations" COMMENT="This table describes the calculated grade_items in more details." PREVIOUS="grade_categories" NEXT="grade_grades">
- <FIELDS>
- <FIELD NAME="id" TYPE="int" LENGTH="10" NOTNULL="true" UNSIGNED="false" SEQUENCE="true" ENUM="false" COMMENT="id of the table, please edit me" NEXT="itemid"/>
- <FIELD NAME="itemid" TYPE="int" LENGTH="10" NOTNULL="true" UNSIGNED="true" SEQUENCE="false" ENUM="false" COMMENT="The grade_item this relates to" PREVIOUS="id" NEXT="calculation"/>
- <FIELD NAME="calculation" TYPE="text" LENGTH="medium" NOTNULL="false" SEQUENCE="false" ENUM="false" COMMENT="Formula describing how to derive this grade from other items, referring to them using [idnumber] ... eg something like:sin(square([XXXXX])) + [YYYY]" PREVIOUS="itemid" NEXT="timecreated"/>
- <FIELD NAME="timecreated" TYPE="int" LENGTH="10" NOTNULL="false" UNSIGNED="true" SEQUENCE="false" ENUM="false" COMMENT="the time this calculation was first created" PREVIOUS="calculation" NEXT="timemodified"/>
- <FIELD NAME="timemodified" TYPE="int" LENGTH="10" NOTNULL="false" UNSIGNED="true" SEQUENCE="false" ENUM="false" COMMENT="the time this calculation was last modified" PREVIOUS="timecreated" NEXT="usermodified"/>
- <FIELD NAME="usermodified" TYPE="int" LENGTH="10" NOTNULL="false" UNSIGNED="true" SEQUENCE="false" ENUM="false" COMMENT="the userid of the person who last modified this calculation" PREVIOUS="timemodified"/>
- </FIELDS>
- <KEYS>
- <KEY NAME="primary" TYPE="primary" FIELDS="id" COMMENT="primary key of the table, please edit me" NEXT="itemid"/>
- <KEY NAME="itemid" TYPE="foreign" FIELDS="itemid" REFTABLE="grade_items" REFFIELDS="id" PREVIOUS="primary" NEXT="usermodified"/>
- <KEY NAME="usermodified" TYPE="foreign" FIELDS="usermodified" REFTABLE="user" REFFIELDS="id" PREVIOUS="itemid"/>
- </KEYS>
- </TABLE>
- <TABLE NAME="grade_grades" COMMENT="grade_grades This table keeps individual grades for each user and each item, exactly as imported or submitted by modules. The rawgrademax/min and rawscaleid are stored here to record the values at the time the grade was stored, because teachers might change this for an activity! All the results are normalised/resampled for the final grade value." PREVIOUS="grade_calculations" NEXT="grade_grades_text">
+ <TABLE NAME="grade_grades" COMMENT="grade_grades This table keeps individual grades for each user and each item, exactly as imported or submitted by modules. The rawgrademax/min and rawscaleid are stored here to record the values at the time the grade was stored, because teachers might change this for an activity! All the results are normalised/resampled for the final grade value." PREVIOUS="grade_categories" NEXT="grade_grades_text">
<FIELDS>
<FIELD NAME="id" TYPE="int" LENGTH="10" NOTNULL="true" UNSIGNED="false" SEQUENCE="true" ENUM="false" COMMENT="id of the table, please edit me" NEXT="itemid"/>
<FIELD NAME="itemid" TYPE="int" LENGTH="10" NOTNULL="true" UNSIGNED="true" SEQUENCE="false" ENUM="false" COMMENT="The item this grade belongs to" PREVIOUS="id" NEXT="userid"/>
$table->addFieldInfo('itemnumber', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, null, null, null, null, null);
$table->addFieldInfo('iteminfo', XMLDB_TYPE_TEXT, 'medium', null, XMLDB_NOTNULL, null, null, null, null);
$table->addFieldInfo('idnumber', XMLDB_TYPE_CHAR, '255', null, null, null, null, null, null);
+ $table->addFieldInfo('calculation', XMLDB_TYPE_TEXT, 'medium', null, null, null, null, null, null);
$table->addFieldInfo('gradetype', XMLDB_TYPE_INTEGER, '4', null, XMLDB_NOTNULL, null, null, null, '0');
$table->addFieldInfo('grademax', XMLDB_TYPE_NUMBER, '10, 5', null, XMLDB_NOTNULL, null, null, null, '100');
$table->addFieldInfo('grademin', XMLDB_TYPE_NUMBER, '10, 5', null, XMLDB_NOTNULL, null, null, null, '0');
/// Launch create table for grade_categories
$result = $result && create_table($table);
- /// Define table grade_calculations to be created
- $table = new XMLDBTable('grade_calculations');
-
- /// Adding fields to table grade_calculations
- $table->addFieldInfo('id', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, XMLDB_SEQUENCE, null, null, null);
- $table->addFieldInfo('itemid', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, null, null, null);
- $table->addFieldInfo('calculation', XMLDB_TYPE_TEXT, 'medium', null, null, null, null, null, null);
- $table->addFieldInfo('timecreated', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, null, null, null, null, null);
- $table->addFieldInfo('timemodified', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, null, null, null, null, null);
- $table->addFieldInfo('usermodified', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, null, null, null);
-
- /// Adding keys to table grade_calculations
- $table->addKeyInfo('primary', XMLDB_KEY_PRIMARY, array('id'));
- $table->addKeyInfo('itemid', XMLDB_KEY_FOREIGN, array('itemid'), 'grade_items', array('id'));
- $table->addKeyInfo('usermodified', XMLDB_KEY_FOREIGN, array('usermodified'), 'user', array('id'));
-
- /// Launch create table for grade_calculations
- $result = $result && create_table($table);
-
/// Define table grade_grades to be created
$table = new XMLDBTable('grade_grades');
$result = $result && add_field($table, $field);
}
- if ($result && $oldversion < 2007042601) {
-
- /// Changing nullability of field usermodified on table grade_calculations to null
- $table = new XMLDBTable('grade_calculations');
- $field = new XMLDBField('usermodified');
- $field->setAttributes(XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, null, null, null, null, null, 'timemodified');
-
- /// Launch change of nullability for field usermodified
- $result = $result && change_field_notnull($table, $field);
- }
-
if ($result && $oldversion < 2007042701) {
/// Define key categoryid (foreign) to be dropped form grade_categories
$result = $result && create_table($table);
}
- /// Remove the obsoleted unitttests tables - they will be recreated automatically
- $tables = array('grade_categories',
- 'scale',
- 'grade_items',
- 'grade_calculations',
- 'grade_grades_raw',
- 'grade_grades_final',
- 'grade_grades_text',
- 'grade_outcomes',
- 'grade_history');
-
- foreach ($tables as $table) {
- $table = new XMLDBTable('unittest_'.$table);
- if (table_exists($table)) {
- drop_table($table);
- }
-
- }
-
/// Define table grade_import_values to be created
$table = new XMLDBTable('grade_import_values');
if (table_exists($table)) {
}
}
+
+/// merge calculation formula into grade_item
+ if ($result && $oldversion < 2007062301) {
+
+ /// Delete obsoleted calculations table - we did not need the data yet
+ $table = new XMLDBTable('grade_calculations');
+ if (table_exists($table)) {
+ drop_table($table);
+ }
+
+ /// Define field calculation to be added to grade_items
+ $table = new XMLDBTable('grade_items');
+ $field = new XMLDBField('calculation');
+
+ if (!field_exists($table, $field)) {
+ $field->setAttributes(XMLDB_TYPE_TEXT, 'medium', null, null, null, null, null, null, 'idnumber');
+ /// Launch add field calculation
+ $result = $result && add_field($table, $field);
+ }
+
+ /// Remove the obsoleted unitttests tables - they will be recreated automatically
+ $tables = array('grade_categories',
+ 'scale',
+ 'grade_items',
+ 'grade_calculations',
+ 'grade_grades_raw',
+ 'grade_grades_final',
+ 'grade_grades_text',
+ 'grade_outcomes',
+ 'grade_history');
+
+ foreach ($tables as $table) {
+ $table = new XMLDBTable('unittest_'.$table);
+ if (table_exists($table)) {
+ drop_table($table);
+ }
+ }
+
+ }
+
return $result;
}
+++ /dev/null
-<?php // $Id$
-
-///////////////////////////////////////////////////////////////////////////
-// //
-// NOTICE OF COPYRIGHT //
-// //
-// Moodle - Modular Object-Oriented Dynamic Learning Environment //
-// http://moodle.com //
-// //
-// Copyright (C) 2001-2007 Martin Dougiamas http://dougiamas.com //
-// //
-// This program is free software; you can redistribute it and/or modify //
-// it under the terms of the GNU General Public License as published by //
-// the Free Software Foundation; either version 2 of the License, or //
-// (at your option) any later version. //
-// //
-// This program is distributed in the hope that it will be useful, //
-// but WITHOUT ANY WARRANTY; without even the implied warranty of //
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the //
-// GNU General Public License for more details: //
-// //
-// http://www.gnu.org/copyleft/gpl.html //
-// //
-///////////////////////////////////////////////////////////////////////////
-
-require_once('grade_object.php');
-
-/**
- * A calculation string used to compute the value displayed by a grade_item.
- * There can be only one grade_calculation per grade_item (one-to-one).
- *
- * Calculation formula may use final grades of other grade items (giXXX
- * where XXX is the id number of grade item). The result is stored in
- * finalgrade field. The rawgrade is not used at all.
- */
-class grade_calculation extends grade_object {
- /**
- * DB Table (used by grade_object).
- * @var string $table
- */
- var $table = 'grade_calculations';
-
- /**
- * Array of class variables that are not part of the DB table fields
- * @var array $nonfields
- */
- var $nonfields = array('table', 'nonfields', 'formula', 'grade_item');
-
- /**
- * A reference to the grade_item this calculation belongs to.
- * @var int $itemid
- */
- var $itemid;
-
- /**
- * The string representation of the calculation.
- * @var string $calculation
- */
- var $calculation;
-
- /**
- * The userid of the person who last modified this calculation.
- * @var int $usermodified
- */
- var $usermodified;
-
- /**
- * Grade item object
- */
- var $grade_item;
-
- /**
- * Math evaluation object
- */
- var $formula;
-
- /**
- * Loads the grade_item object referenced by $this->itemid and saves it as $this->grade_item for easy access.
- * @return object grade_item.
- */
- function load_grade_item() {
- if (empty($this->grade_item) && !empty($this->itemid)) {
- $this->grade_item = grade_item::fetch('id', $this->itemid);
- }
- return $this->grade_item;
- }
-
- /**
- * Applies the formula represented by this object. The parameteres are taken from final
- * grades of grade items in current course only.
- * @return boolean false if error
- */
- function compute() {
- global $CFG;
- require_once($CFG->libdir.'/mathslib.php');
-
- if (empty($this->id) or empty($this->itemid)) {
- debugging('Can not initialize calculation!');
- return false;
- }
-
- // init grade_item
- $this->load_grade_item();
-
- if ($this->grade_item->is_locked()) {
- return true; // no need to recalculate locked items
- }
-
- //get used items
- $useditems = $this->dependson();
-
- // init maths library
- $this->formula = new calc_formula($this->calculation);
-
- // where to look for final grades?
- // this itemid is added so that we use only one query for source and final grades
- $gis = implode(',', array_merge($useditems, array($this->itemid)));
-
- $sql = "SELECT g.*
- FROM {$CFG->prefix}grade_grades g, {$CFG->prefix}grade_items gi
- WHERE gi.id = g.itemid AND gi.courseid={$this->grade_item->courseid} AND gi.id IN ($gis)
- ORDER BY g.userid";
-
- $return = true;
-
- // group the grades by userid and use formula on the group
- if ($rs = get_recordset_sql($sql)) {
- if ($rs->RecordCount() > 0) {
- $prevuser = 0;
- $grades = array();
- $final = null;
- while ($used = rs_fetch_next_record($rs)) {
- if ($used->userid != $prevuser) {
- if (!$this->use_formula($prevuser, $grades, $useditems, $final)) {
- $return = false;
- }
- $prevuser = $used->userid;
- $grades = array();
- $final = null;
- }
- if ($used->itemid == $this->grade_item->id) {
- $final = new grade_grades($used, false); // fetching from db is not needed
- $final->grade_item =& $this->grade_item;
- }
- $grades['gi'.$used->itemid] = $used->finalgrade;
- }
- if (!$this->use_formula($prevuser, $grades, $useditems, $final)) {
- $return = false;
- }
- }
- }
-
- //TODO: we could return array of errors here
- return $return;
- }
-
- /**
- * internal function - does the final grade calculation
- */
- function use_formula($userid, $params, $useditems, $final) {
- if (empty($userid)) {
- return true;
- }
-
- // add missing final grade values
- // not graded (null) is counted as 0 - the spreadsheet way
- foreach($useditems as $gi) {
- if (!array_key_exists('gi'.$gi, $params)) {
- $params['gi'.$gi] = 0;
- } else {
- $params['gi'.$gi] = (float)$params['gi'.$gi];
- }
- }
-
- // can not use own final grade during calculation
- unset($params['gi'.$this->grade_item->id]);
-
- // insert final grade - will be needed later anyway
- if (empty($final)) {
- $final = new grade_grades(array('itemid'=>$this->grade_item->id, 'userid'=>$userid), false);
- $final->insert();
- $final->grade_item =& $this->grade_item;
-
- } else if ($final->is_locked()) {
- // no need to recalculate locked grades
- return;
- }
-
-
- // do the calculation
- $this->formula->set_params($params);
- $result = $this->formula->evaluate();
-
- // store the result
- if ($result === false) {
- // error during calculation
- if (!is_null($final->finalgrade) or !is_null($final->rawgrade)) {
- $final->finalgrade = null;
- $final->rawgrade = null;
- $final->update();
- }
- return false;
-
- } else {
- // normalize
- $result = bounded_number($this->grade_item->grademin, $result, $this->grade_item->grademax);
- if ($this->grade_item->gradetype == GRADE_TYPE_SCALE) {
- $result = round($result+0.00001); // round scales upwards
- }
-
- // store only if final grade changed, remove raw grade because we do not need it
- if ($final->finalgrade != $result or !is_null($final->rawgrade)) {
- $final->finalgrade = $result;
- $final->rawgrade = null;
- $final->update();
- }
- return true;
- }
- }
-
- /**
- * Finds out on which other items does this calculation depend
- * @return array of grade_item ids this one depends on
- */
- function dependson() {
- if (preg_match_all('/gi([0-9]+)/i', $this->calculation, $matches)) {
- return ($matches[1]);
- } else {
- return array();
- }
- }
-
- /**
- * Finds and returns a grade_calculation object based on 1-3 field values.
- *
- * @param boolean $static Unless set to true, this method will also set $this object with the returned values.
- * @param string $field1
- * @param string $value1
- * @param string $field2
- * @param string $value2
- * @param string $field3
- * @param string $value3
- * @param string $fields
- * @return object grade_calculation object or false if none found.
- */
- function fetch($field1, $value1, $field2='', $value2='', $field3='', $value3='', $fields="*") {
- if ($grade_calculation = get_record('grade_calculations', $field1, $value1, $field2, $value2, $field3, $value3, $fields)) {
- if (isset($this) && get_class($this) == 'grade_calculation') {
- print_object($this);
- foreach ($grade_calculation as $param => $value) {
- $this->$param = $value;
- }
- return $this;
- } else {
- $grade_calculation = new grade_calculation($grade_calculation);
- return $grade_calculation;
- }
- } else {
- return false;
- }
- }
-}
-?>
/**
* Finds and returns a grade_category object based on 1-3 field values.
+ * @static
*
* @param string $field1
* @param string $value1
*/
function fetch($field1, $value1, $field2='', $value2='', $field3='', $value3='', $fields="*") {
if ($grade_category = get_record('grade_categories', $field1, $value1, $field2, $value2, $field3, $value3, $fields)) {
- if (isset($this) && get_class($this) == 'grade_category') {
- foreach ($grade_category as $param => $value) {
- $this->$param = $value;
- }
- return $this;
- } else {
- $grade_category = new grade_category($grade_category);
- return $grade_category;
- }
+ $grade_category = new grade_category($grade_category);
+ return $grade_category;
+
} else {
return false;
}
// find grde items of immediate children (category or grade items)
- $dependson = $this->grade_item->dependson();
+ $depends_on = $this->grade_item->depends_on();
$items = array();
- foreach($dependson as $dep) {
+ foreach($depends_on as $dep) {
$items[$dep] = grade_item::fetch('id', $dep);
}
// where to look for final grades - include or grade item too
- $gis = implode(',', array_merge($dependson, array($this->grade_item->id)));
+ $gis = implode(',', array_merge($depends_on, array($this->grade_item->id)));
$sql = "SELECT g.*
FROM {$CFG->prefix}grade_grades g, {$CFG->prefix}grade_items gi
$final = null;
while ($used = rs_fetch_next_record($rs)) {
if ($used->userid != $prevuser) {
- $this->aggregate_grades($prevuser, $items, $grades, $dependson, $final);
+ $this->aggregate_grades($prevuser, $items, $grades, $depends_on, $final);
$prevuser = $used->userid;
$grades = array();
$final = null;
}
$grades[$used->itemid] = $used->finalgrade;
}
- $this->aggregate_grades($prevuser, $items, $grades, $dependson, $final);
+ $this->aggregate_grades($prevuser, $items, $grades, $depends_on, $final);
}
}
/**
* internal function for category grades aggregation
*/
- function aggregate_grades($userid, $items, $grades, $dependson, $final) {
+ function aggregate_grades($userid, $items, $grades, $depends_on, $final) {
if (empty($userid)) {
//ignore first run
return;
break;
case GRADE_AGGREGATE_MEAN_ALL: // Arithmetic average of all grade items including even NULLs; NULL grade caunted as minimum
- $num = count($dependson); // you can calculate sum from this one if you multiply it with count($this->dependson() ;-)
+ $num = count($depends_on); // you can calculate sum from this one if you multiply it with count($this->depends_on() ;-)
$sum = array_sum($grades);
$rawgrade = $sum / $num;
break;
/**
* Finds and returns a grade_grades object based on 1-3 field values.
* @static
+ *
* @param string $field1
* @param string $value1
* @param string $field2
*/
function fetch($field1, $value1, $field2='', $value2='', $field3='', $value3='', $fields="*") {
if ($object = get_record('grade_grades', $field1, $value1, $field2, $value2, $field3, $value3, $fields)) {
- if (isset($this) && get_class($this) == 'grade_grades') {
- foreach ($object as $param => $value) {
- $this->$param = $value;
- }
+ $object = new grade_grades($object);
+ return $object;
- return $this;
- } else {
- $object = new grade_grades($object);
- return $object;
- }
} else {
return false;
}
/**
* Finds and returns a grade_text object based on 1-3 field values.
+ * @static
*
* @param boolean $static Unless set to true, this method will also set $this object with the returned values.
* @param string $field1
*/
function fetch($field1, $value1, $field2='', $value2='', $field3='', $value3='', $fields="*") {
if ($grade_text = get_record('grade_grades_text', $field1, $value1, $field2, $value2, $field3, $value3, $fields)) {
- if (isset($this) && get_class($this) == 'grade_grades_text') {
- foreach ($grade_text as $param => $value) {
- $this->$param = $value;
- }
- return $this;
- } else {
- $grade_text = new grade_grades_text($grade_text);
- return $grade_text;
- }
+ $grade_text = new grade_grades_text($grade_text);
+ return $grade_text;
+
} else {
return false;
}
/**
* Finds and returns a grade_history object based on 1-3 field values.
+ * @static
*
* @param string $field1
* @param string $value1
*/
function fetch($field1, $value1, $field2='', $value2='', $field3='', $value3='', $fields="*") {
if ($grade_history = get_record('grade_history', $field1, $value1, $field2, $value2, $field3, $value3, $fields)) {
- if (isset($this) && get_class($this) == 'grade_history') {
- foreach ($grade_history as $param => $value) {
- $this->$param = $value;
- }
- return $this;
- } else {
- $grade_history = new grade_history($grade_history);
- return $grade_history;
- }
+ $grade_history = new grade_history($grade_history);
+ return $grade_history;
+
} else {
return false;
}
* Array of class variables that are not part of the DB table fields
* @var array $nonfields
*/
- var $nonfields = array('table', 'nonfields', 'calculation', 'scale', 'category', 'outcome');
+ var $nonfields = array('table', 'nonfields', 'formula', 'calculation_normalized', 'scale', 'category', 'outcome');
/**
* The course this grade_item belongs to.
*/
var $idnumber;
+ /**
+ * Calculation string used for this item.
+ * @var string $calculation
+ */
+ var $calculation;
+
+ /**
+ * Indicates if we already tried to normalize the grade calculation formula.
+ * This flag helps to minimize db access when broken formulas used in calculation.
+ * @var boolean
+ */
+ var $calculation_normalized;
+ /**
+ * Math evaluation object
+ */
+ var $formula;
+
/**
* The type of grade (0 = none, 1 = value, 2 = scale, 3 = text)
* @var int $gradetype
*/
var $needsupdate;
- /**
- * Calculation string used for this item.
- * @var string $calculation
- */
- var $calculation;
-
/**
* Constructor. Extends the basic functionality defined in grade_object.
* @param array $params Can also be a standard object.
$db_item = new grade_item(array('id' => $this->id));
+ $calculationdiff = $db_item->calculation != $this->calculation;
$gradetypediff = $db_item->gradetype != $this->gradetype;
$grademaxdiff = $db_item->grademax != $this->grademax;
$grademindiff = $db_item->grademin != $this->grademin;
$needsupdatediff = !$db_item->needsupdate && $this->needsupdate; // force regrading only if setting the flag first time
$lockeddiff = !empty($db_item->locked) && empty($this->locked); // force regrading only when unlocking
- return ($gradetypediff || $grademaxdiff || $grademindiff || $scaleiddiff || $outcomeiddiff ||
- $multfactordiff || $plusfactordiff || $deleteddiff || $needsupdatediff || $lockeddiff);
+ return ($calculationdiff || $gradetypediff || $grademaxdiff || $grademindiff || $scaleiddiff
+ || $outcomeiddiff || $multfactordiff || $plusfactordiff || $deleteddiff || $needsupdatediff
+ || $lockeddiff);
}
/**
* Finds and returns a grade_item object based on 1-3 field values.
+ * @static
*
* @param string $field1
* @param string $value1
*/
function fetch($field1, $value1, $field2='', $value2='', $field3='', $value3='', $fields="*") {
if ($grade_item = get_record('grade_items', $field1, $value1, $field2, $value2, $field3, $value3, $fields)) {
- if (isset($this) && get_class($this) == 'grade_item') {
- foreach ($grade_item as $param => $value) {
- $this->$param = $value;
- }
+ $grade_item = new grade_item($grade_item);
+ return $grade_item;
- return $this;
- } else {
- $grade_item = new grade_item($grade_item);
- return $grade_item;
- }
} else {
return false;
}
* @return boolean Locked state
*/
function is_locked($userid=NULL) {
- if (!empty($this->locked)) {
+ if (!empty($this->locked)) {
return true;
- }
+ }
- if (!empty($userid)) {
+ if (!empty($userid)) {
$grade = new grade_grades(array('itemid'=>$this->id, 'userid'=>$userid));
$grade->grade_item =& $this; // prevent db fetching of cached grade_item
}
if ($this->is_calculated()) {
- if ($this->calculation->compute()) {
+ if ($this->compute()) {
$this->needsupdate = false;
$this->update();
return true;
/**
* Checks if grade calculated. Returns this object's calculation.
- * @return mixed $calculation Calculation object if exists, false otherwise.
+ * @return boolean true if grade item calculated.
*/
function is_calculated() {
- if (is_null($this->calculation)) {
- $this->calculation = grade_calculation::fetch('itemid', $this->id);
+ if (empty($this->calculation)) {
+ return false;
+ }
+
+ /*
+ * The main reason why we use the [#gixxx#] instead of [idnumber] is speed of depends_on(),
+ * we would have to fetch all course grade items to find out the ids.
+ * Also if user changes the idnumber the formula does not need to be updated.
+ */
+
+ // first detect if we need to update calculation formula from [idnumber] to [#giXXX#] (after backup, etc.)
+ if (!$this->calculation_normalized and preg_match_all('/\[(?!#gi)(.*?)\]/', $this->calculation, $matches)) {
+ foreach ($matches[1] as $idnumber) {
+ if ($grade_item = grade_item::fetch('courseid', $this->courseid, 'idnumber', $idnumber)) {
+ $this->calculation = str_replace('['.$grade_item->idnumber.']', '[#gi'.$grade_item->id.'#]', $this->calculation);
+ }
+ }
+ $this->update(); // update in db if needed
+ $this->calculation_normalized = true;
+ return !empty($this->calculation);
}
- return !empty($this->calculation);
+ return true;
}
/**
*/
function get_calculation() {
if ($this->is_calculated()) {
- return $this->calculation->calculation;
+ $formula = $this->calculation;
+ // denormalize formula - convert [#giXX#] to [idnumber]
+ if (preg_match_all('/\[#gi([0-9]+)#\]/', $formula, $matches)) {
+ foreach ($matches[1] as $id) {
+ if ($grade_item = grade_item::fetch('id', $id)) {
+ if (!empty($grade_item->idnumber)) {
+ $formula = str_replace('[#gi'.$grade_item->id.'#]', '['.$grade_item->idnumber.']', $formula);
+ }
+ }
+ }
+ }
+
+ return $formula;
+
} else {
return NULL;
}
* @return boolean success
*/
function set_calculation($formula) {
- // refresh cached calculation object
- $this->calculation = null;
+ $formula = trim($formula);
- $result = true;
+ if (empty($formula)) {
+ $this->calculation = NULL;
- if (empty($formula)) { // We are removing this calculation
- if (!empty($this->id) and $this->is_calculated()) {
- $this->calculation->delete();
- $this->calculation = null; // remove cache
+ } else {
+ if (strpos($formula, '=') !== 0) {
+ $formula = '='.$formula;
}
- } else { // We are updating or creating the calculation entry in the DB
- if ($this->is_calculated()) {
- $this->calculation->calculation = $formula;
- if (!$this->calculation->update()) {
- $this->calculation = null; // remove cache
- $result = false;
- debugging("Could not save the calculation in the database for this grade_item.");
+ // normalize formula - we want grade item ids [#giXXX#] instead of [idnumber]
+ $grade_item = new grade_item(array('courseid'=>$this->courseid), false);
+ if ($grade_items = $grade_item->fetch_all_using_this()) {
+ foreach ($grade_items as $grade_item) {
+ $formula = str_replace('['.$grade_item->idnumber.']', '[#gi'.$grade_item->id.'#]', $formula);
}
-
- } else {
- $grade_calculation = new grade_calculation(array('calculation'=>$formula, 'itemid'=>$this->id), false);
- if (!$grade_calculation->insert()) {
- $this->calculation = null; // remove cache
- $result = false;
- debugging("Could not save the calculation in the database for this grade_item.");
- }
- $this->calculation = $grade_calculation;
}
- }
- $this->force_regrading();
+ $this->calculation = $formula;
+ }
- return $result;
+ $this->calculation_normalized = true;
+ return $this->update();
}
/**
* Finds out on which other items does this depend directly when doing calculation or category agregation
* @return array of grade_item ids this one depends on
*/
- function dependson() {
+ function depends_on() {
if ($this->is_locked()) {
// locked items do not need to be regraded
return array();
}
- if ($calculation = $this->is_calculated()) {
- return $calculation->dependson();
+ if ($this->is_calculated()) {
+ if (preg_match_all('/\[#gi([0-9]+)#\]/', $this->calculation, $matches)) {
+ return array_unique($matches[1]); // remove duplicates
+ } else {
+ return array();
+ }
- } else if ($this->itemtype == 'category') {
- $grade_category = grade_category::fetch('id', $this->iteminstance);
+ } else if ($grade_category = $this->load_category()) {
$children = $grade_category->get_children(1, 'flat');
if (empty($children)) {
$result = array();
- $childrentype = get_class(reset($children));
- if ($childrentype == 'grade_category') {
- foreach ($children as $id => $category) {
- $grade_item = $category->get_grade_item();
- $result[] = $grade_item->id;
- }
- } elseif ($childrentype == 'grade_item') {
- foreach ($children as $id => $grade_item) {
+ foreach ($children as $id => $child) {
+ if (get_class($child) == 'grade_category') {
+ $grade_item = $child->get_grade_item();
$result[] = $grade_item->id;
+
+ } else if (get_class($child) == 'grade_item') {
+ $result[] = $child->id;
}
}
return false;
}
}
+
+ /**
+ * Calculates final grade values useing the formula in calculation property.
+ * The parameteres are taken from final grades of grade items in current course only.
+ * @return boolean false if error
+ */
+ function compute() {
+ global $CFG;
+
+ if (!$this->is_calculated()) {
+ return false;
+ }
+
+ require_once($CFG->libdir.'/mathslib.php');
+
+ if ($this->is_locked()) {
+ return true; // no need to recalculate locked items
+ }
+
+ // get used items
+ $useditems = $this->depends_on();
+
+ // prepare formula and init maths library
+ $formula = preg_replace('/\[#(gi[0-9]+)#\]/', '\1', $this->calculation);
+ $this->formula = new calc_formula($formula);
+
+ // where to look for final grades?
+ // this itemid is added so that we use only one query for source and final grades
+ $gis = implode(',', array_merge($useditems, array($this->id)));
+
+ $sql = "SELECT g.*
+ FROM {$CFG->prefix}grade_grades g, {$CFG->prefix}grade_items gi
+ WHERE gi.id = g.itemid AND gi.courseid={$this->courseid} AND gi.id IN ($gis)
+ ORDER BY g.userid";
+
+ $return = true;
+
+ // group the grades by userid and use formula on the group
+ if ($rs = get_recordset_sql($sql)) {
+ if ($rs->RecordCount() > 0) {
+ $prevuser = 0;
+ $grades = array();
+ $final = null;
+ while ($used = rs_fetch_next_record($rs)) {
+ if ($used->userid != $prevuser) {
+ if (!$this->use_formula($prevuser, $grades, $useditems, $final)) {
+ $return = false;
+ }
+ $prevuser = $used->userid;
+ $grades = array();
+ $final = null;
+ }
+ if ($used->itemid == $this->id) {
+ $final = new grade_grades($used, false); // fetching from db is not needed
+ $final->grade_item =& $this;
+ }
+ $grades['gi'.$used->itemid] = $used->finalgrade;
+ }
+ if (!$this->use_formula($prevuser, $grades, $useditems, $final)) {
+ $return = false;
+ }
+ }
+ }
+
+ //TODO: we could return array of errors here
+ return $return;
+ }
+
+ /**
+ * internal function - does the final grade calculation
+ */
+ function use_formula($userid, $params, $useditems, $final) {
+ if (empty($userid)) {
+ return true;
+ }
+
+ // add missing final grade values
+ // not graded (null) is counted as 0 - the spreadsheet way
+ foreach($useditems as $gi) {
+ if (!array_key_exists('gi'.$gi, $params)) {
+ $params['gi'.$gi] = 0;
+ } else {
+ $params['gi'.$gi] = (float)$params['gi'.$gi];
+ }
+ }
+
+ // can not use own final grade during calculation
+ unset($params['gi'.$this->id]);
+
+ // insert final grade - will be needed later anyway
+ if (empty($final)) {
+ $final = new grade_grades(array('itemid'=>$this->id, 'userid'=>$userid), false);
+ $final->insert();
+ $final->grade_item =& $this;
+
+ } else if ($final->is_locked()) {
+ // no need to recalculate locked grades
+ return;
+ }
+
+
+ // do the calculation
+ $this->formula->set_params($params);
+ $result = $this->formula->evaluate();
+
+ // store the result
+ if ($result === false) {
+ // error during calculation
+ if (!is_null($final->finalgrade) or !is_null($final->rawgrade)) {
+ $final->finalgrade = null;
+ $final->rawgrade = null;
+ $final->update();
+ }
+ return false;
+
+ } else {
+ // normalize
+ $result = bounded_number($this->grademin, $result, $this->grademax);
+ if ($this->gradetype == GRADE_TYPE_SCALE) {
+ $result = round($result+0.00001); // round scales upwards
+ }
+
+ // store only if final grade changed, remove raw grade because we do not need it
+ if ($final->finalgrade != $result or !is_null($final->rawgrade)) {
+ $final->finalgrade = $result;
+ $final->rawgrade = null;
+ $final->update();
+ }
+ return true;
+ }
+ }
+
}
?>
/**
* Finds and returns a grade_outcome object based on 1-3 field values.
+ * @static
*
* @param boolean $static Unless set to true, this method will also set $this object with the returned values.
* @param string $field1
*/
function fetch($field1, $value1, $field2='', $value2='', $field3='', $value3='', $fields="*") {
if ($grade_outcome = get_record('grade_outcomes', $field1, $value1, $field2, $value2, $field3, $value3, $fields)) {
- if (isset($this) && get_class($this) == 'grade_outcome') {
- print_object($this);
- foreach ($grade_outcome as $param => $value) {
- $this->$param = $value;
- }
- return $this;
- } else {
- $grade_outcome = new grade_outcome($grade_outcome);
- return $grade_outcome;
- }
+ $grade_outcome = new grade_outcome($grade_outcome);
+ return $grade_outcome;
+
} else {
return false;
}
/**
* Finds and returns a grade_scale object based on 1-3 field values.
+ * @static
*
* @param string $field1
* @param string $value1
*/
function fetch($field1, $value1, $field2='', $value2='', $field3='', $value3='', $fields="*") {
if ($grade_scale = get_record('scale', $field1, $value1, $field2, $value2, $field3, $value3, $fields)) {
- if (isset($this) && get_class($this) == 'grade_scale') {
- foreach ($grade_scale as $param => $value) {
- $this->$param = $value;
- }
- return $this;
- } else {
- $grade_scale = new grade_scale($grade_scale);
- return $grade_scale;
- }
+ $grade_scale = new grade_scale($grade_scale);
+ return $grade_scale;
+
} else {
return false;
}
require_once($CFG->libdir . '/grade/grade_category.php');
require_once($CFG->libdir . '/grade/grade_item.php');
-require_once($CFG->libdir . '/grade/grade_calculation.php');
require_once($CFG->libdir . '/grade/grade_grades.php');
require_once($CFG->libdir . '/grade/grade_scale.php');
require_once($CFG->libdir . '/grade/grade_outcome.php');
}
//do we have all data for finalizing of this item?
- $dependson = $grade_item->dependson();
+ $depends_on = $grade_item->depends_on();
$doupdate = true;
- foreach ($dependson as $did) {
+ foreach ($depends_on as $did) {
if (!in_array($did, $finalids)) {
$doupdate = false;
}
var $tables = array('grade_categories',
'scale',
'grade_items',
- 'grade_calculations',
'grade_grades',
'grade_grades_text',
'grade_outcomes',
var $grade_items = array();
var $grade_categories = array();
- var $grade_calculations = array();
var $grade_grades = array();
var $grade_grades_text = array();
var $grade_outcomes = array();
$table->addFieldInfo('itemnumber', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, null, null, null, null, null);
$table->addFieldInfo('iteminfo', XMLDB_TYPE_TEXT, 'medium', null, XMLDB_NOTNULL, null, null, null, null);
$table->addFieldInfo('idnumber', XMLDB_TYPE_CHAR, '255', null, null, null, null, null, null);
+ $table->addFieldInfo('calculation', XMLDB_TYPE_TEXT, 'medium', null, null, null, null, null, null);
$table->addFieldInfo('gradetype', XMLDB_TYPE_INTEGER, '4', null, XMLDB_NOTNULL, null, null, null, '1');
$table->addFieldInfo('grademax', XMLDB_TYPE_NUMBER, '10, 5', null, XMLDB_NOTNULL, null, null, null, '100');
$table->addFieldInfo('grademin', XMLDB_TYPE_NUMBER, '10, 5', null, XMLDB_NOTNULL, null, null, null, '0');
$result = $result && create_table($table, true, false);
}
- /// Define table grade_calculations to be created
- $table = new XMLDBTable('grade_calculations');
-
- if ($result && !table_exists($table)) {
-
- /// Adding fields to table grade_calculations
- $table->addFieldInfo('id', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, XMLDB_SEQUENCE, null, null, null);
- $table->addFieldInfo('itemid', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, null, null, null);
- $table->addFieldInfo('calculation', XMLDB_TYPE_TEXT, 'medium', null, null, null, null, null, null);
- $table->addFieldInfo('timecreated', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, null, null, null, null, null);
- $table->addFieldInfo('timemodified', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, null, null, null, null, null);
- $table->addFieldInfo('usermodified', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, null, null, null, null, null);
-
- /// Adding keys to table grade_calculations
- $table->addKeyInfo('primary', XMLDB_KEY_PRIMARY, array('id'));
- $table->addKeyInfo('itemid', XMLDB_KEY_FOREIGN, array('itemid'), 'grade_items', array('id'));
- $table->addKeyInfo('usermodified', XMLDB_KEY_FOREIGN, array('usermodified'), 'user', array('id'));
-
- /// Launch create table for grade_calculations
- $result = $result && create_table($table, true, false);
- }
-
/// Define table grade_grades_text to be created
$table = new XMLDBTable('grade_grades_text');
$grade_item->grademin = 30;
$grade_item->grademax = 110;
$grade_item->itemnumber = 1;
+ $grade_item->idnumber = 'item id 0';
$grade_item->iteminfo = 'Grade item used for unit testing';
$grade_item->timecreated = mktime();
$grade_item->timemodified = mktime();
$grade_item->itemname = 'unittestgradeitem2';
$grade_item->itemtype = 'import';
$grade_item->itemmodule = 'assignment';
+ $grade_item->calculation = '= [#gi'.$this->grade_items[0]->id.'#] + 30 + [item id 0] - [item id 0]';
$grade_item->gradetype = GRADE_TYPE_VALUE;
$grade_item->iteminstance = 2;
$grade_item->itemnumber = null;
}
- /**
- * Load grade_calculation data into the database, and adds the corresponding objects to this class' variable.
- */
- function load_grade_calculations() {
- // Calculation for grade_item 2
- $grade_calculation = new stdClass();
- $grade_calculation->itemid = $this->grade_items[1]->id;
- $grade_calculation->calculation = '= gi'.$this->grade_items[0]->id.' + 30 ';
- $grade_calculation->timecreated = mktime();
- $grade_calculation->timemodified = mktime();
-
- if ($grade_calculation->id = insert_record('grade_calculations', $grade_calculation)) {
- $this->grade_calculations[0] = $grade_calculation;
- $this->grade_items[1]->calculation = $grade_calculation;
- }
- }
-
/**
* Load grade_grades data into the database, and adds the corresponding objects to this class' variable.
*/
+++ /dev/null
-<?php // $Id$
-
-///////////////////////////////////////////////////////////////////////////
-// //
-// NOTICE OF COPYRIGHT //
-// //
-// Moodle - Modular Object-Oriented Dynamic Learning Environment //
-// http://moodle.org //
-// //
-// Copyright (C) 1999-2004 Martin Dougiamas http://dougiamas.com //
-// //
-// This program is free software; you can redistribute it and/or modify //
-// it under the terms of the GNU General Public License as published by //
-// the Free Software Foundation; either version 2 of the License, or //
-// (at your option) any later version. //
-// //
-// This program is distributed in the hope that it will be useful, //
-// but WITHOUT ANY WARRANTY; without even the implied warranty of //
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the //
-// GNU General Public License for more details: //
-// //
-// http://www.gnu.org/copyleft/gpl.html //
-// //
-///////////////////////////////////////////////////////////////////////////
-
-/**
- * Unit tests for grade_calculation object.
- *
- * @author nicolas@moodle.com
- * @license http://www.gnu.org/copyleft/gpl.html GNU Public License
- * @package moodlecore
- */
-
-if (!defined('MOODLE_INTERNAL')) {
- die('Direct access to this script is forbidden.'); /// It must be included from a Moodle page
-}
-
-require_once($CFG->libdir.'/simpletest/fixtures/gradetest.php');
-
-class grade_calculation_test extends grade_test {
-
- function test_grade_calculation_construct() {
- $params = new stdClass();
-
- $params->itemid = $this->grade_items[0]->id;
- $params->calculation = '=MEAN(1, 2)';
-
- $grade_calculation = new grade_calculation($params, false);
- $this->assertEqual($params->itemid, $grade_calculation->itemid);
- $this->assertEqual($params->calculation, $grade_calculation->calculation);
- }
-
- function test_grade_calculation_insert() {
- $grade_calculation = new grade_calculation();
- $this->assertTrue(method_exists($grade_calculation, 'insert'));
-
- $grade_calculation->itemid = $this->grade_items[0]->id;
- $grade_calculation->calculation = '=MEAN(1, 2)';
-
- $grade_calculation->insert();
-
- $last_grade_calculation = end($this->grade_calculations);
-
- $this->assertEqual($grade_calculation->id, $last_grade_calculation->id + 1);
- $this->assertFalse(empty($grade_calculation->timecreated));
- $this->assertFalse(empty($grade_calculation->timemodified));
-
- }
-
- function test_grade_calculation_update() {
- $grade_calculation = new grade_calculation($this->grade_calculations[0]);
- $this->assertTrue(method_exists($grade_calculation, 'update'));
- $grade_calculation->calculation = '=MEAN(1, 2)';
- $this->assertTrue($grade_calculation->update());
- $calculation = get_field('grade_calculations', 'calculation', 'id', $this->grade_calculations[0]->id);
- $this->assertEqual($grade_calculation->calculation, $calculation);
- }
-
- function test_grade_calculation_delete() {
- $grade_calculation = new grade_calculation($this->grade_calculations[0]);
- $this->assertTrue(method_exists($grade_calculation, 'delete'));
-
- $this->assertTrue($grade_calculation->delete());
- $this->assertFalse(get_record('grade_calculations', 'id', $grade_calculation->id));
- }
-
- function test_grade_calculation_fetch() {
- $grade_calculation = new grade_calculation();
- $this->assertTrue(method_exists($grade_calculation, 'fetch'));
-
- $grade_calculation = grade_calculation::fetch('id', $this->grade_calculations[0]->id);
- $this->assertEqual($this->grade_calculations[0]->id, $grade_calculation->id);
- $this->assertEqual($this->grade_calculations[0]->calculation, $grade_calculation->calculation);
- }
-
- function test_grade_calculation_compute() {
- $grade_calculation = new grade_calculation($this->grade_calculations[0]);
- $this->assertTrue(method_exists($grade_calculation, 'compute'));
-
- $grade_item = $grade_calculation->load_grade_item();
-
- $grade_grades = grade_grades::fetch('id', $this->grade_grades[3]->id);
- $grade_grades->delete();
- $grade_grades = grade_grades::fetch('id', $this->grade_grades[4]->id);
- $grade_grades->delete();
- $grade_grades = grade_grades::fetch('id', $this->grade_grades[5]->id);
- $grade_grades->delete();
-
- $grade_calculation->compute();
-
- $grade_grades = grade_grades::fetch('userid', $this->grade_grades[3]->userid, 'itemid', $this->grade_grades[3]->itemid);
- $this->assertEqual($this->grade_grades[3]->finalgrade, $grade_grades->finalgrade);
- $grade_grades = grade_grades::fetch('userid', $this->grade_grades[4]->userid, 'itemid', $this->grade_grades[4]->itemid);
- $this->assertEqual($this->grade_grades[4]->finalgrade, $grade_grades->finalgrade);
- $grade_grades = grade_grades::fetch('userid', $this->grade_grades[5]->userid, 'itemid', $this->grade_grades[5]->itemid);
- $this->assertEqual($this->grade_grades[5]->finalgrade, $grade_grades->finalgrade);
- }
-
-}
-?>
$this->assertEqual($this->grade_grades[0]->finalgrade, $final_grade->finalgrade);\r
}\r
\r
- function test_grade_item_is_calculated() {\r
- $grade_item = new grade_item($this->grade_items[1]);\r
- $this->assertTrue(method_exists($grade_item, 'is_calculated'));\r
- $this->assertTrue($grade_item->is_calculated());\r
- }\r
-\r
- function test_grade_item_set_calculation() {\r
-/* $grade_item = new grade_item($this->grade_items[1]);\r
- $this->assertTrue(method_exists($grade_item, 'set_calculation'));\r
- $this->assertTrue(method_exists($grade_item, 'is_calculated'));\r
-\r
- $calculation = '=SUM([unittestgradeitem1], [unittestgradeitem3])';\r
- $grade_item->set_calculation($calculation);\r
- $new_calculation = $grade_item->is_calculated();\r
-\r
- $this->assertEqual($calculation, $new_calculation->calculation);\r
-*/ }\r
-\r
function test_grade_item_get_category() {\r
$grade_item = new grade_item($this->grade_items[0]);\r
$this->assertTrue(method_exists($grade_item, 'get_category'));\r
$this->assertEqual(round(1.6), round($grade_item->adjust_grade($grade_raw->rawgrade, $grade_raw->grademin, $grade_raw->grademax)));\r
}\r
\r
+ /**\r
+ * Test locking of grade items\r
+ */\r
function test_grade_item_set_locked() {\r
$grade_item = new grade_item($this->grade_items[0]);\r
$this->assertTrue(method_exists($grade_item, 'set_locked'));\r
$this->assertTrue($grade_item->is_locked(1));\r
}\r
\r
- function test_grade_item_dependson() {\r
- $grade_item = new grade_item($this->grade_items[0]);\r
- //TODO\r
- }\r
+ function test_grade_item_depends_on() {\r
+ $grade_item = new grade_item($this->grade_items[1]);\r
\r
+ // calculated grade dependency\r
+ $deps = $grade_item->depends_on();\r
+ sort($deps, SORT_NUMERIC); // for comparison\r
+ $this->assertEqual(array($this->grade_items[0]->id), $deps);\r
+\r
+ // simulate depends on returns none when locked\r
+ $grade_item->locked = time();\r
+ $grade_item->update();\r
+ $deps = $grade_item->depends_on();\r
+ sort($deps, SORT_NUMERIC); // for comparison\r
+ $this->assertEqual(array(), $deps);\r
+\r
+ // category dependency\r
+ $grade_item = new grade_item($this->grade_items[3]);\r
+ $deps = $grade_item->depends_on();\r
+ sort($deps, SORT_NUMERIC); // for comparison\r
+ $res = array($this->grade_items[4]->id, $this->grade_items[5]->id);\r
+ $this->assertEqual($res, $deps);\r
+ }\r
\r
/*\r
function test_grade_item_toggle_hiding() {\r
$this->assertEqual(3, $grade_item->toggle_hiding(true));\r
$this->assertTrue($grade_item->hidden);\r
$this->assertTrue($grade_item->grade_grades[1]->hidden);\r
- $this->assertTrue($grade_item->grade_grades[2]->hidden);\r
+ $this->assertTrue($grade_item->grade_gra\r
+ des[2]->hidden);\r
$this->assertTrue($grade_item->grade_grades[3]->hidden);\r
}\r
*/\r
\r
- function test_float_keys() {\r
+ function test_grade_item_is_calculated() {\r
+ $grade_item = new grade_item($this->grade_items[1]);\r
+ $this->assertTrue(method_exists($grade_item, 'is_calculated'));\r
+ $grade_itemsource = new grade_item($this->grade_items[0]);\r
+ $normalizedformula = str_replace('['.$grade_itemsource->idnumber.']', '[#gi'.$grade_itemsource->id.'#]', $this->grade_items[1]->calculation);\r
+\r
+ $this->assertTrue($grade_item->is_calculated());\r
+ $this->assertEqual($normalizedformula, $grade_item->calculation);\r
+ }\r
+\r
+ function test_grade_item_set_calculation() {\r
+ $grade_item = new grade_item($this->grade_items[1]);\r
+ $this->assertTrue(method_exists($grade_item, 'set_calculation'));\r
+ $grade_itemsource = new grade_item($this->grade_items[0]);\r
+\r
+ $grade_item->set_calculation('=['.$grade_itemsource->idnumber.']');\r
+\r
+ $this->assertTrue(!empty($grade_item->needsupdate));\r
+ $this->assertEqual('=[#gi'.$grade_itemsource->id.'#]', $grade_item->calculation);\r
}\r
+\r
+ function test_grade_item_get_calculation() {\r
+ $grade_item = new grade_item($this->grade_items[1]);\r
+ $this->assertTrue(method_exists($grade_item, 'get_calculation'));\r
+ $grade_itemsource = new grade_item($this->grade_items[0]);\r
+\r
+ $denormalizedformula = str_replace('[#gi'.$grade_itemsource->id.'#]', '['.$grade_itemsource->idnumber.']', $this->grade_items[1]->calculation);\r
+\r
+ $formula = $grade_item->get_calculation();\r
+ $this->assertTrue(!empty($grade_item->needsupdate));\r
+ $this->assertEqual($denormalizedformula, $formula);\r
+ }\r
+\r
+ function test_grade_item_compute() {\r
+ $grade_item = new grade_item($this->grade_items[1]);\r
+ $this->assertTrue(method_exists($grade_item, 'compute'));\r
+\r
+ $grade_grades = grade_grades::fetch('id', $this->grade_grades[3]->id);\r
+ $grade_grades->delete();\r
+ $grade_grades = grade_grades::fetch('id', $this->grade_grades[4]->id);\r
+ $grade_grades->delete();\r
+ $grade_grades = grade_grades::fetch('id', $this->grade_grades[5]->id);\r
+ $grade_grades->delete();\r
+\r
+ $grade_item->compute();\r
+\r
+ $grade_grades = grade_grades::fetch('userid', $this->grade_grades[3]->userid, 'itemid', $this->grade_grades[3]->itemid);\r
+ $this->assertEqual($this->grade_grades[3]->finalgrade, $grade_grades->finalgrade);\r
+ $grade_grades = grade_grades::fetch('userid', $this->grade_grades[4]->userid, 'itemid', $this->grade_grades[4]->itemid);\r
+ $this->assertEqual($this->grade_grades[4]->finalgrade, $grade_grades->finalgrade);\r
+ $grade_grades = grade_grades::fetch('userid', $this->grade_grades[5]->userid, 'itemid', $this->grade_grades[5]->itemid);\r
+ $this->assertEqual($this->grade_grades[5]->finalgrade, $grade_grades->finalgrade);\r
+ }\r
+\r
}\r
?>\r
// This is compared against the values stored in the database to determine
// whether upgrades should be performed (see lib/db/*.php)
- $version = 2007062008; // YYYYMMDD = date
+ $version = 2007062301; // YYYYMMDD = date
// XY = increments within a single day
$release = '1.9 dev'; // Human-friendly version name