No Error Messages.
Operating Version : Ubuntu 16.04 LTS with apache-2 & mysql for database.
I have to build a plugin for my Institute's Website which uses moodle. Basically the core function of the plugin would be to display a chart : frequency of students(on y-axis) and the Gradeletters(x-axis) stored previously in moodle database for a current Gardeitem.
The Fequency would be determined from the ranges of Lower boundary and Higher Boundary of the particular Grade and these boundaries would be taken input from the teacher.
Let's say for example :
I have Gradeitem selected as Mid-Sem. The finalgrade values of the users enrolled in the Mid-Sem course would be taken from the database and based on the boundaries which teacher enters in the fields would be taken to calculate the frequency. I want the plugin to populate the bar on the chart, as soon as the teacher enters the value in the boundary division of the particular grade.
I have coded the plugin but the chart is not working.
Please find repository for the plugin : https://github.com/omrpakash1996/moodle-plugin
Screenshot of the Current state of the Plugin: https://ibb.co/giY4Tb
What specifically isn't working? What have you done to debug it? Exactly how to reproduce the problem you have?
- https://github.com/omrpakash1996/moodle-plugin/blob/master/js/gradedist.js
- https://github.com/omrpakash1996/moodle-plugin/blob/master/index.php
- https://github.com/omrpakash1996/moodle-plugin/blob/master/ajax_handler.php
- https://github.com/omrpakash1996/moodle-plugin/blob/master/lib.php
- https://github.com/omrpakash1996/moodle-plugin/blob/master/edit_form.php
I don't think anybody - certainly not me - is going to spend loads of time debugging your code without something more specific to go on.
okay let's start with a short piece of code.
$lowerboundaries = new stdClass();
$lowerboundaries= array_fill_keys($letters,null);
$higherboundaries=new stdClass();
$higherboundaries=array_fill_keys($letters,null);
$i=1;
foreach ($letters as $letter){
$lowerboundary = new stdClass();$higherboundary =new stdClass();
$lowerboundary->value=0;$higherboundary->value=0;
$lowerboundary->value='grp_gradeboundaries_lower['.$i.']';$higherboundary->value='grp_gradeboundaries_higher['.$i.']';
$lowerboundaries[$letter]=$lowerboundary;
$higherboundaries[$letter]=$higherboundary;
$i++;
}
$grader = new grade_report_gradedist($course->id, $gpr, $context, $letters,$higherboundaries,$lowerboundaries);
This is the code i am using in ajax_handler and doubts to be wrong on inserting array values. If it is okay I pass the values to
$grader = new grade_report_gradedist($course->id, $gpr, $context, $letters,$higherboundaries,$lowerboundaries);
and in lib.php:
class grade_report_gradedist extends grade_report_grader {
private $letters;
private $higherboundaries;
private $lowerboundaries;
public function __construct($courseid, $gpr, $context, $letters,$higherboundaries,$lowerboundaries, $page=null, $sortitemid=null) {
parent::__construct($courseid, $gpr, $context, $page, $sortitemid);
$this->letters = $letters;
$this->lowerboundaries= new stdClass();
$this->lowerboundaries=$lowerboundaries;
$this->higherboundaries=new stdClass();
$this->higherboundaries=$higherboundaries;
}
I think it will be also fine.. after this in lib.php i do have functions
public function load_distribution($letters, $gradeitem=0, $groupid=0, $groupingid=0) {
global $CFG, $DB;
$this->load_users();
$selectedusers = array();
if ($groupingid == 0) {
if ($groupid == 0) { // Tackle all users.
$selectedusers = $this->users;
} else { // Tackle the users of a single group.
$groupusers = groups_get_members($groupid);
$selectedusers = array_intersect_key($groupusers, $this->users);
}
} else { // Tackle the users of the groups of a grouping.
$groupsusers = groups_get_grouping_members($groupingid);
$selectedusers = array_intersect_key($groupsusers, $this->users);
}
$userids = array_keys($selectedusers);
$sql = "SELECT g.*, gi.grademax, gi.grademin
FROM {grade_items} gi,
{grade_grades} g
WHERE g.itemid = gi.id AND gi.courseid = :courseid
AND g.itemid = :gradeitem";
$params = array('gradeitem' => $gradeitem, 'courseid' => $this->courseid);
//krsort($this->letters); // Just to be sure.
$total = 0;
$count = 0;
$return = new stdClass();
$return->distribution = array_fill_keys($this->letters, null);
$return->coverage = array(0, 0);
foreach ($this->letters as $letter) {
$gradedist = new stdClass();
$gradedist->count = 0;
$return->distribution[$letter] = $gradedist;
}
if ($grades = $DB->get_records_sql($sql, $params)) {
foreach ($grades as $grade) {
if (in_array($grade->userid, $userids) && array_key_exists($grade->itemid, $this->gtree->get_items())) {
// Some items may not be present!!
if (is_null($grade->finalgrade)) {
continue;
}
$total++;
// Calculate gradeletter.
$letter = $this->get_gradeletter($letters, $grade);
if (array_key_exists($letter, $return->distribution)) {
$return->distribution[$letter]->count++;
$count++;
}
}
}
}
$return->coverage = array($total - $count, $total, ($total > 0) ? round(($total - $count) * 100 / $total, 2) : 0);
return $return;
}
public function get_gradeletter($letters, $grade) {
if (is_null($grade->finalgrade) || !$gradeitem = grade_item::fetch(array('id' => $grade->itemid))) {
return '-';
}
// Map to range.
$gradeint = $gradeitem->grademax - $gradeitem->grademin;
$value=$grade->finalgrade;
// Calculate gradeletter.
$value = bounded_number(0, $value, $gradeitem->grademax); // Just in case.
foreach ($this->letters as $letter) {
if (($value <=$this->higherboudaries[$letter]->value)&&($value >= $this->lowerboundaries[$letter]->value)) {
return format_string($letter);
}
else{return '-';}
}
}
Now , if it is fine i will post another doubt in the code.
So...
$this->lowerboundaries= new stdClass();
$this->lowerboundaries=$lowerboundaries;
$this->higherboundaries=new stdClass();
$this->higherboundaries=$higherboundaries
You assign a 'stdclass' object to lowerboundaries and then immediately overwrite it with the $lowerboundaries parameter. What do you think the 'new stdclass' assignment is doing? It might not be wrong as such but it's a sign of some muddled thinking.
So, instead of making new stdClass() for $lowerboundaries and $higherboundaries, should I make two .php files(classes) for the above and do create a object of those. Basically then how should i write the classes as earlier, i was doing like this:
$lowerboundaries = new stdClass();
$lowerboundaries= array_fill_keys($letters,null);
$higherboundaries=new stdClass();
$higherboundaries=array_fill_keys($letters,null);
$i=1;
foreach ($letters as $letter){
$lowerboundary = new stdClass();$higherboundary =new stdClass();
$lowerboundary->value=0;$higherboundary->value=0;
$lowerboundary->value='grp_gradeboundaries_lower['.$i.']';$higherboundary->value='grp_gradeboundaries_higher['.$i.']';
$lowerboundaries[$letter]=$lowerboundary;
$higherboundaries[$letter]=$higherboundary;
$i++;
}
Or any alternate method if you suggest.
I think you might be missing my point. I'm not suggesting that this is your problem, but, I like to eradicate any obvious coding errors. Anyway...
$lowerboundaries = something
$lowerboundaries = something else
You set $lowerboundaries to one thing (new stdClass()) and then immediately, without using it, change it to something else. The stdClass() assignment does nothing. So, this makes me think you don't understand what new stdClass() does. Or something like that.
Okay i got your point, removed new stdClass assignment to both of them and ran it again now no issues but bars are not still coming on the chart when i select the grade item.
Moreover lets move ahead..
In handler file later on i have this
$actdist = $grader->load_distribution($letters, $gradeitem, $groupid, $groupingid);
$data = new stdClass();
$data->actdist = $actdist->distribution;
$data->actcoverage = $actdist->coverage;
$data->courseid = $courseid;
$data->gradeitem = $gradeitem;
$data->title = $gradeitems[$gradeitem]->name;
$data->title .= $chartsubtitle;
$data->updateall = $updateall;
echo json_encode($data);
And further i start with index.php file here i do have same scenario
$boundarieslower = optional_param_array('grp_gradeboundaries_lower',array(),PARAM_TEXT);
$boundarieshigher = optional_param_array('grp_gradeboundaries_higher',array(),PARAM_TEXT);
$lowerboundaries = new stdClass();
$lowerboundaries= array_fill_keys($letters,null);
$higherboundaries=new stdClass();
$higherboundaries=array_fill_keys($letters,null);
$i=1;
foreach ($letters as $letter){
$lowerboundary = new stdClass();$higherboundary =new stdClass();
$lowerboundary->value=0;
$higherboundary->value=0;
$lowerboundary->value='grp_gradeboundaries_lower['.$i.']';
$higherboundary->value='grp_gradeboundaries_higher['.$i.']';
$lowerboundaries[$letter]=$lowerboundary;
$higherboundaries[$letter]=$higherboundary;
$i++;
}
$grader = new grade_report_gradedist($course->id, $gpr, $context, $letters,$higherboundaries,$lowerboundaries);
$mdata = new stdClass();
$mdata->gradeitem = $gradeitem;
$i = 1; $max = 500.01;
foreach ($letters as $boundary => $letter) {
$gradelettername = 'grp_gradeletters['.$i.']';
$mdata->$gradelettername = $letter;
$i++;
}
$groupid = 0; $groupingid = 0;
$actdist = $grader->load_distribution($letters, $gradeitem, $groupid, $groupingid);
$gsel = $grader->group_selector;
$mform = new edit_letter_form($returnurl, array(
'id' => $course->id,
'num' => count($letters),
'edit' => $edit,
'gradeitems' => $gradeitems,
'coursegroups' => $coursegroups,
'coursegroupings' => $coursegroupings,
'groupmode' => $groupmode,
'actcoverage' => $actdist->coverage),
'post', '', array('id' => 'letterform'));
$mform->set_data($mdata);
if (($data = $mform->get_data()) ) {
$gradeitem = new stdClass();
$gradeitem->id = $data->gradeitem;
$gradeitem->name = $gradeitems[$data->gradeitem]->name;
$groupid = isset($data->coursegroup) ? $data->coursegroup : 0;
$groupingid = isset($data->coursegrouping) ? $data->coursegrouping : 0;
}
$data = new stdClass();
$data->courseid = $course->id;
$data->actdist = $actdist->distribution;
$data->actcoverage = $actdist->coverage;
$data->title = $gradeitems[$gradeitem]->name;
$data->highcharts = $highcharts;
// Start output.
$jsmodule = array(
'name' => 'gradereport_gradedist',
'fullpath' => '/grade/report/gradedist/js/gradedist.js',
'requires' => array('io-form'),
'strings' => array(array('interval', 'gradereport_gradedist'),
array('decimals', 'gradereport_gradedist'),
array('predecessor', 'gradereport_gradedist'),
array('coverage', 'gradereport_gradedist'),
array('absolut', 'gradereport_gradedist'),
array('gradeletter', 'gradereport_gradedist'),
array('printchart', 'gradereport_gradedist'),
array('downloadpng', 'gradereport_gradedist'),
array('downloadjpeg', 'gradereport_gradedist'),
array('downloadpdf', 'gradereport_gradedist'),
array('downloadsvg', 'gradereport_gradedist'),
array('contextbuttontitle', 'gradereport_gradedist'),
array('highchartsmissing', 'gradereport_gradedist'),
));
$PAGE->requires->js_init_call('M.gradereport_gradedist.init',
array($data), true, $jsmodule);
print_grade_page_head($course->id, 'report', 'gradedist', get_string('pluginname', 'gradereport_gradedist'));
if ($saved) {
echo $OUTPUT->notification(get_string('saved', 'gradereport_gradedist'), 'notifysuccess');
} else if ($boundaryerror) {
echo $OUTPUT->notification(get_string('boundaryerror', 'gradereport_gradedist'));
}
// Gradedist settings.
$mform->display();
echo $OUTPUT->footer();
Also, there's a few is_null() calls in there. Are you sure about that? That specifically checks for a null value... I think you might be looking for isset() or even empty(). Check carefully, you are using the right one.
i am using isset