Browse Source

Adding ranking concept in gradebook items see BT#9428

Julio Montoya 10 years ago
parent
commit
27c7989031

+ 25 - 0
main/gradebook/lib/be/abstractlink.class.php

@@ -521,4 +521,29 @@ abstract class AbstractLink implements GradebookItem
         $sql = "UPDATE $table SET locked = '".intval($locked)."' WHERE id='".$this->id."'";
         Database::query($sql);
     }
+
+    /**
+     * Get current user ranking
+     * @param array $studentList Array with user id and scores
+     * Example: [1 => 5.00, 2 => 8.00]
+     */
+    public static function getCurrentUserRanking($studentList)
+    {
+        $ranking = null;
+        $currentUserId = api_get_user_id();
+        if (!empty($studentList) && !empty($currentUserId)) {
+            asort($studentList);
+            $ranking = $count = count($studentList);
+
+            foreach ($studentList as $userId => $position) {
+                if ($currentUserId == $userId) {
+                    break;
+                }
+                $ranking--;
+            }
+            return array($ranking, $count);
+        }
+
+        return array();
+    }
 }

+ 42 - 21
main/gradebook/lib/be/attendancelink.class.php

@@ -131,7 +131,10 @@ class AttendanceLink extends AbstractLink
 
 		// get attendance qualify max
 		$sql = 'SELECT att.attendance_qualify_max FROM '.$this->get_attendance_table().' att
-  				WHERE att.c_id = '.$this->course_id.' AND att.id = '.intval($this->get_ref_id()).' AND att.session_id='.intval($session_id).'';
+  				WHERE
+  					att.c_id = '.$this->course_id.' AND
+  					att.id = '.intval($this->get_ref_id()).' AND
+  					att.session_id='.intval($session_id).'';
 		$query = Database::query($sql);
 		$attendance = Database::fetch_array($query);
 
@@ -175,23 +178,29 @@ class AttendanceLink extends AbstractLink
 			if ($rescount == 0) {
 				return null;
 			} else {
-				if ($type == 'best') {
-					return array($bestResult, $weight);
+				switch ($type) {
+					case 'best':
+						return array($bestResult, $weight);
+						break;
+					case 'average':
+						return array($sumResult / $rescount, $weight);
+						break;
+					case 'ranking':
+						return AbstractLink::getCurrentUserRanking($students);
+						break;
+					default:
+						return array($sum, $rescount);
+						break;
 				}
-				if ($type == 'average') {
-					return array($sumResult/$rescount, $weight);
-				}
-				return array($sum , $rescount);
 			}
 		}
 	}
 
-	// INTERNAL FUNCTIONS
-
 	/**
 	 * Lazy load function to get the database table of the student publications
 	 */
-	private function get_attendance_table() {
+	private function get_attendance_table()
+	{
 		$this->attendance_table = Database :: get_course_table(TABLE_ATTENDANCE);
 		return $this->attendance_table;
 	}
@@ -199,19 +208,24 @@ class AttendanceLink extends AbstractLink
 	/**
 	 * Lazy load function to get the database table of the item properties
 	 */
-	private function get_itemprop_table () {
+	private function get_itemprop_table()
+	{
 		$this->itemprop_table = Database :: get_course_table(TABLE_ITEM_PROPERTY);
 		return $this->itemprop_table;
 	}
 
-	public function needs_name_and_description() {
+	public function needs_name_and_description()
+	{
 		return false;
 	}
-	public function needs_max() {
+
+	public function needs_max()
+	{
 		return false;
 	}
 
-	public function needs_results() {
+	public function needs_results()
+	{
 		return false;
 	}
 
@@ -227,13 +241,16 @@ class AttendanceLink extends AbstractLink
 		}
 	}
 
-	public function get_description() {
+	public function get_description()
+	{
 		return '';
 	}
+
 	/**
 	 * Check if this still links to an exercise
 	 */
-	public function is_valid_link() {
+	public function is_valid_link()
+	{
 		$session_id = api_get_session_id();
 		$sql = 'SELECT count(att.id) FROM '.$this->get_attendance_table().' att
         		 WHERE att.c_id = '.$this->course_id.' AND att.id = '.intval($this->get_ref_id()).' ';
@@ -242,23 +259,26 @@ class AttendanceLink extends AbstractLink
 		return ($number[0] != 0);
 	}
 
-	public function get_test_id() {
+	public function get_test_id()
+	{
 		return 'DEBUG:ID';
 	}
 
-	public function get_link() {
+	public function get_link()
+	{
 		//it was extracts the attendance id
 		$session_id = api_get_session_id();
 		$sql = 'SELECT * FROM '.$this->get_attendance_table().' att
     			WHERE att.c_id = '.$this->course_id.' AND att.id = '.intval($this->get_ref_id()).' ';
 		$result = Database::query($sql);
-		$row    = Database::fetch_array($result,'ASSOC');
+		$row = Database::fetch_array($result,'ASSOC');
 		$attendance_id = $row['id'];
 		$url = api_get_path(WEB_PATH).'main/attendance/index.php?action=attendance_sheet_list&gradebook=view&attendance_id='.$attendance_id.'&session_id='.$session_id.'&cidReq='.$this->get_course_code();
 		return $url;
 	}
 
-	private function get_attendance_data() {
+	private function get_attendance_data()
+	{
 		$tbl_name = $this->get_attendance_table();
 		$session_id = api_get_session_id();
 		if ($tbl_name == '') {
@@ -272,7 +292,8 @@ class AttendanceLink extends AbstractLink
 		return $this->attendance_data;
 	}
 
-	public function get_icon_name() {
+	public function get_icon_name()
+	{
 		return 'attendance';
 	}
 }

+ 79 - 19
main/gradebook/lib/be/category.class.php

@@ -61,6 +61,9 @@ class Category implements GradebookItem
         return $this->user_id;
     }
 
+    /**
+     * @return float
+     */
     public function get_certificate_min_score()
     {
         if (!empty($this->certificate_min_score)) {
@@ -78,56 +81,89 @@ class Category implements GradebookItem
         return $this->course_code;
     }
 
+    /**
+     * @return mixed
+     */
     public function get_parent_id()
     {
         return $this->parent;
     }
 
+    /**
+     * @return mixed
+     */
     public function get_weight()
     {
         return $this->weight;
     }
 
+    /**
+     * @return bool
+     */
     public function is_locked()
     {
         return isset($this->locked) && $this->locked == 1 ? true : false;
     }
 
+    /**
+     * @return mixed
+     */
     public function is_visible()
     {
         return $this->visible;
     }
 
+    /**
+     * @param int $id
+     */
     public function set_id($id)
     {
         $this->id = $id;
     }
 
+    /**
+     * @param string $name
+     */
     public function set_name($name)
     {
         $this->name = $name;
     }
 
+    /**
+     * @param string $description
+     */
     public function set_description($description)
     {
         $this->description = $description;
     }
 
+    /**
+     * @param int $user_id
+     */
     public function set_user_id($user_id)
     {
         $this->user_id = $user_id;
     }
 
+    /**
+     * @param string $course_code
+     */
     public function set_course_code($course_code)
     {
         $this->course_code = $course_code;
     }
 
-    public function set_certificate_min_score ($min_score = null)
+    /**
+     * @param float $min_score
+     */
+    public function set_certificate_min_score($min_score = null)
     {
         $this->certificate_min_score = $min_score;
     }
 
+    /**
+     * @param int $parent
+     */
     public function set_parent_id($parent)
     {
         $this->parent = intval($parent);
@@ -172,6 +208,10 @@ class Category implements GradebookItem
         return 'category';
     }
 
+    /**
+     * @param bool $from_db
+     * @return array|resource
+     */
     public function get_skills($from_db = true)
     {
         if ($from_db) {
@@ -185,6 +225,9 @@ class Category implements GradebookItem
         return $skills;
     }
 
+    /**
+     * @return array
+     */
     public function get_skills_for_select()
     {
         $skills = $this->get_skills();
@@ -781,8 +824,12 @@ class Category implements GradebookItem
      * @return    array (score sum, weight sum)
      *             or null if no scores available
      */
-    public function calc_score($stud_id = null, $type = null, $course_code = '', $session_id = null)
-    {
+    public function calc_score(
+        $stud_id = null,
+        $type = null,
+        $course_code = '',
+        $session_id = null
+    ) {
         // Get appropriate subcategories, evaluations and links
         if (!empty($course_code)) {
             $cats  = $this->get_subcategories($stud_id, $course_code, $session_id);
@@ -799,17 +846,24 @@ class Category implements GradebookItem
         $ressum = 0;
         $weightsum = 0;
         $bestResult = 0;
+        $students = [];
 
         if (!empty($cats)) {
             /** @var Category $cat */
             foreach ($cats as $cat) {
-                $score = $cat->calc_score($stud_id, $type, $course_code, $session_id);
+                $score = $cat->calc_score(
+                    $stud_id,
+                    $type,
+                    $course_code,
+                    $session_id
+                );
 
                 if ($cat->get_weight() != 0) {
                     $catweight = $cat->get_weight();
                     $rescount++;
                     $weightsum += $catweight;
                 }
+
                 if (isset($score)) {
                     $ressum += $score[0]/$score[1] * $catweight;
                     $bestResult += $ressum;
@@ -821,12 +875,15 @@ class Category implements GradebookItem
             /** @var Evaluation $eval */
             foreach ($evals as $eval) {
                 $evalres = $eval->calc_score($stud_id, $type);
-
+                if ($type == 'ranking') {
+                    var_dump($evalres);
+                }
+                $students[$stud_id] = $evalres[0];
                 if (isset($evalres) && $eval->get_weight() != 0) {
                     $evalweight = $eval->get_weight();
                     $weightsum += $evalweight;
                     $rescount++;
-                    $ressum += $evalres[0]/$evalres[1] * $evalweight;
+                    $ressum += $evalres[0] / $evalres[1] * $evalweight;
                 } else {
                     if ($eval->get_weight() != 0) {
                         $evalweight = $eval->get_weight();
@@ -834,9 +891,6 @@ class Category implements GradebookItem
                     }
                 }
             }
-            if ($type == 'best') {
-                //var_dump($ressum);
-            }
         }
 
         if (!empty($links)) {
@@ -848,6 +902,7 @@ class Category implements GradebookItem
            foreach ($links as $link) {
                 $linkres = $link->calc_score($stud_id, $type);
                 if (!empty($linkres) && $link->get_weight() != 0) {
+                    $students[$stud_id] = $linkres[0];
                     $linkweight = $link->get_weight();
                     $link_res_denom = $linkres[1] == 0 ? 1 : $linkres[1];
                     $rescount++;
@@ -861,22 +916,27 @@ class Category implements GradebookItem
                     }
                 }
             }
-            if ($type == 'best') {
-                //var_dump($ressum);
-            }
         }
 
         if ($rescount == 0) {
             return null;
         } else {
-            if ($type == 'best') {
-                return array($ressum, $weightsum);
+            switch ($type) {
+                case 'best':
+                    return array($ressum, $weightsum);
+                    break;
+                case 'average':
+                    return array($ressum, $weightsum);
+                    break;
+                case 'ranking':
+                    //var_dump($students);
+                    return null;
+                    return AbstractLink::getCurrentUserRanking($students);
+                    break;
+                default:
+                    return array($ressum, $weightsum);
+                    break;
             }
-            if ($type == 'average') {
-                return array($ressum, $weightsum);
-            }
-
-            return array($ressum, $weightsum);
         }
     }
 

+ 32 - 13
main/gradebook/lib/be/evaluation.class.php

@@ -268,7 +268,12 @@ class Evaluation implements GradebookItem
 	 */
 	public function add()
 	{
-		if (isset($this->name) && isset($this->user_id) && isset($this->weight) && isset ($this->eval_max) && isset($this->visible)) {
+		if (isset($this->name) &&
+			isset($this->user_id) &&
+			isset($this->weight) &&
+			isset ($this->eval_max) &&
+			isset($this->visible)
+		) {
 			$tbl_grade_evaluations = Database :: get_main_table(TABLE_MAIN_GRADEBOOK_EVALUATION);
 
 			$sql = 'INSERT INTO '.$tbl_grade_evaluations
@@ -424,14 +429,15 @@ class Evaluation implements GradebookItem
 		}
 		$result = Database::query($sql);
 		$number=Database::fetch_row($result);
-		return ($number[0] != 0);
+		return $number[0] != 0;
 	}
 
 	/**
 	 * Are there any results for this evaluation yet ?
 	 * The 'max' property should not be changed then.
 	 */
-	public function has_results() {
+	public function has_results()
+	{
 		$tbl_grade_results = Database :: get_main_table(TABLE_MAIN_GRADEBOOK_RESULT);
 		$sql='SELECT count(id) AS number FROM '.$tbl_grade_results
 			.' WHERE evaluation_id = '.intval($this->id);
@@ -444,7 +450,8 @@ class Evaluation implements GradebookItem
 	/**
 	 * Delete all results for this evaluation
 	 */
-	public function delete_results() {
+	public function delete_results()
+	{
 		$tbl_grade_results = Database :: get_main_table(TABLE_MAIN_GRADEBOOK_RESULT);
 		$sql = 'DELETE FROM '.$tbl_grade_results.' WHERE evaluation_id = '.intval($this->id);
 		Database::query($sql);
@@ -453,7 +460,8 @@ class Evaluation implements GradebookItem
 	/**
 	 * Delete this evaluation and all underlying results.
 	 */
-	public function delete_with_results(){
+	public function delete_with_results()
+	{
 		$this->delete_results();
 		$this->delete();
 	}
@@ -461,7 +469,8 @@ class Evaluation implements GradebookItem
 	/**
 	 * Check if the given score is possible for this evaluation
 	 */
-	public function is_valid_score ($score) {
+	public function is_valid_score ($score)
+	{
 		return (is_numeric($score) && $score >= 0 && $score <= $this->eval_max);
 	}
 
@@ -481,9 +490,11 @@ class Evaluation implements GradebookItem
 		$weight = 0;
 		$sumResult = 0;
 
+		$students = [];
+		/** @var Result $res */
 		foreach ($results as $res) {
 			$score = $res->get_score();
-			if ((!empty ($score)) || ($score == '0')) {
+			if (!empty($score) || $score == '0') {
 				$rescount++;
 				$sum += $score / $this->get_max();
 				$sumResult += $score;
@@ -492,6 +503,7 @@ class Evaluation implements GradebookItem
 				}
 				$weight = $this->get_max();
 			}
+			$students[$res->get_user_id()] = $score;
 		}
 
 		if ($rescount == 0) {
@@ -499,13 +511,20 @@ class Evaluation implements GradebookItem
 		} else if (isset($stud_id)) {
 			return array($score, $this->get_max());
 		} else {
-			if ($type == 'best') {
-				return array($bestResult, $weight);
-			}
-			if ($type == 'average') {
-				return array($sumResult/$rescount, $weight);
+			switch ($type) {
+				case 'best':
+					return array($bestResult, $weight);
+					break;
+				case 'average':
+					return array($sumResult/$rescount, $weight);
+					break;
+				case 'ranking':
+					return AbstractLink::getCurrentUserRanking($students);
+					break;
+				default:
+					return array($sum, $rescount);
+					break;
 			}
-			return array($sum, $rescount);
 		}
 	}
 

+ 22 - 12
main/gradebook/lib/be/exerciselink.class.php

@@ -194,13 +194,14 @@ class ExerciseLink extends AbstractLink
         in exercice/exercice.php, look for note-query-exe-results marker*/
         $session_id = api_get_session_id();
         $courseId = $this->getCourseId();
+
         if (!$this->is_hp) {
             $sql = "SELECT * FROM $tblStats
                     WHERE
-                        exe_exo_id      = ".intval($this->get_ref_id())." AND
-                        orig_lp_id      = 0 AND
+                        exe_exo_id = ".intval($this->get_ref_id())." AND
+                        orig_lp_id = 0 AND
                         orig_lp_item_id = 0 AND
-                        status      <> 'incomplete' AND
+                        status <> 'incomplete' AND
                         session_id = $session_id";
 
             if (isset($stud_id)) {
@@ -210,7 +211,7 @@ class ExerciseLink extends AbstractLink
 
         } else {
             $sql = "SELECT * FROM $tblHp hp, $tblDoc doc
-                     WHERE
+                    WHERE
                         hp.c_id = $courseId AND
                         hp.exe_user_id = $stud_id  AND
                         hp.exe_name = doc.path AND
@@ -237,10 +238,11 @@ class ExerciseLink extends AbstractLink
             $bestResult = 0;
             $weight = 0;
             $sumResult = 0;
+
             while ($data = Database::fetch_array($scores, 'ASSOC')) {
-                if (!in_array($data['exe_user_id'], $students)) {
+                if (!isset($students[$data['exe_user_id']])) {
                     if ($data['exe_weighting'] != 0) {
-                        $students[] = $data['exe_user_id'];
+                        $students[$data['exe_user_id']] = $data['exe_result'];
                         $student_count++;
                         if ($data['exe_result'] > $bestResult) {
                             $bestResult = $data['exe_result'];
@@ -251,16 +253,24 @@ class ExerciseLink extends AbstractLink
                     }
                 }
             }
+
             if ($student_count == 0) {
                 return null;
             } else {
-                if ($type == 'best') {
-                    return array($bestResult, $weight);
-                }
-                if ($type == 'average') {
-                    return array($sumResult/$student_count, $weight);
+                switch ($type) {
+                    case 'best':
+                        return array($bestResult, $weight);
+                        break;
+                    case 'average':
+                        return array($sumResult/$student_count, $weight);
+                        break;
+                    case 'ranking':
+                        return AbstractLink::getCurrentUserRanking($students);
+                        break;
+                    default:
+                        return array($sum, $student_count);
+                        break;
                 }
-                return array($sum, $student_count);
             }
         }
     }

+ 23 - 13
main/gradebook/lib/be/forumthreadlink.class.php

@@ -1,5 +1,6 @@
 <?php
 /* For licensing terms, see /license.txt */
+
 /**
  * Gradebook link to student publication item
  * @author Bert Steppé
@@ -51,12 +52,14 @@ class ForumThreadLink extends AbstractLink
 
 		$result = Database::query($sql);
 
-		$cats=array();
+		$cats = array();
 		while ($data=Database::fetch_array($result)) {
-			if ( isset($data['thread_title_qualify']) and $data['thread_title_qualify']!=""){
-				$cats[] = array ($data['thread_id'], $data['thread_title_qualify']);
+			if (isset($data['thread_title_qualify']) and
+				$data['thread_title_qualify'] != ""
+			) {
+				$cats[] = array($data['thread_id'], $data['thread_title_qualify']);
 			} else {
-				$cats[] = array ($data['thread_id'], $data['thread_title']);
+				$cats[] = array($data['thread_id'], $data['thread_title']);
 			}
 		}
 		return $cats;
@@ -71,6 +74,7 @@ class ForumThreadLink extends AbstractLink
 		if (empty($this->course_code)) {
 			die('Error in get_not_created_links() : course code not set');
 		}
+
 		$tbl_grade_links 	= Database :: get_course_table(TABLE_FORUM_THREAD);
 		$tbl_item_property	= Database :: get_course_table(TABLE_ITEM_PROPERTY);
 		$session_id = api_get_session_id();
@@ -98,12 +102,11 @@ class ForumThreadLink extends AbstractLink
 				$cats[] = array ($data['thread_id'], $data['thread_title']);
 			}
 		}
-		$my_cats=isset($cats)?$cats:null;
+		$my_cats = isset($cats) ? $cats : null;
 
 		return $my_cats;
 	}
 
-
 	/**
 	 * Has anyone done this exercise yet ?
 	 */
@@ -162,7 +165,7 @@ class ForumThreadLink extends AbstractLink
 			$sumResult = 0;
 
 			while ($data = Database::fetch_array($scores)) {
-				if (!(array_key_exists($data['user_id'],$students))) {
+				if (!(array_key_exists($data['user_id'], $students))) {
 					if ($assignment['thread_qualify_max'] != 0) {
 						$students[$data['user_id']] = $data['qualify'];
 						$rescount++;
@@ -179,13 +182,20 @@ class ForumThreadLink extends AbstractLink
 			if ($rescount == 0) {
 				return null;
 			} else {
-				if ($type == 'average') {
-					return array($sumResult/$rescount, $weight);
-				}
-				if ($type == 'best') {
-					return array($bestResult, $weight);
+				switch ($type) {
+					case 'best':
+						return array($bestResult, $weight);
+						break;
+					case 'average':
+						return array($sumResult/$rescount, $weight);
+						break;
+					case 'ranking':
+						return AbstractLink::getCurrentUserRanking($students);
+						break;
+					default:
+						return array($sum, $rescount);
+						break;
 				}
-				return array($sum , $rescount);
 			}
 		}
 	}

+ 14 - 6
main/gradebook/lib/be/learnpathlink.class.php

@@ -150,13 +150,21 @@ class LearnpathLink extends AbstractLink
 			if ($rescount == 0) {
 				return null;
 			} else {
-				if ($type == 'average') {
-					return array($sumResult/$rescount, 100);
-				}
-				if ($type == 'best') {
-					return array($bestResult, 100);
+
+				switch ($type) {
+					case 'best':
+						return array($bestResult, 100);
+						break;
+					case 'average':
+						return array($sumResult/$rescount, 100);
+						break;
+					case 'ranking':
+						return AbstractLink::getCurrentUserRanking($students);
+						break;
+					default:
+						return array($sum, $rescount);
+						break;
 				}
-				return array($sum, $rescount);
 			}
 		}
 	}

+ 2 - 3
main/gradebook/lib/be/result.class.php

@@ -69,8 +69,6 @@ class Result
         $this->score = $score;
     }
 
-// CRUD FUNCTIONS
-
     /**
      * Retrieve results and return them as an array of Result objects
      * @param $id result id
@@ -87,7 +85,8 @@ class Result
 
         if (is_null($id) && is_null($user_id) && !is_null($evaluation_id)) {
             // Verified_if_exist_evaluation
-            $sql = 'SELECT COUNT(*) AS count FROM ' . $tbl_grade_results . '
+            $sql = 'SELECT COUNT(*) AS count
+                    FROM ' . $tbl_grade_results . '
                     WHERE evaluation_id="' . Database::escape_string($evaluation_id) . '";';
             $result = Database::query($sql);
             $existEvaluation = Database::result($result, 0, 0);

+ 14 - 6
main/gradebook/lib/be/studentpublicationlink.class.php

@@ -219,6 +219,7 @@ class StudentPublicationLink extends AbstractLink
 			$bestResult = 0;
 			$weight = 0;
 			$sumResult = 0;
+			$myResult = 0;
 
 			while ($data = Database::fetch_array($scores)) {
 				if (!(array_key_exists($data['user_id'], $students))) {
@@ -239,13 +240,20 @@ class StudentPublicationLink extends AbstractLink
 			if ($rescount == 0) {
 				return null;
 			} else {
-				if ($type == 'best') {
-					return array($bestResult, $weight);
+				switch ($type) {
+					case 'best':
+						return array($bestResult, $weight);
+						break;
+					case 'average':
+						return array($sumResult/$rescount, $weight);
+						break;
+					case 'ranking':
+						return AbstractLink::getCurrentUserRanking($students);
+						break;
+					default:
+						return array($sum, $rescount);
+						break;
 				}
-				if ($type == 'average') {
-					return array($sumResult/$rescount, $weight);
-				}
-				return array($sum, $rescount);
 			}
 		}
 	}

+ 26 - 10
main/gradebook/lib/be/surveylink.class.php

@@ -10,6 +10,9 @@ class SurveyLink extends AbstractLink
 {
 	private $survey_table = null;
 
+	/**
+	 * Constructor
+	 */
 	public function __construct()
 	{
 		parent::__construct();
@@ -95,9 +98,14 @@ class SurveyLink extends AbstractLink
 		$sql = 'SELECT survey_id, title, code
     			FROM '.$this->get_survey_table().' AS srv
 				WHERE survey_id NOT IN
-					(SELECT ref_id FROM '.$tbl_grade_links.'
-					WHERE type = '.LINK_SURVEY." AND course_code = '".$this->get_course_code()."'"
-			.') AND srv.session_id='.api_get_session_id().'';
+					(
+					SELECT ref_id FROM '.$tbl_grade_links.'
+					WHERE
+						type = '.LINK_SURVEY.' AND
+						course_code = '".$this->get_course_code()."'
+					)
+					AND srv.session_id = '.api_get_session_id();
+
 		$result = Database::query($sql);
 
 		$links = array();
@@ -172,7 +180,7 @@ class SurveyLink extends AbstractLink
 		if ($get_individual_score) {
 			// for 1 student
 			if ($data = Database::fetch_array($sql_result)) {
-				return array ($data['answered'] ? $max_score : 0, $max_score);
+				return array($data['answered'] ? $max_score : 0, $max_score);
 			}
 			return array(0, $max_score);
 		} else {
@@ -194,13 +202,21 @@ class SurveyLink extends AbstractLink
 			if ($rescount == 0) {
 				return null;
 			}
-			if ($type == 'best') {
-				return array($bestResult, $rescount);
-			}
-			if ($type == 'average') {
-				return array($sum, $rescount);
+
+			switch ($type) {
+				case 'best':
+					return array($bestResult, $rescount);
+					break;
+				case 'average':
+					return array($sum, $rescount);
+					break;
+				case 'ranking':
+					return null;
+					break;
+				default:
+					return array($sum, $rescount);
+					break;
 			}
-			return array($sum, $rescount);
 		}
 	}
 

+ 75 - 44
main/gradebook/lib/fe/gradebooktable.class.php

@@ -54,7 +54,7 @@ class GradebookTable extends SortableTable
         } else {
             $this->set_header($column++, get_lang('Weight'), false);
             $this->set_header($column++, get_lang('Result'), false);
-            $this->set_header($column++, get_lang('Global'), false);
+            $this->set_header($column++, get_lang('Ranking'), false);
             $this->set_header($column++, get_lang('Best'), false);
             $this->set_header($column++, get_lang('Average'), false);
 
@@ -114,7 +114,7 @@ class GradebookTable extends SortableTable
         //variables load in index.php
         global $certificate_min_score;
         // determine sorting type
-        $col_adjust = (api_is_allowed_to_edit() ? 1 : 0);
+        $col_adjust = api_is_allowed_to_edit() ? 1 : 0;
         // By id
         $this->column = 5;
 
@@ -150,10 +150,27 @@ class GradebookTable extends SortableTable
         $course_code = api_get_course_id();
         $session_id = api_get_session_id();
         $status_user = api_get_status_of_user_in_course($user_id, $course_code);
+
+        if (empty($session_id)) {
+            $statusToFilter = STUDENT;
+        } else {
+            $statusToFilter = 0;
+        }
+
+        $studentList = CourseManager::get_user_list_from_course_code(
+            $course_code,
+            $session_id,
+            null,
+            null,
+            $statusToFilter
+        );
+
         $data_array = $this->datagen->get_data(
             $sorting,
             $from,
-            $this->per_page
+            $this->per_page,
+            false,
+            $studentList
         );
 
         // generate the data to display
@@ -175,11 +192,11 @@ class GradebookTable extends SortableTable
             // list of items inside the gradebook (exercises, lps, forums, etc)
             $row  = array();
             /** @var AbstractLink $item */
-            $item = $item_category = $data[0];
+            $item = $mainCategory = $data[0];
 
             //if the item is invisible, wrap it in a span with class invisible
-            $invisibility_span_open  = (api_is_allowed_to_edit() && $item->is_visible() == '0') ? '<span class="invisible">' : '';
-            $invisibility_span_close = (api_is_allowed_to_edit() && $item->is_visible() == '0') ? '</span>' : '';
+            $invisibility_span_open  = api_is_allowed_to_edit() && $item->is_visible() == '0' ? '<span class="invisible">' : '';
+            $invisibility_span_close = api_is_allowed_to_edit() && $item->is_visible() == '0' ? '</span>' : '';
 
             // Id
             if (api_is_allowed_to_edit(null, true)) {
@@ -228,7 +245,7 @@ class GradebookTable extends SortableTable
             if (api_is_allowed_to_edit(null, true)) {
                 $weight_total_links += $data[3];
             } else {
-                $cattotal   = Category :: load($_GET['selectcat']);
+                $cattotal = Category::load($_GET['selectcat']);
                 $scoretotal = $cattotal[0]->calc_score(api_get_user_id());
                 $item_value = $scoredisplay->display_score($scoretotal, SCORE_SIMPLE);
             }
@@ -249,7 +266,10 @@ class GradebookTable extends SortableTable
                     $score = $score[0]/$score[1]*$item->get_weight();
                     $score = $scoredisplay->display_score(array($score, null), SCORE_SIMPLE);
 
-                    $categoryScore = $scoredisplay->display_score(array($score, $mainCategoryWeight), SCORE_DIV);
+                    $categoryScore = $scoredisplay->display_score(
+                        array($score, $mainCategoryWeight),
+                        SCORE_DIV
+                    );
                     $scoreToDisplay = Display::tip($score, $completeScore);
                 } else {
                     $categoryScoreArray = [0, $item->get_weight()];
@@ -262,17 +282,13 @@ class GradebookTable extends SortableTable
                     $value_data = isset($data[4]) ? $data[4] : null;
                     $best = isset($data['best']) ? $data['best'] : null;
                     $average = isset($data['average']) ? $data['average'] : null;
+                    $ranking = isset($data['ranking']) ? $data['ranking'] : null;
 
                     $totalResult = [
                         $totalResult[0] + $data['result_score'][0],
                         $totalResult[1] + $data['result_score'][1],
                     ];
 
-                    $totalGlobal = [
-                        $totalGlobal[0] +  $categoryScoreArray[0],
-                        $totalGlobal[1] + $categoryScoreArray[1],
-                    ];
-
                     $totalBest = [
                         $totalBest[0] + $data['best_score'][0],
                         $totalBest[1] + $data['best_score'][1],
@@ -285,8 +301,8 @@ class GradebookTable extends SortableTable
 
                     // Student result
                     $row[] = $value_data;
-                    // Global
-                    $row[] = $categoryScore;
+                    // Ranking
+                    $row[] = $ranking;
                     // Best
                     $row[] = $best;
                     // Average
@@ -379,22 +395,19 @@ class GradebookTable extends SortableTable
                                 $value_data = isset($data[4]) ? $data[4] : null;
 
                                 if (!is_null($value_data)) {
-                                    $score = $item->calc_score(api_get_user_id());
-                                    $new_score = $data[3] * $score[0] / $score[1];
-                                    $new_score = floatval(number_format($new_score, api_get_setting('gradebook_number_decimals')));
+                                    //$score = $item->calc_score(api_get_user_id());
+                                    //$new_score = $data[3] * $score[0] / $score[1];
+                                    //$new_score = floatval(number_format($new_score, api_get_setting('gradebook_number_decimals')));
 
                                     // Result
                                     $row[] = $value_data;
 
                                     $best = isset($data['best']) ? $data['best'] : null;
                                     $average = isset($data['average']) ? $data['average'] : null;
+                                    $ranking = isset($data['ranking']) ? $data['ranking'] : null;
 
-                                    // Global
-                                    $categoryScore = $scoredisplay->display_score(
-                                        array($new_score, $cattotal[0]->get_weight()),
-                                        SCORE_DIV
-                                    );
-                                    $row[] = $categoryScore;
+                                    // Ranking
+                                    $row[] = $ranking;
                                     // Best
                                     $row[] = $best;
                                     // Average
@@ -416,7 +429,12 @@ class GradebookTable extends SortableTable
                             // Compare the category weight to the sum of all weights inside the category
                             if (intval($total_weight) == $category_weight) {
                                 $label = null;
-                                $total = GradebookUtils::score_badges(array($total_weight.' / '.$category_weight, '100'));
+                                $total = GradebookUtils::score_badges(
+                                    array(
+                                        $total_weight.' / '.$category_weight,
+                                        '100'
+                                    )
+                                );
                             } else {
                                 $label = Display::return_icon(
                                     'warning.png',
@@ -445,7 +463,9 @@ class GradebookTable extends SortableTable
                 $main_weight = intval($main_cat[0]->get_weight());
 
                 if (intval($total_categories_weight) == $main_weight) {
-                    $total = GradebookUtils::score_badges(array($total_categories_weight.' / '.$main_weight, '100'));
+                    $total = GradebookUtils::score_badges(
+                        array($total_categories_weight.' / '.$main_weight, '100')
+                    );
                 } else {
                     $total = Display::badge($total_categories_weight.' / '.$main_weight, 'warning');
                 }
@@ -471,8 +491,16 @@ class GradebookTable extends SortableTable
                     SCORE_DIV
                 );
 
-                $totalGlobal = $scoredisplay->display_score(
-                    $totalGlobal,
+                $totalRanking = array();
+                foreach ($studentList as $student) {
+                    $score = $main_cat[0]->calc_score($student['user_id']);
+                    $totalRanking[$student['user_id']] = $score[0];
+                }
+
+                $totalRanking = AbstractLink::getCurrentUserRanking($totalRanking);
+
+                $totalRanking = $scoredisplay->display_score(
+                    $totalRanking,
                     SCORE_DIV
                 );
 
@@ -492,7 +520,7 @@ class GradebookTable extends SortableTable
                     null,
                     $main_weight,
                     $totalResult,
-                    $totalGlobal,
+                    $totalRanking,
                     $totalBest,
                     $totalAverage,
                 );
@@ -501,12 +529,13 @@ class GradebookTable extends SortableTable
             }
         }
 
-        // warning messages
+        // Warning messages
         $view = isset($_GET['view']) ? $_GET['view']: null;
-        if (api_is_allowed_to_edit()) {
 
+        if (api_is_allowed_to_edit()) {
             if (isset($_GET['selectcat']) &&
-                $_GET['selectcat'] > 0 && $view <> 'presence'
+                $_GET['selectcat'] > 0 &&
+                $view <> 'presence'
             ) {
                 $id_cat = intval($_GET['selectcat']);
                 $category = Category::load($id_cat);
@@ -562,7 +591,10 @@ class GradebookTable extends SortableTable
                     }
                 }
 
-                if (is_array($weight_categories) && is_array($certificate_min_scores) && is_array($course_codes)) {
+                if (is_array($weight_categories) &&
+                    is_array($certificate_min_scores) &&
+                    is_array($course_codes)
+                ) {
                     $warning_message = '';
                     for ($x = 0; $x<count($weight_categories);$x++) {
                         $weight_category = intval($weight_categories[$x]);
@@ -590,7 +622,7 @@ class GradebookTable extends SortableTable
      * @param $item
      * @return mixed
      */
-    private function build_certificate_min_score ($item)
+    private function build_certificate_min_score($item)
     {
         return $item->get_certificate_min_score();
     }
@@ -608,7 +640,7 @@ class GradebookTable extends SortableTable
      * @param $item
      * @return mixed
      */
-    private function build_course_code ($item)
+    private function build_course_code($item)
     {
         return $item->get_course_code();
     }
@@ -617,7 +649,7 @@ class GradebookTable extends SortableTable
      * @param $item
      * @return string
      */
-    private function build_id_column ($item)
+    private function build_id_column($item)
     {
         switch ($item->get_item_type()) {
             // category
@@ -693,24 +725,23 @@ class GradebookTable extends SortableTable
                     . $item->get_name()
                     . '</a>';
 
-                } elseif ($show_message===false && !api_is_allowed_to_edit() && !(ScoreDisplay :: instance()->is_custom())) {
+                } elseif ($show_message === false && !api_is_allowed_to_edit() && !ScoreDisplay :: instance()->is_custom()) {
                     return '&nbsp;'
                     . '<a href="gradebook_statistics.php?selecteval=' . $item->get_id() . '">'
                     . $item->get_name()
                     . '</a>';
-
                 } else {
                     return '['.get_lang('Evaluation').']&nbsp;&nbsp;'.$item->get_name().$show_message;
                 }
-            // link
-            case 'L' :
-                $cat 			= new Category();
-                $course_id	 	= CourseManager::get_course_by_category($_GET['selectcat']);
-                $show_message	= $cat->show_message_resource_delete($course_id);
+            case 'L':
+                // link
+                $cat = new Category();
+                $course_id = CourseManager::get_course_by_category($_GET['selectcat']);
+                $show_message = $cat->show_message_resource_delete($course_id);
 
                 $url = $item->get_link();
 
-                if (isset($url) && $show_message===false) {
+                if (isset($url) && $show_message === false) {
                     $text = '&nbsp;<a href="' . $item->get_link() . '">'
                         . $item->get_name()
                         . '</a>';

+ 108 - 29
main/gradebook/lib/gradebook_data_generator.class.php

@@ -80,7 +80,7 @@ class GradebookDataGenerator
      * 4: date
      * 5: student's score (if student logged in)
      */
-    public function get_data($sorting = 0, $start = 0, $count = null, $ignore_score_color = false)
+    public function get_data($sorting = 0, $start = 0, $count = null, $ignore_score_color = false, $studentList = array())
     {
         //$status = CourseManager::get_user_in_course_status(api_get_user_id(), api_get_course_id());
         // do some checks on count, redefine if invalid value
@@ -112,12 +112,29 @@ class GradebookDataGenerator
         // get selected items
         $visibleitems = array_slice($allitems, $start, $count);
         //status de user in course
-        $user_id = api_get_user_id();
+        $userId = api_get_user_id();
         $course_code = api_get_course_id();
-        $status_user = api_get_status_of_user_in_course($user_id, $course_code);
+        $sessionId = api_get_session_id();
+        $status_user = api_get_status_of_user_in_course($userId, $course_code);
+
+        if (empty($sessionId)) {
+            $statusToFilter = STUDENT;
+        } else {
+            $statusToFilter = 0;
+        }
+
+        $userCount = CourseManager::get_user_list_from_course_code(
+            $course_code,
+            $sessionId,
+            null,
+            null,
+            $statusToFilter,
+            true
+        );
 
         // Generate the data to display
         $data = array();
+
         /** @var GradebookItem $item */
         $totalWeight = 0;
         foreach ($visibleitems as $item) {
@@ -130,38 +147,76 @@ class GradebookDataGenerator
             $totalWeight += $item->get_weight();
             $row[] = $item->get_weight();
             if (count($this->evals_links) > 0) {
+                // Items inside a category.
                 if (!api_is_allowed_to_edit() || $status_user != 1 ) {
-                    $row[] = $this->build_result_column($item, $ignore_score_color)['display'];
-                    $row['result_score'] = $this->build_result_column($item, $ignore_score_color)['score'];
-                    $row['best'] = $this->buildBestResultColumn($item)['display'];
-                    $row['best_score'] = $this->buildBestResultColumn($item)['score'];
-                    $row['average'] = $this->buildAverageResultColumn($item)['display'];
-                    $row['average_score'] = $this->buildAverageResultColumn($item)['score'];
+                    $resultColumn = $this->build_result_column(
+                        api_get_user_id(),
+                        $item,
+                        $ignore_score_color
+                    );
+
+                    $row[] = $resultColumn['display'];
+                    $row['result_score'] = $resultColumn['score'];
+
+                    // Best
+                    $best = $this->buildBestResultColumn($item);
+                    $row['best'] = $best['display'];
+                    $row['best_score'] = $best['score'];
+
+                    // Average
+                    $average = $this->buildAverageResultColumn($item);
+                    $row['average'] = $average['display'];
+                    $row['average_score'] = $average['score'];
+
+                    // Ranking
+                    $ranking = $this->buildRankingColumn($item, $userCount);
+
+                    $row['ranking'] = $ranking['display'];
+                    $row['ranking_score'] = $ranking['score'];
+
                     $row[] = $item;
                 }
             } else {
-                $row[] = $this->build_result_column($item, $ignore_score_color, true)['display'];
-                $row['result_score'] = $this->build_result_column($item, $ignore_score_color)['score'];
-                $row['best'] = $this->buildBestResultColumn($item)['display'];
-                $row['best_score'] = $this->buildBestResultColumn($item)['score'];
-                $row['average'] = $this->buildAverageResultColumn($item)['display'];
-                $row['average_score'] = $this->buildAverageResultColumn($item)['score'];
+                // Category.
+
+                // Result
+                $result = $this->build_result_column($userId, $item, $ignore_score_color, true);
+                $row[] = $result['display'];
+                $row['result_score'] = $result['score'];
+
+                // Best
+                $best = $this->buildBestResultColumn($item);
+                $row['best'] = $best['display'];
+                $row['best_score'] = $best['score'];
+
+                // Average
+                $average = $this->buildAverageResultColumn($item);
+                $row['average'] = $average['display'];
+                $row['average_score'] = $average['score'];
+
+                // Ranking
+                $rankingStudentList = array();
+                foreach ($studentList as $user) {
+                    $score = $this->build_result_column(
+                        $user['user_id'],
+                        $item,
+                        $ignore_score_color,
+                        true
+                    );
+                    $rankingStudentList[$user['user_id']] = $score['display'][0];
+                }
+                $scoreDisplay = ScoreDisplay::instance();
+
+                $score = AbstractLink::getCurrentUserRanking($rankingStudentList);
+                $row['ranking'] = $scoreDisplay->display_score($score, SCORE_DIV);
+
             }
             $data[] = $row;
         }
 
-        // Total
-        /*$totalRow = [];
-        $totalRow[] = null;
-        $totalRow[] = get_lang('Total');
-        $totalRow[] = null; // Description
-        $totalRow[] = $totalWeight;
-        $data[] = $totalRow;*/
-
         return $data;
     }
 
-
     /**
      * Get best result of an item
      * @param GradebookItem $item
@@ -200,14 +255,35 @@ class GradebookDataGenerator
     }
 
     /**
+     * @param GradebookItem $item
+     * @return string
+     */
+    private function buildRankingColumn(GradebookItem $item, $userCount = 0)
+    {
+        $score = $item->calc_score(null, 'ranking');
+        $score[1] = $userCount;
+        $scoreDisplay = ScoreDisplay::instance();
+
+        return array(
+            'display' => $scoreDisplay->display_score($score, SCORE_DIV),
+            'score' => $score
+        );
+    }
+
+    /**
+     * @param int $userId
      * @param GradebookItem $item
      * @param $ignore_score_color
      * @return null|string
      */
-    private function build_result_column($item, $ignore_score_color, $forceSimpleResult = false)
-    {
-        $scoredisplay = ScoreDisplay :: instance();
-        $score = $item->calc_score(api_get_user_id());
+    private function build_result_column(
+        $userId,
+        $item,
+        $ignore_score_color,
+        $forceSimpleResult = false
+    ) {
+        $scoredisplay = ScoreDisplay::instance();
+        $score = $item->calc_score($userId);
 
         if (!empty($score)) {
             switch ($item->get_item_type()) {
@@ -221,7 +297,10 @@ class GradebookDataGenerator
                         if ($forceSimpleResult) {
                             return
                                 array(
-                                    'display' => $scoredisplay->display_score($score, SCORE_DIV),
+                                    'display' => $scoredisplay->display_score(
+                                        $score,
+                                        SCORE_DIV
+                                    ),
                                     'score' => $score
                                 );
                         }

+ 3 - 3
main/gradebook/lib/scoredisplay.class.php

@@ -422,10 +422,10 @@ class ScoreDisplay
     private function display_as_div($score)
     {
         if ($score == 1) {
-            return '0/0';
+            return '0 / 0';
         } else {
-            $score[0] =$this->format_score($score[0]);
-            $score[1] =$this->format_score($score[1]);
+            $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];
         }
     }

+ 1 - 1
main/gradebook/lib/user_data_generator.class.php

@@ -146,7 +146,7 @@ class UserDataGenerator
 			$row[] = $this->build_course_name($item);
 			$row[] = $this->build_category_name($item);
 			$row[] = $this->build_average_column($item, $ignore_score_color);
-			$row[] = $this->build_result_column($item, $ignore_score_color)['display'];
+			$row[] = $this->build_result_column($item, $ignore_score_color);
 			if ($scoredisplay->is_custom())
 				$row[] = $this->build_mask_column($item, $ignore_score_color);
 			$data[] = $row;