category_id = $category_id; } // Loading portal settings + using standard functions. $value = api_get_setting('gradebook_score_display_coloring'); $value = $value['my_display_coloring']; // Setting coloring. $this->coloring_enabled = $value == 'true' ? true : false; if ($this->coloring_enabled) { $value = api_get_setting('gradebook_score_display_colorsplit'); if (isset($value)) { $this->color_split_value = $value; } } //Setting custom enabled $value = api_get_setting('gradebook_score_display_custom'); $value = $value['my_display_custom']; $this->custom_enabled = $value == 'true' ? true : false; if ($this->custom_enabled) { $params = array('category = ?' => array('Gradebook')); $displays = api_get_settings_params($params); $portal_displays = array(); if (!empty($displays)) { foreach ($displays as $display) { $data = explode('::', $display['selected_value']); if (empty($data[1])) { $data[1] = ""; } $portal_displays[$data[0]] = array('score' => $data[0], 'display' => $data[1]); } sort($portal_displays); } $this->custom_display = $portal_displays; if (count($this->custom_display)>0) { $value = api_get_setting('gradebook_score_display_upperlimit'); $value = $value['my_display_upperlimit']; $this->upperlimit_included = $value == 'true' ? true : false; $this->custom_display_conv = $this->convert_displays($this->custom_display); } } //If teachers can override the portal parameters if (api_get_setting('teachers_can_change_score_settings') == 'true') { //Load course settings if ($this->custom_enabled) { $this->custom_display = $this->get_custom_displays(); if (count($this->custom_display)> 0) { $this->custom_display_conv = $this->convert_displays($this->custom_display); } } if ($this->coloring_enabled) { $this->color_split_value = $this->get_score_color_percent(); } } } /** * Get the instance of this class * @param int $category_id */ public static function instance($category_id = 0) { static $instance; if (!isset ($instance)) { $instance = new ScoreDisplay($category_id); } return $instance; } /** * Compare the custom display of 2 scores, can be useful in sorting */ public static function compare_scores_by_custom_display ($score1, $score2) { if (!isset($score1)) { return (isset($score2) ? 1 : 0); } elseif (!isset($score2)) { return -1; } else { $scoredisplay = ScoreDisplay :: instance(); $custom1 = $scoredisplay->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); } } } /** * 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; } /** * 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; } /** * Get current gradebook category id * @return int Category id */ private function get_current_gradebook_category_id() { $tbl_gradebook_category = Database :: get_main_table(TABLE_MAIN_GRADEBOOK_CATEGORY); $curr_course_code = api_get_course_id(); $curr_session_id = api_get_session_id(); if (empty($curr_session_id)) { $session_condition = ' AND session_id is null '; } else { $session_condition = ' AND session_id = '.$curr_session_id; } $sql = 'SELECT id FROM '.$tbl_gradebook_category.' WHERE course_code = "'.$curr_course_code.'" '. $session_condition; $rs = Database::query($sql); $category_id = 0; if (Database::num_rows($rs) > 0) { $row = Database::fetch_row($rs); $category_id = $row[0]; } return $category_id; } /** * Update custom score display settings * @param array $displays 2-dimensional array - every sub array must have keys (score, display) * @param int score color percent (optional) * @param int gradebook category id (optional) */ public function update_custom_score_display_settings($displays, $scorecolpercent = 0, $category_id = null) { $this->custom_display = $displays; $this->custom_display_conv = $this->convert_displays($this->custom_display); if (isset($category_id)) { $category_id = intval($category_id); } else { $category_id = $this->get_current_gradebook_category_id(); } // remove previous settings $table = Database :: get_main_table(TABLE_MAIN_GRADEBOOK_SCORE_DISPLAY); $sql = 'DELETE FROM '.$table.' WHERE category_id = '.$category_id; Database::query($sql); // add new settings $count = 0; foreach ($displays as $display) { $params = [ 'score' => $display['score'], 'display' => $display['display'], 'category_id' => $category_id, 'score_color_percent' => $scorecolpercent, ]; Database::insert($table, $params); $count++; } } /** * @param int $category_id * @return false|null */ public function insert_defaults($category_id) { if (empty($category_id)) { return false; } //Get this from DB settings $display = array( 50 => get_lang('GradebookFailed'), 60 => get_lang('GradebookPoor'), 70 => get_lang('GradebookFair'), 80 => get_lang('GradebookGood'), 90 => get_lang('GradebookOutstanding'), 100 => get_lang('GradebookExcellent') ); $tbl_display = Database :: get_main_table(TABLE_MAIN_GRADEBOOK_SCORE_DISPLAY); foreach($display as $value => $text) { $params = array( 'score' => $value, 'display' => $text, 'category_id' => $category_id, 'score_color_percent' => 0, ); Database::insert($tbl_display, $params); } } /** * @return integer */ public function get_number_decimals() { $number_decimals = api_get_setting('gradebook_number_decimals'); if (!isset($number_decimals)) { $number_decimals = 0; } return $number_decimals; } /** * Formats a number depending of the number of decimals * * @param float $score * @return float the score formatted */ public function format_score($score) { return floatval(number_format($score, $this->get_number_decimals())); } /** * Display a score according to the current settings * @param array $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) * * @return string */ public function display_score( $score, $type = SCORE_DIV_PERCENT, $what = SCORE_BOTH, $no_color = false ) { $my_score = $score == 0 ? 1 : $score; if ($type == SCORE_BAR) { $percentage = $my_score[0]/$my_score[1]*100; return Display::bar_progress($percentage); } if ($type == SCORE_SIMPLE) { $simple_score = $this->format_score($my_score[0]); return $simple_score; } if ($this->custom_enabled && isset($this->custom_display_conv)) { $display = $this->display_default($my_score, $type); } else { // if no custom display set, use default display $display = $this->display_default($my_score, $type); } if ($this->coloring_enabled && $no_color == false) { $my_score_denom = isset($score[1]) && !empty($score[1]) ? $score[1] : 1; $scoreCleaned = isset($score[0]) ? $score[0] : 0; if (($scoreCleaned / $my_score_denom) < ($this->color_split_value / 100)) { $display = Display::tag('font', $display, array('color'=>'red')); } } return $display; } /** * @param $score * @param integer $type * @return string */ 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); case SCORE_DECIMAL : // 0.50 (X/Y) return $this->display_as_decimal($score); case SCORE_DIV_PERCENT_WITH_CUSTOM : // X / Y (XX %) - Good! $custom = $this->display_custom($score); if (!empty($custom)) { $custom = ' - '.$custom; } return $this->display_as_div($score).' (' . $this->display_as_percent($score) . ')'.$custom; case SCORE_DIV_SIMPLE_WITH_CUSTOM : // X - Good! $custom = $this->display_custom($score); if (!empty($custom)) { $custom = ' - '.$custom; } return $this->display_simple_score($score).$custom; break; case SCORE_DIV_SIMPLE_WITH_CUSTOM_LETTERS: $custom = $this->display_custom($score); if (!empty($custom)) { $custom = ' - '.$custom; } $score = $this->display_simple_score($score); //needs sudo apt-get install php5-intl if (class_exists('NumberFormatter')) { $iso = api_get_language_isocode(); $f = new NumberFormatter($iso, NumberFormatter::SPELLOUT); $letters = $f->format($score); $letters = api_strtoupper($letters); $letters = " ($letters) "; } return $score.$letters.$custom; break; case SCORE_CUSTOM: // Good! return $this->display_custom($score); } } /** * @param array $score * @return float|string */ private function display_simple_score($score) { if (isset($score[0])) { return $this->format_score($score[0]); } return ''; } /** * Returns "1" for array("100", "100"); * @param array $score * @return float */ private function display_as_decimal($score) { $score_denom = ($score[1]==0) ? 1 : $score[1]; return $this->format_score($score[0]/$score_denom); } /** * Returns "100 %" for array("100", "100"); */ private function display_as_percent($score) { $score_denom = ($score[1]==0) ? 1 : $score[1]; return $this->format_score($score[0]/$score_denom*100) . ' %'; } /** * Returns 10.00 / 10.00 for array("100", "100"); * @param array $score * * @return string */ private function display_as_div($score) { if ($score == 1) { return '0 / 0'; } else { $score[0] = isset($score[0]) ? $this->format_score($score[0]) : 0; $score[1] = isset($score[1]) ? $this->format_score($score[1]) : 0; return $score[0] . ' / ' . $score[1]; } } /** * Depends on the teacher's configuration of thresholds. i.e. [0 50] "Bad", [50:100] "Good" * @param array $score */ 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 { if (!empty($this->custom_display_conv)) { foreach ($this->custom_display_conv as $displayitem) { if ($scaledscore < $displayitem['score'] || $displayitem['score'] == 1) { return $displayitem['display']; } } } } } /** * Get score color percent by category * @param int Gradebook category id * @return int Score */ private function get_score_color_percent($category_id = null) { $tbl_display = Database :: get_main_table(TABLE_MAIN_GRADEBOOK_SCORE_DISPLAY); if (isset($category_id)) { $category_id = intval($category_id); } else { $category_id = $this->get_current_gradebook_category_id(); } $sql = 'SELECT score_color_percent FROM '.$tbl_display.' WHERE category_id = '.$category_id.' LIMIT 1'; $result = Database::query($sql); $score = 0; if (Database::num_rows($result) > 0) { $row = Database::fetch_row($result); $score = $row[0]; } return $score; } /** * Get current custom score display settings * @param int Gradebook category id * @return array 2-dimensional array every element contains 3 subelements (id, score, display) */ private function get_custom_displays($category_id = null) { $tbl_display = Database :: get_main_table(TABLE_MAIN_GRADEBOOK_SCORE_DISPLAY); if (isset($category_id)) { $category_id = intval($category_id); } else { $category_id = $this->get_current_gradebook_category_id(); } $sql = 'SELECT * FROM '.$tbl_display.' WHERE category_id = '.$category_id.' ORDER BY score'; $result = Database::query($sql); return Database::store_result($result,'ASSOC'); } /** * 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(); if (isset($highest) && !empty($highest) && $highest > 0) { $newelement['score'] = $element['score'] / $highest; } else { $newelement['score'] = 0; } $newelement['display'] = $element['display']; $converted2[] = $newelement; } return $converted2; } else { return null; } } /** * @param array $item1 * @param array $item2 * @return int */ private function sort_display($item1, $item2) { if ($item1['score'] === $item2['score']) { return 0; } else { return ($item1['score'] < $item2['score'] ? -1 : 1); } } }