From b444b77af03db5cddab32bc165c7ed254b96e82a Mon Sep 17 00:00:00 2001 From: David Mudrak Date: Mon, 4 Jan 2010 17:43:31 +0000 Subject: [PATCH] First drafts of the Number of errors grading strategy --- mod/workshop/grading/noerrors/gradingform.php | 102 +++++++++ mod/workshop/grading/noerrors/strategy.php | 196 ++++++++++++++++++ mod/workshop/grading/strategy.php | 2 +- mod/workshop/lang/en_utf8/workshop.php | 38 +++- mod/workshop/settings.php | 8 + 5 files changed, 344 insertions(+), 2 deletions(-) create mode 100644 mod/workshop/grading/noerrors/gradingform.php create mode 100644 mod/workshop/grading/noerrors/strategy.php diff --git a/mod/workshop/grading/noerrors/gradingform.php b/mod/workshop/grading/noerrors/gradingform.php new file mode 100644 index 0000000000..a59e469c0d --- /dev/null +++ b/mod/workshop/grading/noerrors/gradingform.php @@ -0,0 +1,102 @@ +. + + +/** + * This file defines an mform to edit "Number of errors" grading strategy forms. + * + * @package mod-workshop + * @copyright 2009 David Mudrak + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ + +defined('MOODLE_INTERNAL') || die(); + +require_once(dirname(dirname(dirname(__FILE__))).'/lib.php'); // module library +require_once(dirname(dirname(__FILE__)).'/gradingform.php'); // parent class definition + + +/** + * Class for editing "Number of errors" grading strategy forms. + * + * @uses moodleform + */ +class workshop_edit_noerrors_strategy_form extends workshop_edit_strategy_form { + + /** + * Define the elements to be displayed at the form + * + * Called by the parent::definition() + * + * @access protected + * @return void + */ + protected function definition_inner(&$mform) { + + $workshopconfig = get_config('workshop'); + $weights = workshop_get_dimension_weights(); + + $repeated = array(); + $repeated[] =& $mform->createElement('hidden', 'dimensionid', 0); + $repeated[] =& $mform->createElement('header', 'dimension', + get_string('dimensionnumbernoerrors', 'workshop', '{no}')); + $repeated[] =& $mform->createElement('htmleditor', 'description', + get_string('dimensiondescription', 'workshop'), array()); + $repeated[] =& $mform->createElement('text', 'grade0', get_string('noerrorsgrade0', 'workshop'), array('size'=>'15')); + $repeated[] =& $mform->createElement('text', 'grade1', get_string('noerrorsgrade1', 'workshop'), array('size'=>'15')); + $repeated[] =& $mform->createElement('select', 'weight', get_string('dimensionweight', 'workshop'), $weights); + + $repeatedoptions = array(); + $repeatedoptions['description']['type'] = PARAM_CLEANHTML; + $repeatedoptions['description']['helpbutton'] = array('dimensiondescription', + get_string('dimensiondescription', 'workshop'), 'workshop'); + $repeatedoptions['grade0']['type'] = PARAM_TEXT; + $repeatedoptions['grade0']['default'] = $workshopconfig->noerrorsgrade0; + $repeatedoptions['grade1']['type'] = PARAM_TEXT; + $repeatedoptions['grade1']['default'] = $workshopconfig->noerrorsgrade1; + $repeatedoptions['weight']['default'] = 1; + + $numofdimensionstoadd = 2; + $numofinitialdimensions = 3; + $numofdisplaydimensions = max($this->strategy->get_number_of_dimensions() + $numofdimensionstoadd, + $numofinitialdimensions); + $numofdisplaydimensions = $this->repeat_elements($repeated, $numofdisplaydimensions, $repeatedoptions, + 'numofdimensions', 'adddimensions', $numofdimensionstoadd, + get_string('addmoredimensionsnoerrors', 'workshop', $numofdimensionstoadd)); + $mform->addElement('header', 'mappingheader', get_string('noerrorsgrademapping', 'workshop')); + $mform->addElement('static', 'mappinginfo', get_string('noerrorsmaperror', 'workshop'), + get_string('noerrorsmapgrade', 'workshop')); + $percents = array(); + $percents[''] = ''; + for ($i = 100; $i >= 0; $i--) { + $percents[$i] = get_string('percents', 'workshop', $i); + } + $mform->addElement('static', 'mappingzero', 0, get_string('percents', 'workshop', 100)); + $mform->addElement('hidden', 'map[0]', 100); + for ($i = 1; $i <= $numofdisplaydimensions; $i++) { + $selects = array(); + $selects[] =& $mform->createElement('select', "map[$i]", $i, $percents); + $selects[] =& $mform->createElement('static', "mapdefault[$i]", '', + get_string('percents', 'workshop', floor(100 - $i * 100 / $numofdisplaydimensions))); + $mform->addGroup($selects, "grademapping$i", $i, array(' '), false); + $mform->setDefault("map[$i]", ''); + } + + } + + +} diff --git a/mod/workshop/grading/noerrors/strategy.php b/mod/workshop/grading/noerrors/strategy.php new file mode 100644 index 0000000000..0c97faf3e0 --- /dev/null +++ b/mod/workshop/grading/noerrors/strategy.php @@ -0,0 +1,196 @@ +. + + +/** + * This file defines a class with "Number of errors" grading strategy logic + * + * @package mod-workshop + * @copyright 2009 David Mudrak + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ + +defined('MOODLE_INTERNAL') || die(); + +require_once(dirname(dirname(__FILE__)) . '/strategy.php'); // parent class + + +/** + * "Number of errors" grading strategy logic. + */ +class workshop_noerrors_strategy extends workshop_base_strategy { + + public function load_grading_form() { + global $DB; + + $dims = $DB->get_records('workshop_forms_' . $this->name, array('workshopid' => $this->workshop->id), 'sort'); + $maps = $DB->get_records('workshop_forms_noerrors_map', array('workshopid' => $this->workshop->id), 'nonegative'); + $this->nodimensions = count($dims); + return $this->_cook_database_records($dims, $maps); + } + + + /** + * Transpones the dimension data from DB so the assessment form editor can be populated by set_data + * + * Called internally from load_grading_form(). Could be private but keeping protected + * for unit testing purposes. + * + * @param array $dims Array of raw dimension records as fetched by get_record() + * @param array $maps Array of grade mappings + * @return array Object to be used by the mform set_data + */ + protected function _cook_database_records(array $dims, array $maps) { + + $formdata = array(); + + // cook dimensions + $key = 0; + foreach ($dims as $dimension) { + $formdata['dimensionid[' . $key . ']'] = $dimension->id; + $formdata['description[' . $key . ']'] = $dimension->description; + $formdata['descriptionformat[' . $key . ']'] = $dimension->descriptionformat; + $formdata['grade0[' . $key . ']'] = $dimension->grade0; + $formdata['grade1[' . $key . ']'] = $dimension->grade1; + $formdata['weight[' . $key . ']'] = $dimension->weight; + $key++; + } + + // cook grade mappings + foreach ($maps as $map) { + $formdata['map[' . $map->nonegative . ']'] = $map->grade; + } + + return (object)$formdata; + } + + + /** + * Save the definition of a "Number of errors" grading form + * + * The dimensions data are stored in workshop_forms_noerrors. The data that map the + * number of errors to a grade are saved into workshop_forms_noerrors_map. + * + * @uses $DB + * @param object $data Raw data returned by the dimension editor form + * @return void + */ + public function save_grading_form(stdClass $data) { + global $DB; + + if (!isset($data->strategyname) || ($data->strategyname != $this->name)) { + // the workshop strategy has changed since the form was opened for editing + throw new moodle_exception('strategyhaschanged', 'workshop'); + } + + // save the dimensions data + $dims = $this->_cook_form_data($data); + $todelete = array(); + foreach ($dims as $record) { + if (empty($record->description)) { + if (!empty($record->id)) { + // existing record with empty description - to be deleted + $todelete[] = $record->id; + } + continue; + } + if (empty($record->id)) { + // new field + $record->id = $DB->insert_record('workshop_forms_' . $this->name, $record); + } else { + // exiting field + $DB->update_record('workshop_forms_' . $this->name, $record); + } + } + // delete dimensions if the teacher removed the description + $DB->delete_records_list('workshop_forms_' . $this->name, 'id', $todelete); + + // re-save the mappings + $current = array(); + $currentx = $DB->get_records('workshop_forms_noerrors_map', array('workshopid' => $this->workshop->id)); + foreach ($currentx as $id => $map) { + $current[$map->nonegative] = $map->grade; + } + unset($currentx); + $todelete = array(); + + foreach ($data->map as $nonegative => $grade) { + if ($nonegative == 0) { + // no negative response automatically maps to 100%, do not save such mapping + continue; + } + if (!is_numeric($grade)) { + // no grade set for this number of negative responses + $todelete[] = $nonegative; + continue; + } + if (isset($current[$nonegative])) { + $DB->set_field('workshop_forms_noerrors_map', 'grade', $grade, + array('workshopid' => $this->workshop->id, 'nonegative' => $nonegative)); + } else { + $DB->insert_record('workshop_forms_noerrors_map', + (object)array('workshopid' => $this->workshop->id, 'nonegative' => $nonegative, 'grade' => $grade)); + } + } + // clear mappings that are not valid any more + if (!empty($todelete)) { + list($insql, $params) = $DB->get_in_or_equal($todelete); + $insql = 'nonegative ' . $insql . ' OR '; + } else { + list($insql, $params) = array('', array()); + } + $sql = 'DELETE FROM {workshop_forms_noerrors_map} + WHERE ((' . $insql . 'nonegative > ?) AND (workshopid = ?))'; + $params[] = count($data->map) - 1; + $params[] = $this->workshop->id; + if (!$DB->execute($sql, $params)){ + print_error('err_removegrademappings', 'workshop'); + } + } + + + /** + * Prepares dimensions data returned by mform so they can be saved into database + * + * It automatically adds some columns into every record. The sorting is + * done by the order of the returned array and starts with 1. + * Called internally from save_grading_form() only. Could be private but + * keeping protected for unit testing purposes. + * + * @param object $raw Raw data returned by mform + * @return array Array of objects to be inserted/updated in DB + */ + protected function _cook_form_data(stdClass $raw) { + + $cook = array(); + + for ($k = 0; $k < $raw->numofdimensions; $k++) { + $cook[$k] = new stdClass(); + $cook[$k]->id = isset($raw->dimensionid[$k]) ? $raw->dimensionid[$k] : null; + $cook[$k]->workshopid = $this->workshop->id; + $cook[$k]->sort = $k + 1; + $cook[$k]->description = isset($raw->description[$k]) ? $raw->description[$k] : null; + $cook[$k]->descriptionformat = FORMAT_HTML; + $cook[$k]->grade0 = isset($raw->grade0[$k]) ? $raw->grade0[$k] : null; + $cook[$k]->grade1 = isset($raw->grade1[$k]) ? $raw->grade1[$k] : null; + $cook[$k]->weight = isset($raw->weight[$k]) ? $raw->weight[$k] : null; + } + return $cook; + } + + +} diff --git a/mod/workshop/grading/strategy.php b/mod/workshop/grading/strategy.php index f769ee5734..da2f2172cd 100644 --- a/mod/workshop/grading/strategy.php +++ b/mod/workshop/grading/strategy.php @@ -150,7 +150,7 @@ abstract class workshop_base_strategy implements workshop_strategy { * By default, the number of loaded dimensions is set by load_grading_form() * * @access public - * @return void + * @return Array of records */ public function get_number_of_dimensions() { return $this->nodimensions; diff --git a/mod/workshop/lang/en_utf8/workshop.php b/mod/workshop/lang/en_utf8/workshop.php index f3cc64315f..3ff68f25b3 100644 --- a/mod/workshop/lang/en_utf8/workshop.php +++ b/mod/workshop/lang/en_utf8/workshop.php @@ -26,6 +26,29 @@ defined('MOODLE_INTERNAL') || die(); +$string[''] = ''; +$string[''] = ''; +$string[''] = ''; +$string[''] = ''; +$string[''] = ''; +$string[''] = ''; +$string[''] = ''; +$string[''] = ''; +$string[''] = ''; +$string[''] = ''; +$string[''] = ''; +$string[''] = ''; +$string[''] = ''; +$string[''] = ''; +$string[''] = ''; +$string[''] = ''; +$string[''] = ''; +$string[''] = ''; +$string[''] = ''; +$string[''] = ''; +$string[''] = ''; +$string[''] = ''; +$string[''] = ''; $string[''] = ''; $string[''] = ''; $string[''] = ''; @@ -36,6 +59,7 @@ $string[''] = ''; $string[''] = ''; $string['accesscontrol'] = 'Access control'; $string['addmoredimensionsaccumulative'] = 'Blanks for $a more aspects'; +$string['addmoredimensionsnoerrors'] = 'Blanks for $a more assertions'; $string['agreeassessments'] = 'Assessments must be agreed'; $string['agreeassessmentsdesc'] = 'Authors may comment assessments of their work and agree/disagree with it'; $string['anonymity'] = 'Anonymity mode'; @@ -62,14 +86,18 @@ $string['configgrade'] = 'Default maximum grade for submission in workshops'; $string['configgradinggrade'] = 'Default maximum grade for assessment in workshops'; $string['configmaxbytes'] = 'Default maximum submission file size for all workshops on the site (subject to course limits and other local settings)'; $string['confignexassessments'] = 'Default number of examples to be reviewed by a user in the example assessment phase'; +$string['confignoerrorsgrade0'] = 'The default word describing the negative assessment of an assertion in "Number of errors" grading strategy.'; +$string['confignoerrorsgrade1'] = 'The default word describing the positive assessment of an assertion in "Number of errors" grading strategy.'; $string['confignsassessments'] = 'Default number of allocated submissions to be reviewed by a user in the assessment phase'; $string['configstrategy'] = 'Default grading strategy for workshops'; $string['dimensiondescription'] = 'Description'; $string['dimensionnumberaccumulative'] = 'Aspect $a'; +$string['dimensionnumbernoerrors'] = 'Assertion $a'; $string['dimensionweight'] = 'Weight'; $string['editgradingform'] = 'Edit grading form'; $string['editinggradingform'] = 'Editing grading form'; $string['editingsubmission'] = 'Editing submission'; +$string['err_removegrademappings'] = 'Unable to remove the unused grade mappings'; $string['examplesbeforeassessment'] = 'Examples are available after own submission and must be assessed before peer/self assessment phase'; $string['examplesbeforesubmission'] = 'Examples must be assessed before own submission'; $string['examplesmode'] = 'Mode of examples assessment'; @@ -87,14 +115,22 @@ $string['modulenameplural'] = 'Workshops'; $string['modulename'] = 'Workshop'; $string['nattachments'] = 'Maximum number of submission attachments'; $string['nexassessments'] = 'Number of required assessments of examples'; +$string['noerrorsgrademapping'] = 'Grade mapping table'; +$string['noerrorsgrade0default'] = 'No'; +$string['noerrorsgrade0'] = 'Word for the error'; +$string['noerrorsgrade1default'] = 'Yes'; +$string['noerrorsgrade1'] = 'Word for the success'; +$string['noerrorsmaperror'] = 'Number of errors is less than or equals'; +$string['noerrorsmapgrade'] = 'Grade for submission'; $string['nsassessments'] = 'Number of required assessments of other users\' work'; +$string['percents'] = '$a%'; $string['releasegrades'] = 'Push final grades into the gradebook'; $string['requirepassword'] = 'Require password'; $string['saveandclose'] = 'Save and close'; $string['saveandcontinue'] = 'Save and continue editing'; $string['strategyaccumulative'] = 'Accumulative grading'; -$string['strategyerrorbanded'] = 'Error banded grading'; $string['strategy'] = 'Grading strategy'; +$string['strategynoerrors'] = 'Number of errors'; $string['strategynograding'] = 'No grading'; $string['strategyrubric'] = 'Rubric grading'; $string['submissionattachment'] = 'Attachment'; diff --git a/mod/workshop/settings.php b/mod/workshop/settings.php index 24675bf6a7..7a6f127cb6 100644 --- a/mod/workshop/settings.php +++ b/mod/workshop/settings.php @@ -70,6 +70,14 @@ foreach (workshop_get_comparison_levels() as $code => $level) { $settings->add(new admin_setting_configselect('workshop/assessmentcomps', get_string('assessmentcomps', 'workshop'), get_string('configassessmentcomps', 'workshop'), WORKSHOP_COMPARISON_NORMAL, $levels)); +$settings->add(new admin_setting_configtext('workshop/noerrorsgrade0', get_string('noerrorsgrade0', 'workshop'), + get_string('confignoerrorsgrade0', 'workshop'), get_string('noerrorsgrade0default', 'workshop'), + $paramtype=PARAM_TEXT, $size=15)); + +$settings->add(new admin_setting_configtext('workshop/noerrorsgrade1', get_string('noerrorsgrade1', 'workshop'), + get_string('confignoerrorsgrade1', 'workshop'), get_string('noerrorsgrade1default', 'workshop'), + $paramtype=PARAM_TEXT, $size=15)); + /* $settings->add(new admin_setting_configcheckbox('assignment_showrecentsubmissions', get_string('showrecentsubmissions', 'assignment'), get_string('configshowrecentsubmissions', 'assignment'), 1)); -- 2.39.5