MDL-20236 overall codebase architecture cleanup and fixing regression

See the issue description for more details
This commit is contained in:
David Mudrak 2010-01-04 18:05:48 +00:00
parent 6516b9e9e4
commit f05c168d2e
35 changed files with 530 additions and 577 deletions

View File

@ -192,27 +192,29 @@ class workshop_manual_allocator implements workshop_allocator {
$peers = array();
$rs = $this->workshop->get_allocations_recordset();
foreach ($rs as $allocation) {
$currentuserid = $allocation->authorid;
if (!isset($peers[$currentuserid])) {
$peers[$currentuserid] = new stdClass();
$peers[$currentuserid]->id = $allocation->authorid;
$peers[$currentuserid]->firstname = $allocation->authorfirstname;
$peers[$currentuserid]->lastname = $allocation->authorlastname;
$peers[$currentuserid]->picture = $allocation->authorpicture;
$peers[$currentuserid]->imagealt = $allocation->authorimagealt;
$peers[$currentuserid]->submissionid = $allocation->submissionid;
$peers[$currentuserid]->submissiontitle = $allocation->submissiontitle;
$peers[$currentuserid]->submissiongrade = $allocation->submissiongrade;
$peers[$currentuserid]->reviewedby = array(); // users who are reviewing this user's submission
$peers[$currentuserid]->reviewerof = array(); // users whom submission is being reviewed by this user
}
if (!empty($allocation->reviewerid)) {
// example: "submission of user with id 45 is reviewed by user with id 87 in the assessment record 12"
$peers[$currentuserid]->reviewedby[$allocation->reviewerid] = $allocation->assessmentid;
if (!is_null($rs)) {
foreach ($rs as $allocation) {
$currentuserid = $allocation->authorid;
if (!isset($peers[$currentuserid])) {
$peers[$currentuserid] = new stdClass();
$peers[$currentuserid]->id = $allocation->authorid;
$peers[$currentuserid]->firstname = $allocation->authorfirstname;
$peers[$currentuserid]->lastname = $allocation->authorlastname;
$peers[$currentuserid]->picture = $allocation->authorpicture;
$peers[$currentuserid]->imagealt = $allocation->authorimagealt;
$peers[$currentuserid]->submissionid = $allocation->submissionid;
$peers[$currentuserid]->submissiontitle = $allocation->submissiontitle;
$peers[$currentuserid]->submissiongrade = $allocation->submissiongrade;
$peers[$currentuserid]->reviewedby = array(); // users who are reviewing this user's submission
$peers[$currentuserid]->reviewerof = array(); // users whom submission is being reviewed by this user
}
if (!empty($allocation->reviewerid)) {
// example: "submission of user with id 45 is reviewed by user with id 87 in the assessment record 12"
$peers[$currentuserid]->reviewedby[$allocation->reviewerid] = $allocation->assessmentid;
}
}
$rs->close();
}
$rs->close();
foreach ($peers as $author) {
foreach ($author->reviewedby as $reviewerid => $assessmentid) {
@ -230,8 +232,8 @@ class workshop_manual_allocator implements workshop_allocator {
$data = new stdClass();
$data->wsoutput = $wsoutput;
$data->peers = $peers;
$data->authors = $this->workshop->get_potential_authors();
$data->reviewers = $this->workshop->get_potential_reviewers();
$data->authors = $this->workshop->get_potential_authors($PAGE->context);
$data->reviewers = $this->workshop->get_potential_reviewers($PAGE->context);
$data->hlauthorid = $hlauthorid;
$data->hlreviewerid = $hlreviewerid;
$data->msg = $msg;

View File

@ -75,14 +75,14 @@ class workshop_random_allocator implements workshop_allocator {
$o = array(); // list of output messages
$numofreviews = required_param('numofreviews', PARAM_INT);
$numper = required_param('numper', PARAM_INT);
$removecurrent = required_param('removecurrent', PARAM_INT);
$assesswosubmission = required_param('assesswosubmission', PARAM_INT);
$removecurrent = optional_param('removecurrent', false, PARAM_BOOL);
$assesswosubmission = optional_param('assesswosubmission', false, PARAM_BOOL);
$addselfassessment = optional_param('addselfassessment', false, PARAM_BOOL);
$musthavesubmission = empty($assesswosubmission);
$addselfassessment = optional_param('addselfassessment', false, PARAM_INT); // may be frozen in the form
$authors = $this->workshop->get_potential_authors();
$authors = $this->workshop->get_potential_authors($PAGE->context);
$authors = $this->workshop->get_grouped($authors);
$reviewers = $this->workshop->get_potential_reviewers($musthavesubmission);
$reviewers = $this->workshop->get_potential_reviewers($PAGE->context, $musthavesubmission);
$reviewers = $this->workshop->get_grouped($reviewers);
$assessments = $this->workshop->get_all_assessments();

View File

@ -72,22 +72,17 @@ class workshop_random_allocator_form extends moodleform {
$mform->setDefault('numper', workshop_random_allocator::USERTYPE_AUTHOR);
$mform->addGroup($grpnumofreviews, 'grpnumofreviews', get_string('numofreviews', 'workshop'), array(' '), false);
$mform->addElement('advcheckbox', 'removecurrent', get_string('removecurrentallocations', 'workshopallocation_random'));
$mform->addElement('checkbox', 'removecurrent', get_string('removecurrentallocations', 'workshopallocation_random'));
$mform->setDefault('removecurrent', 0);
$mform->addElement('advcheckbox', 'assesswosubmission', get_string('assesswosubmission', 'workshopallocation_random'));
$mform->addElement('checkbox', 'assesswosubmission', get_string('assesswosubmission', 'workshopallocation_random'));
$mform->setDefault('assesswosubmission', 0);
$grpselfassessment = array();
$grpselfassessment[] = $mform->createElement('advcheckbox', 'addselfassessment');
$mform->setDefault('addselfassessment', 0);
if (!$workshop->useselfassessment) {
$grpselfassessment[] = $mform->createElement('static', 'selfassessmentcheck', '',
get_string('selfassessmentdisabled', 'workshop'));
}
$mform->addGroup($grpselfassessment, 'grpselfassessment', get_string('addselfassessment', 'workshopallocation_random'));
if (!$workshop->useselfassessment) {
$mform->freeze(array('grpselfassessment'));
if (empty($workshop->useselfassessment)) {
$mform->addElement('static', 'addselfassessment', get_string('addselfassessment', 'workshopallocation_random'),
get_string('selfassessmentdisabled', 'workshop'));
} else {
$mform->addElement('checkbox', 'addselfassessment', get_string('addselfassessment', 'workshopallocation_random'));
}
$this->add_action_buttons();

View File

@ -16,7 +16,7 @@
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
/**
* Unit tests for mod/workshop/allocation/random/allocator.php
* Unit tests for Random allocation
*
* @package mod-workshop
* @copyright 2009 David Mudrak <david.mudrak@gmail.com>
@ -26,7 +26,8 @@
defined('MOODLE_INTERNAL') || die();
// Include the code to test
require_once($CFG->dirroot . '/mod/workshop/allocation/random/allocator.php');
require_once($CFG->dirroot . '/mod/workshop/locallib.php');
require_once($CFG->dirroot . '/mod/workshop/allocation/random/lib.php');
/**
* Make protected methods we want to test public

View File

@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
<XMLDB PATH="mod/workshop/db" VERSION="20090907" COMMENT="XMLDB file for Moodle mod/workshop"
<XMLDB PATH="mod/workshop/db" VERSION="20090908" COMMENT="XMLDB file for Moodle mod/workshop"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="../../../lib/xmldb/xmldb.xsd"
>
@ -93,33 +93,20 @@
<KEY NAME="overriddenby_fk" TYPE="foreign" FIELDS="gradinggradeoverby" REFTABLE="user" REFFIELDS="id" PREVIOUS="reviewer_fk"/>
</KEYS>
</TABLE>
<TABLE NAME="workshop_grades" COMMENT="How the reviewers filled-up the grading forms, given grades and comments" PREVIOUS="workshop_assessments" NEXT="workshop_forms">
<TABLE NAME="workshop_grades" COMMENT="How the reviewers filled-up the grading forms, given grades and comments" PREVIOUS="workshop_assessments">
<FIELDS>
<FIELD NAME="id" TYPE="int" LENGTH="10" NOTNULL="true" UNSIGNED="true" SEQUENCE="true" NEXT="assessmentid"/>
<FIELD NAME="assessmentid" TYPE="int" LENGTH="10" NOTNULL="true" UNSIGNED="true" SEQUENCE="false" COMMENT="Part of which assessment this grade is of" PREVIOUS="id" NEXT="dimensionid"/>
<FIELD NAME="dimensionid" TYPE="int" LENGTH="10" NOTNULL="true" UNSIGNED="true" SEQUENCE="false" COMMENT="Foreign key. References dimension id in one of the grading strategy tables." PREVIOUS="assessmentid" NEXT="grade"/>
<FIELD NAME="grade" TYPE="int" LENGTH="10" NOTNULL="true" UNSIGNED="true" SEQUENCE="false" COMMENT="Given grade in the referenced assessment dimension." PREVIOUS="dimensionid" NEXT="peercomment"/>
<FIELD NAME="assessmentid" TYPE="int" LENGTH="10" NOTNULL="true" UNSIGNED="true" SEQUENCE="false" COMMENT="Part of which assessment this grade is of" PREVIOUS="id" NEXT="strategy"/>
<FIELD NAME="strategy" TYPE="char" LENGTH="30" NOTNULL="true" SEQUENCE="false" PREVIOUS="assessmentid" NEXT="dimensionid"/>
<FIELD NAME="dimensionid" TYPE="int" LENGTH="10" NOTNULL="true" UNSIGNED="true" SEQUENCE="false" COMMENT="Foreign key. References dimension id in one of the grading strategy tables." PREVIOUS="strategy" NEXT="grade"/>
<FIELD NAME="grade" TYPE="number" LENGTH="10" NOTNULL="true" UNSIGNED="true" SEQUENCE="false" DECIMALS="5" COMMENT="Given grade in the referenced assessment dimension." PREVIOUS="dimensionid" NEXT="peercomment"/>
<FIELD NAME="peercomment" TYPE="text" LENGTH="big" NOTNULL="false" SEQUENCE="false" COMMENT="Reviewer's comment to the grade value." PREVIOUS="grade" NEXT="peercommentformat"/>
<FIELD NAME="peercommentformat" TYPE="int" LENGTH="3" NOTNULL="false" UNSIGNED="false" DEFAULT="0" SEQUENCE="false" COMMENT="The format of peercomment field" PREVIOUS="peercomment"/>
</FIELDS>
<KEYS>
<KEY NAME="primary" TYPE="primary" FIELDS="id" NEXT="assessment_fk"/>
<KEY NAME="assessment_fk" TYPE="foreign" FIELDS="assessmentid" REFTABLE="workshop_assessments" REFFIELDS="id" PREVIOUS="primary" NEXT="dimension_fk"/>
<KEY NAME="dimension_fk" TYPE="foreign" FIELDS="dimensionid" REFTABLE="workshop_forms" REFFIELDS="id" PREVIOUS="assessment_fk" NEXT="formfield"/>
<KEY NAME="formfield" TYPE="unique" FIELDS="assessmentid, dimensionid" COMMENT="The combination of assessmentid and dimensionid must be unique" PREVIOUS="dimension_fk"/>
</KEYS>
</TABLE>
<TABLE NAME="workshop_forms" COMMENT="Meta table to provide unique id for every assessment dimension which is needed for file api support." PREVIOUS="workshop_grades">
<FIELDS>
<FIELD NAME="id" TYPE="int" LENGTH="10" NOTNULL="true" UNSIGNED="true" SEQUENCE="true" NEXT="workshopid"/>
<FIELD NAME="workshopid" TYPE="int" LENGTH="10" NOTNULL="true" UNSIGNED="true" SEQUENCE="false" COMMENT="Workshop ID" PREVIOUS="id" NEXT="sort"/>
<FIELD NAME="sort" TYPE="int" LENGTH="10" NOTNULL="false" UNSIGNED="true" DEFAULT="0" SEQUENCE="false" COMMENT="Defines the dimension order within the assessment form" PREVIOUS="workshopid" NEXT="strategy"/>
<FIELD NAME="strategy" TYPE="char" LENGTH="30" NOTNULL="true" SEQUENCE="false" COMMENT="Defines the target assessment form table" PREVIOUS="sort" NEXT="localid"/>
<FIELD NAME="localid" TYPE="int" LENGTH="10" NOTNULL="true" UNSIGNED="true" SEQUENCE="false" COMMENT="The foreign primary key of one of the assessment forms tables." PREVIOUS="strategy"/>
</FIELDS>
<KEYS>
<KEY NAME="primary" TYPE="primary" FIELDS="id" NEXT="workshop_fk"/>
<KEY NAME="workshop_fk" TYPE="foreign" FIELDS="workshopid" REFTABLE="workshop" REFFIELDS="id" PREVIOUS="primary"/>
<KEY NAME="assessment_fk" TYPE="foreign" FIELDS="assessmentid" REFTABLE="workshop_assessments" REFFIELDS="id" PREVIOUS="primary" NEXT="formfield_uk"/>
<KEY NAME="formfield_uk" TYPE="unique" FIELDS="assessmentid, strategy, dimensionid" COMMENT="The combination of assessmentid, strategy and dimensionid must be unique" PREVIOUS="assessment_fk"/>
</KEYS>
</TABLE>
</TABLES>

View File

@ -53,8 +53,8 @@ $wsoutput = $PAGE->theme->get_renderer('mod_workshop', $PAGE);
switch ($tool) {
case 'mksubmissions':
$authors = $workshop->get_potential_authors(false);
$authorswithsubmission = $workshop->get_potential_authors(true);
$authors = $workshop->get_potential_authors($PAGE->context, false);
$authorswithsubmission = $workshop->get_potential_authors($PAGE->context, true);
$authors = array_diff_key($authors, $authorswithsubmission);
echo $OUTPUT->header();
$c = 0; // counter

View File

@ -70,7 +70,7 @@ if ($mform->is_cancelled()) {
echo $OUTPUT->header();
$currenttab = 'editform';
include(dirname(__FILE__) . '/tabs.php');
echo $OUTPUT->heading(get_string('pluginname', 'workshopgrading_' . $workshop->strategy));
echo $OUTPUT->heading(get_string('pluginname', 'workshopform_' . $workshop->strategy));
$mform->display();

View File

@ -50,8 +50,8 @@ class workshop_accumulative_assessment_form extends workshop_assessment_form {
for ($i = 0; $i < $nodims; $i++) {
// dimension header
$dimtitle = get_string('dimensionnumber', 'workshopgrading_accumulative', $i+1);
$mform->addElement('header', "dimensionhdr__idx_$i", $dimtitle);
$dimtitle = get_string('dimensionnumber', 'workshopform_accumulative', $i+1);
$mform->addElement('header', 'dimensionhdr__idx_'.$i, $dimtitle);
// dimension id
$mform->addElement('hidden', 'dimensionid__idx_'.$i, $fields->{'dimensionid__idx_'.$i});
@ -66,12 +66,12 @@ class workshop_accumulative_assessment_form extends workshop_assessment_form {
$mform->addElement('html', $desc);
// grade for this aspect
$label = get_string('dimensiongrade', 'workshopgrading_accumulative');
$label = get_string('dimensiongrade', 'workshopform_accumulative');
$options = make_grades_menu($fields->{'grade__idx_' . $i});
$mform->addElement('select', 'grade__idx_' . $i, $label, $options);
// comment
$label = get_string('dimensioncomment', 'workshopgrading_accumulative');
$label = get_string('dimensioncomment', 'workshopform_accumulative');
//$mform->addElement('editor', 'peercomment__idx_' . $i, $label, null, array('maxfiles' => 0));
$mform->addElement('textarea', 'peercomment__idx_' . $i, $label, array('cols' => 60, 'rows' => 5));
}

View File

@ -1,20 +1,23 @@
<?xml version="1.0" encoding="UTF-8" ?>
<XMLDB PATH="mod/workshop/db" VERSION="20090813" COMMENT="XMLDB file for Moodle mod/workshop"
<XMLDB PATH="mod/workshop/db" VERSION="20090908" COMMENT="XMLDB file for Moodle mod/workshop"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="../../../lib/xmldb/xmldb.xsd"
>
<TABLES>
<TABLE NAME="workshop_forms_accumulative" COMMENT="The assessment dimensions definitions of Accumulative grading strategy forms">
<TABLE NAME="workshopform_accumulative" COMMENT="The assessment dimensions definitions of Accumulative grading strategy forms">
<FIELDS>
<FIELD NAME="id" TYPE="int" LENGTH="10" NOTNULL="true" UNSIGNED="true" SEQUENCE="true" NEXT="description"/>
<FIELD NAME="description" TYPE="text" LENGTH="big" NOTNULL="false" SEQUENCE="false" COMMENT="The description of the dimension" PREVIOUS="id" NEXT="descriptionformat"/>
<FIELD NAME="id" TYPE="int" LENGTH="10" NOTNULL="true" UNSIGNED="true" SEQUENCE="true" NEXT="workshopid"/>
<FIELD NAME="workshopid" TYPE="int" LENGTH="10" NOTNULL="true" UNSIGNED="true" SEQUENCE="false" COMMENT="Workshop ID" PREVIOUS="id" NEXT="sort"/>
<FIELD NAME="sort" TYPE="int" LENGTH="10" NOTNULL="false" UNSIGNED="true" DEFAULT="0" SEQUENCE="false" COMMENT="Defines the dimension order within the assessment form" PREVIOUS="workshopid" NEXT="description"/>
<FIELD NAME="description" TYPE="text" LENGTH="big" NOTNULL="false" SEQUENCE="false" COMMENT="The description of the dimension" PREVIOUS="sort" NEXT="descriptionformat"/>
<FIELD NAME="descriptionformat" TYPE="int" LENGTH="3" NOTNULL="false" UNSIGNED="true" DEFAULT="0" SEQUENCE="false" COMMENT="The format of the description field" PREVIOUS="description" NEXT="grade"/>
<FIELD NAME="grade" TYPE="int" LENGTH="10" NOTNULL="true" UNSIGNED="false" SEQUENCE="false" COMMENT="If greater than 0, then the value is maximum grade on a scale 0..grade. If lesser than 0, then its absolute value is the id of a record in scale table. If equals 0, then no grading is possible for this dimension, just commenting." PREVIOUS="descriptionformat" NEXT="weight"/>
<FIELD NAME="weight" TYPE="int" LENGTH="5" NOTNULL="false" UNSIGNED="false" DEFAULT="1" SEQUENCE="false" COMMENT="The weigh of the dimension" PREVIOUS="grade"/>
</FIELDS>
<KEYS>
<KEY NAME="primary" TYPE="primary" FIELDS="id"/>
<KEY NAME="primary" TYPE="primary" FIELDS="id" NEXT="workshop_fk"/>
<KEY NAME="workshop_fk" TYPE="foreign" FIELDS="workshopid" REFTABLE="workshop" REFFIELDS="id" PREVIOUS="primary"/>
</KEYS>
</TABLE>
</TABLES>
</XMLDB>
</XMLDB>

View File

@ -55,20 +55,21 @@ class workshop_edit_accumulative_strategy_form extends workshop_edit_strategy_fo
$weights = workshop_get_dimension_weights();
for ($i = 0; $i < $norepeats; $i++) {
$mform->addElement('header', 'dimension'.$i, get_string('dimensionnumber', 'workshopgrading_accumulative', $i+1));
$mform->addElement('hidden', 'dimensionid__idx_'.$i); // the id in workshop_forms
$mform->addElement('header', 'dimension'.$i, get_string('dimensionnumber', 'workshopform_accumulative', $i+1));
$mform->addElement('hidden', 'dimensionid__idx_'.$i);
$mform->addElement('editor', 'description__idx_'.$i.'_editor',
get_string('dimensiondescription', 'workshopgrading_accumulative'), '', $descriptionopts);
get_string('dimensiondescription', 'workshopform_accumulative'), '', $descriptionopts);
// todo replace modgrade with an advanced element (usability issue discussed with Olli)
$mform->addElement('modgrade', 'grade__idx_'.$i,
get_string('dimensionmaxgrade','workshopgrading_accumulative'), null, true);
get_string('dimensionmaxgrade','workshopform_accumulative'), null, true);
$mform->setDefault('grade__idx_'.$i, 10);
$mform->addElement('select', 'weight__idx_'.$i,
get_string('dimensionweight', 'workshopgrading_accumulative'), $weights);
get_string('dimensionweight', 'workshopform_accumulative'), $weights);
$mform->setDefault('weight__idx_'.$i, 1);
}
$mform->registerNoSubmitButton('noadddims');
$mform->addElement('submit', 'noadddims', get_string('addmoredimensions', 'workshopgrading_accumulative',
$mform->addElement('submit', 'noadddims', get_string('addmoredimensions', 'workshopform_accumulative',
WORKSHOP_STRATEGY_ADDDIMS));
$mform->closeHeaderBefore('noadddims');
$this->set_data($current);

View File

@ -53,8 +53,6 @@ class workshop_accumulative_strategy implements workshop_strategy {
$this->descriptionopts = array('trusttext' => true, 'subdirs' => false, 'maxfiles' => -1);
}
/// Public API
/**
* Factory method returning an instance of an assessment form editor class
*
@ -112,34 +110,29 @@ class workshop_accumulative_strategy implements workshop_strategy {
$norepeats = $data->norepeats;
$data = $this->prepare_database_fields($data);
$masters = $data->forms; // data to be saved into workshop_forms
$locals = $data->accumulative; // data to be saved into workshop_forms_accumulative
$todelete = array(); // master ids to be deleted
$records = $data->accumulative; // records to be saved into {workshopform_accumulative}
$todelete = array(); // dimension ids to be deleted
for ($i=0; $i < $norepeats; $i++) {
$local = $locals[$i];
$master = $masters[$i];
if (empty($local->description_editor['text'])) {
if (!empty($master->id)) {
$record = $records[$i];
if (empty($record->description_editor['text'])) {
if (!empty($record->id)) {
// existing record with empty description - to be deleted
$todelete[] = $master->id;
$todelete[] = $record->id;
}
continue;
}
if (empty($master->id)) {
if (empty($record->id)) {
// new field
$local->id = $DB->insert_record("workshop_forms_accumulative", $local);
$master->localid = $local->id;
$master->id = $DB->insert_record("workshop_forms", $master);
$record->id = $DB->insert_record('workshopform_accumulative', $record);
} else {
// exiting field
$DB->update_record("workshop_forms", $master);
$local->id = $DB->get_field("workshop_forms", "localid", array("id" => $master->id), MUST_EXIST);
$DB->update_record('workshopform_accumulative', $record);
}
// re-save with correct path to embeded media files
$local = file_postupdate_standard_editor($local, 'description', $this->descriptionopts,
$PAGE->context, 'workshop_dimension_description', $master->id);
$DB->update_record("workshop_forms_accumulative", $local);
$record = file_postupdate_standard_editor($record, 'description', $this->descriptionopts,
$PAGE->context, 'workshopform_accumulative_description', $record->id);
$DB->update_record('workshopform_accumulative', $record);
}
$this->delete_dimensions($todelete);
}
@ -162,12 +155,12 @@ class workshop_accumulative_strategy implements workshop_strategy {
// rewrite URLs to the embeded files
for ($i = 0; $i < $nodimensions; $i++) {
$fields->{'description__idx_'.$i} = file_rewrite_pluginfile_urls($fields->{'description__idx_'.$i},
'pluginfile.php', $PAGE->context->id, 'workshop_dimension_description', $fields->{'dimensionid__idx_'.$i});
'pluginfile.php', $PAGE->context->id, 'workshopform_accumulative_description', $fields->{'dimensionid__idx_'.$i});
}
if ('assessment' === $mode and !empty($assessment)) {
// load the previously saved assessment data
$grades = $this->reindex_grades_by_dimension($this->get_current_assessment_data($assessment));
$grades = $this->get_current_assessment_data($assessment);
$current = new stdClass();
for ($i = 0; $i < $nodimensions; $i++) {
$dimid = $fields->{'dimensionid__idx_'.$i};
@ -181,6 +174,7 @@ class workshop_accumulative_strategy implements workshop_strategy {
// set up the required custom data common for all strategies
$customdata['strategy'] = $this;
$customdata['workshop'] = $this->workshop;
$customdata['mode'] = $mode;
// set up strategy-specific custom data
@ -211,10 +205,11 @@ class workshop_accumulative_strategy implements workshop_strategy {
$grade = new stdClass();
$grade->id = $data->{'gradeid__idx_' . $i};
$grade->assessmentid = $assessment->id;
$grade->strategy = 'accumulative';
$grade->dimensionid = $data->{'dimensionid__idx_' . $i};
$grade->grade = $data->{'grade__idx_' . $i};
$grade->peercomment = $data->{'peercomment__idx_' . $i};
$grade->peercommentformat = FORMAT_HTML;
$grade->peercommentformat = FORMAT_MOODLE;
if (empty($grade->id)) {
// new grade
$grade->id = $DB->insert_record('workshop_grades', $grade);
@ -238,7 +233,9 @@ class workshop_accumulative_strategy implements workshop_strategy {
return false;
}
/// Internal methods
////////////////////////////////////////////////////////////////////////////////
// Internal methods //
////////////////////////////////////////////////////////////////////////////////
/**
* Loads the fields of the assessment form currently used in this workshop
@ -248,12 +245,11 @@ class workshop_accumulative_strategy implements workshop_strategy {
protected function load_fields() {
global $DB;
$sql = "SELECT master.id,dim.description,dim.descriptionformat,dim.grade,dim.weight
FROM {workshop_forms} master
INNER JOIN {workshop_forms_accumulative} dim ON (dim.id=master.localid)
WHERE master.workshopid = :workshopid AND master.strategy = :strategy
ORDER BY master.sort";
$params = array("workshopid" => $this->workshop->id, "strategy" => $this->workshop->strategy);
$sql = 'SELECT *
FROM {workshopform_accumulative}
WHERE workshopid = :workshopid
ORDER BY sort';
$params = array('workshopid' => $this->workshop->id);
return $DB->get_records_sql($sql, $params);
}
@ -269,7 +265,7 @@ class workshop_accumulative_strategy implements workshop_strategy {
$formdata = new stdClass();
$key = 0;
foreach ($raw as $dimension) {
$formdata->{'dimensionid__idx_' . $key} = $dimension->id; // master id, not the local one!
$formdata->{'dimensionid__idx_' . $key} = $dimension->id;
$formdata->{'description__idx_' . $key} = $dimension->description;
$formdata->{'description__idx_' . $key.'format'} = $dimension->descriptionformat;
$formdata->{'grade__idx_' . $key} = $dimension->grade;
@ -287,20 +283,16 @@ class workshop_accumulative_strategy implements workshop_strategy {
* @param array $masterids
* @return void
*/
protected function delete_dimensions($masterids) {
protected function delete_dimensions(array $ids) {
global $DB, $PAGE;
$masters = $DB->get_records_list("workshop_forms", "id", $masterids, "", "id,localid");
$masterids = array_keys($masters); // now contains only those really existing
$localids = array();
$fs = get_file_storage();
foreach ($masters as $itemid => $master) {
$fs->delete_area_files($PAGE->context->id, 'workshop_dimension_description', $itemid);
$localids[] = $master->localid;
$fs = get_file_storage();
foreach ($ids as $id) {
if (!empty($id)) { // to prevent accidental removal of all files in the area
$fs->delete_area_files($PAGE->context->id, 'workshopform_accumulative_description', $id);
}
}
$DB->delete_records_list("workshop_forms_accumulative", "id", $localids);
$DB->delete_records_list("workshop_forms", "id", $masterids);
$DB->delete_records_list('workshopform_accumulative', 'id', $ids);
}
/**
@ -318,57 +310,38 @@ class workshop_accumulative_strategy implements workshop_strategy {
global $PAGE;
$cook = new stdClass(); // to be returned
$cook->forms = array(); // to be stored in {workshop_forms}
$cook->accumulative = array(); // to be stored in {workshop_forms_accumulative}
$cook->accumulative = array(); // records to be stored in {workshopform_accumulative}
for ($i = 0; $i < $raw->norepeats; $i++) {
$cook->forms[$i] = new stdClass();
$cook->forms[$i]->id = $raw->{'dimensionid__idx_'.$i};
$cook->forms[$i]->workshopid = $this->workshop->id;
$cook->forms[$i]->sort = $i + 1;
$cook->forms[$i]->strategy = 'accumulative';
$cook->accumulative[$i] = new stdClass();
$cook->accumulative[$i] = new stdClass();
$cook->accumulative[$i]->id = $raw->{'dimensionid__idx_'.$i};
$cook->accumulative[$i]->workshopid = $this->workshop->id;
$cook->accumulative[$i]->sort = $i + 1;
$cook->accumulative[$i]->description_editor = $raw->{'description__idx_'.$i.'_editor'};
$cook->accumulative[$i]->grade = $raw->{'grade__idx_'.$i};
$cook->accumulative[$i]->weight = $raw->{'weight__idx_'.$i};
$cook->accumulative[$i]->grade = $raw->{'grade__idx_'.$i};
$cook->accumulative[$i]->weight = $raw->{'weight__idx_'.$i};
}
return $cook;
}
/**
* Returns the list of current grades filled by the reviewer
* Returns the list of current grades filled by the reviewer indexed by dimensionid
*
* @param stdClass $assessment Assessment record
* @return array of filtered records from the table workshop_grades
* @return array [int dimensionid] => stdClass workshop_grades record
*/
protected function get_current_assessment_data(stdClass $assessment) {
global $DB;
// fetch all grades accociated with this assessment
$grades = $DB->get_records("workshop_grades", array("assessmentid" => $assessment->id));
list($dimsql, $dimparams) = $DB->get_in_or_equal(array_keys($this->dimensions), SQL_PARAMS_NAMED);
// beware! the caller may rely on the returned array is indexed by dimensionid
$sql = "SELECT dimensionid, *
FROM {workshop_grades}
WHERE assessmentid = :assessmentid AND strategy= :strategy AND dimensionid $dimsql";
$params = array('assessmentid' => $assessment->id, 'strategy' => 'acumulative');
$params = array_merge($params, $dimparams);
// filter grades given under an other strategy or assessment form
foreach ($grades as $grade) {
if (!isset($this->dimensions[$grade->dimensionid])) {
unset ($grades[$grade->id]);
}
}
return $grades;
}
/**
* Reindexes the records returned by {@link get_current_assessment_data} by dimensionid
*
* @param mixed $grades
* @return array
*/
protected function reindex_grades_by_dimension($grades) {
$reindexed = array();
foreach ($grades as $grade) {
$reindexed[$grade->dimensionid] = $grade;
}
return $reindexed;
return $DB->get_records_sql($sql, $params);
}
/**
@ -405,7 +378,7 @@ class workshop_accumulative_strategy implements workshop_strategy {
if ($dimension->weight < 0) {
throw new coding_exception('Negative weights are not supported any more. Something is wrong with your data');
}
if ($dimension->weight == 0 or $dimension->grade == 0) {
if (grade_floats_equal($dimension->weight, 0) or grade_floats_equal($dimension->grade, 0)) {
// does not influence the final grade
continue;
}
@ -424,7 +397,7 @@ class workshop_accumulative_strategy implements workshop_strategy {
if ($sumweights === 0) {
return 0;
}
return $sumgrades / $sumweights;
return grade_floatval($sumgrades / $sumweights);
}
/**

View File

@ -16,7 +16,7 @@
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
/**
* Unit tests for (some of) mod/workshop/grading/accumulative/strategy.php
* Unit tests for Accumulative grading strategy logic
*
* @package mod-workshop
* @copyright 2009 David Mudrak <david.mudrak@gmail.com>
@ -26,7 +26,8 @@
defined('MOODLE_INTERNAL') || die();
// Include the code to test
require_once($CFG->dirroot . '/mod/workshop/grading/accumulative/strategy.php');
require_once($CFG->dirroot . '/mod/workshop/locallib.php');
require_once($CFG->dirroot . '/mod/workshop/form/accumulative/lib.php');
global $DB;
Mock::generate(get_class($DB), 'mockDB');
@ -93,18 +94,18 @@ class workshop_accumulative_strategy_test extends UnitTestCase {
public function test_calculate_peer_grade_one_numerical() {
// fixture set-up
$this->strategy->dimensions[1003] = (object)array('grade' => 20, 'weight' => 1);
$grades[] = (object)array('dimensionid' => 1003, 'grade' => 5);
$this->strategy->dimensions[1003] = (object)array('grade' => '20', 'weight' => '1');
$grades[] = (object)array('dimensionid' => 1003, 'grade' => '5.00000');
// excercise SUT
$suggested = $this->strategy->calculate_peer_grade($grades);
// validate
$this->assertEqual(5/20, $suggested);
$this->assertEqual(grade_floatval(5/20), $suggested);
}
public function test_calculate_peer_grade_negative_weight() {
// fixture set-up
$this->strategy->dimensions[1003] = (object)array('grade' => 20, 'weight' => -1);
$grades[] = (object)array('dimensionid' => 1003, 'grade' => 20);
$this->strategy->dimensions[1003] = (object)array('grade' => '20', 'weight' => '-1');
$grades[] = (object)array('dimensionid' => 1003, 'grade' => '20');
$this->expectException('coding_exception');
// excercise SUT
$suggested = $this->strategy->calculate_peer_grade($grades);
@ -112,46 +113,46 @@ class workshop_accumulative_strategy_test extends UnitTestCase {
public function test_calculate_peer_grade_one_numerical_weighted() {
// fixture set-up
$this->strategy->dimensions[1003] = (object)array('grade' => 20, 'weight' => 3);
$grades[] = (object)array('dimensionid' => 1003, 'grade' => 5);
$this->strategy->dimensions[1003] = (object)array('grade' => '20', 'weight' => '3');
$grades[] = (object)array('dimensionid' => '1003', 'grade' => '5');
// excercise SUT
$suggested = $this->strategy->calculate_peer_grade($grades);
// validate
$this->assertEqual(5/20, $suggested);
$this->assertEqual(grade_floatval(5/20), $suggested);
}
public function test_calculate_peer_grade_three_numericals_same_weight() {
// fixture set-up
$this->strategy->dimensions[1003] = (object)array('grade' =>20, 'weight' => 2);
$this->strategy->dimensions[1004] = (object)array('grade' =>100, 'weight' => 2);
$this->strategy->dimensions[1005] = (object)array('grade' =>10, 'weight' => 2);
$this->strategy->dimensions[1003] = (object)array('grade' => '20', 'weight' => '2');
$this->strategy->dimensions[1004] = (object)array('grade' => '100', 'weight' => '2');
$this->strategy->dimensions[1005] = (object)array('grade' => '10', 'weight' => '2');
$grades[] = (object)array('dimensionid' => 1003, 'grade' => 11);
$grades[] = (object)array('dimensionid' => 1004, 'grade' => 87);
$grades[] = (object)array('dimensionid' => 1005, 'grade' => 10);
$grades[] = (object)array('dimensionid' => 1003, 'grade' => '11.00000');
$grades[] = (object)array('dimensionid' => 1004, 'grade' => '87.00000');
$grades[] = (object)array('dimensionid' => 1005, 'grade' => '10.00000');
// excercise SUT
$suggested = $this->strategy->calculate_peer_grade($grades);
// validate
$this->assertEqual((11/20 + 87/100 + 10/10)/3, $suggested);
$this->assertEqual(grade_floatval((11/20 + 87/100 + 10/10)/3), $suggested);
}
public function test_calculate_peer_grade_three_numericals_different_weights() {
// fixture set-up
$this->strategy->dimensions[1003] = (object)array('grade' =>15, 'weight' => 3);
$this->strategy->dimensions[1004] = (object)array('grade' =>80, 'weight' => 1);
$this->strategy->dimensions[1005] = (object)array('grade' =>5, 'weight' => 2);
$this->strategy->dimensions[1003] = (object)array('grade' => '15', 'weight' => 3);
$this->strategy->dimensions[1004] = (object)array('grade' => '80', 'weight' => 1);
$this->strategy->dimensions[1005] = (object)array('grade' => '5', 'weight' => 2);
$grades[] = (object)array('dimensionid' => 1003, 'grade' => 7);
$grades[] = (object)array('dimensionid' => 1004, 'grade' => 66);
$grades[] = (object)array('dimensionid' => 1005, 'grade' => 4);
$grades[] = (object)array('dimensionid' => 1003, 'grade' => '7.00000');
$grades[] = (object)array('dimensionid' => 1004, 'grade' => '66.00000');
$grades[] = (object)array('dimensionid' => 1005, 'grade' => '4.00000');
// excercise SUT
$suggested = $this->strategy->calculate_peer_grade($grades);
// validate
$this->assertEqual((7/15*3 + 66/80*1 + 4/5*2)/6, $suggested);
$this->assertEqual(grade_floatval((7/15*3 + 66/80*1 + 4/5*2)/6), $suggested);
}
public function test_calculate_peer_grade_one_scale_max() {
@ -159,31 +160,31 @@ class workshop_accumulative_strategy_test extends UnitTestCase {
// fixture set-up
$mockscale = 'E,D,C,B,A';
$this->strategy->dimensions[1008] = (object)array('grade' => -10, 'weight' => 1);
$grades[] = (object)array('dimensionid' => 1008, 'grade' => 5);
$DB->expectOnce('get_field', array("scales", "scale", array("id" => 10), MUST_EXIST));
$this->strategy->dimensions[1008] = (object)array('grade' => '-10', 'weight' => 1);
$grades[] = (object)array('dimensionid' => 1008, 'grade' => '5.00000');
$DB->expectOnce('get_field', array('scales', 'scale', array('id' => 10), MUST_EXIST));
$DB->setReturnValue('get_field', $mockscale);
// excercise SUT
$suggested = $this->strategy->calculate_peer_grade($grades);
// validate
$this->assertEqual(1, $suggested);
$this->assertEqual(1.00000, $suggested);
}
public function test_calculate_peer_grade_one_scale_min_with_scale_caching() {
global $DB;
// fixture set-up
$this->strategy->dimensions[1008] = (object)array('grade' => -10, 'weight' => 1);
$grades[] = (object)array('dimensionid' => 1008, 'grade' => 1);
$DB->expectNever('get_field', array("scales", "scale", array("id" => 10), MUST_EXIST)); // cached
$this->strategy->dimensions[1008] = (object)array('grade' => '-10', 'weight' => 1);
$grades[] = (object)array('dimensionid' => 1008, 'grade' => '1.00000');
$DB->expectNever('get_field', array('scales', 'scale', array('id' => 10), MUST_EXIST)); // cached
// excercise SUT
$suggested = $this->strategy->calculate_peer_grade($grades);
// validate
$this->assertEqual(0, $suggested);
$this->assertEqual(0.00000, $suggested);
}
public function test_calculate_peer_grade_two_scales_weighted() {
@ -193,23 +194,23 @@ class workshop_accumulative_strategy_test extends UnitTestCase {
$mockscale13 = 'Poor,Good,Excellent';
$mockscale17 = '-,*,**,***,****,*****,******';
$this->strategy->dimensions[1012] = (object)array('grade' => -13, 'weight' => 2);
$this->strategy->dimensions[1019] = (object)array('grade' => -17, 'weight' => 3);
$this->strategy->dimensions[1012] = (object)array('grade' => '-13', 'weight' => 2);
$this->strategy->dimensions[1019] = (object)array('grade' => '-17', 'weight' => 3);
$grades[] = (object)array('dimensionid' => 1012, 'grade' => 2); // "Good"
$grades[] = (object)array('dimensionid' => 1019, 'grade' => 5); // "****"
$grades[] = (object)array('dimensionid' => 1012, 'grade' => '2.00000'); // "Good"
$grades[] = (object)array('dimensionid' => 1019, 'grade' => '5.00000'); // "****"
$DB->expectAt(0, 'get_field', array("scales", "scale", array("id" => 13), MUST_EXIST));
$DB->expectAt(0, 'get_field', array('scales', 'scale', array('id' => 13), MUST_EXIST));
$DB->setReturnValueAt(0, 'get_field', $mockscale13);
$DB->expectAt(1, 'get_field', array("scales", "scale", array("id" => 17), MUST_EXIST));
$DB->expectAt(1, 'get_field', array('scales', 'scale', array('id' => 17), MUST_EXIST));
$DB->setReturnValueAt(1, 'get_field', $mockscale17);
// excercise SUT
$suggested = $this->strategy->calculate_peer_grade($grades);
// validate
$this->assertEqual((1/2*2 + 4/6*3)/5, $suggested);
$this->assertEqual(grade_floatval((1/2*2 + 4/6*3)/5), $suggested);
}
public function test_calculate_peer_grade_scale_exception() {
@ -218,8 +219,8 @@ class workshop_accumulative_strategy_test extends UnitTestCase {
// fixture set-up
$mockscale13 = 'Poor,Good,Excellent';
$this->strategy->dimensions[1012] = (object)array('grade' => -13, 'weight' => 1);
$DB->expectNever('get_field', array("scales", "scale", array("id" => 13), MUST_EXIST)); // cached
$grades[] = (object)array('dimensionid' => 1012, 'grade' => 4); // exceeds the number of scale items
$DB->expectNever('get_field', array('scales', 'scale', array('id' => 13), MUST_EXIST)); // cached
$grades[] = (object)array('dimensionid' => 1012, 'grade' => '4.00000'); // exceeds the number of scale items
$this->expectException('coding_exception');
// excercise SUT

View File

@ -53,7 +53,11 @@ class workshop_assessment_form extends moodleform {
$mform = $this->_form;
$this->mode = $this->_customdata['mode']; // influences the save buttons
$this->strategy = $this->_customdata['strategy']; // strategy name sends back for cross check
$this->strategy = $this->_customdata['strategy']; // instance of the strategy api class
$this->workshop = $this->_customdata['workshop']; // instance of the workshop api class
// add the data common for all subplugins
$mform->addElement('hidden', 'strategy', $this->workshop->strategy);
// add the strategy-specific fields
$this->definition_inner($mform);

View File

@ -0,0 +1,21 @@
<?xml version="1.0" encoding="UTF-8" ?>
<XMLDB PATH="mod/workshop/db" VERSION="20090908" COMMENT="XMLDB file for Moodle Comments grading strategy"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="../../../lib/xmldb/xmldb.xsd"
>
<TABLES>
<TABLE NAME="workshopform_comments" COMMENT="The assessment dimensions definitions of Comments strategy forms">
<FIELDS>
<FIELD NAME="id" TYPE="int" LENGTH="10" NOTNULL="true" UNSIGNED="true" SEQUENCE="true" NEXT="workshopid"/>
<FIELD NAME="workshopid" TYPE="int" LENGTH="10" NOTNULL="true" UNSIGNED="true" SEQUENCE="false" COMMENT="Workshop ID" PREVIOUS="id" NEXT="sort"/>
<FIELD NAME="sort" TYPE="int" LENGTH="10" NOTNULL="false" UNSIGNED="true" DEFAULT="0" SEQUENCE="false" COMMENT="Defines the dimension order within the assessment form" PREVIOUS="workshopid" NEXT="description"/>
<FIELD NAME="description" TYPE="text" LENGTH="big" NOTNULL="false" SEQUENCE="false" COMMENT="The description of the dimension" PREVIOUS="sort" NEXT="descriptionformat"/>
<FIELD NAME="descriptionformat" TYPE="int" LENGTH="3" NOTNULL="false" UNSIGNED="true" DEFAULT="0" SEQUENCE="false" COMMENT="The format of the description field" PREVIOUS="description"/>
</FIELDS>
<KEYS>
<KEY NAME="primary" TYPE="primary" FIELDS="id" NEXT="workshop_fk"/>
<KEY NAME="workshop_fk" TYPE="foreign" FIELDS="workshopid" REFTABLE="workshop" REFFIELDS="id" PREVIOUS="primary"/>
</KEYS>
</TABLE>
</TABLES>
</XMLDB>

View File

@ -58,7 +58,8 @@ class workshop_edit_strategy_form extends moodleform {
$this->workshop = $this->_customdata['workshop'];
$this->strategy = $this->_customdata['strategy'];
$mform->addElement('hidden', 'workshopid', $this->workshop->id);
$mform->addElement('hidden', 'workshopid', $this->workshop->id); // workshopid
$mform->addElement('hidden', 'strategy', $this->workshop->strategy); // strategy name
$this->definition_inner($mform);

View File

@ -46,7 +46,7 @@ interface workshop_strategy {
*
* Assessment dimension (also know as assessment element) represents one aspect or criterion
* to be evaluated. Each dimension consists of a set of form fields. Strategy-specific information
* are saved in workshop_forms_{strategyname} tables.
* are saved in workshopform_{strategyname} tables.
*
* @param stdClass $data Raw data as returned by the form editor
* @return void
@ -65,7 +65,9 @@ interface workshop_strategy {
* Saves the filled assessment and returns the grade for submission as suggested by the reviewer
*
* This method processes data submitted using the form returned by {@link get_assessment_form()}
* The returned grade should be rounded to 5 decimals as with round($grade, 5).
*
* @see grade_floatval()
* @param stdClass $assessment Assessment being filled
* @param stdClass $data Raw data as returned by the assessment form
* @return float|null Raw grade (0 to 1) for submission as suggested by the peer or null if impossible to count

View File

@ -16,7 +16,7 @@
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
/**
* This file defines an mform to assess a submission by noerrors grading strategy
* This file defines an mform to assess a submission by numerrors grading strategy
*
* @package mod-workshop
* @copyright 2009 David Mudrak <david.mudrak@gmail.com>
@ -28,11 +28,11 @@ defined('MOODLE_INTERNAL') || die();
require_once(dirname(dirname(__FILE__)).'/assessment_form.php'); // parent class definition
/**
* Class representing a form for assessing submissions by noerrors grading strategy
* Class representing a form for assessing submissions by numerrors grading strategy
*
* @uses moodleform
*/
class workshop_noerrors_assessment_form extends workshop_assessment_form {
class workshop_numerrors_assessment_form extends workshop_assessment_form {
/**
* Define the elements to be displayed at the form
@ -50,7 +50,7 @@ class workshop_noerrors_assessment_form extends workshop_assessment_form {
for ($i = 0; $i < $nodims; $i++) {
// dimension header
$dimtitle = get_string('dimensionnumber', 'workshopgrading_noerrors', $i+1);
$dimtitle = get_string('dimensionnumber', 'workshopform_numerrors', $i+1);
$mform->addElement('header', "dimensionhdr__idx_$i", $dimtitle);
// dimension id
@ -60,19 +60,19 @@ class workshop_noerrors_assessment_form extends workshop_assessment_form {
$mform->addElement('hidden', 'gradeid__idx_'.$i); // value set by set_data() later
// dimension description
$desc = '<div id="id_dim_'.$fields->{'dimensionid__idx_'.$i}.'_desc" class="fitem description noerrors">'."\n";
$desc = '<div id="id_dim_'.$fields->{'dimensionid__idx_'.$i}.'_desc" class="fitem description numerrors">'."\n";
$desc .= format_text($fields->{'description__idx_'.$i}, $fields->{'description__idx_'.$i.'format'});
$desc .= "\n</div>";
$mform->addElement('html', $desc);
// evaluation of the assertion
$label = get_string('dimensiongrade', 'workshopgrading_noerrors');
$label = get_string('dimensiongrade', 'workshopform_numerrors');
$mform->addElement('radio', 'grade__idx_' . $i, 'Your assessment', $fields->{'grade0__idx_'.$i}, 0); // todo localize
$mform->addElement('radio', 'grade__idx_' . $i, '', $fields->{'grade1__idx_'.$i}, 1);
$mform->setDefault('grade__idx_' . $i, 0);
// comment
$label = get_string('dimensioncomment', 'workshopgrading_noerrors');
$label = get_string('dimensioncomment', 'workshopform_numerrors');
$mform->addElement('textarea', 'peercomment__idx_' . $i, $label, array('cols' => 60, 'rows' => 5));
}
$this->set_data($current);

View File

@ -1,13 +1,15 @@
<?xml version="1.0" encoding="UTF-8" ?>
<XMLDB PATH="mod/workshop/db" VERSION="20090831" COMMENT="XMLDB file for Moodle mod/workshop/grading/noerrors"
<XMLDB PATH="mod/workshop/db" VERSION="20090908" COMMENT="XMLDB file for Moodle Number of errors subplugin"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="../../../lib/xmldb/xmldb.xsd"
>
<TABLES>
<TABLE NAME="workshop_forms_noerrors" COMMENT="The assessment dimensions definitions of Number of errors grading strategy forms" NEXT="workshop_forms_noerrors_map">
<TABLE NAME="workshopform_numerrors" COMMENT="The assessment dimensions definitions of Number of errors grading strategy forms" NEXT="workshopform_numerrors_map">
<FIELDS>
<FIELD NAME="id" TYPE="int" LENGTH="10" NOTNULL="true" UNSIGNED="true" SEQUENCE="true" NEXT="description"/>
<FIELD NAME="description" TYPE="text" LENGTH="big" NOTNULL="false" SEQUENCE="false" COMMENT="The description of the dimension" PREVIOUS="id" NEXT="descriptionformat"/>
<FIELD NAME="id" TYPE="int" LENGTH="10" NOTNULL="true" UNSIGNED="true" SEQUENCE="true" NEXT="workshopid"/>
<FIELD NAME="workshopid" TYPE="int" LENGTH="10" NOTNULL="true" UNSIGNED="true" SEQUENCE="false" COMMENT="Workshop ID" PREVIOUS="id" NEXT="sort"/>
<FIELD NAME="sort" TYPE="int" LENGTH="10" NOTNULL="false" UNSIGNED="true" DEFAULT="0" SEQUENCE="false" COMMENT="Defines the dimension order within the assessment form" PREVIOUS="workshopid" NEXT="description"/>
<FIELD NAME="description" TYPE="text" LENGTH="big" NOTNULL="false" SEQUENCE="false" COMMENT="The description of the dimension" PREVIOUS="sort" NEXT="descriptionformat"/>
<FIELD NAME="descriptionformat" TYPE="int" LENGTH="3" NOTNULL="false" UNSIGNED="true" DEFAULT="0" SEQUENCE="false" COMMENT="The format of the description field" PREVIOUS="description" NEXT="descriptiontrust"/>
<FIELD NAME="descriptiontrust" TYPE="int" LENGTH="10" NOTNULL="false" UNSIGNED="true" SEQUENCE="false" PREVIOUS="descriptionformat" NEXT="grade0"/>
<FIELD NAME="grade0" TYPE="char" LENGTH="50" NOTNULL="false" SEQUENCE="false" COMMENT="The word describing the negative evaluation (like Poor, Missing, Absent, etc.). If NULL, it defaults to a translated string False" PREVIOUS="descriptiontrust" NEXT="grade1"/>
@ -15,10 +17,11 @@
<FIELD NAME="weight" TYPE="int" LENGTH="5" NOTNULL="false" UNSIGNED="false" DEFAULT="1" SEQUENCE="false" COMMENT="Weight of this dimension" PREVIOUS="grade1"/>
</FIELDS>
<KEYS>
<KEY NAME="primary" TYPE="primary" FIELDS="id"/>
<KEY NAME="primary" TYPE="primary" FIELDS="id" NEXT="workshop_fk"/>
<KEY NAME="workshop_fk" TYPE="foreign" FIELDS="workshopid" REFTABLE="workshop" REFFIELDS="id" PREVIOUS="primary"/>
</KEYS>
</TABLE>
<TABLE NAME="workshop_forms_noerrors_map" COMMENT="This maps the number of errors to a percentual grade for submission" PREVIOUS="workshop_forms_noerrors">
<TABLE NAME="workshopform_numerrors_map" COMMENT="This maps the number of errors to a percentual grade for submission" PREVIOUS="workshopform_numerrors">
<FIELDS>
<FIELD NAME="id" TYPE="int" LENGTH="10" NOTNULL="true" UNSIGNED="true" SEQUENCE="true" NEXT="workshopid"/>
<FIELD NAME="workshopid" TYPE="int" LENGTH="10" NOTNULL="true" UNSIGNED="true" SEQUENCE="false" COMMENT="The id of the workshop" PREVIOUS="id" NEXT="nonegative"/>

View File

@ -33,7 +33,7 @@ require_once(dirname(dirname(__FILE__)).'/edit_form.php'); // parent class de
*
* @uses moodleform
*/
class workshop_edit_noerrors_strategy_form extends workshop_edit_strategy_form {
class workshop_edit_numerrors_strategy_form extends workshop_edit_strategy_form {
/**
* Define the elements to be displayed at the form
@ -44,7 +44,7 @@ class workshop_edit_noerrors_strategy_form extends workshop_edit_strategy_form {
*/
protected function definition_inner(&$mform) {
$plugindefaults = get_config('workshopgrading_noerrors');
$plugindefaults = get_config('workshopform_numerrors');
$nodimensions = $this->_customdata['nodimensions']; // number of currently filled dimensions
$norepeats = $this->_customdata['norepeats']; // number of dimensions to display
$descriptionopts = $this->_customdata['descriptionopts']; // wysiwyg fields options
@ -57,23 +57,23 @@ class workshop_edit_noerrors_strategy_form extends workshop_edit_strategy_form {
$weights = workshop_get_dimension_weights();
for ($i = 0; $i < $norepeats; $i++) {
$mform->addElement('header', 'dimension'.$i, get_string('dimensionnumber', 'workshopgrading_noerrors', $i+1));
$mform->addElement('header', 'dimension'.$i, get_string('dimensionnumber', 'workshopform_numerrors', $i+1));
$mform->addElement('hidden', 'dimensionid__idx_'.$i); // the id in workshop_forms
$mform->addElement('editor', 'description__idx_'.$i.'_editor',
get_string('dimensiondescription', 'workshopgrading_noerrors'), '', $descriptionopts);
$mform->addElement('text', 'grade0__idx_'.$i, get_string('grade0', 'workshopgrading_noerrors'), array('size'=>'15'));
get_string('dimensiondescription', 'workshopform_numerrors'), '', $descriptionopts);
$mform->addElement('text', 'grade0__idx_'.$i, get_string('grade0', 'workshopform_numerrors'), array('size'=>'15'));
$mform->setDefault('grade0__idx_'.$i, $plugindefaults->grade0);
$mform->setType('grade0__idx_'.$i, PARAM_TEXT);
$mform->addElement('text', 'grade1__idx_'.$i, get_string('grade1', 'workshopgrading_noerrors'), array('size'=>'15'));
$mform->addElement('text', 'grade1__idx_'.$i, get_string('grade1', 'workshopform_numerrors'), array('size'=>'15'));
$mform->setDefault('grade1__idx_'.$i, $plugindefaults->grade1);
$mform->setType('grade1__idx_'.$i, PARAM_TEXT);
$mform->addElement('select', 'weight__idx_'.$i, get_string('dimensionweight', 'workshopgrading_noerrors'), $weights);
$mform->addElement('select', 'weight__idx_'.$i, get_string('dimensionweight', 'workshopform_numerrors'), $weights);
$mform->setDefault('weight__idx_'.$i, 1);
}
$mform->addElement('header', 'mappingheader', get_string('grademapping', 'workshopgrading_noerrors'));
$mform->addElement('static', 'mappinginfo', get_string('maperror', 'workshopgrading_noerrors'),
get_string('mapgrade', 'workshopgrading_noerrors'));
$mform->addElement('header', 'mappingheader', get_string('grademapping', 'workshopform_numerrors'));
$mform->addElement('static', 'mappinginfo', get_string('maperror', 'workshopform_numerrors'),
get_string('mapgrade', 'workshopform_numerrors'));
// get the total weight of all items == maximum weighted number of errors
$totalweight = 0;
@ -87,20 +87,20 @@ class workshop_edit_noerrors_strategy_form extends workshop_edit_strategy_form {
$percents = array();
$percents[''] = '';
for ($i = 100; $i >= 0; $i--) {
$percents[$i] = get_string('percents', 'workshopgrading_noerrors', $i);
$percents[$i] = get_string('percents', 'workshopform_numerrors', $i);
}
$mform->addElement('static', 'mappingzero', 0, get_string('percents', 'workshopgrading_noerrors', 100));
$mform->addElement('static', 'mappingzero', 0, get_string('percents', 'workshopform_numerrors', 100));
for ($i = 1; $i <= $totalweight; $i++) {
$selects = array();
$selects[] = $mform->createElement('select', 'map__idx_'.$i, $i, $percents);
$selects[] = $mform->createElement('static', 'mapdefault__idx_'.$i, '',
get_string('percents', 'workshopgrading_noerrors', floor(100 - $i * 100 / $totalweight)));
get_string('percents', 'workshopform_numerrors', floor(100 - $i * 100 / $totalweight)));
$mform->addGroup($selects, 'grademapping'.$i, $i, array(' '), false);
$mform->setDefault('map__idx_'.$i, '');
}
$mform->registerNoSubmitButton('noadddims');
$mform->addElement('submit', 'noadddims', get_string('addmoredimensions', 'workshopgrading_noerrors',
$mform->addElement('submit', 'noadddims', get_string('addmoredimensions', 'workshopform_numerrors',
WORKSHOP_STRATEGY_ADDDIMS));
$mform->closeHeaderBefore('noadddims');
$this->set_data($current);

View File

@ -25,12 +25,13 @@
defined('MOODLE_INTERNAL') || die();
require_once(dirname(dirname(__FILE__)) . '/lib.php'); // interface definition
require_once(dirname(dirname(__FILE__)) . '/lib.php'); // interface definition
require_once($CFG->libdir . '/gradelib.php'); // to handle float vs decimal issues
/**
* "Number of errors" grading strategy logic.
*/
class workshop_noerrors_strategy implements workshop_strategy {
class workshop_numerrors_strategy implements workshop_strategy {
/** @var workshop the parent workshop instance */
protected $workshop;
@ -57,8 +58,6 @@ class workshop_noerrors_strategy implements workshop_strategy {
$this->descriptionopts = array('trusttext' => true, 'subdirs' => false, 'maxfiles' => -1);
}
/// Public API methods
/**
* Factory method returning an instance of an assessment form editor class
*
@ -83,7 +82,7 @@ class workshop_noerrors_strategy implements workshop_strategy {
for ($i = 0; $i < $nodimensions; $i++) {
// prepare all editor elements
$fields = file_prepare_standard_editor($fields, 'description__idx_'.$i, $this->descriptionopts,
$PAGE->context, 'workshop_dimension_description', $fields->{'dimensionid__idx_'.$i});
$PAGE->context, 'workshopform_numerrors_description', $fields->{'dimensionid__idx_'.$i});
}
$customdata = array();
@ -95,7 +94,7 @@ class workshop_noerrors_strategy implements workshop_strategy {
$customdata['current'] = $fields;
$attributes = array('class' => 'editstrategyform');
return new workshop_edit_noerrors_strategy_form($actionurl, $customdata, 'post', '', $attributes);
return new workshop_edit_numerrors_strategy_form($actionurl, $customdata, 'post', '', $attributes);
}
/**
@ -117,35 +116,30 @@ class workshop_noerrors_strategy implements workshop_strategy {
$norepeats = $data->norepeats;
$data = $this->prepare_database_fields($data);
$masters = $data->forms; // data to be saved into {workshop_forms}
$locals = $data->noerrors; // data to be saved into {workshop_forms_noerrors}
$mappings = $data->mappings; // data to be saved into {workshop_forms_noerrors_map}
$todelete = array(); // master ids to be deleted
$records = $data->numerrors; // data to be saved into {workshopform_numerrors}
$mappings = $data->mappings; // data to be saved into {workshopform_numerrors_map}
$todelete = array(); // dimension ids to be deleted
for ($i=0; $i < $norepeats; $i++) {
$local = $locals[$i];
$master = $masters[$i];
if (empty($local->description_editor['text'])) {
if (!empty($master->id)) {
// existing record with empty description - to be deleted
$todelete[] = $master->id;
$record = $records[$i];
if (empty($record->description_editor['text'])) {
if (!empty($record->id)) {
// existing dimension record with empty description - to be deleted
$todelete[] = $record->id;
}
continue;
}
if (empty($master->id)) {
if (empty($record->id)) {
// new field
$local->id = $DB->insert_record('workshop_forms_noerrors', $local);
$master->localid = $local->id;
$master->id = $DB->insert_record('workshop_forms', $master);
$record->id = $DB->insert_record('workshopform_numerrors', $record);
} else {
// exiting field
$DB->update_record('workshop_forms', $master);
$local->id = $DB->get_field('workshop_forms', 'localid', array('id' => $master->id), MUST_EXIST);
$DB->update_record('workshopform_numerrors', $record);
}
// re-save with correct path to embeded media files
$local = file_postupdate_standard_editor($local, 'description', $this->descriptionopts,
$PAGE->context, 'workshop_dimension_description', $master->id);
$DB->update_record('workshop_forms_noerrors', $local);
$record = file_postupdate_standard_editor($record, 'description', $this->descriptionopts, $PAGE->context,
'workshopform_numerrors_description', $record->id);
$DB->update_record('workshopform_numerrors', $record);
}
$this->delete_dimensions($todelete);
@ -158,10 +152,10 @@ class workshop_noerrors_strategy implements workshop_strategy {
continue;
}
if (isset($this->mappings[$nonegative])) {
$DB->set_field('workshop_forms_noerrors_map', 'grade', $grade,
$DB->set_field('workshopform_numerrors_map', 'grade', $grade,
array('workshopid' => $this->workshop->id, 'nonegative' => $nonegative));
} else {
$DB->insert_record('workshop_forms_noerrors_map',
$DB->insert_record('workshopform_numerrors_map',
(object)array('workshopid' => $this->workshop->id, 'nonegative' => $nonegative, 'grade' => $grade));
}
}
@ -172,13 +166,11 @@ class workshop_noerrors_strategy implements workshop_strategy {
} else {
$insql = '';
}
$sql = "DELETE FROM {workshop_forms_noerrors_map}
$sql = "DELETE FROM {workshopform_numerrors_map}
WHERE (($insql nonegative > :nodimensions) AND (workshopid = :workshopid))";
$params['nodimensions'] = $norepeats;
$params['workshopid'] = $this->workshop->id;
if (!$DB->execute($sql, $params)){
print_error('err_removegrademappings', 'workshop');
}
$DB->execute($sql, $params);
}
/**
@ -199,12 +191,12 @@ class workshop_noerrors_strategy implements workshop_strategy {
// rewrite URLs to the embeded files
for ($i = 0; $i < $nodimensions; $i++) {
$fields->{'description__idx_'.$i} = file_rewrite_pluginfile_urls($fields->{'description__idx_'.$i},
'pluginfile.php', $PAGE->context->id, 'workshop_dimension_description', $fields->{'dimensionid__idx_'.$i});
'pluginfile.php', $PAGE->context->id, 'workshopform_numerrors_description', $fields->{'dimensionid__idx_'.$i});
}
if ('assessment' === $mode and !empty($assessment)) {
// load the previously saved assessment data
$grades = $this->reindex_grades_by_dimension($this->get_current_assessment_data($assessment));
$grades = $this->get_current_assessment_data($assessment);
$current = new stdClass();
for ($i = 0; $i < $nodimensions; $i++) {
$dimid = $fields->{'dimensionid__idx_'.$i};
@ -217,6 +209,7 @@ class workshop_noerrors_strategy implements workshop_strategy {
}
// set up the required custom data common for all strategies
$customdata['workshop'] = $this->workshop;
$customdata['strategy'] = $this;
$customdata['mode'] = $mode;
@ -224,9 +217,9 @@ class workshop_noerrors_strategy implements workshop_strategy {
$customdata['nodims'] = $nodimensions;
$customdata['fields'] = $fields;
$customdata['current'] = isset($current) ? $current : null;
$attributes = array('class' => 'assessmentform noerrors');
$attributes = array('class' => 'assessmentform numerrors');
return new workshop_noerrors_assessment_form($actionurl, $customdata, 'post', '', $attributes);
return new workshop_numerrors_assessment_form($actionurl, $customdata, 'post', '', $attributes);
}
/**
@ -246,12 +239,13 @@ class workshop_noerrors_strategy implements workshop_strategy {
}
for ($i = 0; $i < $data->nodims; $i++) {
$grade = new stdClass();
$grade->id = $data->{'gradeid__idx_' . $i};
$grade->assessmentid = $assessment->id;
$grade->dimensionid = $data->{'dimensionid__idx_' . $i};
$grade->grade = $data->{'grade__idx_' . $i};
$grade->peercomment = $data->{'peercomment__idx_' . $i};
$grade->peercommentformat = FORMAT_HTML;
$grade->id = $data->{'gradeid__idx_' . $i};
$grade->assessmentid = $assessment->id;
$grade->strategy = 'numerrors';
$grade->dimensionid = $data->{'dimensionid__idx_' . $i};
$grade->grade = $data->{'grade__idx_' . $i};
$grade->peercomment = $data->{'peercomment__idx_' . $i};
$grade->peercommentformat = FORMAT_HTML;
if (empty($grade->id)) {
// new grade
$grade->id = $DB->insert_record('workshop_grades', $grade);
@ -275,7 +269,9 @@ class workshop_noerrors_strategy implements workshop_strategy {
return false;
}
/// Internal methods
////////////////////////////////////////////////////////////////////////////////
// Internal methods //
////////////////////////////////////////////////////////////////////////////////
/**
* Loads the fields of the assessment form currently used in this workshop
@ -285,12 +281,11 @@ class workshop_noerrors_strategy implements workshop_strategy {
protected function load_fields() {
global $DB;
$sql = 'SELECT master.id,dim.description,dim.descriptionformat,dim.grade0,dim.grade1,dim.weight
FROM {workshop_forms} master
INNER JOIN {workshop_forms_noerrors} dim ON (dim.id=master.localid)
WHERE master.workshopid = :workshopid AND master.strategy = :strategy
ORDER BY master.sort';
$params = array('workshopid' => $this->workshop->id, 'strategy' => $this->workshop->strategy);
$sql = 'SELECT *
FROM {workshopform_numerrors}
WHERE workshopid = :workshopid
ORDER BY sort';
$params = array('workshopid' => $this->workshop->id);
return $DB->get_records_sql($sql, $params);
}
@ -302,7 +297,7 @@ class workshop_noerrors_strategy implements workshop_strategy {
*/
protected function load_mappings() {
global $DB;
return $DB->get_records('workshop_forms_noerrors_map', array('workshopid' => $this->workshop->id), 'nonegative',
return $DB->get_records('workshopform_numerrors_map', array('workshopid' => $this->workshop->id), 'nonegative',
'nonegative,grade'); // we can use nonegative as key here as it must be unique within workshop
}
@ -318,7 +313,7 @@ class workshop_noerrors_strategy implements workshop_strategy {
$formdata = new stdClass();
$key = 0;
foreach ($dims as $dimension) {
$formdata->{'dimensionid__idx_' . $key} = $dimension->id; // master id, not the local one!
$formdata->{'dimensionid__idx_' . $key} = $dimension->id;
$formdata->{'description__idx_' . $key} = $dimension->description;
$formdata->{'description__idx_' . $key.'format'} = $dimension->descriptionformat;
$formdata->{'grade0__idx_' . $key} = $dimension->grade0;
@ -339,27 +334,21 @@ class workshop_noerrors_strategy implements workshop_strategy {
*
* todo we may check that there are no assessments done using these dimensions and probably remove them
*
* @param array $masterids
* @param array $ids list to delete
* @return void
*/
protected function delete_dimensions($masterids) {
protected function delete_dimensions(array $ids) {
global $DB, $PAGE;
$masters = $DB->get_records_list('workshop_forms', 'id', $masterids, '', 'id,localid');
$masterids = array_keys($masters); // now contains only those really existing
$localids = array();
$fs = get_file_storage();
foreach ($masters as $itemid => $master) {
$fs->delete_area_files($PAGE->context->id, 'workshop_dimension_description', $itemid);
$localids[] = $master->localid;
foreach ($ids as $id) {
$fs->delete_area_files($PAGE->context->id, 'workshopform_numerrors_description', $id);
}
$DB->delete_records_list('workshop_forms_noerrors', 'id', $localids);
$DB->delete_records_list('workshop_forms', 'id', $masterids);
$DB->delete_records_list('workshopform_numerrors', 'id', $ids);
}
/**
* Prepares data returned by {@link workshop_edit_noerrors_strategy_form} so they can be saved into database
* Prepares data returned by {@link workshop_edit_numerrors_strategy_form} 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.
@ -372,23 +361,19 @@ class workshop_noerrors_strategy implements workshop_strategy {
protected function prepare_database_fields(stdClass $raw) {
global $PAGE;
$cook = new stdClass(); // to be returned
$cook->forms = array(); // to be stored in {workshop_forms}
$cook->noerrors = array(); // to be stored in {workshop_forms_noerrors}
$cook->mappings = array(); // to be stored in {workshop_forms_noerrors_map}
$cook = new stdClass(); // to be returned
$cook->numerrors = array(); // to be stored in {workshopform_numerrors}
$cook->mappings = array(); // to be stored in {workshopform_numerrors_map}
for ($i = 0; $i < $raw->norepeats; $i++) {
$cook->forms[$i] = new stdClass();
$cook->forms[$i]->id = $raw->{'dimensionid__idx_'.$i};
$cook->forms[$i]->workshopid = $this->workshop->id;
$cook->forms[$i]->sort = $i + 1;
$cook->forms[$i]->strategy = 'noerrors';
$cook->noerrors[$i] = new stdClass();
$cook->noerrors[$i]->description_editor = $raw->{'description__idx_'.$i.'_editor'};
$cook->noerrors[$i]->grade0 = $raw->{'grade0__idx_'.$i};
$cook->noerrors[$i]->grade1 = $raw->{'grade1__idx_'.$i};
$cook->noerrors[$i]->weight = $raw->{'weight__idx_'.$i};
$cook->numerrors[$i] = new stdClass();
$cook->numerrors[$i]->id = $raw->{'dimensionid__idx_'.$i};
$cook->numerrors[$i]->workshopid = $this->workshop->id;
$cook->numerrors[$i]->sort = $i + 1;
$cook->numerrors[$i]->description_editor = $raw->{'description__idx_'.$i.'_editor'};
$cook->numerrors[$i]->grade0 = $raw->{'grade0__idx_'.$i};
$cook->numerrors[$i]->grade1 = $raw->{'grade1__idx_'.$i};
$cook->numerrors[$i]->weight = $raw->{'weight__idx_'.$i};
}
$i = 1;
@ -413,30 +398,15 @@ class workshop_noerrors_strategy implements workshop_strategy {
protected function get_current_assessment_data(stdClass $assessment) {
global $DB;
// fetch all grades accociated with this assessment
$grades = $DB->get_records('workshop_grades', array('assessmentid' => $assessment->id));
list($dimsql, $dimparams) = $DB->get_in_or_equal(array_keys($this->dimensions), SQL_PARAMS_NAMED);
// beware! the caller may rely on the returned array is indexed by dimensionid
$sql = "SELECT dimensionid, *
FROM {workshop_grades}
WHERE assessmentid = :assessmentid AND strategy= :strategy AND dimensionid $dimsql";
$params = array('assessmentid' => $assessment->id, 'strategy' => 'numerrors');
$params = array_merge($params, $dimparams);
// filter grades given under an other strategy or assessment form
foreach ($grades as $grade) {
if (!isset($this->dimensions[$grade->dimensionid])) {
unset ($grades[$grade->id]);
}
}
return $grades;
}
/**
* Reindexes the records returned by {@link get_current_assessment_data} by dimensionid
*
* @param mixed $grades
* @return array
*/
protected function reindex_grades_by_dimension($grades) {
$reindexed = array();
foreach ($grades as $grade) {
$reindexed[$grade->dimensionid] = $grade;
}
return $reindexed;
return $DB->get_records_sql($sql, $params);
}
/**
@ -449,7 +419,7 @@ class workshop_noerrors_strategy implements workshop_strategy {
$grades = $this->get_current_assessment_data($assessment);
$suggested = $this->calculate_peer_grade($grades);
if (!is_null($suggested)) {
// todo save into workshop_assessments
$this->workshop->set_peer_grade($assessment->id, $suggested);
}
return $suggested;
}
@ -466,7 +436,7 @@ class workshop_noerrors_strategy implements workshop_strategy {
}
$sumerrors = 0; // sum of the weighted errors (ie the negative responses)
foreach ($grades as $grade) {
if (empty($grade->grade)) {
if (grade_floats_different($grade->grade, 1.00000)) {
// negative reviewer's response
$sumerrors += $this->dimensions[$grade->dimensionid]->weight;
}
@ -490,12 +460,12 @@ class workshop_noerrors_strategy implements workshop_strategy {
* 6 | 0%
* With this mapping, one error is mapped to 100% grade and 4 errors is mapped to 60%.
*
* @param mixed $noerrors Number of errors
* @param mixed $numerrors Number of errors
* @return float Raw grade (0 to 1) for the given number of negative assertions
*/
protected function errors_to_grade($noerrors) {
protected function errors_to_grade($numerrors) {
$grade = 100;
for ($i = 1; $i <= $noerrors; $i++) {
for ($i = 1; $i <= $numerrors; $i++) {
if (isset($this->mappings[$i])) {
$grade = $this->mappings[$i]->grade;
}
@ -506,6 +476,6 @@ class workshop_noerrors_strategy implements workshop_strategy {
if ($grade < 0) {
$grade = 0;
}
return $grade/100;
return grade_floatval($grade/100);
}
}

View File

@ -27,10 +27,10 @@
defined('MOODLE_INTERNAL') || die();
$settings->add(new admin_setting_configtext('workshopgrading_noerrors/grade0', get_string('grade0', 'workshopgrading_noerrors'),
get_string('configgrade0', 'workshopgrading_noerrors'),
get_string('grade0default', 'workshopgrading_noerrors'), $paramtype=PARAM_TEXT, $size=15));
$settings->add(new admin_setting_configtext('workshopform_numerrors/grade0', get_string('grade0', 'workshopform_numerrors'),
get_string('configgrade0', 'workshopform_numerrors'),
get_string('grade0default', 'workshopform_numerrors'), $paramtype=PARAM_TEXT, $size=15));
$settings->add(new admin_setting_configtext('workshopgrading_noerrors/grade1', get_string('grade1', 'workshopgrading_noerrors'),
get_string('configgrade1', 'workshopgrading_noerrors'),
get_string('grade1default', 'workshopgrading_noerrors'), $paramtype=PARAM_TEXT, $size=15));
$settings->add(new admin_setting_configtext('workshopform_numerrors/grade1', get_string('grade1', 'workshopform_numerrors'),
get_string('configgrade1', 'workshopform_numerrors'),
get_string('grade1default', 'workshopform_numerrors'), $paramtype=PARAM_TEXT, $size=15));

View File

@ -16,7 +16,7 @@
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
/**
* Unit tests for (some of) mod/workshop/grading/noerrors/strategy.php
* Unit tests for Number of errors grading logic
*
* @package mod-workshop
* @copyright 2009 David Mudrak <david.mudrak@gmail.com>
@ -26,7 +26,8 @@
defined('MOODLE_INTERNAL') || die();
// Include the code to test
require_once($CFG->dirroot . '/mod/workshop/grading/noerrors/strategy.php');
require_once($CFG->dirroot . '/mod/workshop/locallib.php');
require_once($CFG->dirroot . '/mod/workshop/form/numerrors/lib.php');
global $DB;
Mock::generate(get_class($DB), 'mockDB');
@ -34,7 +35,7 @@ Mock::generate(get_class($DB), 'mockDB');
/**
* Test subclass that makes all the protected methods we want to test public
*/
class testable_workshop_noerrors_strategy extends workshop_noerrors_strategy {
class testable_workshop_numerrors_strategy extends workshop_numerrors_strategy {
/** allows to set dimensions manually */
public $dimensions = array();
@ -50,7 +51,7 @@ class testable_workshop_noerrors_strategy extends workshop_noerrors_strategy {
}
}
class workshop_noerrors_strategy_test extends UnitTestCase {
class workshop_numerrors_strategy_test extends UnitTestCase {
/** real database */
protected $realDB;
@ -71,9 +72,9 @@ class workshop_noerrors_strategy_test extends UnitTestCase {
$cm = (object)array('id' => 3);
$course = (object)array('id' => 11);
$workshop = (object)array('id' => 42, 'strategy' => 'noerrors');
$workshop = (object)array('id' => 42, 'strategy' => 'numerrors');
$this->workshop = new workshop($workshop, $cm, $course);
$this->strategy = new testable_workshop_noerrors_strategy($this->workshop);
$this->strategy = new testable_workshop_numerrors_strategy($this->workshop);
}
public function tearDown() {
@ -98,14 +99,14 @@ class workshop_noerrors_strategy_test extends UnitTestCase {
public function test_calculate_peer_grade_no_error() {
// fixture set-up
$this->strategy->dimensions = array();
$this->strategy->dimensions[108] = (object)array('weight' => 1);
$this->strategy->dimensions[109] = (object)array('weight' => 1);
$this->strategy->dimensions[111] = (object)array('weight' => 1);
$this->strategy->dimensions[108] = (object)array('weight' => '1');
$this->strategy->dimensions[109] = (object)array('weight' => '1');
$this->strategy->dimensions[111] = (object)array('weight' => '1');
$this->strategy->mappings = array();
$grades = array();
$grades[] = (object)array('dimensionid' => 108, 'grade' => 1);
$grades[] = (object)array('dimensionid' => 111, 'grade' => 1);
$grades[] = (object)array('dimensionid' => 109, 'grade' => 1);
$grades[] = (object)array('dimensionid' => 108, 'grade' => '1.00000');
$grades[] = (object)array('dimensionid' => 111, 'grade' => '1.00000');
$grades[] = (object)array('dimensionid' => 109, 'grade' => '1.00000');
// excercise SUT
$suggested = $this->strategy->calculate_peer_grade($grades);
// validate
@ -115,19 +116,19 @@ class workshop_noerrors_strategy_test extends UnitTestCase {
public function test_calculate_peer_grade_one_error() {
// fixture set-up
$this->strategy->dimensions = array();
$this->strategy->dimensions[108] = (object)array('weight' => 1);
$this->strategy->dimensions[109] = (object)array('weight' => 1);
$this->strategy->dimensions[111] = (object)array('weight' => 1);
$this->strategy->dimensions[108] = (object)array('weight' => '1');
$this->strategy->dimensions[109] = (object)array('weight' => '1');
$this->strategy->dimensions[111] = (object)array('weight' => '1');
$this->strategy->mappings = array(
1 => (object)array('grade' => 80.0),
2 => (object)array('grade' => 60.0),
1 => (object)array('grade' => '80.00000'),
2 => (object)array('grade' => '60.00000'),
);
$grades = array();
$grades[] = (object)array('dimensionid' => 108, 'grade' => 1);
$grades[] = (object)array('dimensionid' => 111, 'grade' => 0);
$grades[] = (object)array('dimensionid' => 109, 'grade' => 1);
$grades[] = (object)array('dimensionid' => 108, 'grade' => '1.00000');
$grades[] = (object)array('dimensionid' => 111, 'grade' => '0.00000');
$grades[] = (object)array('dimensionid' => 109, 'grade' => '1.00000');
// excercise SUT
$suggested = $this->strategy->calculate_peer_grade($grades);
@ -138,20 +139,20 @@ class workshop_noerrors_strategy_test extends UnitTestCase {
public function test_calculate_peer_grade_three_errors_same_weight_a() {
// fixture set-up
$this->strategy->dimensions = array();
$this->strategy->dimensions[108] = (object)array('weight' => 1);
$this->strategy->dimensions[109] = (object)array('weight' => 1);
$this->strategy->dimensions[111] = (object)array('weight' => 1);
$this->strategy->dimensions[108] = (object)array('weight' => '1.00000');
$this->strategy->dimensions[109] = (object)array('weight' => '1.00000');
$this->strategy->dimensions[111] = (object)array('weight' => '1.00000');
$this->strategy->mappings = array(
1 => (object)array('grade' => 80.0),
2 => (object)array('grade' => 60.0),
3 => (object)array('grade' => 10.0),
1 => (object)array('grade' => '80.00000'),
2 => (object)array('grade' => '60.00000'),
3 => (object)array('grade' => '10.00000'),
);
$grades = array();
$grades[] = (object)array('dimensionid' => 108, 'grade' => 0);
$grades[] = (object)array('dimensionid' => 111, 'grade' => 0);
$grades[] = (object)array('dimensionid' => 109, 'grade' => 0);
$grades[] = (object)array('dimensionid' => 108, 'grade' => '0.00000');
$grades[] = (object)array('dimensionid' => 111, 'grade' => '0.00000');
$grades[] = (object)array('dimensionid' => 109, 'grade' => '0.00000');
// excercise SUT
$suggested = $this->strategy->calculate_peer_grade($grades);
@ -162,20 +163,20 @@ class workshop_noerrors_strategy_test extends UnitTestCase {
public function test_calculate_peer_grade_three_errors_same_weight_b() {
// fixture set-up
$this->strategy->dimensions = array();
$this->strategy->dimensions[108] = (object)array('weight' => 1);
$this->strategy->dimensions[109] = (object)array('weight' => 1);
$this->strategy->dimensions[111] = (object)array('weight' => 1);
$this->strategy->dimensions[108] = (object)array('weight' => '1.00000');
$this->strategy->dimensions[109] = (object)array('weight' => '1.00000');
$this->strategy->dimensions[111] = (object)array('weight' => '1.00000');
$this->strategy->mappings = array(
1 => (object)array('grade' => 80.0),
2 => (object)array('grade' => 60.0),
3 => (object)array('grade' => 0.0),
1 => (object)array('grade' => '80.00000'),
2 => (object)array('grade' => '60.00000'),
3 => (object)array('grade' => '0.00000'),
);
$grades = array();
$grades[] = (object)array('dimensionid' => 108, 'grade' => 0);
$grades[] = (object)array('dimensionid' => 111, 'grade' => 0);
$grades[] = (object)array('dimensionid' => 109, 'grade' => 0);
$grades[] = (object)array('dimensionid' => 108, 'grade' => '0.00000');
$grades[] = (object)array('dimensionid' => 111, 'grade' => '0.00000');
$grades[] = (object)array('dimensionid' => 109, 'grade' => '0.00000');
// excercise SUT
$suggested = $this->strategy->calculate_peer_grade($grades);
@ -186,20 +187,20 @@ class workshop_noerrors_strategy_test extends UnitTestCase {
public function test_calculate_peer_grade_one_error_weighted() {
// fixture set-up
$this->strategy->dimensions = array();
$this->strategy->dimensions[108] = (object)array('weight' => 1);
$this->strategy->dimensions[109] = (object)array('weight' => 2);
$this->strategy->dimensions[111] = (object)array('weight' => 0);
$this->strategy->dimensions[108] = (object)array('weight' => '1');
$this->strategy->dimensions[109] = (object)array('weight' => '2');
$this->strategy->dimensions[111] = (object)array('weight' => '0');
$this->strategy->mappings = array(
1 => (object)array('grade' => 66.0),
2 => (object)array('grade' => 33.0),
3 => (object)array('grade' => 0.0),
1 => (object)array('grade' => '66.00000'),
2 => (object)array('grade' => '33.00000'),
3 => (object)array('grade' => '0.00000'),
);
$grades = array();
$grades[] = (object)array('dimensionid' => 108, 'grade' => 1);
$grades[] = (object)array('dimensionid' => 111, 'grade' => 1);
$grades[] = (object)array('dimensionid' => 109, 'grade' => 0);
$grades[] = (object)array('dimensionid' => 108, 'grade' => '1.00000');
$grades[] = (object)array('dimensionid' => 111, 'grade' => '1.00000');
$grades[] = (object)array('dimensionid' => 109, 'grade' => '0.00000');
// excercise SUT
$suggested = $this->strategy->calculate_peer_grade($grades);
@ -210,20 +211,20 @@ class workshop_noerrors_strategy_test extends UnitTestCase {
public function test_calculate_peer_grade_zero_weight() {
// fixture set-up
$this->strategy->dimensions = array();
$this->strategy->dimensions[108] = (object)array('weight' => 1);
$this->strategy->dimensions[109] = (object)array('weight' => 2);
$this->strategy->dimensions[111] = (object)array('weight' => 0);
$this->strategy->dimensions[108] = (object)array('weight' => '1');
$this->strategy->dimensions[109] = (object)array('weight' => '2');
$this->strategy->dimensions[111] = (object)array('weight' => '0');
$this->strategy->mappings = array(
1 => (object)array('grade' => 66.0),
2 => (object)array('grade' => 33.0),
3 => (object)array('grade' => 0.0),
1 => (object)array('grade' => '66.00000'),
2 => (object)array('grade' => '33.00000'),
3 => (object)array('grade' => '0.00000'),
);
$grades = array();
$grades[] = (object)array('dimensionid' => 108, 'grade' => 1);
$grades[] = (object)array('dimensionid' => 111, 'grade' => 0);
$grades[] = (object)array('dimensionid' => 109, 'grade' => 1);
$grades[] = (object)array('dimensionid' => 108, 'grade' => '1.00000');
$grades[] = (object)array('dimensionid' => 111, 'grade' => '0.00000');
$grades[] = (object)array('dimensionid' => 109, 'grade' => '1.00000');
// excercise SUT
$suggested = $this->strategy->calculate_peer_grade($grades);
@ -234,24 +235,24 @@ class workshop_noerrors_strategy_test extends UnitTestCase {
public function test_calculate_peer_grade_sum_weight() {
// fixture set-up
$this->strategy->dimensions = array();
$this->strategy->dimensions[108] = (object)array('weight' => 1);
$this->strategy->dimensions[109] = (object)array('weight' => 2);
$this->strategy->dimensions[111] = (object)array('weight' => 3);
$this->strategy->dimensions[108] = (object)array('weight' => '1');
$this->strategy->dimensions[109] = (object)array('weight' => '2');
$this->strategy->dimensions[111] = (object)array('weight' => '3');
$this->strategy->mappings = array(
1 => (object)array('grade' => 90.0),
2 => (object)array('grade' => 80.0),
3 => (object)array('grade' => 70.0),
4 => (object)array('grade' => 60.0),
5 => (object)array('grade' => 30.0),
6 => (object)array('grade' => 5.0),
7 => (object)array('grade' => 0.0),
1 => (object)array('grade' => '90.00000'),
2 => (object)array('grade' => '80.00000'),
3 => (object)array('grade' => '70.00000'),
4 => (object)array('grade' => '60.00000'),
5 => (object)array('grade' => '30.00000'),
6 => (object)array('grade' => '5.00000'),
7 => (object)array('grade' => '0.00000'),
);
$grades = array();
$grades[] = (object)array('dimensionid' => 108, 'grade' => 0);
$grades[] = (object)array('dimensionid' => 111, 'grade' => 0);
$grades[] = (object)array('dimensionid' => 109, 'grade' => 0);
$grades[] = (object)array('dimensionid' => 108, 'grade' => '0.00000');
$grades[] = (object)array('dimensionid' => 111, 'grade' => '0.00000');
$grades[] = (object)array('dimensionid' => 109, 'grade' => '0.00000');
// excercise SUT
$suggested = $this->strategy->calculate_peer_grade($grades);

View File

@ -1,31 +1,34 @@
<?xml version="1.0" encoding="UTF-8" ?>
<XMLDB PATH="mod/workshop/db" VERSION="20090831" COMMENT="XMLDB file for Moodle mod/workshop/grading/rubric"
<XMLDB PATH="mod/workshop/db" VERSION="20090908" COMMENT="XMLDB file for workshop Rubric grading strategy"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="../../../lib/xmldb/xmldb.xsd"
>
<TABLES>
<TABLE NAME="workshop_forms_rubric" COMMENT="The assessment dimensions definitions of Rubric grading strategy forms" PREVIOUS="workshop_forms_nograding" NEXT="workshop_forms_rubric_levels">
<TABLE NAME="workshopform_rubric" COMMENT="The assessment dimensions definitions of Rubric grading strategy forms" NEXT="workshopform_rubric_levels">
<FIELDS>
<FIELD NAME="id" TYPE="int" LENGTH="10" NOTNULL="true" UNSIGNED="true" SEQUENCE="true" NEXT="description"/>
<FIELD NAME="description" TYPE="text" LENGTH="big" NOTNULL="false" SEQUENCE="false" COMMENT="The description of the dimension" PREVIOUS="id" NEXT="descriptionformat"/>
<FIELD NAME="id" TYPE="int" LENGTH="10" NOTNULL="true" UNSIGNED="true" SEQUENCE="true" NEXT="workshopid"/>
<FIELD NAME="workshopid" TYPE="int" LENGTH="10" NOTNULL="true" UNSIGNED="true" SEQUENCE="false" COMMENT="Workshop ID" PREVIOUS="id" NEXT="sort"/>
<FIELD NAME="sort" TYPE="int" LENGTH="10" NOTNULL="false" UNSIGNED="true" DEFAULT="0" SEQUENCE="false" COMMENT="Defines the dimension order within the assessment form" PREVIOUS="workshopid" NEXT="description"/>
<FIELD NAME="description" TYPE="text" LENGTH="big" NOTNULL="false" SEQUENCE="false" COMMENT="The description of the dimension" PREVIOUS="sort" NEXT="descriptionformat"/>
<FIELD NAME="descriptionformat" TYPE="int" LENGTH="3" NOTNULL="false" UNSIGNED="true" DEFAULT="0" SEQUENCE="false" COMMENT="The format of the description field" PREVIOUS="description"/>
</FIELDS>
<KEYS>
<KEY NAME="primary" TYPE="primary" FIELDS="id"/>
<KEY NAME="primary" TYPE="primary" FIELDS="id" NEXT="workshop_fk"/>
<KEY NAME="workshop_fk" TYPE="foreign" FIELDS="workshopid" REFTABLE="workshop" REFFIELDS="id" PREVIOUS="primary"/>
</KEYS>
</TABLE>
<TABLE NAME="workshop_forms_rubric_levels" COMMENT="The definition of rubric rating scales" PREVIOUS="workshop_forms_rubric">
<TABLE NAME="workshopform_rubric_levels" COMMENT="The definition of rubric rating scales" PREVIOUS="workshopform_rubric">
<FIELDS>
<FIELD NAME="id" TYPE="int" LENGTH="10" NOTNULL="true" UNSIGNED="true" SEQUENCE="true" NEXT="dimensionid"/>
<FIELD NAME="dimensionid" TYPE="int" LENGTH="10" NOTNULL="true" UNSIGNED="true" SEQUENCE="false" COMMENT="Which criterion this level is part of" PREVIOUS="id" NEXT="grade"/>
<FIELD NAME="grade" TYPE="int" LENGTH="10" NOTNULL="true" UNSIGNED="true" SEQUENCE="false" COMMENT="Grade representing this level." PREVIOUS="dimensionid" NEXT="description"/>
<FIELD NAME="grade" TYPE="number" LENGTH="10" NOTNULL="true" UNSIGNED="true" SEQUENCE="false" DECIMALS="5" COMMENT="Grade representing this level." PREVIOUS="dimensionid" NEXT="description"/>
<FIELD NAME="description" TYPE="text" LENGTH="big" NOTNULL="false" SEQUENCE="false" COMMENT="The definition of this level" PREVIOUS="grade" NEXT="descriptionformat"/>
<FIELD NAME="descriptionformat" TYPE="int" LENGTH="3" NOTNULL="false" UNSIGNED="true" DEFAULT="0" SEQUENCE="false" COMMENT="The format of the description field" PREVIOUS="description"/>
</FIELDS>
<KEYS>
<KEY NAME="primary" TYPE="primary" FIELDS="id" NEXT="dimension_fk"/>
<KEY NAME="dimension_fk" TYPE="foreign" FIELDS="dimensionid" REFTABLE="workshop_forms_rubric" REFFIELDS="id" PREVIOUS="primary"/>
<KEY NAME="dimension_fk" TYPE="foreign" FIELDS="dimensionid" REFTABLE="workshopform_rubric" REFFIELDS="id" PREVIOUS="primary"/>
</KEYS>
</TABLE>
</TABLES>
</XMLDB>
</XMLDB>

View File

@ -1,18 +0,0 @@
<?xml version="1.0" encoding="UTF-8" ?>
<XMLDB PATH="mod/workshop/db" VERSION="20090831" COMMENT="XMLDB file for Moodle mod/workshop/grading/nograding"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="../../../lib/xmldb/xmldb.xsd"
>
<TABLES>
<TABLE NAME="workshop_forms_nograding" COMMENT="The assessment dimensions definitions of No grading strategy forms">
<FIELDS>
<FIELD NAME="id" TYPE="int" LENGTH="10" NOTNULL="true" UNSIGNED="true" SEQUENCE="true" NEXT="description"/>
<FIELD NAME="description" TYPE="text" LENGTH="big" NOTNULL="false" SEQUENCE="false" COMMENT="The description of the dimension" PREVIOUS="id" NEXT="descriptionformat"/>
<FIELD NAME="descriptionformat" TYPE="int" LENGTH="3" NOTNULL="false" UNSIGNED="true" DEFAULT="0" SEQUENCE="false" COMMENT="The format of the description field" PREVIOUS="description"/>
</FIELDS>
<KEYS>
<KEY NAME="primary" TYPE="primary" FIELDS="id"/>
</KEYS>
</TABLE>
</TABLES>
</XMLDB>

View File

@ -42,7 +42,6 @@ $string['allocatedetails'] = 'expected: $a->expected<br />submitted: $a->submitt
$string['allocationdone'] = 'Allocation done';
$string['allocationerror'] = 'Allocation error';
$string['allocation'] = 'Submission allocation';
$string['areadimensiondescription'] = 'Assessment form fields';
$string['areasubmissionattachment'] = 'Submission attachments';
$string['areasubmissioncontent'] = 'Submission texts';
$string['assessallexamples'] = 'Assess all examples';

View File

@ -62,7 +62,7 @@ function workshop_supports($feature) {
case FEATURE_GROUPMEMBERSONLY: return true;
case FEATURE_MOD_INTRO: return true;
case FEATURE_MOD_SUBPLUGINS: return array(
'workshopgrading' => 'mod/workshop/grading',
'workshopform' => 'mod/workshop/form',
'workshopallocation' => 'mod/workshop/allocation'
);
default: return null;
@ -124,6 +124,9 @@ function workshop_update_instance($data) {
$data->timemodified = time();
$data->id = $data->instance;
// todo - if the grading strategy is being changed, we must replace all aggregated peer grades with nulls
// todo - if maximum grades are being changed, we should probably recalculate or invalidate them
$DB->update_record('workshop', $data);
$context = get_context_instance(CONTEXT_MODULE, $data->coursemodule);
@ -296,6 +299,10 @@ function workshop_get_extra_capabilities() {
* The file area workshop_intro for the activity introduction field is added automatically
* by {@link file_browser::get_file_info_module()}
*
* TODO: we use the following areas
* workshopform_accumulative_description
* workshopform_numerrors_description
*
* @param stdClass $course
* @param stdClass $cm
* @param stdClass $context
@ -305,7 +312,6 @@ function workshop_get_file_areas($course, $cm, $context) {
$areas = array();
if (has_capability('moodle/course:managefiles', $context)) {
$areas['workshop_instructauthors'] = get_string('areainstructauthors', 'workshop');
$areas['workshop_dimension_description'] = get_string('areadimensiondescription', 'workshop');
$areas['workshop_submission_content'] = get_string('areasubmissioncontent', 'workshop');
$areas['workshop_submission_attachment'] = get_string('areasubmissionattachment', 'workshop');
}
@ -363,6 +369,7 @@ function workshop_pluginfile($course, $cminfo, $context, $filearea, array $args,
send_stored_file($file, $lifetime, 0);
}
/** todo - this filearea has been replaced by subplugins' areas
if ($filearea === 'workshop_dimension_description') {
$itemid = (int)array_shift($args);
if (!$dimension = $DB->get_record('workshop_forms', array('id' => $itemid))) {
@ -386,6 +393,7 @@ function workshop_pluginfile($course, $cminfo, $context, $filearea, array $args,
// finally send the file
send_stored_file($file);
}
*/
if ($filearea === 'workshop_submission_content' or $filearea === 'workshop_submission_attachment') {
$itemid = (int)array_shift($args);
@ -469,6 +477,7 @@ function workshop_get_file_info($browser, $areas, $course, $cm, $context, $filea
return new file_info_stored($browser, $context, $storedfile, $urlbase, $topvisiblename, true, true, false, false);
}
/* todo was replaced by subplugins' areas
if ($filearea === 'workshop_dimension_description') {
// always only itemid 0 - TODO not true, review
@ -486,6 +495,7 @@ function workshop_get_file_info($browser, $areas, $course, $cm, $context, $filea
}
return new file_info_stored($browser, $context, $storedfile, $urlbase, $areas[$filearea], false, true, true, false);
}
*/
if ($filearea === 'workshop_instructauthors') {
// always only itemid 0
@ -630,14 +640,15 @@ function workshop_get_dimension_weights() {
/**
* Return an array of the localized grading strategy names
*
* @todo remove this function from lib.php
* $return array Array ['string' => 'string']
*/
function workshop_get_strategies() {
$installed = get_plugin_list('workshopgrading');
$installed = get_plugin_list('workshopform');
$forms = array();
foreach ($installed as $strategy => $strategypath) {
if (file_exists($strategypath . '/strategy.php')) {
$forms[$strategy] = get_string('pluginname', 'workshopgrading_' . $strategy);
if (file_exists($strategypath . '/lib.php')) {
$forms[$strategy] = get_string('pluginname', 'workshopform_' . $strategy);
}
}
return $forms;

View File

@ -58,18 +58,12 @@ class workshop {
/** @var stdClass course record */
public $course = null;
/** @var stdClass the workshop instance context */
public $context = null;
/**
* @var workshop_strategy grading strategy instance
* Do not use directly, get the instance using {@link workshop::grading_strategy_instance()}
*/
protected $strategyinstance = null;
/** @var stdClass underlying database record */
protected $dbrecord = null;
/**
* Initializes the workshop API instance using the data from DB
*
@ -81,25 +75,13 @@ class workshop {
* @param stdClass $course Course record from {course} table
*/
public function __construct(stdClass $dbrecord, stdClass $cm, stdClass $course) {
$this->dbrecord = $dbrecord;
$this->cm = $cm;
$this->course = $course;
$this->context = get_context_instance(CONTEXT_MODULE, $this->cm->id);
}
/**
* Magic method to retrieve the value of the underlying database record's field
*
* @throws coding_exception if the field does not exist
* @param mixed $key the name of the database field
* @return mixed|null the value of the field
*/
public function __get($key) {
if (!isset($this->dbrecord->{$key})) {
// todo remove the comment here // throw new coding_exception('You are trying to get a non-existing property');
return null;
foreach ($dbrecord as $field => $value) {
$this->{$field} = $value;
}
return $this->dbrecord->{$key};
$this->cm = $cm;
$this->course = $course; // beware - this replaces the standard course field in the instance table
// this is intentional - IMO there should be no such field as it violates
// 3rd normal form with no real performance gain
}
/**
@ -107,12 +89,15 @@ class workshop {
*
* Example submissions are ignored.
*
* @param array $userids
* @return TODO
* @param array $userids
* @return array
*/
protected function users_with_submission(array $userids) {
global $DB;
if (empty($userids)) {
return array();
}
$userswithsubmission = array();
list($usql, $uparams) = $DB->get_in_or_equal($userids, SQL_PARAMS_NAMED);
$sql = "SELECT id,userid
@ -133,11 +118,12 @@ class workshop {
*
* The returned objects contain id, lastname and firstname properties and are ordered by lastname,firstname
*
* @param stdClass $context
* @param bool $musthavesubmission If true, return only users who have already submitted. All possible authors otherwise.
* @return array array[userid] => stdClass{->id ->lastname ->firstname}
*/
public function get_potential_authors($musthavesubmission=true) {
$users = get_users_by_capability($this->context, 'mod/workshop:submit',
public function get_potential_authors(stdClass $context, $musthavesubmission=true) {
$users = get_users_by_capability($context, 'mod/workshop:submit',
'u.id, u.lastname, u.firstname', 'u.lastname,u.firstname', '', '', '', '', false, false, true);
if ($musthavesubmission) {
$users = array_intersect_key($users, $this->users_with_submission(array_keys($users)));
@ -150,11 +136,12 @@ class workshop {
*
* The returned objects contain id, lastname and firstname properties and are ordered by lastname,firstname
*
* @param stdClass $context
* @param bool $musthavesubmission If true, return only users who have already submitted. All possible users otherwise.
* @return array array[userid] => stdClass{->id ->lastname ->firstname}
*/
public function get_potential_reviewers($musthavesubmission=false) {
$users = get_users_by_capability($this->context, 'mod/workshop:peerassess',
public function get_potential_reviewers(stdClass $context, $musthavesubmission=false) {
$users = get_users_by_capability($context, 'mod/workshop:peerassess',
'u.id, u.lastname, u.firstname', 'u.lastname,u.firstname', '', '', '', '', false, false, true);
if ($musthavesubmission) {
// users without their own submission can not be reviewers
@ -215,7 +202,7 @@ class workshop {
*
* @param mixed $userid int|array|'all' If set to [array of] integer, return submission[s] of the given user[s] only
* @param mixed $examples false|true|'all' Only regular submissions, only examples, all submissions
* @return stdClass moodle_recordset
* @return array
*/
public function get_submissions($userid='all', $examples=false) {
global $DB;
@ -390,14 +377,18 @@ class workshop {
* Note that the returned recordset includes participants without submission as well as those
* without any review allocated yet.
*
* @return stdClass moodle_recordset
* @return null|stdClass moodle_recordset
*/
public function get_allocations_recordset() {
global $DB;
global $DB, $PAGE;
$users = get_users_by_capability($this->context, array('mod/workshop:submit', 'mod/workshop:peerassess'),
$users = get_users_by_capability($PAGE->context, array('mod/workshop:submit', 'mod/workshop:peerassess'),
'u.id', 'u.lastname,u.firstname', '', '', '', '', false, false, true);
if (empty($users)) {
return null;
}
list($usql, $params) = $DB->get_in_or_equal(array_keys($users), SQL_PARAMS_NAMED);
$params['workshopid'] = $this->id;
@ -469,11 +460,11 @@ class workshop {
global $CFG; // because we require other libs here
if (is_null($this->strategyinstance)) {
$strategylib = dirname(__FILE__) . '/grading/' . $this->strategy . '/strategy.php';
$strategylib = dirname(__FILE__) . '/form/' . $this->strategy . '/lib.php';
if (is_readable($strategylib)) {
require_once($strategylib);
} else {
throw new coding_exception('the grading subplugin must contain library ' . $strategylib);
throw new coding_exception('the grading forms subplugin must contain library ' . $strategylib);
}
$classname = 'workshop_' . $this->strategy . '_strategy';
$this->strategyinstance = new $classname($this);
@ -493,7 +484,7 @@ class workshop {
$installed = get_plugin_list('workshopallocation');
$forms = array();
foreach ($installed as $allocation => $allocationpath) {
if (file_exists($allocationpath . '/allocator.php')) {
if (file_exists($allocationpath . '/lib.php')) {
$forms[$allocation] = get_string('pluginname', 'workshopallocation_' . $allocation);
}
}
@ -515,11 +506,11 @@ class workshop {
public function allocator_instance($method) {
global $CFG; // because we require other libs here
$allocationlib = dirname(__FILE__) . '/allocation/' . $method . '/allocator.php';
$allocationlib = dirname(__FILE__) . '/allocation/' . $method . '/lib.php';
if (is_readable($allocationlib)) {
require_once($allocationlib);
} else {
throw new coding_exception('Unable to find allocator.php');
throw new coding_exception('Unable to find the allocation library ' . $allocationlib);
}
$classname = 'workshop_' . $method . '_allocator';
return new $classname($this);
@ -650,16 +641,17 @@ class workshop {
* @return string
*/
public function strategy_name() {
return get_string('pluginname', 'workshopgrading_' . $this->strategy);
return get_string('pluginname', 'workshopform_' . $this->strategy);
}
/**
* Prepare an individual workshop plan for the given user.
*
* @param mixed $userid
* @return TODO
* @param int $userid whom the plan is prepared for
* @param stdClass context of the planned workshop
* @return stdClass data object to be passed to the renderer
*/
public function prepare_user_plan($userid) {
public function prepare_user_plan($userid, stdClass $context) {
global $DB;
$phases = array();
@ -668,21 +660,21 @@ class workshop {
$phase = new stdClass();
$phase->title = get_string('phasesetup', 'workshop');
$phase->tasks = array();
if (has_capability('moodle/course:manageactivities', $this->context, $userid)) {
if (has_capability('moodle/course:manageactivities', $context, $userid)) {
$task = new stdClass();
$task->title = get_string('taskintro', 'workshop');
$task->link = $this->updatemod_url();
$task->completed = !(trim(strip_tags($this->intro)) == '');
$phase->tasks['intro'] = $task;
}
if (has_capability('moodle/course:manageactivities', $this->context, $userid)) {
if (has_capability('moodle/course:manageactivities', $context, $userid)) {
$task = new stdClass();
$task->title = get_string('taskinstructauthors', 'workshop');
$task->link = $this->updatemod_url();
$task->completed = !(trim(strip_tags($this->instructauthors)) == '');
$phase->tasks['instructauthors'] = $task;
}
if (has_capability('mod/workshop:editdimensions', $this->context, $userid)) {
if (has_capability('mod/workshop:editdimensions', $context, $userid)) {
$task = new stdClass();
$task->title = get_string('editassessmentform', 'workshop');
$task->link = $this->editform_url();
@ -707,7 +699,7 @@ class workshop {
$phase = new stdClass();
$phase->title = get_string('phasesubmission', 'workshop');
$phase->tasks = array();
if (has_capability('mod/workshop:submit', $this->context, $userid)) {
if (has_capability('mod/workshop:submit', $context, $userid)) {
$task = new stdClass();
$task->title = get_string('tasksubmit', 'workshop');
$task->link = $this->submission_url();
@ -720,7 +712,7 @@ class workshop {
}
$phase->tasks['submit'] = $task;
}
if (has_capability('moodle/course:manageactivities', $this->context, $userid)) {
if (has_capability('moodle/course:manageactivities', $context, $userid)) {
$task = new stdClass();
$task->title = get_string('taskinstructreviewers', 'workshop');
$task->link = $this->updatemod_url();
@ -732,30 +724,32 @@ class workshop {
$phase->tasks['instructreviewers'] = $task;
}
$phases[self::PHASE_SUBMISSION] = $phase;
if (has_capability('mod/workshop:allocate', $this->context, $userid)) {
if (has_capability('mod/workshop:allocate', $context, $userid)) {
$task = new stdClass();
$task->title = get_string('allocate', 'workshop');
$task->link = $this->allocation_url();
$rs = $this->get_allocations_recordset();
$authors = array();
$allocations = array(); // 'submissionid' => isallocated
foreach ($rs as $allocation) {
if (!isset($authors[$allocation->authorid])) {
$authors[$allocation->authorid] = true;
}
if (isset($allocation->submissionid)) {
if (!isset($allocations[$allocation->submissionid])) {
$allocations[$allocation->submissionid] = false;
$rs = $this->get_allocations_recordset();
if (!is_null($rs)) {
foreach ($rs as $allocation) {
if (!isset($authors[$allocation->authorid])) {
$authors[$allocation->authorid] = true;
}
if (!empty($allocation->reviewerid)) {
$allocations[$allocation->submissionid] = true;
if (isset($allocation->submissionid)) {
if (!isset($allocations[$allocation->submissionid])) {
$allocations[$allocation->submissionid] = false;
}
if (!empty($allocation->reviewerid)) {
$allocations[$allocation->submissionid] = true;
}
}
}
$rs->close();
}
$numofauthors = count($authors);
$numofsubmissions = count($allocations);
$numofallocated = count(array_filter($allocations));
$rs->close();
if ($numofsubmissions == 0) {
$task->completed = null;
} elseif ($numofsubmissions == $numofallocated) {
@ -785,7 +779,7 @@ class workshop {
$phase = new stdClass();
$phase->title = get_string('phaseassessment', 'workshop');
$phase->tasks = array();
$phase->isreviewer = has_capability('mod/workshop:peerassess', $this->context, $userid);
$phase->isreviewer = has_capability('mod/workshop:peerassess', $context, $userid);
$phase->assessments = $this->get_assessments_by_reviewer($userid);
$numofpeers = 0; // number of allocated peer-assessments
$numofpeerstodo = 0; // number of peer-assessments to do
@ -866,7 +860,7 @@ class workshop {
}
// Add phase swithing actions
if (has_capability('mod/workshop:switchphase', $this->context, $userid)) {
if (has_capability('mod/workshop:switchphase', $context, $userid)) {
foreach ($phases as $phasecode => $phase) {
if (! $phase->active) {
$action = new stdClass();

View File

@ -66,11 +66,11 @@ $settings->add(new admin_setting_configselect('workshop/assessmentcomps', get_st
get_string('configassessmentcomps', 'workshop'), WORKSHOP_COMPARISON_NORMAL, $levels));
// include the settings of grading strategy subplugins
$strategies = get_plugin_list('workshopgrading');
$strategies = get_plugin_list('workshopform');
foreach ($strategies as $strategy => $path) {
if (file_exists($settingsfile = $path . '/settings.php')) {
$settings->add(new admin_setting_heading('workshopgradingsetting'.$strategy,
get_string('pluginname', 'workshopgrading_' . $strategy), ''));
$settings->add(new admin_setting_heading('workshopformsetting'.$strategy,
get_string('pluginname', 'workshopform_' . $strategy), ''));
include($settingsfile);
}
}

View File

@ -1,43 +1,43 @@
/**
* Submission - one line summary display
*/
.submission-summary {
.mod-workshop .submission-summary {
position: relative;
margin-bottom: 10px;
}
.submission-summary .title,
.submission-summary .author,
.submission-summary .author .fullname,
.submission-summary .author .picture {
.mod-workshop .submission-summary .title,
.mod-workshop .submission-summary .author,
.mod-workshop .submission-summary .author .fullname,
.mod-workshop .submission-summary .author .picture {
display: inline;
}
.submission-summary .title,
.submission-summary .userdate {
.mod-workshop .submission-summary .title,
.mod-workshop .submission-summary .userdate {
margin: 0px 0px 0px 40px;
}
.submission-summary .author {
.mod-workshop .submission-summary .author {
margin-left: 1ex;
}
.submission-summary.anonymous .title,
.submission-summary.anonymous .author,
.submission-summary.anonymous .userdate {
.mod-workshop .submission-summary.anonymous .title,
.mod-workshop .submission-summary.anonymous .author,
.mod-workshop .submission-summary.anonymous .userdate {
margin: 0px 0px 0px 5px;
}
.submission-summary .userdate {
.mod-workshop .submission-summary .userdate {
font-size: x-small;
color: #333;
}
.submission-summary .userdate span {
.mod-workshop .submission-summary .userdate span {
font-style: italic;
}
.submission-summary .author .picture {
.mod-workshop .submission-summary .author .picture {
position: absolute;
top: 0px;
left: 0px;
@ -46,57 +46,57 @@
/**
* Submission - full display
*/
.submission-full {
.mod-workshop .submission-full {
border: 1px solid #ddd;
margin: 0px 0px 1em 0px;
}
.submission-full .header {
.mod-workshop .submission-full .header {
position: relative;
background-color: #ddd;
padding: 3px;
}
.submission-full .header .title,
.submission-full .header .author,
.submission-full .header .userdate {
.mod-workshop .submission-full .header .title,
.mod-workshop .submission-full .header .author,
.mod-workshop .submission-full .header .userdate {
margin: 0px 0px 0px 80px;
}
.submission-full.anonymous .header .title,
.submission-full.anonymous .header .author,
.submission-full.anonymous .header .userdate {
.mod-workshop .submission-full.anonymous .header .title,
.mod-workshop .submission-full.anonymous .header .author,
.mod-workshop .submission-full.anonymous .header .userdate {
margin: 0px 0px 0px 5px;
}
.submission-full .header .userdate.modified {
.mod-workshop .submission-full .header .userdate.modified {
margin-left: 10px;
padding-left: 10px;
border-left: 1px solid #000;
}
.submission-full .header .userdate {
.mod-workshop .submission-full .header .userdate {
font-size: x-small;
color: #333;
display: inline;
}
.submission-full .header .userdate span {
.mod-workshop .submission-full .header .userdate span {
font-style: italic;
}
.submission-full .header .author .picture {
.mod-workshop .submission-full .header .author .picture {
position: absolute;
top: 3px;
left: 3px;
}
.submission-full .content,
.submission-full .attachments {
.mod-workshop .submission-full .content,
.mod-workshop .submission-full .attachments {
padding: 5px 10px;
}
.submission-full .attachments .files img.icon {
.mod-workshop .submission-full .attachments .files img.icon {
margin-right: 5px;
}
@ -218,103 +218,99 @@
margin-top: 1em;
}
/**
* Assessment
*/
.assessmentform .description {
margin: 0px 1em;
}
/**
* User plan
*/
.userplan {
.mod-workshop .userplan {
width: 70%;
margin: 1em auto 1em auto;
font-size: 80%;
border-left: 1px solid #ddd;
border-right: 1px solid #ddd;
}
.userplan th {
.mod-workshop .userplan th {
vertical-align: bottom;
white-space: normal;
color: #999;
border-top: 1px solid #ddd;
border-bottom: 1px solid #ddd;
padding: 3px;
}
.userplan th.active {
.mod-workshop .userplan th.active {
vertical-align: top;
color: black;
font-size: 140%;
border: 1px solid #ddd;
border-bottom: none;
background-color: #e7f1c3;
background: #e7f1c3;
}
.userplan td {
.mod-workshop .userplan td {
width: 20%;
vertical-align: top;
border-right: 1px solid #ddd;
background-color: #f5f5f5;
}
.userplan td,
.userplan td a,
.userplan td a:link,
.userplan td a:hover,
.userplan td a:visited,
.userplan td a:active {
.mod-workshop .userplan td,
.mod-workshop .userplan td a,
.mod-workshop .userplan td a:link,
.mod-workshop .userplan td a:hover,
.mod-workshop .userplan td a:visited,
.mod-workshop .userplan td a:active {
color: #999;
}
.userplan td.active,
.userplan td.active a,
.userplan td.active a:link,
.userplan td.active a:hover,
.userplan td.active a:visited,
.userplan td.active a:active {
.mod-workshop .userplan td.active,
.mod-workshop .userplan td.active a,
.mod-workshop .userplan td.active a:link,
.mod-workshop .userplan td.active a:hover,
.mod-workshop .userplan td.active a:visited,
.mod-workshop .userplan td.active a:active {
color: black;
}
.userplan td.lastcol {
.mod-workshop .userplan td.lastcol {
border-right: none;
}
.userplan td.active {
.mod-workshop .userplan td.active {
border-left: 1px solid #ddd;
border-right: 1px solid #ddd;
background-color: #e7f1c3;
}
.userplan tr.phasetasks li {
.mod-workshop .userplan tr.phasetasks li {
background-image: url(../../pix/i/completion-auto-n.gif);
background-position: top left;
background-repeat: no-repeat;
}
.userplan tr.phasetasks li.completed {
.mod-workshop .userplan tr.phasetasks li.completed {
background-image: url(../../pix/i/completion-auto-y.gif);
}
.userplan tr.phasetasks li.fail {
.mod-workshop .userplan tr.phasetasks li.fail {
background-image: url(../../pix/i/completion-auto-fail.gif);
}
.userplan tr.phasetasks li.info {
.mod-workshop .userplan tr.phasetasks li.info {
background-image: url(../../pix/i/info.gif);
}
.userplan tr.phasetasks .tasks {
.mod-workshop .userplan tr.phasetasks .tasks {
list-style:none;
margin: 3px;
padding: 0px;
}
.userplan tr.phasetasks .title {
.mod-workshop .userplan tr.phasetasks .title {
padding: 0px 10px 0px 20px;
}
.userplan tr.phasetasks .details {
.mod-workshop .userplan tr.phasetasks .details {
padding: 0px 10px 0px 25px;
font-size: 80%;
}
@ -322,7 +318,10 @@
/**
* Assessment
*/
.assessment-summary.graded {
.mod-workshop .assessment-summary.graded {
background-color: #e7f1c3;
}
.mod-workshop .assessmentform .description {
margin: 0px 1em;
}

View File

@ -40,16 +40,16 @@ $inactive = array();
$activated = array();
// top level tabs
if (has_capability('mod/workshop:view', $workshop->context)) {
if (has_capability('mod/workshop:view', $PAGE->context)) {
$row[] = new tabobject('info', $workshop->view_url()->out(), get_string('info', 'workshop'));
}
if (has_capability('mod/workshop:editdimensions', $workshop->context)) {
if (has_capability('mod/workshop:editdimensions', $PAGE->context)) {
$row[] = new tabobject('editform', $workshop->editform_url()->out(), get_string('editassessmentform', 'workshop'));
}
if (has_capability('mod/workshop:submit', $workshop->context)) {
if (has_capability('mod/workshop:submit', $PAGE->context)) {
$row[] = new tabobject('submission', $workshop->submission_url()->out(), get_string('submission', 'workshop'));
}
if (has_capability('mod/workshop:allocate', $workshop->context)) {
if (has_capability('mod/workshop:allocate', $PAGE->context)) {
$row[] = new tabobject('allocation', $workshop->allocation_url()->out(), get_string('allocate', 'workshop'));
}
if (has_capability('moodle/site:config', get_system_context())) {

View File

@ -76,7 +76,7 @@ $wsoutput = $PAGE->theme->get_renderer('mod_workshop', $PAGE);
echo $OUTPUT->header();
include(dirname(__FILE__) . '/tabs.php');
echo $OUTPUT->heading(format_string($workshop->name), 2);
echo $wsoutput->user_plan($workshop->prepare_user_plan($USER->id));
echo $wsoutput->user_plan($workshop->prepare_user_plan($USER->id, $PAGE->context));
switch ($workshop->phase) {
case workshop::PHASE_SETUP: