Browse Source

Add new exercise report, showing sessions and exercise categories

See BT#13187

- Add course id when creating new objects Answer/Question/Exercise
- Format code
Julio 7 years ago
parent
commit
eb7d4027e6

+ 16 - 15
main/exercise/TestCategory.php

@@ -316,13 +316,14 @@ class TestCategory
      * return : array of category id (integer)
      * hubert.borderiou 07-04-2011
      * @param int $exerciseId
+     * @param int $courseId
      *
      * @return array
      */
-    public static function getListOfCategoriesIDForTest($exerciseId)
+    public static function getListOfCategoriesIDForTest($exerciseId, $courseId = 0)
     {
         // parcourir les questions d'un test, recup les categories uniques dans un tableau
-        $exercise = new Exercise();
+        $exercise = new Exercise($courseId);
         $exercise->read($exerciseId, false);
         $categoriesInExercise = $exercise->getQuestionWithCategories();
         // the array given by selectQuestionList start at indice 1 and not at indice 0 !!! ???
@@ -337,14 +338,14 @@ class TestCategory
     }
 
     /**
-     * @param Exercise $exercise_obj
+     * @param Exercise $exercise
      * @return array
      */
-    public static function getListOfCategoriesIDForTestObject(Exercise $exercise_obj)
+    public static function getListOfCategoriesIDForTestObject(Exercise $exercise)
     {
         // parcourir les questions d'un test, recup les categories uniques dans un tableau
         $categories_in_exercise = array();
-        $question_list = $exercise_obj->getQuestionOrderedListByName();
+        $question_list = $exercise->getQuestionOrderedListByName();
 
         // the array given by selectQuestionList start at indice 1 and not at indice 0 !!! ???
         foreach ($question_list as $questionInfo) {
@@ -397,13 +398,13 @@ class TestCategory
     }
 
     /**
-     * @param Exercise $exercise_obj
+     * @param Exercise $exercise
      * @return array
      */
-    public static function getListOfCategoriesForTest(Exercise $exercise_obj)
+    public static function getListOfCategoriesForTest(Exercise $exercise)
     {
         $result = array();
-        $categories = self::getListOfCategoriesIDForTestObject($exercise_obj);
+        $categories = self::getListOfCategoriesIDForTestObject($exercise);
         foreach ($categories as $cat_id) {
             $cat = new TestCategory();
             $cat = (array) $cat->getCategory($cat_id);
@@ -1011,19 +1012,19 @@ class TestCategory
 
     /**
      * Returns the category form.
-     * @param Exercise $exercise_obj
+     * @param Exercise $exercise
      * @return string
      */
-    public function returnCategoryForm(Exercise $exercise_obj)
+    public function returnCategoryForm(Exercise $exercise)
     {
-        $categories = $this->getListOfCategoriesForTest($exercise_obj);
-        $saved_categories = $exercise_obj->get_categories_in_exercise();
+        $categories = $this->getListOfCategoriesForTest($exercise);
+        $saved_categories = $exercise->get_categories_in_exercise();
         $return = null;
 
         if (!empty($categories)) {
-            $nbQuestionsTotal = $exercise_obj->getNumberQuestionExerciseCategory();
-            $exercise_obj->setCategoriesGrouping(true);
-            $real_question_count = count($exercise_obj->getQuestionList());
+            $nbQuestionsTotal = $exercise->getNumberQuestionExerciseCategory();
+            $exercise->setCategoriesGrouping(true);
+            $real_question_count = count($exercise->getQuestionList());
 
             $warning = null;
             if ($nbQuestionsTotal != $real_question_count) {

+ 1 - 1
main/exercise/exercise.class.php

@@ -3475,7 +3475,7 @@ class Exercise
         }
 
         // Construction of the Answer object
-        $objAnswerTmp = new Answer($questionId);
+        $objAnswerTmp = new Answer($questionId, $course_id);
         $nbrAnswers = $objAnswerTmp->selectNbrAnswers();
 
         if ($debug) {

+ 1 - 1
main/exercise/question.class.php

@@ -159,7 +159,7 @@ abstract class Question
                 $objQuestion->extra = $object->extra;
                 $objQuestion->course = $course_info;
                 $objQuestion->feedback = isset($object->feedback) ? $object->feedback : '';
-                $objQuestion->category = TestCategory::getCategoryForQuestion($id);
+                $objQuestion->category = TestCategory::getCategoryForQuestion($id, $course_id);
 
                 $tblQuiz = Database::get_course_table(TABLE_QUIZ_TEST);
                 $sql = "SELECT DISTINCT q.exercice_id

+ 52 - 0
main/inc/ajax/model.ajax.php

@@ -33,6 +33,7 @@ if (!in_array(
     $action,
     array(
         'get_exercise_results',
+        'get_exercise_results_report',
         'get_work_student_list_overview',
         'get_hotpotatoes_exercise_results',
         'get_work_teacher',
@@ -520,6 +521,19 @@ switch ($action) {
             $whereCondition
         );
         break;
+    case 'get_exercise_results_report':
+        $exerciseId = $_REQUEST['exercise_id'];
+        $courseId = $_REQUEST['course_id'];
+        $startDate = Database::escape_string($_REQUEST['start_date']);
+        $courseInfo = api_get_course_info_by_id($courseId);
+        $whereCondition .= " AND exe_date > '$startDate' ";
+        $count = ExerciseLib::get_count_exam_results(
+            $exerciseId,
+            $whereCondition,
+            $courseInfo['code'],
+            true
+        );
+        break;
     case 'get_hotpotatoes_exercise_results':
         $hotpot_path = $_REQUEST['path'];
         $count = ExerciseLib::get_count_exam_hotpotatoes_results($hotpot_path);
@@ -1147,6 +1161,43 @@ switch ($action) {
             $whereCondition
         );
         break;
+    case 'get_exercise_results_report':
+        api_protect_admin_script();
+
+        // Used inside ExerciseLib::get_exam_results_data()
+        $documentPath = api_get_path(SYS_COURSE_PATH).$courseInfo['path']."/document";
+
+        $columns = array(
+            'firstname',
+            'lastname',
+            'username',
+            'session',
+            'start_date',
+            'exe_date',
+            'score'
+        );
+        $categoryList = TestCategory::getListOfCategoriesIDForTest($exerciseId, $courseId);
+        if (!empty($categoryList)) {
+            foreach ($categoryList as $categoryInfo) {
+                $columns[] = 'category_'.$categoryInfo['id'];
+            }
+        }
+
+        $columns[] = 'actions';
+
+        $result = ExerciseLib::get_exam_results_data(
+            $start,
+            $limit,
+            $sidx,
+            $sord,
+            $exerciseId,
+            $whereCondition,
+            false,
+            $courseInfo['code'],
+            true,
+            true
+        );
+        break;
     case 'get_hotpotatoes_exercise_results':
         $course = api_get_course_info();
         $documentPath = api_get_path(SYS_COURSE_PATH).$course['path']."/document";
@@ -1966,6 +2017,7 @@ $allowed_actions = array(
     'get_session_progress',
     'get_exercise_progress',
     'get_exercise_results',
+    'get_exercise_results_report',
     'get_work_student_list_overview',
     'get_hotpotatoes_exercise_results',
     'get_work_teacher',

+ 116 - 33
main/inc/lib/exercise.lib.php

@@ -1508,9 +1508,12 @@ HOTSPOT;
      * Gets count of exam results
      * @param int $exerciseId
      * @param array $conditions
+     * @param string $courseCode
+     * @param bool $showSession
+     *
      * @return array
      */
-    public static function get_count_exam_results($exerciseId, $conditions)
+    public static function get_count_exam_results($exerciseId, $conditions, $courseCode = '', $showSession = false)
     {
         $count = self::get_exam_results_data(
             null,
@@ -1519,8 +1522,11 @@ HOTSPOT;
             null,
             $exerciseId,
             $conditions,
-            true
+            true,
+            $courseCode,
+            $showSession
         );
+
         return $count;
     }
 
@@ -1680,7 +1686,9 @@ HOTSPOT;
         $exercise_id,
         $extra_where_conditions = null,
         $get_count = false,
-        $courseCode = null
+        $courseCode = null,
+        $showSessionField = false,
+        $showExerciseCategories = false
     ) {
         //@todo replace all this globals
         global $documentPath, $filter;
@@ -1688,9 +1696,7 @@ HOTSPOT;
         $courseCode = empty($courseCode) ? api_get_course_id() : $courseCode;
         $courseInfo = api_get_course_info($courseCode);
         $course_id = $courseInfo['real_id'];
-        $sessionId = api_get_session_id();
         $is_allowedToEdit = api_is_allowed_to_edit(null, true) || api_is_allowed_to_edit(true) || api_is_drh() || api_is_student_boss();
-
         $TBL_USER = Database::get_main_table(TABLE_MAIN_USER);
         $TBL_EXERCICES = Database::get_course_table(TABLE_QUIZ_TEST);
         $TBL_GROUP_REL_USER = Database::get_course_table(TABLE_GROUP_USER);
@@ -1698,10 +1704,14 @@ HOTSPOT;
         $TBL_TRACK_EXERCICES = Database::get_main_table(TABLE_STATISTIC_TRACK_E_EXERCISES);
         $TBL_TRACK_HOTPOTATOES = Database::get_main_table(TABLE_STATISTIC_TRACK_E_HOTPOTATOES);
         $TBL_TRACK_ATTEMPT_RECORDING = Database::get_main_table(TABLE_STATISTIC_TRACK_E_ATTEMPT_RECORDING);
-
-        $session_id_and = ' AND te.session_id = '.$sessionId.' ';
+        $sessionId = api_get_session_id();
+        $session_id_and = '';
+        $sessionCondition = '';
+        if (!$showSessionField) {
+            $session_id_and = " AND te.session_id = '.$sessionId ";
+            $sessionCondition = " AND  ttte.session_id = $sessionId";
+        }
         $exercise_id = intval($exercise_id);
-
         $exercise_where = '';
         if (!empty($exercise_id)) {
             $exercise_where .= ' AND te.exe_exo_id = '.$exercise_id.'  ';
@@ -1717,12 +1727,13 @@ HOTSPOT;
         $sql_inner_join_tbl_track_exercices = "
         (
             SELECT DISTINCT ttte.*, if(tr.exe_id,1, 0) as revised
-            FROM $TBL_TRACK_EXERCICES ttte LEFT JOIN $TBL_TRACK_ATTEMPT_RECORDING tr
+            FROM $TBL_TRACK_EXERCICES ttte 
+            LEFT JOIN $TBL_TRACK_ATTEMPT_RECORDING tr
             ON (ttte.exe_id = tr.exe_id)
             WHERE
                 c_id = $course_id AND
-                exe_exo_id = $exercise_id AND
-                ttte.session_id = ".$sessionId."
+                exe_exo_id = $exercise_id 
+                $sessionCondition
         )";
 
         if ($is_allowedToEdit) {
@@ -1841,6 +1852,7 @@ HOTSPOT;
                     te.exe_weighting,
                     te.exe_date,
                     te.exe_id,
+                    te.session_id,
                     email as exemail,
                     te.start_date,
                     ce.expired_time,
@@ -1947,7 +1959,6 @@ HOTSPOT;
 
             $lp_list_obj = new LearnpathList(api_get_user_id());
             $lp_list = $lp_list_obj->get_flat_list();
-
             $oldIds = array_column($lp_list, 'lp_old_id', 'iid');
 
             if (is_array($results)) {
@@ -2108,12 +2119,12 @@ HOTSPOT;
                                     break;
                                 case 2: //finished but not marked as such
                                     $actions .= '<a href="exercise_report.php?'
-                                        . api_get_cidreq()
-                                        . '&exerciseId='
-                                        . $exercise_id
-                                        . '&a=close&id='
-                                        . $id
-                                        . '">'.
+                                        .api_get_cidreq()
+                                        .'&exerciseId='
+                                        .$exercise_id
+                                        .'&a=close&id='
+                                        .$id
+                                        .'">'.
                                         Display:: return_icon(
                                             'lock.png',
                                             get_lang('MarkAttemptAsClosed'),
@@ -2127,13 +2138,12 @@ HOTSPOT;
                                     );
                                     break;
                                 case 3: //still ongoing
-                                    $actions .= "".
-                                        Display:: return_icon(
-                                            'clock.png',
-                                            get_lang('AttemptStillOngoingPleaseWait'),
-                                            array(),
-                                            ICON_SIZE_SMALL
-                                        );
+                                    $actions .= Display:: return_icon(
+                                        'clock.png',
+                                        get_lang('AttemptStillOngoingPleaseWait'),
+                                        array(),
+                                        ICON_SIZE_SMALL
+                                    );
                                     $actions .= '';
                                     $revisedLabel = Display::label(
                                         get_lang('Ongoing'),
@@ -2158,9 +2168,8 @@ HOTSPOT;
                                     false
                                 );
                                 $actions .= '<a href="http://www.whatsmyip.org/ip-geo-location/?ip='.$ip.'" target="_blank">'
-                                . Display::return_icon('info.png', $ip)
-                                .'</a>';
-
+                                    .Display::return_icon('info.png', $ip)
+                                    .'</a>';
 
                                 $recalculateUrl = api_get_path(WEB_CODE_PATH).'exercise/recalculate.php?'.
                                     api_get_cidreq().'&'.
@@ -2180,7 +2189,8 @@ HOTSPOT;
                                     ]
                                 );
 
-                                $delete_link = '<a href="exercise_report.php?'.api_get_cidreq().'&filter_by_user='.intval($_GET['filter_by_user']).'&filter='.$filter.'&exerciseId='.$exercise_id.'&delete=delete&did='.$id.'"
+                                $filterByUser = isset($_GET['filter_by_user']) ? (int) $_GET['filter_by_user'] : 0;
+                                $delete_link = '<a href="exercise_report.php?'.api_get_cidreq().'&filter_by_user='.$filterByUser.'&filter='.$filter.'&exerciseId='.$exercise_id.'&delete=delete&did='.$id.'"
                                 onclick="javascript:if(!confirm(\'' . sprintf(
                                     get_lang('DeleteAttempt'),
                                     $results[$i]['username'],
@@ -2201,7 +2211,6 @@ HOTSPOT;
                                 }
                                 $actions .= $delete_link;
                             }
-
                         } else {
                             $attempt_url = api_get_path(WEB_CODE_PATH).'exercise/result.php?'.api_get_cidreq().'&id='.$results[$i]['exe_id'].'&id_session='.$sessionId;
                             $attempt_link = Display::url(
@@ -2215,10 +2224,84 @@ HOTSPOT;
                             $actions .= $attempt_link;
                         }
                         $actions .= '</div>';
-
-                        $results[$i]['id'] = $results[$i]['exe_id'];
+                        $exeId = $results[$i]['exe_id'];
+                        $results[$i]['id'] = $exeId;
 
                         if ($is_allowedToEdit) {
+                            $sessionName = '';
+                            if (!empty($results[$i]['session_id'])) {
+                                $sessionName = api_get_session_name($results[$i]['session_id']);
+                            }
+                            $objExercise = new Exercise($course_id);
+                            if ($showExerciseCategories) {
+                                $question_list = array();
+                                // Getting attempt info
+                                $exercise_stat_info = $objExercise->get_stat_track_exercise_info_by_exe_id($exeId);
+                                if (!empty($exercise_stat_info['data_tracking'])) {
+                                    $question_list = explode(',', $exercise_stat_info['data_tracking']);
+                                    if (!empty($question_list)) {
+                                        foreach ($question_list as $questionId) {
+                                            $objQuestionTmp = Question::read($questionId, $course_id);
+                                            // We're inside *one* question. Go through each possible answer for this question
+                                            $result = $objExercise->manage_answer(
+                                                $exeId,
+                                                $questionId,
+                                                null,
+                                                'exercise_result',
+                                                false,
+                                                false,
+                                                true,
+                                                false,
+                                                $objExercise->selectPropagateNeg(),
+                                                null,
+                                                true
+                                            );
+
+                                            $my_total_score = $result['score'];
+                                            $my_total_weight = $result['weight'];
+
+                                            // Category report
+                                            $category_was_added_for_this_test = false;
+                                            if (isset($objQuestionTmp->category) && !empty($objQuestionTmp->category)) {
+                                                if (!isset($category_list[$objQuestionTmp->category]['score'])) {
+                                                    $category_list[$objQuestionTmp->category]['score'] = 0;
+                                                }
+                                                if (!isset($category_list[$objQuestionTmp->category]['total'])) {
+                                                    $category_list[$objQuestionTmp->category]['total'] = 0;
+                                                }
+                                                $category_list[$objQuestionTmp->category]['score'] += $my_total_score;
+                                                $category_list[$objQuestionTmp->category]['total'] += $my_total_weight;
+                                                $category_was_added_for_this_test = true;
+                                            }
+
+                                            if (isset($objQuestionTmp->category_list) && !empty($objQuestionTmp->category_list)) {
+                                                foreach ($objQuestionTmp->category_list as $category_id) {
+                                                    $category_list[$category_id]['score'] += $my_total_score;
+                                                    $category_list[$category_id]['total'] += $my_total_weight;
+                                                    $category_was_added_for_this_test = true;
+                                                }
+                                            }
+
+                                            // No category for this question!
+                                            if ($category_was_added_for_this_test == false) {
+                                                if (!isset($category_list['none']['score'])) {
+                                                    $category_list['none']['score'] = 0;
+                                                }
+                                                if (!isset($category_list['none']['total'])) {
+                                                    $category_list['none']['total'] = 0;
+                                                }
+
+                                                $category_list['none']['score'] += $my_total_score;
+                                                $category_list['none']['total'] += $my_total_weight;
+                                            }
+                                        }
+                                    }
+                                }
+                            }
+                            foreach ($category_list as $categoryId => $result) {
+                                $results[$i]['category_'.$categoryId] = self::show_score($result['score'], $result['total']);
+                            }
+                            $results[$i]['session'] = $sessionName;
                             $results[$i]['status'] = $revisedLabel;
                             $results[$i]['score'] = $score;
                             $results[$i]['lp'] = $lp_name;
@@ -4116,7 +4199,7 @@ EOT;
                 if ($show_results) {
                     $question_content .= '</div>';
                 }
-                if(!$show_only_score){
+                if (!$show_only_score) {
                     $exercise_content .= Display::div(Display::panel($question_content),array('class' => 'question-panel'));
                 }
             } // end foreach() block that loops over all questions

+ 18 - 15
main/inc/lib/myspace.lib.php

@@ -18,37 +18,40 @@ class MySpace
      */
     public static function getAdminActions()
     {
-        $actions = array(
-            //array('url' => api_get_path(WEB_CODE_PATH).'mySpace/index.php', 'content' => get_lang('Home')),
-            array(
+        $actions = [
+            [
                 'url' => api_get_path(WEB_CODE_PATH).'mySpace/admin_view.php?display=coaches',
                 'content' => get_lang('DisplayCoaches'),
-            ),
-            array(
+            ],
+            [
                 'url' => api_get_path(WEB_CODE_PATH).'mySpace/admin_view.php?display=user',
                 'content' => get_lang('DisplayUserOverview'),
-            ),
-            array(
+            ],
+            [
                 'url' => api_get_path(WEB_CODE_PATH).'mySpace/admin_view.php?display=session',
                 'content' => get_lang('DisplaySessionOverview'),
-            ),
-            array(
+            ],
+            [
                 'url' => api_get_path(WEB_CODE_PATH).'mySpace/admin_view.php?display=course',
                 'content' => get_lang('DisplayCourseOverview'),
-            ),
-            array(
+            ],
+            [
                 'url' => api_get_path(WEB_CODE_PATH).'tracking/question_course_report.php?view=admin',
                 'content' => get_lang('LPQuestionListResults'),
-            ),
-            array(
+            ],
+            [
                 'url' => api_get_path(WEB_CODE_PATH).'tracking/course_session_report.php?view=admin',
                 'content' => get_lang('LPExerciseResultsBySession'),
-            ),
+            ],
             [
                 'url' => api_get_path(WEB_CODE_PATH).'mySpace/admin_view.php?display=accessoverview',
                 'content' => get_lang('DisplayAccessOverview').' ('.get_lang('Beta').')',
             ],
-        );
+            [
+                'url' => api_get_path(WEB_CODE_PATH).'mySpace/exercise_category_report.php',
+                'content' => get_lang('ExerciseCategoryAllSessionsReport'),
+            ],
+        ];
 
         return Display::actions($actions, null);
     }

+ 195 - 0
main/mySpace/exercise_category_report.php

@@ -0,0 +1,195 @@
+<?php
+/* For licensing terms, see /license.txt */
+
+$cidReset = true;
+
+require_once __DIR__.'/../inc/global.inc.php';
+
+api_protect_admin_script();
+
+$exportCSV = isset($_GET['export']) && $_GET['export'] === 'csv' ? true : false;
+
+// the section (for the tabs)
+$this_section = SECTION_TRACKING;
+
+$csv_content = array();
+$nameTools = get_lang('MySpace');
+
+$is_platform_admin = api_is_platform_admin();
+$is_drh = api_is_drh();
+$is_session_admin = api_is_session_admin();
+
+if ($exportCSV) {
+    if ($display == 'user') {
+        MySpace::export_tracking_user_overview();
+        exit;
+    } elseif ($display == 'session') {
+        MySpace::export_tracking_session_overview();
+        exit;
+    } elseif ($display == 'course') {
+        MySpace::export_tracking_course_overview();
+        exit;
+    }
+}
+
+$currentUrl = api_get_self();
+$courseId = isset($_GET['course_id']) ? (int) $_GET['course_id'] : 0;
+$defaults = [];
+$defaults['start_date'] = isset($_GET['start_date']) ? Security::remove_XSS($_GET['start_date']) : '';
+$defaults['course_id'] = $courseId;
+
+
+$htmlHeadXtra[] = api_get_jqgrid_js();
+$htmlHeadXtra[] = '<script>
+$(document).ready( function() {
+    $("#exercise_course_id").on("change", function(e) {        
+        var data = $(this).select2(\'data\');
+        var option = data[0];
+        //Then I take the values like if I work with an array
+        var value = option.id;        
+        var selectedDate = $("#start_date").datepicker({ dateFormat: \'dd,MM,yyyy\' }).val();        
+        window.location.replace("'.$currentUrl.'?start_date="+selectedDate+"&course_id="+value);
+    });	
+});
+</script>';
+
+Display::display_header($nameTools);
+
+$form = new FormValidator('exercise', 'get');
+$form->addDatePicker('start_date', get_lang('StartDate'));
+if (empty($courseId)) {
+    $form->addSelectAjax(
+        'course_id',
+        get_lang('Course'),
+        null,
+        [
+            'url' => api_get_path(WEB_AJAX_PATH).'course.ajax.php?a=search_course'
+        ]
+    );
+} else {
+    $courseInfo = api_get_course_info_by_id($courseId);
+    $form->addHidden('course_id', $courseId);
+    $form->addLabel(get_lang('Course'), $courseInfo['name']);
+    $exerciseList = ExerciseLib::get_all_exercises_for_course_id(
+        $courseInfo,
+        0,
+        $courseId,
+        true
+    );
+
+    if (!empty($exerciseList)) {
+        $options = [];
+        foreach ($exerciseList as $exercise) {
+            $options[$exercise['id']] = $exercise['title'];
+        }
+        $form->addSelect('exercise_id', get_lang('Exercises'), $options);
+    } else {
+        $form->addLabel(get_lang('Exercises'), Display::return_message(get_lang('NoExercises')));
+    }
+}
+
+$form->setDefaults($defaults);
+$form->addButtonSearch(get_lang('Search'));
+
+$form->display();
+
+if ($form->validate()) {
+    $values = $form->getSubmitValues();
+    $exerciseId = $values['exercise_id'];
+    $startDate = Security::remove_XSS($values['start_date']);
+    $url = api_get_path(WEB_AJAX_PATH).'model.ajax.php?a=get_exercise_results_report&exercise_id='.$exerciseId.'&course_id='.$courseId.'&start_date='.$startDate;
+
+    $categoryList = TestCategory::getListOfCategoriesIDForTest($exerciseId, $courseId);
+    $columns = array(
+        get_lang('FirstName'),
+        get_lang('LastName'),
+        get_lang('LoginName'),
+        get_lang('Session'),
+        get_lang('StartDate'),
+        get_lang('EndDate'),
+        get_lang('Score')
+    );
+
+    if (!empty($categoryList)) {
+        foreach ($categoryList as $categoryInfo) {
+            $columns[] = $categoryInfo['title'];
+        }
+    }
+    $columns[] = get_lang('Actions');
+
+    $columnModel = array(
+        array('name' => 'firstname', 'index' => 'firstname', 'width' => '50', 'align' => 'left', 'search' => 'true'),
+        array('name' => 'lastname', 'index' => 'lastname', 'width' => '50', 'align' => 'left', 'formatter' => 'action_formatter', 'search' => 'true'),
+        array('name' => 'login', 'index' => 'username', 'width' => '40', 'align' => 'left', 'search' => 'true', 'hidden' => 'true'),
+        array('name' => 'session', 'index' => 'session', 'width' => '40', 'align' => 'left', 'search' => 'false'),
+        array('name' => 'start_date', 'index' => 'start_date', 'width' => '60', 'align' => 'left', 'search' => 'true'),
+        array('name' => 'exe_date', 'index' => 'exe_date', 'width' => '60', 'align' => 'left', 'search' => 'true'),
+        array('name' => 'score', 'index' => 'exe_result', 'width' => '50', 'align' => 'center', 'search' => 'true')
+    );
+
+    if (!empty($categoryList)) {
+        foreach ($categoryList as $categoryInfo) {
+            $columnModel[] = array('name' => 'category_'.$categoryInfo['id'], 'index' => 'exe_result', 'width' => '50', 'align' => 'center', 'search' => 'true');
+        }
+    }
+
+    $columnModel[] = array(
+        'name' => 'actions',
+        'index' => 'actions',
+        'width' => '60',
+        'align' => 'left',
+        'search' => 'false',
+        'sortable' => 'false',
+        'hidden' => 'true'
+    );
+
+    $extra_params['autowidth'] = 'true';
+
+//height auto
+    $extra_params['height'] = 'auto';
+    $actionLinks = '
+    // add username as title in lastname filed - ref 4226
+    function action_formatter(cellvalue, options, rowObject) {
+        // rowObject is firstname,lastname,login,... get the third word
+        var loginx = "'.api_htmlentities(sprintf(get_lang("LoginX"), ":::"), ENT_QUOTES).'";
+        var tabLoginx = loginx.split(/:::/);
+        // tabLoginx[0] is before and tabLoginx[1] is after :::
+        // may be empty string but is defined
+        return "<span title=\""+tabLoginx[0]+rowObject[2]+tabLoginx[1]+"\">"+cellvalue+"</span>";
+    }';
+    $tableId = 'results';
+    ?>
+    <script>
+        $(function() {
+            <?php
+            echo Display::grid_js(
+                'results',
+                $url,
+                $columns,
+                $columnModel,
+                $extra_params,
+                array(),
+                $actionLinks,
+                true
+            );
+            ?>
+        });
+    </script>
+    <?php
+
+    echo '<script>$(function() {
+            jQuery("#'.$tableId.'").jqGrid("navGrid","#'.$tableId.'_pager",{view:false, edit:false, add:false, del:false, search:false, excel:true});
+            jQuery("#'.$tableId.'").jqGrid("navButtonAdd","#'.$tableId.'_pager",{
+                   caption:"",
+                   title:"' . get_lang('ExportExcel').'",
+                   onClickButton : function () {
+                       jQuery("#'.$tableId.'").jqGrid("excelExport",{"url":"'.$url.'&export_format=xls"});
+                   }
+            });
+        });</script>';
+
+    echo Display::grid_html('results');
+}
+
+Display::display_footer();
+