display_custom($score1); $custom2 = $scoredisplay->display_custom($score2); if ($custom1 == $custom2) { return 0; } else { return (($score1[0]/$score1[1]) < ($score2[0]/$score2[1]) ? -1 : 1); } } } // As object private $coloring_enabled; private $color_split_value; private $custom_enabled; private $upperlimit_included; private $custom_display; private $custom_display_conv; /** * Protected constructor - call instance() to instantiate */ protected function ScoreDisplay() { $this->coloring_enabled = $this->load_bool_setting('gradebook_score_display_coloring',0); if ($this->coloring_enabled) { $this->color_split_value = $this->load_int_setting('gradebook_score_display_colorsplit',50); } $this->custom_enabled = $this->load_bool_setting('gradebook_score_display_custom', 0); if ($this->custom_enabled) { $this->upperlimit_included = $this->load_bool_setting('gradebook_score_display_upperlimit', 0); $this->custom_display = $this->get_custom_displays(); $this->custom_display_conv = $this->convert_displays($this->custom_display); } } /** * Is coloring enabled ? */ public function is_coloring_enabled () { return $this->coloring_enabled; } /** * Is custom score display enabled ? */ public function is_custom () { return $this->custom_enabled; } /** * Is upperlimit included ? */ public function is_upperlimit_included () { return $this->upperlimit_included; } /** * Update the 'coloring' setting * @param boolean $coloring coloring enabled or disabled */ public function set_coloring_enabled ($coloring) { $this->coloring_enabled = $coloring; $this->save_bool_setting ('gradebook_score_display_coloring', $coloring); } /** * Update the 'colorsplit' setting * @param int $colorsplit color split value, in percent */ public function set_color_split_value ($colorsplit) { $this->color_split_value = $colorsplit; $this->save_int_setting ('gradebook_score_display_colorsplit', $colorsplit); } /** * Update the 'custom' setting * @param boolean $custom custom enabled or disabled */ public function set_custom ($custom) { $this->custom_enabled = $custom; $this->save_bool_setting ('gradebook_score_display_custom', $custom); } /** * Update the 'upperlimit' setting * @param boolean $upperlimit_included true if upper limit must be included, false otherwise */ public function set_upperlimit_included ($upperlimit_included) { $this->upperlimit_incl = $upperlimit_included; $this->save_bool_setting ('gradebook_score_display_upperlimit', $upperlimit_included); } /** * If custom score display is enabled, this will return the current settings. * See also update_custom_score_display_settings * @return array current settings (or null if feature not enabled) */ public function get_custom_score_display_settings() { return $this->custom_display; } /** * If coloring is enabled, scores below this value will be displayed in red. * @return int color split value, in percent (or null if feature not enabled) */ public function get_color_split_value() { return $this->color_split_value; } /** * Update custom score display settings * @param array $displays 2-dimensional array - every subarray must have keys (score, display) */ public function update_custom_score_display_settings ($displays) { $this->custom_display = $displays; $this->custom_display_conv = $this->convert_displays($this->custom_display); // remove previous settings $tbl_display = Database :: get_main_table(TABLE_MAIN_GRADEBOOK_SCORE_DISPLAY); $sql = 'TRUNCATE TABLE '.$tbl_display; api_sql_query($sql, __FILE__, __LINE__); // add new settings $sql = 'INSERT INTO '.$tbl_display.' (id, score, display) VALUES '; $count = 0; foreach ($displays as $display) { if ($count > 0) { $sql .= ','; } $sql .= "(NULL, '".$display['score']."', '".Database::escape_string($display['display'])."')"; $count++; } api_sql_query($sql, __FILE__, __LINE__); } /** * Display a score according to the current settings * @param array $score score data structure, as returned by the calc_score functions * @param int $type one of the following constants: SCORE_DIV, SCORE_PERCENT, SCORE_DIV_PERCENT, SCORE_AVERAGE * (ignored for student's view if custom score display is enabled) * @param int $what one of the following constants: SCORE_BOTH, SCORE_ONLY_DEFAULT, SCORE_ONLY_CUSTOM (default: SCORE_BOTH) * (only taken into account if custom score display is enabled and for course/platform admin) */ public function display_score($score,$type,$what = SCORE_BOTH) { $type2 = $type & 7; // removes the 'SCORE_IGNORE_SPLIT' bit $split_enabled = ($type2 == $type); $my_score=($score==0) ? 1 : $score; if ($this->custom_enabled && isset($this->custom_display_conv)) { // students only see the custom display if (!api_is_allowed_to_create_course()) { $display = $this->display_custom($my_score); } // course/platform admins elseif ($what == SCORE_ONLY_DEFAULT) { $display = $this->display_default ($my_score, $type2); } elseif ($what == SCORE_ONLY_CUSTOM) { $display = $this->display_custom ($my_score); } else { $display = $this->display_default ($my_score, $type2); if ($this->display_custom ($my_score)!='') $display.= ' ('.$this->display_custom ($my_score).')'; } } else { // if no custom display set, use default display $display = $this->display_default ($my_score, $type2); } return (($split_enabled ? $this->get_color_display_start_tag($my_score) : '') . $display . ($split_enabled ? $this->get_color_display_end_tag($my_score) : '')); } // Internal functions private function display_default ($score, $type) { switch ($type) { case SCORE_DIV : // X / Y return $this->display_as_div($score); case SCORE_PERCENT : // XX % return $this->display_as_percent($score); case SCORE_DIV_PERCENT : // X / Y (XX %) return $this->display_as_div($score) . ' (' . $this->display_as_percent($score) . ')'; case SCORE_AVERAGE : // XX % return $this->display_as_percent($score); } } private function display_as_percent ($score) { $score_denom=($score[1]==0) ? 1 : $score[1]; return round(($score[0] / $score_denom) * 100,2) . ' %'; } private function display_as_div ($score) { if ($score==1) { return '0/0'; } else { return $score[0] . ' / ' . $score[1]; } } private function display_custom ($score) { $my_score_denom= ($score[1]==0)?1:$score[1]; $scaledscore = $score[0] / $my_score_denom; if ($this->upperlimit_included) { foreach ($this->custom_display_conv as $displayitem) { if ($scaledscore <= $displayitem['score']) { return $displayitem['display']; } } } else { foreach ($this->custom_display_conv as $displayitem) { if ($scaledscore < $displayitem['score'] || $displayitem['score'] == 1) { return $displayitem['display']; } } } } private function load_bool_setting ($property, $default = 0) { $value = $this->load_int_setting($property, $default); return ($value == 'true' ? true : false); } private function load_int_setting ($property, $default = 0) { $tbl_setting = Database :: get_main_table(TABLE_MAIN_SETTINGS_CURRENT); $sql = "SELECT selected_value FROM ".$tbl_setting ." WHERE category = 'Gradebook' AND variable = '".$property."'"; $result = api_sql_query($sql, __FILE__, __LINE__); if ($data = Database::fetch_row($result)) { return $data[0]; } else { // if not present, add default setting into table... $sql = "INSERT INTO ".$tbl_setting ." (variable, selected_value, category)" ." VALUES ('".$property."', '".$default."','Gradebook')"; api_sql_query($sql, __FILE__, __LINE__); // ...and return default value return $default; } } private function save_bool_setting ($property, $value) { $this->save_int_setting ($property, ($value ? 'true' : 'false') ); } private function save_int_setting ($property, $value) { $tbl_setting = Database :: get_main_table(TABLE_MAIN_SETTINGS_CURRENT); $sql = 'UPDATE '.$tbl_setting ." SET selected_value = '".$value."' " ." WHERE variable = '".$property."' AND category='Gradebook'"; api_sql_query($sql, __FILE__, __LINE__); } /** * Get current custom score display settings * @return array 2-dimensional array - every element contains 3 subelements (id, score, display) */ private function get_custom_displays() { $tbl_display = Database :: get_main_table(TABLE_MAIN_GRADEBOOK_SCORE_DISPLAY); $sql = 'SELECT * FROM '.$tbl_display.' ORDER BY score'; //echo $sql; $result = api_sql_query($sql, __FILE__, __LINE__); return api_store_result($result); } /** * Convert display settings to internally used values */ private function convert_displays($custom_display) { if (isset($custom_display)) { // get highest score entry, and copy each element to a new array $converted = array(); $highest = 0; foreach ($custom_display as $element) { if ($element['score'] > $highest) { $highest = $element['score']; } $converted[] = $element; } // sort the new array (ascending) usort($converted, array('ScoreDisplay', 'sort_display')); // adjust each score in such a way that // each score is scaled between 0 and 1 // the highest score in this array will be equal to 1 $converted2 = array(); foreach ($converted as $element) { $newelement = array(); $newelement['score'] = $element['score'] / $highest; $newelement['display'] = $element['display']; $converted2[] = $newelement; } return $converted2; } else { return null; } } private function sort_display ($item1, $item2) { if ($item1['score'] == $item2['score']) { return 0; } else { return ($item1['score'] < $item2['score'] ? -1 : 1); } } private function get_color_display_start_tag($score) { $my_score_denom=($score[1]==0)?1:$score[1]; if ($this->coloring_enabled && ($score[0]/$my_score_denom) < ($this->color_split_value / 100)) { return ''; } else { return ''; } } private function get_color_display_end_tag($score) { $my_score_denom=($score[1]==0)?1:$score[1]; if ($this->coloring_enabled && ($score[0]/$my_score_denom) < ($this->color_split_value / 100)) { return ''; } else { return ''; } } }