Parent Directory
|
Revision Log
CONTRIB-497 *Added more visualizations *Added selector UI Widget for flex/flare visualization *Refactored some of flex actionscript code. *Added defaults for selected group and items in visualizations. *Improved removal of nodes and edges when an item or group is deselected in a legend. *Fixed a memory leak realting to the removal and addtion of nodes. *Added more options for and control of the flex/flare based visualization from the Moodle back end.
<?php
///////////////////////////////////////////////////////////////////////////
// //
// NOTICE OF COPYRIGHT //
// //
// Moodle - Modular Object-Oriented Dynamic Learning Environment //
// http://moodle.org //
// //
// Copyright (C) 1999 onwards Martin Dougiamas http://moodle.com //
// //
// This program is free software; you can redistribute it and/or modify //
// it under the terms of the GNU General Public License as published by //
// the Free Software Foundation; either version 2 of the License, or //
// (at your option) any later version. //
// //
// This program is distributed in the hope that it will be useful, //
// but WITHOUT ANY WARRANTY; without even the implied warranty of //
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the //
// GNU General Public License for more details: //
// //
// http://www.gnu.org/copyleft/gpl.html //
// //
///////////////////////////////////////////////////////////////////////////
require_once($CFG->dirroot . '/grade/report/lib.php');
require_once($CFG->libdir.'/tablelib.php');
foreach (glob($CFG->dirroot . '/grade/report/visual/visualizations/visual_*.php') as $filename) {
require_once($filename);
}
class grade_report_visual extends grade_report {
/**
* Capability to view hidden items.
* TODO: Add a check for hidden items and grades.
* @var bool $canviewhidden
*/
public $canviewhidden;
public $nullgradesasmin = false;
private static $visualizations = array();
/**
* Grade objects of users in the course
* @var array $grades
*/
public $grades = array();
private $visdata = array();
private $visid = 'grades_vs_students';
private $flashvars = array();
private $flashvarshtml;
/**
* The html of the report to output.
* @var string $html
*/
public $html;
/**
* Constructor. Initialises grade_tree, sets up group, baseurl
* and pbarurl.
* @param int $courseid the coures id for the report
* @param object $gpr grade plugin tracking object
* @context string $context
*/
public function __construct($courseid, $gpr, $context, $visid=null) {
global $CFG;
parent::__construct($courseid, $gpr, $context, null);
$this->canviewhidden = has_capability('moodle/grade:viewhidden', get_context_instance(CONTEXT_COURSE, $this->course->id));
if(!is_null($visid)) {
$this->visid = $visid;
}
/// Set up urls
$this->baseurl = 'index.php?id=' . $this->courseid;
$this->pbarurl = 'index.php?id=' . $this->courseid;
/// Build grade tree
$this->gtree = new grade_tree($this->courseid, false);
$this->load_visualizations();
$this->set_up_flashvars();
/// Set up Groups
if($visid && grade_report_visual::get_visualization($visid)->usegroups) {
$this->setup_groups();
}
}
/// Added to keep grade_report happy
public function process_data($data){}
public function process_action($target, $action){}
/**
* Load all the visualization classes into $visualizations.
* Looks in /visualizations and trys to make an instence of any
* class that is in a file that starts with visual_ and extends
* visualization directly.
* @param bool $return if true return visualizations array, else store in $this->visualizations
* @returns array array of clases that extend visualization
*/
private function load_visualizations($return=false) {
global $CFG;
if(!isset(grade_report_visual::$visualizations) || is_null(grade_report_visual::$visualizations) || empty(grade_report_visual::$visualizations)) {
$visualizations = array();
foreach (glob($CFG->dirroot . '/grade/report/visual/visualizations/visual_*.php') as $path) {
$filename = substr(basename($path, '.php'), 7);
if(class_exists($filename) && get_parent_class($class = new $filename) == 'visualization' ) {
$visualizations[$filename] = $class;
}
}
if($return) {
return $visualizations;
} else {
grade_report_visual::$visualizations = $visualizations;
}
} else if($return) {
return grade_report_visual::$visualizations;
}
}
/**
* Returns the current visualizations being used in the report
* or if none are set, it returns the them as whould be loaded
* by load_visualizations.
* @returns array array of classes that extend visualization
*/
public function get_visualizations() {
if(!isset(grade_report_visual::$visualizations) || is_null(grade_report_visual::$visualizations) || empty(grade_report_visual::$visualizations)) {
return grade_report_visual::load_visualizations(true);
} else {
return grade_report_visual::$visualizations;
}
}
public function get_visualization($filename) {
if(!isset(grade_report_visual::$visualizations) || is_null(grade_report_visual::$visualizations) || empty(grade_report_visual::$visualizations) || is_null(grade_report_visual::$visualizations[$filename])) {
if(class_exists($filename) && get_parent_class($class = new $filename) == 'visualization' ) {
return $class;
} else {
return null;
}
} else {
return grade_report_visual::$visualizations[$filename];
}
}
/**
* Based on load user function from grader report.
* Pulls out the userids of the users to be used in the stats.
* @return array array of user ids to use in stats
*/
public function load_users() {
global $CFG, $DB;
if(isset($DB) && !is_null($DB)) {
$params = array();
list($usql, $gbr_params) = $DB->get_in_or_equal(explode(',', $this->gradebookroles));
$sql = "SELECT u.id, u.firstname, u.lastname, u.imagealt, u.picture, u.idnumber, u.username
FROM {user} u
JOIN {role_assignments} ra ON u.id = ra.userid
$this->groupsql
WHERE ra.roleid $usql
$this->groupwheresql
AND ra.contextid ".get_related_contexts_string($this->context);
$params = array_merge($gbr_params, $this->groupwheresql_params);
$this->users = $DB->get_records_sql($sql, $params);
} else {
$sql = "SELECT u.id, u.firstname, u.lastname, u.imagealt, u.picture, u.idnumber
FROM {$CFG->prefix}user u
JOIN {$CFG->prefix}role_assignments ra ON u.id = ra.userid
$this->groupsql
WHERE ra.roleid in ($this->gradebookroles)
$this->groupwheresql
AND ra.contextid ".get_related_contexts_string($this->context);
$this->users = get_records_sql($sql);
}
if (empty($this->users)) {
$this->userselect = '';
$this->users = array();
$this->userselect_params = array();
} else {
if(isset($DB) && !is_null($DB)) {
list($usql, $params) = $DB->get_in_or_equal(array_keys($this->users));
$this->userselect = "AND g.userid $usql";
$this->userselect_params = $params;
}else{
$this->userselect = 'AND g.userid in ('.implode(',', array_keys($this->users)).')';
}
}
return $this->users;
}
/**
* Harvest the grades from the data base and build the finalgrades array.
* Filters out hidden, locked and null grades based on users settings.
* Partly based on grader reports load_final_grades function.
*/
public function harvest_data() {
global $CFG, $DB;
$params = array();
if(isset($DB) && !is_null($DB)) {
$params = array_merge(array($this->courseid), $this->userselect_params);
/// please note that we must fetch all grade_grades fields if we want to contruct grade_grade object from it!
$sql = "SELECT g.*
FROM {grade_items} gi,
{grade_grades} g
WHERE g.itemid = gi.id AND gi.courseid = ? {$this->userselect}";
$grades = $DB->get_records_sql($sql, $params);
} else {
/// please note that we must fetch all grade_grades fields if we want to contruct grade_grade object from it!
$sql = "SELECT g.*
FROM {$CFG->prefix}grade_items gi,
{$CFG->prefix}grade_grades g
WHERE g.itemid = gi.id AND gi.courseid = {$this->courseid} {$this->userselect}";
$grades = get_records_sql($sql);
}
$userids = array_keys($this->users);
if ($grades) {
foreach ($grades as $graderec) {
if (in_array($graderec->userid, $userids) and array_key_exists($graderec->itemid, $this->gtree->items)) { // some items may not be present!!
$this->grades[$graderec->itemid][$graderec->userid] = new grade_grade($graderec, false);
$this->grades[$graderec->itemid][$graderec->userid]->grade_item =& $this->gtree->items[$graderec->itemid]; // db caching
}
}
}
if($this->nullgradesasmin) {
/// prefil grades that do not exist yet
foreach ($userids as $userid) {
foreach ($this->gtree->items as $itemid=>$unused) {
if (!isset($this->grades[$itemid][$userid])) {
$this->grades[$itemid][$userid] = new grade_grade();
$this->grades[$itemid][$userid]->itemid = $itemid;
$this->grades[$itemid][$userid]->userid = $userid;
$this->grades[$itemid][$userid]->grade_item =& $this->gtree->items[$itemid]; // db caching
$this->grades[$itemid][$userid]->finalgrade = $this->grades[$itemid][$userid]->grade_item->mingrade;
}
}
}
}
/*$this->finalgrades = array();
/// Build finalgrades array and filliter out unwanted grades.
foreach ($this->gtree->items as $id=>$item) {
if(($item->gradetype == GRADE_TYPE_SCALE && ($this->get_pref('stats', 'showscaleitems') || is_null($this->get_pref('stats', 'showscaleitems'))))
|| ($item->gradetype == GRADE_TYPE_VALUE && ($this->get_pref('stats', 'showvalueitems') || is_null($this->get_pref('stats', 'showvalueitems'))))) {
$this->finalgrades[$id] = array();
$i = 0;
if(isset($this->grades[$id]) && !is_null($this->grades[$id])) {
foreach ($this->grades[$id] as $grade) {
if( (($grade->is_hidden() && ($this->get_pref('stats', 'usehidden') || is_null($this->get_pref('stats', 'usehidden')))) || !$grade->is_hidden())
&& (($grade->is_locked() && ($this->get_pref('stats', 'uselocked') || is_null($this->get_pref('stats', 'uselocked')))) || !$grade->is_locked())) {
if($this->get_pref('stats', 'incompleasmin') && is_null($grade->finalgrade)) {
$this->finalgrades[$id][$i] = $item->grademin;
$i++;
} elseif(!is_null($grade->finalgrade)) {
$this->finalgrades[$id][$i] = $grade->finalgrade;
$i++;
}
}
}
}
}
}*/
}
/**
* TODO: have this make the data depending on what kind of visulsation
* is needed rather then a singal visulasztion witch is currently hardcoded.
*/
public function report_data($all = false) {
if($all) {
$visuals = $this->get_visualizations();
foreach($visuals as $key=>$visual) {
$this->visdata[$key] = $visual->report_data($this);
}
} else {
$visual = $this->get_visualization($this->visid);
$this->visdata[$this->visid] = $visual->report_data($this);
}
}
private function set_up_flashvars() {
global $USER, $SESSION, $CFG;
$flashvars = array();
$flashvars['username'] = $USER->username;
$flashvars['userid'] = $USER->id;
$flashvars['courseid'] = $this->courseid;
$flashvars['coursefullname'] = $this->course->fullname;
$flashvars['courseshortname'] = $this->course->shortname;
$flashvars['sessionid'] = session_id();
$flashvars['sessioncookie'] = $CFG->sessioncookie;
$flashvars['sessiontest'] = $SESSION->session_test;
$flashvars['dirroot'] = $CFG->dirroot;
$flashvars['wwwroot'] = $CFG->wwwroot;
$flashvars['visid'] = $this->visid;
foreach($flashvars as $key=>$val) {
$this->flashvarshtml .= $key. '=' . addslashes(urlencode(strip_tags($val))) . '&';
}
$this->flashvarshtml = substr($this->flashvarshtml, 0, strlen($this->flashvarshtml) - 1);
}
/**
*TODO: Have this call on flex.php to generate html for the report.,
*rather then having it hardcoded as it is now.
*/
public function adapt_html($printerversion = false, $return = false) {
global $CFG;
$flashvarshtml = $this->flashvarshtml;
$visual = $this->get_visualization($this->visid);
ob_start();
require($CFG->dirroot.'/grade/report/visual/flex.php');
$this->html = ob_get_clean();
if($return) {
return $this->html;
} else {
echo $this->html;
}
}
public function adapt_data($return = false) {
if($return) {
return $this->get_tab(true);
} else {
echo $this->get_tab(true);
}
}
public function visualization_selector($return = false) {
$visuals = $this->get_visualizations();
$visualmenu = array();
$vislabel = $this->get_lang_string('visualselector', 'gradereport_visual');
foreach($visuals as $key=>$visual) {
$visualmenu[$key] = format_string($visual->name);
}
if(count($visualmenu) > 1) {
$selectorhtml = popup_form($this->pbarurl . '&visid=', $visualmenu, 'selectvisual', $this->visid, '', '', '', true, 'self', $vislabel);
} else {
$selectorhtml = '';
}
if($return) {
return $selectorhtml;
} else {
echo $selectorhtml;
}
}
public static function truncate($string, $max = 25, $end = '...') {
if(strlen($string) <= $max) {
return $string;
}
return substr_replace($string, $end, $max - strlen($end));
}
/**
* Returns the data for a visulazation in json format.
* TODO: Use moodle's json encoding functions rather then phps.
* @param boolean $return if true return a string, other wise echo the data.
* @return string If return is set to true, returns a string of the data in json format.
*/
private function get_json($return = true) {
if ($return) {
return json_encode($this->visdata[$this->visid]);
} else {
echo json_encode($this->visdata[$this->visid]);
}
}
/**
* Returns the data for a visulasation in tab format.
* @param boolean $return if true return a string, other wise echo the data.
* @return string If return is set to true, returns a string of the data in tab format.
*/
private function get_tab($return = true) {
if ($return) {
return $this->tab_encode($this->visdata[$this->visid]);
} else {
echo $this->tab_encode($this->visdata[$this->visid]);
}
}
/**
* Encodes an array to a string using the tab format.
*@param array $data the array to encode.
*@return string a string encoded in tab format based on the given array.
*/
public static function tab_encode(array $data, $useindexes = false) {
$outstring = '';
foreach($data as $key=>$row) {
if(is_array($row)) {
if($useindexes) {
$outstring .= $key . "\t";
}
foreach($row as $col) {
$outstring .= $col . "\t";
}
$outstring[strlen($outstring) - 1] = "\n";
} else {
if($useindexes) {
$outstring .= $key . "\t" . $row . "\n";
} else {
$outstring .= $row . "\n";
}
}
}
return $outstring;
}
}
?>
| Moodle CVS Admin | ViewVC Help |
| Powered by ViewVC 1.0.7 |