PageRenderTime 57ms CodeModel.GetById 13ms RepoModel.GetById 0ms app.codeStats 1ms

/appLms/admin/modules/report/class.report_aggregate.php

https://github.com/wanadli75/cocalms
PHP | 2216 lines | 1612 code | 418 blank | 186 comment | 377 complexity | c2a17e7f3c6b8d753f16cd61856ac44c MD5 | raw file
Possible License(s): GPL-2.0, CC-BY-3.0
  1. <?php defined("IN_FORMA") or die('Direct access is forbidden.');
  2. /* ======================================================================== \
  3. | FORMA - The E-Learning Suite |
  4. | |
  5. | Copyright (c) 2013 (Forma) |
  6. | http://www.formalms.org |
  7. | License http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt |
  8. | |
  9. | from docebo 4.0.5 CE 2008-2012 (c) docebo |
  10. | License http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt |
  11. \ ======================================================================== */
  12. require_once($GLOBALS['where_lms'].'/lib/lib.course.php');
  13. require_once(dirname(__FILE__).'/class.report.php');
  14. define('_RA_CATEGORY_COURSES', 'courses');
  15. define('_RA_CATEGORY_COURSECATS', 'coursecategories');
  16. define('_RA_CATEGORY_TIME', 'time');
  17. define('_RA_CATEGORY_COMMUNICATIONS', 'communications');
  18. define('_RA_CATEGORY_GAMES', 'games');
  19. define('_DECIMAL_SEPARATOR', '.');
  20. define('_PERCENT_SIMBOL', '%');
  21. class Report_Aggregate extends Report {
  22. var $page_title = false;
  23. var $db = NULL;
  24. function Report_Aggregate() {
  25. $this->db = DbConn::getInstance();
  26. $this->lang =& DoceboLanguage::createInstance('report', 'framework');
  27. $this->_set_columns_category(_RA_CATEGORY_COURSES, Lang::t('_RU_CAT_COURSES', 'report'), 'get_courses_filter', 'show_report_courses', '_get_courses_query');
  28. $this->_set_columns_category(_RA_CATEGORY_COURSECATS, Lang::t('_RA_CAT_COURSECATS', 'report'), 'get_coursecategories_filter', 'show_report_coursecategories', '_get_coursecategories_query');
  29. $this->_set_columns_category(_RA_CATEGORY_TIME, Lang::t('_RA_CAT_TIME', 'report'), 'get_time_filter', 'show_report_time', '_get_time_query');
  30. $this->_set_columns_category(_RA_CATEGORY_COMMUNICATIONS, Lang::t('_RU_CAT_COMMUNICATIONS', 'report'), 'get_communications_filter', 'show_report_communications', '_get_communications_query');
  31. $this->_set_columns_category(_RA_CATEGORY_GAMES, Lang::t('_RU_CAT_GAMES', 'report'), 'get_games_filter', 'show_report_games', '_get_games_query');
  32. }
  33. //users and orgchart selection
  34. function get_rows_filter() {
  35. $back_url = $this->back_url;
  36. $jump_url = $this->jump_url;
  37. $next_url = $this->next_url;
  38. require_once(_base_.'/lib/lib.form.php');
  39. require_once($GLOBALS['where_framework'].'/lib/lib.directory.php');
  40. require_once(_base_.'/lib/lib.userselector.php');
  41. require_once($GLOBALS['where_lms'].'/lib/lib.course.php');
  42. require_once($GLOBALS['where_lms'].'/lib/lib.course_managment.php');
  43. $lang =& DoceboLanguage::createInstance('report', 'framework');
  44. //update session
  45. $ref =& $_SESSION['report_tempdata'];
  46. if (!isset($ref['rows_filter'])) {
  47. $ref['rows_filter'] = array( //default values
  48. 'select_all' => false,
  49. 'selection_type' => 'users',
  50. 'selection' => array()
  51. );
  52. } else {
  53. //already resolved in switch block
  54. }
  55. $step = Get::req('step', DOTY_ALPHANUM, 'sel_type');
  56. switch ($step) {
  57. case 'sel_type': {
  58. $values = array('users' => $this->lang->def('_USERS'), 'groups'=>$this->lang->def('_GROUPS'));
  59. $sel_val = (isset($ref['rows_filter']['selection_type']) ? $ref['rows_filter']['selection_type'] : 'users');
  60. $out = Form::openForm('selection_type_form', $jump_url);
  61. $out .= Form::getRadioSet($this->lang->def('_AGGREGATE_ON'), 'selection_type', 'selection_type', array_flip($values) , $sel_val)
  62. .'<div class="nofloat"></div>';
  63. $out .= Form::openButtonSpace();
  64. $out .= Form::getButton('ok_selection', 'ok_selection', $this->lang->def('_CONFIRM'));
  65. $out .= Form::getButton('undo', 'undo', $this->lang->def('_UNDO'));
  66. $out .= Form::closeButtonSpace();
  67. $out .= Form::getHidden('step', 'step', 'sel_data');
  68. $out .= Form::closeForm();
  69. cout($out);
  70. } break;
  71. case 'sel_data': {
  72. $type = Get::req('selection_type', DOTY_ALPHANUM, 'users');
  73. //$aclManager = new DoceboACLManager();
  74. $user_select = new UserSelector();
  75. if (Get::req('is_updating', DOTY_INT, 0)>0) {
  76. $ref['rows_filter']['select_all'] = ( Get::req('select_all', DOTY_INT, 0)>0 ? true : false );
  77. $ref['rows_filter']['selection_type'] = $type;
  78. //$ref['rows_filter']['selection'] = $user_select->getSelection($_POST);
  79. } else { //maybe redoundant
  80. if (!isset($ref['rows_filter']['select_all'])) $ref['rows_filter']['select_all'] = false;
  81. if (!isset($ref['rows_filter']['selection_type'])) $ref['rows_filter']['selection_type'] = 'groups';
  82. if (!isset($ref['rows_filter']['selection'])) $ref['rows_filter']['selection'] = array();
  83. $user_select->resetSelection($ref['rows_filter']['selection']);
  84. //$ref['users'] = array(); it should already have been set to void array, if non existent
  85. }
  86. if(isset($_POST['cancelselector']))
  87. Util::jump_to($back_url);
  88. elseif(isset($_POST['okselector'])) {
  89. $ref['rows_filter']['selection'] = $user_select->getSelection($_POST);
  90. Util::jump_to($next_url);
  91. }
  92. //set page
  93. switch ($type) {
  94. case 'groups': {
  95. $user_select->show_user_selector = FALSE;
  96. $user_select->show_group_selector = TRUE;
  97. $user_select->show_orgchart_selector = TRUE;
  98. } break;
  99. case 'users': {
  100. $user_select->show_user_selector = TRUE;
  101. $user_select->show_group_selector = TRUE;
  102. $user_select->show_orgchart_selector = TRUE;
  103. } break;
  104. }
  105. //$user_select->show_orgchart_simple_selector = FALSE;
  106. //$user_select->multi_choice = TRUE;
  107. $user_select->addFormInfo(
  108. ($type=='users' ? Form::getCheckbox($lang->def('_REPORT_FOR_ALL'), 'select_all', 'select_all', 1, $ref['rows_filter']['select_all']) : '').
  109. Form::getBreakRow().
  110. Form::getHidden('selection_type', 'selection_type', $type).
  111. Form::getHidden('step', 'step', 'sel_data').
  112. Form::getHidden('is_updating', 'is_updating', 1).
  113. Form::getHidden('substep', 'substep', 'user_selection').
  114. Form::getHidden('second_step', 'second_step', 1));
  115. $user_select->setPageTitle('');
  116. $user_select->loadSelector(Util::str_replace_once('&', '&amp;', $jump_url),
  117. false,
  118. $this->lang->def('_CHOOSE_USER_FOR_REPORT'),
  119. true);
  120. } break;
  121. }
  122. }
  123. function get_courses_filter() {
  124. $back_url = $this->back_url;
  125. $jump_url = $this->jump_url;
  126. $next_url = $this->next_url;
  127. require_once(_base_.'/lib/lib.form.php');
  128. require_once($GLOBALS['where_lms'].'/lib/lib.course.php');
  129. require_once($GLOBALS['where_lms'].'/lib/lib.course_managment.php');
  130. $lang =& DoceboLanguage::createInstance('report', 'framework');
  131. //$sel = new Course_Manager();
  132. //$sel->setLink('index.php?modname=report&op=report_rows_filter');
  133. if (isset($_POST['undo_filter'])) Util::jump_to($back_url);
  134. //set $_POST data in $_SESSION['report_tempdata']
  135. $selector = new Selector_Course();
  136. if (!isset($_SESSION['report_tempdata']['columns_filter'])) {
  137. $_SESSION['report_tempdata']['columns_filter'] = array(
  138. 'all_courses' => true,
  139. 'selected_courses' => array(),
  140. 'showed_columns' => array('completed'=>true, 'initinere'=>true, 'notstarted'=>true, 'show_percentages'=>true)
  141. );
  142. }
  143. $ref =& $_SESSION['report_tempdata']['columns_filter'];
  144. if (isset($_POST['update_tempdata'])) {
  145. $selector->parseForState($_POST);
  146. $temp = $selector->getSelection($_POST);
  147. $ref['selected_courses'] = $temp;
  148. $ref['all_courses'] = (Get::req('all_courses', DOTY_INT, 1)==1 ? true : false);
  149. $ref['showed_columns'] = array(
  150. 'completed' => (Get::req('cols_completed', DOTY_INT, 0)>0 ? true : false),
  151. 'initinere' => (Get::req('cols_initinere', DOTY_INT, 0)>0 ? true : false),
  152. 'notstarted' => (Get::req('cols_notstarted', DOTY_INT, 0)>0 ? true : false),
  153. 'show_percentages' => (Get::req('cols_show_percentages', DOTY_INT, 0)>0 ? true : false));
  154. }
  155. else
  156. {
  157. $selector->resetSelection($ref['selected_courses']);
  158. }
  159. //back to columns category selection
  160. if (isset($_POST['undo_filter'])) {
  161. Util::jump_to($back_url);
  162. }
  163. //filter setting done, go to next step
  164. if (isset($_POST['import_filter']) || isset($_POST['show_filter']) || isset($_POST['pre_filter'])) {
  165. $temp_url = $next_url;
  166. if (isset($_POST['pre_filter'])) $temp_url.='&show=1&nosave=1';
  167. if (isset($_POST['show_filter'])) $temp_url.='&show=1';
  168. Util::jump_to($temp_url);
  169. }
  170. $temp = count($ref['selected_courses']);
  171. $box = new ReportBox('courses_selector');
  172. $box->title = $this->lang->def('_COURSES_SELECTION_TITLE');
  173. $box->description = false;
  174. $boxlang =& DoceboLanguage::createInstance('report', 'framework');
  175. $box->body .= '<div class="fc_filter_line filter_corr">';
  176. $box->body .= '<input id="all_courses" name="all_courses" type="radio" value="1" '.($ref['all_courses'] ? 'checked="checked"' : '').' />';
  177. $box->body .= ' <label for="all_courses">'.$boxlang->def('_ALL_COURSES').'</label>';
  178. $box->body .= ' <input id="sel_courses" name="all_courses" type="radio" value="0" '.($ref['all_courses'] ? '' : 'checked="checked"').' />';
  179. $box->body .= ' <label for="sel_courses">'.$boxlang->def('_SEL_COURSES').'</label>';
  180. $box->body .= '</div>';
  181. $box->body .= '<div id="selector_container"'.($ref['all_courses'] ? ' style="display:none"' : '').'>';
  182. $box->body .= $selector->loadCourseSelector(true).'</div>';
  183. $box->footer = $boxlang->def('_CURRENT_SELECTION').':&nbsp;<span id="csel_foot">'.($ref['all_courses'] ? $boxlang->def('_ALL') : ($temp!='' ? $temp : '0')).'</span>';
  184. YuiLib::load(array(
  185. 'yahoo' => 'yahoo-min.js',
  186. 'yahoo-dom-event' => 'yahoo-dom-event.js',
  187. 'element' => 'element-beta-min.js',
  188. 'datasource' => 'datasource-beta-min.js',
  189. 'connection' => 'connection-min.js',
  190. 'event' => 'event-min.js',
  191. 'json' => 'json-beta-min.js'
  192. ), array(
  193. '/assets/skins/sam' => 'skin.css'
  194. ));
  195. addJs($GLOBALS['where_lms_relative'].'/admin/modules/report/','courses_filter.js');
  196. cout('<script type="text/javascript"> '."\n".
  197. 'var courses_count="'.($temp!='' ? $temp : '0').'";'."\n".
  198. 'var courses_all="'.$boxlang->def('_ALL').'";'."\n".
  199. 'YAHOO.util.Event.addListener(window, "load", function(e){ courses_selector_init(); });'."\n".
  200. '</script>', 'page_head');
  201. //columns selection
  202. $col_box = new ReportBox('columns_selection');
  203. $col_box->title = $this->lang->def('_REPORT_SEL_COLUMNS');
  204. $col_box->description = $this->lang->def('_SELECT_THE_DATA_COL_NEEDED');
  205. $col_box->body .= Form::getOpenFieldSet($this->lang->def('_STATUS'));
  206. $col_box->body .= Form::getCheckBox(Lang::t('_USER_STATUS_SUBS', 'course'), 'cols_notstarted', 'cols_notstarted', 1, $ref['showed_columns']['notstarted']);
  207. $col_box->body .= Form::getCheckBox(Lang::t('_USER_STATUS_BEGIN', 'course'), 'cols_initinere', 'cols_initinere', 1, $ref['showed_columns']['initinere']);
  208. $col_box->body .= Form::getCheckBox(Lang::t('_USER_STATUS_END', 'course'), 'cols_completed', 'cols_completed', 1, $ref['showed_columns']['completed']);
  209. $col_box->body .= Form::getCheckBox(Lang::t('_PERCENTAGE', 'course'), 'cols_show_percentages', 'cols_show_percentages', 1, $ref['showed_columns']['show_percentages']);
  210. $col_box->body .= Form::getCloseFieldSet();
  211. cout(Form::openForm('first_step_user_filter', $jump_url, false, 'post').
  212. $box->get().
  213. $col_box->get().
  214. Form::getHidden('update_tempdata', 'update_tempdata', 1));
  215. }
  216. function show_report_courses($data = NULL, $other = '') {
  217. if ($data===NULL)
  218. cout( $this->_get_courses_query() );
  219. else
  220. cout( $this->_get_courses_query('html', $data, $other) );
  221. }
  222. function _get_courses_query($type = 'html', $report_data = NULL, $other = '') {
  223. require_once($GLOBALS['where_lms'].'/lib/lib.course.php');
  224. require_once(dirname(__FILE__).'/report_tableprinter.php');
  225. if ($report_data==NULL) $ref =& $_SESSION['report_tempdata']; else $ref =& $report_data;
  226. $fw = $GLOBALS['prefix_fw'];
  227. $lms = $GLOBALS['prefix_lms'];
  228. $sel_all = $ref['rows_filter']['select_all'];
  229. $sel_type = $ref['rows_filter']['selection_type'];
  230. $selection = $ref['rows_filter']['selection'];
  231. $all_courses = $ref['columns_filter']['all_courses'];
  232. $courses = $ref['columns_filter']['selected_courses'];
  233. $cols =& $ref['columns_filter']['showed_columns'];
  234. $acl = new DoceboACLManager();
  235. $html = '';
  236. $man = new Man_Course();
  237. $courses_codes = $man->getAllCourses();
  238. if ($all_courses) {
  239. $courses = array();
  240. foreach ($courses_codes as $key=>$val) $courses[] = $key;
  241. }
  242. /*
  243. if(Docebo::user()->getUserLevelId() != ADMIN_GROUP_GODADMIN) {
  244. // if the usre is a subadmin with only few course assigned
  245. require_once(_base_.'/lib/lib.preference.php');
  246. $adminManager = new AdminPreference();
  247. $admin_tree = $adminManager->getAdminTree(Docebo::user()->getIdST());
  248. $courses = array_intersect($courses, $admin_tree['courses']);
  249. }
  250. */
  251. $increment = 0;
  252. if ($cols['completed']) $increment++;
  253. if ($cols['initinere']) $increment++;
  254. if ($cols['notstarted']) $increment++;
  255. if ($cols['show_percentages']) $increment = $increment*2;
  256. /*
  257. //admin users filter
  258. $acl_man = Docebo::user()->getACLManager();
  259. $userlevelid = Docebo::user()->getUserLevelId();
  260. if ( $userlevelid != ADMIN_GROUP_GODADMIN ) {
  261. require_once(_base_.'/lib/lib.preference.php');
  262. $adminManager = new AdminPreference();
  263. $admin_tree = $adminManager->getAdminTree(Docebo::user()->getIdST());
  264. $admin_users = $acl_man->getAllUsersFromSelection($admin_tree);
  265. $admin_users = array_unique($admin_users);
  266. }*/
  267. $userlevelid = Docebo::user()->getUserLevelId();
  268. if( $userlevelid != ADMIN_GROUP_GODADMIN && !Docebo::user()->isAnonymous()) {
  269. //filter users
  270. $alluser = false;
  271. require_once(_base_.'/lib/lib.preference.php');
  272. $adminManager = new AdminPreference();
  273. $admin_users = $adminManager->getAdminUsers(Docebo::user()->getIdST());
  274. //$user_selected = array_intersect($user_selected, $admin_users);
  275. //unset($admin_users);
  276. //filter courses
  277. $admin_courses = $adminManager->getAdminCourse(Docebo::user()->getIdST());
  278. if ($all_courses)
  279. {
  280. $all_courses = false;
  281. $rs = sql_query("SELECT idCourse FROM %lms_course");
  282. $course_selected = array();
  283. while (list($id_course) = sql_fetch_row($rs)) { $course_selected[] = $id_course; }
  284. }
  285. if(isset($admin_courses['course'][0]))
  286. {
  287. //No filter
  288. }
  289. elseif(isset($admin_courses['course'][-1]))
  290. {
  291. require_once(_lms_.'/lib/lib.catalogue.php');
  292. $cat_man = new Catalogue_Manager();
  293. $user_catalogue = $cat_man->getUserAllCatalogueId(Docebo::user()->getIdSt());
  294. if(count($user_catalogue) > 0)
  295. {
  296. $courses = array(0);
  297. foreach($user_catalogue as $id_cat)
  298. {
  299. $catalogue_course =& $cat_man->getCatalogueCourse($id_cat, true);
  300. $courses = array_merge($courses, $catalogue_course);
  301. }
  302. foreach($courses as $id_course)
  303. if($id_course != 0)
  304. $admin_courses['course'][$id_course] = $id_course;
  305. }
  306. elseif(Get::sett('on_catalogue_empty', 'off') == 'on')
  307. {
  308. //No filter
  309. }
  310. if(!empty($admin_courses['course']))
  311. {
  312. $_clist = array_values($admin_courses['course']);
  313. $course_selected = array_intersect($course_selected, $_clist);
  314. }
  315. else
  316. $course_selected = array();
  317. }
  318. else
  319. {
  320. $array_courses = array();
  321. $array_courses = array_merge($array_courses, $admin_courses['course']);
  322. if(!empty($admin_courses['coursepath']))
  323. {
  324. require_once(_lms_.'/lib/lib.coursepath.php');
  325. $path_man = new Catalogue_Manager();
  326. $coursepath_course =& $path_man->getAllCourses($admin_courses['coursepath']);
  327. $array_courses = array_merge($array_courses, $coursepath_course);
  328. }
  329. if(!empty($admin_courses['catalogue']))
  330. {
  331. require_once(_lms_.'/lib/lib.catalogue.php');
  332. $cat_man = new Catalogue_Manager();
  333. foreach($admin_courses['catalogue'] as $id_cat)
  334. {
  335. $catalogue_course =& $cat_man->getCatalogueCourse($id_cat, true);
  336. $array_courses = array_merge($array_courses, $catalogue_course);
  337. }
  338. }
  339. $admin_courses['course'] = array_merge($admin_courses['course'], $array_courses);
  340. if(!empty($admin_courses['course']))
  341. {
  342. $_clist = array_values($admin_courses['course']);
  343. $course_selected = array_intersect($course_selected, $_clist);
  344. }
  345. else
  346. $course_selected = array();
  347. }
  348. unset($admin_courses);
  349. }
  350. switch ($sel_type) {
  351. case 'groups': {
  352. //retrieve all labels
  353. $orgchart_labels = array();
  354. $query = "SELECT * FROM ".$fw."_org_chart WHERE lang_code='".getLanguage()."'";
  355. $res = sql_query($query);
  356. while ($row = mysql_fetch_assoc($res)) {
  357. $orgchart_labels[$row['id_dir']] = $row['translation'];
  358. }
  359. $labels = array();
  360. $query = "SELECT * FROM ".$fw."_group WHERE (hidden='false' OR groupid LIKE '/oc_%' OR groupid LIKE '/ocd_%') AND type='free'";
  361. $res = sql_query($query);
  362. while ($row = mysql_fetch_assoc($res)) {
  363. if ($row['hidden']=='false') {
  364. $labels[$row['idst']] = $acl->relativeId($row['groupid']);
  365. } else {
  366. $temp = explode("_", $row['groupid']); //echo '<div>'.print_r($temp,true).'</div>';
  367. if ($temp[0]=='/oc') {
  368. $labels[$row['idst']] = ($temp[1]!=0 ? $orgchart_labels[$temp[1]] : '');
  369. } elseif ($temp[0]=='/ocd') {
  370. $labels[$row['idst']] = ($temp[1]!=0 ? $orgchart_labels[$temp[1]] : '');
  371. }
  372. }
  373. }
  374. $tot_size = 2;
  375. $head1 = array( array('colspan'=>2, 'value'=>$this->lang->def('_GROUPS')) );
  376. $head2 = array($this->lang->def('_NAME'), $this->lang->def('_TOTAL'));
  377. foreach ($courses as $course) {
  378. $head1[] = array(
  379. 'value' => ( $courses_codes[$course]['code'] ? '['.$courses_codes[$course]['code'].'] ' : '' )
  380. .$courses_codes[$course]['name'],
  381. 'colspan' => $increment
  382. );
  383. if ($cols['completed']) $head2[] = $this->lang->def('_USER_STATUS_END');
  384. if ($cols['completed'] && $cols['show_percentages']) $head2[] = _PERCENT_SIMBOL;
  385. if ($cols['initinere']) $head2[] = $this->lang->def('_USER_STATUS_BEGIN');
  386. if ($cols['initinere'] && $cols['show_percentages']) $head2[] = _PERCENT_SIMBOL;
  387. if ($cols['notstarted']) $head2[] = $this->lang->def('_USER_STATUS_SUBS');
  388. if ($cols['notstarted'] && $cols['show_percentages']) $head2[] = _PERCENT_SIMBOL;
  389. $tot_size += $increment;
  390. }
  391. $buffer = new ReportTablePrinter($type, true);
  392. $buffer->openTable('','');
  393. $buffer->openHeader();
  394. $buffer->addHeader($head1);
  395. $buffer->addHeader($head2);
  396. $buffer->closeHeader();
  397. $tot_users = 0;
  398. $course_stats = array();
  399. //for each group, retrieve label and user statistics
  400. foreach ($selection as $dir_id=>$group_id) {
  401. $group_users = $acl->getGroupAllUser($group_id);
  402. if ( $userlevelid != ADMIN_GROUP_GODADMIN && !Docebo::user()->isAnonymous()) { $group_users = array_intersect($group_users, $admin_users); }
  403. $users_num = count($group_users);
  404. $line = array();
  405. $line[] = $labels[$group_id];
  406. $line[] = $users_num;
  407. $tot_users += $users_num;
  408. if (count($group_users)>0) {
  409. $query = "SELECT cu.idUser, cu.idCourse, cu.status ".
  410. " FROM ".$lms."_courseuser as cu, ".$lms."_course as c, ".$fw."_user as u ".
  411. " WHERE cu.idUser=u.idst AND cu.idCourse=c.idCourse ".
  412. " AND u.idst IN (".implode(",", $group_users).") ".
  413. (!$all_courses ? " AND c.idCourse IN (".implode(",", $courses)." )" : "");
  414. $res = sql_query($query);
  415. //$tot_completed = 0;
  416. while ($row = mysql_fetch_assoc($res) ) {
  417. if (!isset($course_stats[$row['idCourse']][$group_id])) {
  418. $course_stats[$row['idCourse']][$group_id] = array(
  419. 'completed' => 0,
  420. 'initinere' => 0,
  421. 'notstarted' => 0,
  422. 'total' => 0
  423. );
  424. }
  425. switch ((int)$row['status']) {
  426. case 2: $course_stats[$row['idCourse']][$group_id]['completed']++; break;
  427. case 1: $course_stats[$row['idCourse']][$group_id]['initinere']++; break;
  428. case 0: $course_stats[$row['idCourse']][$group_id]['notstarted']++; break;
  429. }
  430. $course_stats[$row['idCourse']][$group_id]['total']++;
  431. }
  432. foreach ($courses as $course) {
  433. if (isset($course_stats[$course][$group_id])) {
  434. if ($course_stats[$course][$group_id]['total']==0) $dividend = 1; else $dividend = $course_stats[$course][$group_id]['total'];
  435. if ($cols['completed']) $line[] = $course_stats[$course][$group_id]['completed'];
  436. if ($cols['completed'] && $cols['show_percentages']) $line[] = number_format(100.0*$course_stats[$course][$group_id]['completed']/$dividend, 2, ',', '')._PERCENT_SIMBOL;
  437. if ($cols['initinere']) $line[] = $course_stats[$course][$group_id]['initinere'];
  438. if ($cols['initinere'] && $cols['show_percentages']) $line[] = number_format(100.0*$course_stats[$course][$group_id]['initinere']/$dividend, 2, ',', '')._PERCENT_SIMBOL;
  439. if ($cols['notstarted']) $line[] = $course_stats[$course][$group_id]['notstarted'];
  440. if ($cols['notstarted'] && $cols['show_percentages']) $line[] = number_format(100.0*$course_stats[$course][$group_id]['notstarted']/$dividend, 2, ',', '')._PERCENT_SIMBOL;
  441. } else {
  442. if ($cols['completed']) $line[] = '0';
  443. if ($cols['completed'] && $cols['show_percentages']) $line[] = '0,00%';
  444. if ($cols['initinere']) $line[] = '0';
  445. if ($cols['initinere'] && $cols['show_percentages']) $line[] = '0,00%';
  446. if ($cols['notstarted']) $line[] = '0';
  447. if ($cols['notstarted'] && $cols['show_percentages']) $line[] = '0,00%';
  448. }
  449. }
  450. //$line[] = $tot_completed;
  451. } else {
  452. foreach ($courses as $course) {
  453. if ($cols['completed']) $line[] = '0';
  454. if ($cols['completed'] && $cols['show_percentages']) $line[] = '0,00%';
  455. if ($cols['initinere']) $line[] = '0';
  456. if ($cols['initinere'] && $cols['show_percentages']) $line[] = '0,00%';
  457. if ($cols['notstarted']) $line[] = '0';
  458. if ($cols['notstarted'] && $cols['show_percentages']) $line[] = '0,00%';
  459. }
  460. }
  461. $buffer->addLine($line);
  462. }
  463. $buffer->closeBody();
  464. //echo '<pre>'.print_r($course_stats,true).'</pre>';
  465. //calc totals
  466. $foot = array('', $tot_users);
  467. foreach ($courses as $course) {
  468. $completed_total = 0;
  469. $initinere_total = 0;
  470. $notstarted_total = 0;
  471. $total_total = 0;
  472. foreach ($selection as $dir_id=>$group_id) {
  473. $completed_total += (isset($course_stats[$course][$group_id]['completed']) ? $course_stats[$course][$group_id]['completed'] : 0);
  474. $initinere_total += (isset($course_stats[$course][$group_id]['initinere']) ? $course_stats[$course][$group_id]['initinere'] : 0);
  475. $notstarted_total += (isset($course_stats[$course][$group_id]['notstarted']) ? $course_stats[$course][$group_id]['notstarted'] : 0);
  476. $total_total += (isset($course_stats[$course][$group_id]['total']) ? $course_stats[$course][$group_id]['total'] : 0);
  477. }
  478. if ($cols['completed']) $foot[] = $completed_total;
  479. if ($cols['completed'] && $cols['show_percentages']) $foot[] = ($total_total!=0 ? number_format(100.0*$completed_total/$total_total, 2, _DECIMAL_SEPARATOR, '')._PERCENT_SIMBOL : '0'._DECIMAL_SEPARATOR.'00'._PERCENT_SIMBOL);
  480. if ($cols['initinere']) $foot[] = $initinere_total;
  481. if ($cols['initinere'] && $cols['show_percentages']) $foot[] = ($total_total!=0 ? number_format(100.0*$initinere_total/$total_total, 2, _DECIMAL_SEPARATOR, '')._PERCENT_SIMBOL : '0'._DECIMAL_SEPARATOR.'00'._PERCENT_SIMBOL);
  482. if ($cols['notstarted']) $foot[] = $notstarted_total;
  483. if ($cols['notstarted'] && $cols['show_percentages']) $foot[] = ($total_total!=0 ? number_format(100.0*$notstarted_total/$total_total, 2, _DECIMAL_SEPARATOR, '')._PERCENT_SIMBOL : '0'._DECIMAL_SEPARATOR.'00'._PERCENT_SIMBOL);
  484. }
  485. $buffer->setFoot($foot);
  486. $buffer->closeTable();
  487. $html .= $buffer->get();
  488. } break;
  489. case 'users': {
  490. $temp = array();
  491. // resolve the user selection
  492. $users =& $acl->getAllUsersFromIdst($selection);
  493. if ( $userlevelid != ADMIN_GROUP_GODADMIN && !Docebo::user()->isAnonymous()) { $users = array_intersect($users, $admin_users); }
  494. if (count($users)<=0) {
  495. $html .= '<p>'.$this->lang->def('_EMPTY_SELECTION').'</p>';
  496. break;
  497. }
  498. $query = "SELECT cu.idUser, cu.idCourse, cu.status, u.userId, c.code, u.firstname, u.lastname ".
  499. " FROM ( ".$lms."_courseuser as cu ".
  500. " JOIN ".$lms."_course as c ON ( cu.idCourse = c.idCourse) ) ".
  501. " JOIN ".$fw."_user as u ON (cu.idUser = u.idst) ".
  502. " WHERE 1 ".
  503. " AND cu.idCourse IN (".implode(",", $courses).") ".
  504. ($sel_all ? "" : " AND idUser IN (".implode(",", $users).")")."";
  505. $res = sql_query($query);
  506. while ($row = mysql_fetch_array($res) ) {
  507. if(!isset($temp[$row['idUser']])) {
  508. $temp[$row['idUser']] = array (
  509. 'username' => $acl->relativeId($row['userId']),
  510. 'fullname' => $row['lastname'].' '.$row['firstname'],
  511. 'courses' => array()
  512. );
  513. }
  514. $temp[$row['idUser']]['courses'][$row['idCourse']] = $row['status'];
  515. }
  516. //echo '<pre>';
  517. //print_r($temp);
  518. //draw table
  519. $tot_size = 1;
  520. $head2 = array($this->lang->def('_USERNAME'), $this->lang->def('_FULLNAME'));
  521. $head1 = array(array('colspan'=>2, 'value'=>$this->lang->def('_USER')));
  522. foreach ($courses as $course) {
  523. $head1[] = array(
  524. 'value' => ( $courses_codes[$course]['code'] ? '['.$courses_codes[$course]['code'].'] ' : '' )
  525. .$courses_codes[$course]['name'],
  526. 'colspan' => $increment
  527. );
  528. if ($cols['completed']) $head2[] = $this->lang->def('_USER_STATUS_END');
  529. if ($cols['completed'] && $cols['show_percentages']) $head2[] = _PERCENT_SIMBOL;
  530. if ($cols['initinere']) $head2[] = $this->lang->def('_USER_STATUS_BEGIN');
  531. if ($cols['initinere'] && $cols['show_percentages']) $head2[] = _PERCENT_SIMBOL;
  532. if ($cols['notstarted']) $head2[] = $this->lang->def('_USER_STATUS_SUBS');
  533. if ($cols['notstarted'] && $cols['show_percentages']) $head2[] = _PERCENT_SIMBOL;
  534. $tot_size += $increment;
  535. }
  536. $buffer = new ReportTablePrinter($type, true);
  537. $buffer->openTable('','');
  538. $buffer->openHeader();
  539. $buffer->addHeader($head1);
  540. $buffer->addHeader($head2);
  541. $buffer->closeHeader();
  542. $completed_total = array();
  543. $initinere_total = array();
  544. $notstarted_total = array();
  545. $courses_total = array();
  546. foreach($courses as $course) {
  547. $completed_total[$course] = 0;
  548. $initinere_total[$course] = 0;
  549. $notstarted_total[$course] = 0;
  550. $courses_total[$course] = 0;
  551. }
  552. $buffer->openBody();
  553. foreach ($temp as $id_user => $table_row) {
  554. $line = array();
  555. $line[] = $table_row['username'];
  556. $line[] = $table_row['fullname'];
  557. foreach ($courses as $course) {
  558. if(isset($table_row['courses'][$course])) {
  559. if ($cols['completed']) $line[] = ($table_row['courses'][$course] == 2 ? 1 : 0);
  560. if ($cols['completed'] && $cols['show_percentages']) $line[] = ($table_row['courses'][$course] == 2 ? '100'._DECIMAL_SEPARATOR.'00'._PERCENT_SIMBOL : '0'._PERCENT_SIMBOL);
  561. if ($cols['initinere']) $line[] = ($table_row['courses'][$course] == 1 ? 1 : 0);
  562. if ($cols['initinere'] && $cols['show_percentages']) $line[] = ($table_row['courses'][$course] == 1 ? '100'._DECIMAL_SEPARATOR.'00'._PERCENT_SIMBOL : '0'._PERCENT_SIMBOL);
  563. if ($cols['notstarted']) $line[] = ($table_row['courses'][$course] == 0 ? 1 : 0);
  564. if ($cols['notstarted'] && $cols['show_percentages']) $line[] = ($table_row['courses'][$course] == 0 ? '100'._DECIMAL_SEPARATOR.'00'._PERCENT_SIMBOL : '0'._PERCENT_SIMBOL);
  565. switch ((int)$table_row['courses'][$course]) {
  566. case 2: if (isset($completed_total[$course])) $completed_total[$course] += 1; else $completed_course[$course] = 1; break;
  567. case 1: if (isset($initinere_total[$course])) $initinere_total[$course] += 1; else $initinere_course[$course] = 1; break;
  568. case 0: if (isset($notstarted_total[$course])) $notstarted_total[$course] += 1; else $notstarted_course[$course] = 1; break;
  569. }
  570. if (isset($courses_total[$course])) $courses_total[$course] += 1; else $courses_total[$course] = 1;
  571. } else {
  572. if ($cols['completed']) $line[] = '0';
  573. if ($cols['completed'] && $cols['show_percentages']) $line[] = '0'._PERCENT_SIMBOL;
  574. if ($cols['initinere']) $line[] = '0';
  575. if ($cols['initinere'] && $cols['show_percentages']) $line[] = '0'._PERCENT_SIMBOL;
  576. if ($cols['notstarted']) $line[] = '0';
  577. if ($cols['notstarted'] && $cols['show_percentages']) $line[] = '0'._PERCENT_SIMBOL;
  578. if (isset($courses_total[$course])) $courses_total[$course] += 1; else $courses_total[$course] = 1;
  579. }
  580. }
  581. $buffer->addLine($line);
  582. }
  583. $buffer->closeBody();
  584. $totals_line = array('', '');
  585. foreach ($courses as $course) {
  586. $completed_num = isset($completed_total[$course]) ? $completed_total[$course] : '0';
  587. $initinere_num = isset($initinere_total[$course]) ? $initinere_total[$course] : '0';
  588. $notstarted_num = isset($notstarted_total[$course]) ? $notstarted_total[$course] : '0';
  589. $total_num = isset($courses_total[$course]) ? $courses_total[$course] : '0';
  590. if ($cols['completed']) $totals_line[] = $completed_num;
  591. if ($cols['completed'] && $cols['show_percentages']) $totals_line[] = $total_num!=0 ? number_format(100.0*$completed_num/$total_num, 2, _DECIMAL_SEPARATOR, '')._PERCENT_SIMBOL : '0'._DECIMAL_SEPARATOR.'00'._PERCENT_SIMBOL;
  592. if ($cols['initinere']) $totals_line[] = $initinere_num;
  593. if ($cols['initinere'] && $cols['show_percentages']) $totals_line[] = $total_num!=0 ? number_format(100.0*$initinere_num/$total_num, 2, _DECIMAL_SEPARATOR, '')._PERCENT_SIMBOL : '0'._DECIMAL_SEPARATOR.'00'._PERCENT_SIMBOL;
  594. if ($cols['notstarted']) $totals_line[] = $notstarted_num;
  595. if ($cols['notstarted'] && $cols['show_percentages']) $totals_line[] = $total_num!=0 ? number_format(100.0*$notstarted_num/$total_num, 2, _DECIMAL_SEPARATOR, '')._PERCENT_SIMBOL : '0'._DECIMAL_SEPARATOR.'00'._PERCENT_SIMBOL;
  596. }
  597. $buffer->setFoot($totals_line);
  598. $buffer->closeTable();
  599. $html .= $buffer->get();
  600. } break;
  601. }
  602. return $html;
  603. }
  604. //----------------------------------------------------------------------------
  605. function show_report_coursecategories($data = NULL, $other = '') {
  606. if ($data===NULL)
  607. cout( $this->_get_coursecategories_query() );
  608. else
  609. cout( $this->_get_coursecategories_query('html', $data, $other) );
  610. }
  611. function get_coursecategories_filter() {
  612. $back_url = $this->back_url;
  613. $jump_url = $this->jump_url;
  614. $next_url = $this->next_url;
  615. require_once(_base_.'/lib/lib.form.php');
  616. require_once($GLOBALS['where_lms'].'/lib/lib.course.php');
  617. require_once($GLOBALS['where_lms'].'/lib/category/lib.categorytree.php');
  618. $lang =& DoceboLanguage::createInstance('report', 'framework');
  619. if (isset($_POST['undo_filter'])) Util::jump_to($back_url);
  620. if (!isset($_SESSION['report_tempdata']['columns_filter'])) {
  621. $_SESSION['report_tempdata']['columns_filter'] = array(
  622. 'all_categories' => true,
  623. 'selected_categories' => array(),
  624. 'showed_columns' => array(/*'completed'=>true, 'initinere'=>true, 'notstarted'=>true, 'show_percentages'=>true*/)
  625. );
  626. }
  627. $ref =& $_SESSION['report_tempdata']['columns_filter'];
  628. $tree = new CourseCategoryTree('course_categories_selector', false, false, _TREE_COLUMNS_TYPE_RADIO);
  629. $tree->init();
  630. if (isset($_POST['update_tempdata'])) {
  631. $ref['selected_categories'] = isset($_POST['course_categories_selector_input']) ? explode(",", $_POST['course_categories_selector_input']) : array();
  632. $ref['showed_columns'] = array();
  633. } else {
  634. if ( isset($ref['selected_categories']) && count($ref['selected_categories'])>0 )
  635. $tree->setInitialSelection($ref['selected_categories']);
  636. }
  637. //back to columns category selection
  638. if (isset($_POST['undo_filter'])) {
  639. Util::jump_to($back_url);
  640. }
  641. //filter setting done, go to next step
  642. if (isset($_POST['import_filter']) || isset($_POST['show_filter']) || isset($_POST['pre_filter'])) {
  643. $temp_url = $next_url;
  644. if (isset($_POST['pre_filter'])) $temp_url.='&show=1&nosave=1';
  645. if (isset($_POST['show_filter'])) $temp_url.='&show=1';
  646. Util::jump_to($temp_url);
  647. }
  648. //produce output
  649. $html = '';
  650. $output = $tree->get(true, true, 'treeCat');
  651. cout($output['js'], 'page_head');
  652. $box = new ReportBox('coursecategories_selector');
  653. $box->title = $this->lang->def('_COURSES_SELECTION_TITLE');
  654. $box->description = false;
  655. $boxlang =& DoceboLanguage::createInstance('report', 'framework');
  656. $box->body .= '<div class="">'.$output['html'].'</div>';
  657. $box->body .= Form::getHidden('update_tempdata', 'update_tempdata', 1);
  658. $box->body .= Form::openButtonSpace();
  659. $box->body .= '<button class="button" type="button" onclick="treeCat.clearSelection();">'. Lang::t('_RESET', 'standard').'</button>';
  660. $box->body .= Form::closeButtonSpace();
  661. $html = $box->get();
  662. cout($html);
  663. }
  664. function _get_coursecategories_query($type = 'html', $report_data = NULL, $other = '') {
  665. require_once($GLOBALS['where_lms'].'/lib/lib.course.php');
  666. require_once(dirname(__FILE__).'/report_tableprinter.php');
  667. if ($report_data==NULL) $ref =& $_SESSION['report_tempdata']; else $ref =& $report_data;
  668. $fw = $GLOBALS['prefix_fw'];
  669. $lms = $GLOBALS['prefix_lms'];
  670. $sel_all = $ref['rows_filter']['select_all'];
  671. $sel_type = $ref['rows_filter']['selection_type'];
  672. $selection = $ref['rows_filter']['selection'];
  673. $categories = $ref['columns_filter']['selected_categories'];
  674. $cols =& $ref['columns_filter']['showed_columns'];
  675. if (!$sel_all && count($selection)<=0) {
  676. cout( '<p>'.$this->lang->def('_EMPTY_SELECTION').'</p>' );
  677. return;
  678. }
  679. $acl = new DoceboACLManager();
  680. $acl->include_suspended = true;
  681. $html = '';
  682. //admin users filter
  683. $userlevelid = Docebo::user()->getUserLevelId();
  684. if ( $userlevelid != ADMIN_GROUP_GODADMIN && !Docebo::user()->isAnonymous()) {
  685. require_once(_base_.'/lib/lib.preference.php');
  686. $adminManager = new AdminPreference();
  687. $admin_tree = $adminManager->getAdminTree(Docebo::user()->getIdST());
  688. $admin_users = $acl->getAllUsersFromIdst($admin_tree);
  689. $admin_users = array_unique($admin_users);
  690. }
  691. //course categories names
  692. $res = sql_query("SELECT * FROM ".$lms."_category ");
  693. $categories_names = array();
  694. $categories_limit = array();
  695. while ($row = mysql_fetch_assoc($res)) {
  696. $categories_names[ $row['idCategory'] ] = ($row['path']!='/root/' ? end( explode("/", $row['path'])) : Lang::t('_CATEGORY', 'admin_course_management', 'lms'));// Lang::t('_ROOT'));
  697. $categories_paths[ $row['idCategory'] ] = ($row['path']!='/root/' ? substr($row['path'], 5, (strlen($row['path'])-5)) : Lang::t('_CATEGORY', 'admin_course_management'));// Lang::t('_ROOT'));
  698. $categories_limit[ $row['idCategory'] ] = array($row['iLeft'], $row['iRight']);
  699. }
  700. $user_courses = false;
  701. if(Docebo::user()->getUserLevelId() != ADMIN_GROUP_GODADMIN && !Docebo::user()->isAnonymous()) {
  702. // if the usre is a subadmin with only few course assigned
  703. require_once(_base_.'/lib/lib.preference.php');
  704. $adminManager = new AdminPreference();
  705. $admin_courses = $adminManager->getAdminCourse(Docebo::user()->getIdST());
  706. if(isset($admin_courses['course'][0]))
  707. $user_course = false;
  708. elseif(isset($admin_courses['course'][-1]))
  709. {
  710. require_once(_lms_.'/lib/lib.catalogue.php');
  711. $cat_man = new Catalogue_Manager();
  712. $user_catalogue = $cat_man->getUserAllCatalogueId(Docebo::user()->getIdSt());
  713. if(count($user_catalogue) > 0)
  714. {
  715. $courses = array(0);
  716. foreach($user_catalogue as $id_cat)
  717. {
  718. $catalogue_course =& $cat_man->getCatalogueCourse($id_cat, true);
  719. $courses = array_merge($courses, $catalogue_course);
  720. }
  721. foreach($courses as $id_course)
  722. if($id_course != 0)
  723. $admin_courses['course'][$id_course] = $id_course;
  724. }
  725. elseif(Get::sett('on_catalogue_empty', 'off') == 'on')
  726. $user_course = false;
  727. $user_courses = $admin_courses['course'];
  728. }
  729. else
  730. {
  731. $array_courses = array();
  732. $array_courses = array_merge($array_courses, $admin_courses['course']);
  733. if(!empty($admin_courses['coursepath']))
  734. {
  735. require_once(_lms_.'/lib/lib.coursepath.php');
  736. $path_man = new Catalogue_Manager();
  737. $coursepath_course =& $path_man->getAllCourses($admin_courses['coursepath']);
  738. $array_courses = array_merge($array_courses, $coursepath_course);
  739. }
  740. if(!empty($admin_courses['catalogue']))
  741. {
  742. require_once(_lms_.'/lib/lib.catalogue.php');
  743. $cat_man = new Catalogue_Manager();
  744. foreach($admin_courses['catalogue'] as $id_cat)
  745. {
  746. $catalogue_course =& $cat_man->getCatalogueCourse($id_cat, true);
  747. $array_courses = array_merge($array_courses, $catalogue_course);
  748. }
  749. }
  750. $admin_courses['course'] = array_merge($admin_courses['course'], $array_courses);
  751. $user_courses = $admin_courses['course'];
  752. }
  753. }
  754. //create table
  755. switch ($sel_type) {
  756. case 'users': {
  757. //table data
  758. $data = array();
  759. $head1 = array('');
  760. $head2 = array( $this->lang->def('_USER'));
  761. $totals = array();
  762. foreach ($categories as $idcat) {
  763. $index = (int)str_replace("d", "", $idcat);
  764. $head1[] = array('colspan'=>2, 'value'=>$categories_paths[$index]);
  765. $head2[] = $this->lang->def('_COMPLETED');
  766. $head2[] = $this->lang->def('incomplete');
  767. $is_descendant = strpos($idcat, "d");
  768. if ($is_descendant === false) {
  769. $condition = " AND cat.idCategory=".$index." ";
  770. } else {
  771. list($left, $right) = $categories_limit[$index];//sql_fetch_row( sql_query("SELECT iLeft, iRight FROM ".$lms."_category WHERE idCAtegory=".$index) );
  772. $condition = " AND cat.iLeft >= ".$left." AND cat.iRight <= ".$right." ";
  773. }
  774. //resolve user selection
  775. if ($sel_all)
  776. $selection = $acl->getAllUsersIdst();
  777. else
  778. $selection = $acl->getAllUsersFromIdst( $selection ); //resolve group and orgchart selection
  779. $query = "SELECT cu.idUser, cat.idCategory, c.idCourse, c.code, cu.status "
  780. ." FROM ".$lms."_course as c JOIN ".$lms."_category as cat JOIN ".$lms."_courseuser as cu "
  781. ." ON (c.idCourse=cu.idCourse AND c.idCategory=cat.idCategory) "
  782. ." WHERE ".($sel_all ? " 1 " : " cu.idUser IN (".implode(",", $selection).") " )
  783. .$condition
  784. .( $user_courses != false ? " AND c.idCourse IN ( '".implode("','", $user_courses)."' ) " : '' );
  785. $res = sql_query($query);
  786. $temp = array();
  787. $total_1 = 0;
  788. $total_2 = 0;
  789. while ($row = mysql_fetch_assoc($res)) {
  790. $iduser = $row['idUser'];
  791. if (!isset($temp[ $iduser ]))
  792. $temp[ $iduser ] = array(
  793. 'completed' => 0,
  794. 'not_completed' => 0
  795. );
  796. switch ($row['status']) {
  797. case 0:
  798. case 1: { $temp[$iduser]['not_completed']++; $total_2++; } break;
  799. case 2: { $temp[$iduser]['completed']++; $total_1++; } break;
  800. }
  801. }
  802. $totals[] = $total_1;
  803. $totals[] = $total_2;
  804. $data[ $index ] = $temp;
  805. //unset($temp); //free memory
  806. }
  807. $buffer = new ReportTablePrinter($type, true);
  808. $buffer->openTable('','');
  809. $buffer->openHeader();
  810. $buffer->addHeader($head1);
  811. $buffer->addHeader($head2);
  812. $buffer->closeHeader();
  813. //retrieve usernames
  814. $usernames = array();
  815. $res = sql_query("SELECT idst, userid FROM ".$fw."_user WHERE idst IN (".implode(",", $selection).")");
  816. while (list($idst, $userid) = sql_fetch_row($res))
  817. $usernames[$idst] = $acl->relativeId( $userid );
  818. //user cycle
  819. $buffer->openBody();
  820. foreach ($selection as $user) {
  821. $line = array();
  822. $line[] = ( isset($usernames[ $user ]) ? $usernames[ $user ] : '' );
  823. foreach ($categories as $idcat) {
  824. if ($idcat != '') {
  825. $index = (int)str_replace("d", "", $idcat);
  826. if (isset($data[$index][$user])) {
  827. $line[] = $data[$index][$user]['completed'];
  828. $line[] = $data[$index][$user]['not_completed'];
  829. } else {
  830. $line[] = '0';
  831. $line[] = '0';
  832. }
  833. }
  834. }
  835. $buffer->addLine($line);
  836. }
  837. $buffer->closeBody();
  838. //set totals
  839. $foot = array('');
  840. foreach ($totals as $total) { $foot[] = $total; }
  841. $buffer->setFoot($foot);
  842. //unset($data); //free memory
  843. $buffer->closeTable();
  844. $html .= $buffer->get();
  845. } break;
  846. //-----------------------------------------
  847. case 'groups': {
  848. //table data
  849. $data = array();
  850. //retrieve all labels
  851. $orgchart_labels = array();
  852. $query = "SELECT * FROM ".$fw."_org_chart WHERE lang_code='".getLanguage()."'";
  853. $res = sql_query($query);
  854. while ($row = mysql_fetch_assoc($res)) {
  855. $orgchart_labels[$row['id_dir']] = $row['translation'];
  856. }
  857. $labels = array();
  858. //$query = "SELECT * FROM ".$fw."_group WHERE (hidden='false' OR groupid LIKE '/oc_%' OR groupid LIKE '/ocd_%') AND type='free'";
  859. $query = "SELECT * FROM ".$fw."_group WHERE groupid LIKE '/oc\_%' OR groupid LIKE '/ocd\_%' OR hidden = 'false' ";
  860. $res = sql_query($query);
  861. while ($row = mysql_fetch_assoc($res)) {
  862. if ($row['hidden']=='false') {
  863. $labels[$row['idst']] = $acl->relativeId($row['groupid']);
  864. } else {
  865. $temp = explode("_", $row['groupid']); //echo '<div>'.print_r($temp,true).'</div>';
  866. if ($temp[0]=='/oc') {
  867. $labels[$row['idst']] = ($temp[1]!=0 ? $orgchart_labels[$temp[1]] : '');
  868. } elseif ($temp[0]=='/ocd') {
  869. $labels[$row['idst']] = ($temp[1]!=0 ? $orgchart_labels[$temp[1]] : '');
  870. }
  871. }
  872. }
  873. //solve groups user
  874. $solved_groups = array();
  875. $subgroups_list = array();
  876. foreach ($selection as $group) {
  877. $temp = $acl->getGroupGDescendants($group);
  878. $temp[] = $group;
  879. foreach ($temp as $idst_subgroup) {
  880. $solved_groups[$idst_subgroup] = $group;
  881. }
  882. $subgroups_list = array_merge( $subgroups_list, $temp );
  883. }
  884. $tot_size = 2;
  885. $totals = array();
  886. $head1 = array( array('colspan'=>2, 'value'=>$this->lang->def('_GROUPS')) );
  887. $head2 = array($this->lang->def('_NAME'), $this->lang->def('_TOTAL'));
  888. foreach ($categories as $idcat) {
  889. $index = (int)str_replace("d", "", $idcat);
  890. $head1[] = array('colspan'=>2, 'value'=>$categories_paths[$index]);
  891. $head2[] = $this->lang->def('_COMPLETED');
  892. $head2[] = $this->lang->def('incomplete');
  893. $is_descendant = strpos($idcat, "d");
  894. $condition = '';
  895. if ($is_descendant === false) {
  896. $condition = " AND cat.idCategory=".$index." ";
  897. } else {
  898. list($left, $right) = $categories_limit[$index];//sql_fetch_row( sql_query("SELECT iLeft, iRight FROM ".$lms."_category WHERE idCAtegory=".$index) );
  899. $condition = " AND cat.iLeft >= ".$left." AND cat.iRight <= ".$right." ";
  900. }
  901. $query = "SELECT gm.idst as idGroup, cu.idUser, cat.idCategory, c.idCourse, c.code, cu.status "
  902. ." FROM ".$lms."_course as c JOIN ".$lms."_category as cat JOIN ".$lms."_courseuser as cu JOIN ".$fw."_group_members as gm "
  903. ." ON (c.idCourse=cu.idCourse AND c.idCategory=cat.idCategory AND cu.idUser=gm.idstMember) "
  904. ." WHERE ".($sel_all ? " 1 " : " gm.idst IN (".implode(",", $subgroups_list).") " ) //idst of the groups
  905. .$condition
  906. .( $user_courses != false ? " AND c.idCourse IN ( '".implode("','", $user_courses)."' ) " : '' );
  907. $res = sql_query($query);
  908. $temp = array();
  909. $total_1 = 0;
  910. $total_2 = 0;
  911. while ($row = mysql_fetch_assoc($res)) {
  912. $id_group = $solved_groups[ $row['idGroup'] ];
  913. if (!isset($temp[ $id_group ]))
  914. $temp[ $id_group ] = array(
  915. 'completed' => 0,
  916. 'not_completed' => 0
  917. );
  918. switch ($row['status']) {
  919. case 0:
  920. case 1: { $temp[$id_group]['not_completed']++; $total_2++; } break;
  921. case 2: { $temp[$id_group]['completed']++; $total_1++; } break;
  922. }
  923. }
  924. $totals[]= $total_1;
  925. $totals[]= $total_2;
  926. $data[ $index ] = $temp;
  927. //unset($temp); //free memory
  928. }
  929. $buffer = new ReportTablePrinter($type, true);
  930. $buffer->openTable('','');
  931. $buffer->openHeader();
  932. $buffer->addHeader($head1);
  933. $buffer->addHeader($head2);
  934. $buffer->closeHeader();
  935. $tot_users = 0;
  936. $buffer->openBody();
  937. foreach ($selection as $dir_id=>$group_id) {
  938. $group_users = $acl->getGroupAllUser($group_id);
  939. if ( $userlevelid != ADMIN_GROUP_GODADMIN && !Docebo::user()->isAnonymous()) { $group_users = array_intersect($group_users, $admin_users); }
  940. $users_num = count($group_users);
  941. $line = array();
  942. $line[] = $labels[$group_id];
  943. $line[] = $users_num;
  944. $tot_users += $users_num;
  945. foreach ($categories as $idcat) {
  946. if ($idcat != '') {
  947. $index = (int)str_replace("d", "", $idcat);
  948. if (isset($data[$index][$group_id])) {
  949. $line[] = $data[$index][$group_id]['completed'];
  950. $line[] = $data[$index][$group_id]['not_completed'];
  951. } else {
  952. $line[] = '0';
  953. $line[] = '0';
  954. }
  955. }
  956. }
  957. $buffer->addLine($line);
  958. }
  959. $buffer->closeBody();
  960. //totals ...
  961. $foot = array('', $tot_users);
  962. foreach ($totals as $total) { $foot[] = $total; }
  963. $buffer->setFoot($foot);
  964. $buffer->closeTable();
  965. $html .= $buffer->get();
  966. } break;
  967. } //end switch
  968. $GLOBALS['page']->add($html, 'content');
  969. }
  970. //----------------------------------------------------------------------------
  971. function show_report_time($data = NULL, $other = '') {
  972. if ($data===NULL)
  973. cout( $this->_get_time_query() );
  974. else
  975. cout( $this->_get_time_query('html', $data, $other) );
  976. }
  977. function get_time_filter() {
  978. $back_url = $this->back_url;
  979. $jump_url = $this->jump_url;
  980. $next_url = $this->next_url;
  981. require_once(_base_.'/lib/lib.form.php');
  982. $lang =& DoceboLanguage::createInstance('report', 'framework');
  983. //$sel = new Course_Manager();
  984. //$sel->setLink('index.php?modname=report&op=report_rows_filter');
  985. if (isset($_POST['undo_filter'])) Util::jump_to($back_url);
  986. if (!isset($_SESSION['report_tempdata']['columns_filter'])) {
  987. $_SESSION['report_tempdata']['columns_filter'] = array(
  988. 'timetype' => 'years',
  989. 'years' => 1,
  990. 'months' => 12
  991. );
  992. }
  993. $ref =& $_SESSION['report_tempdata']['columns_filter'];
  994. if (isset($_POST['update_tempdata'])) {
  995. $ref['years'] = Get::req('years', DOTY_INT, 1);
  996. } else {
  997. //...
  998. }
  999. //back to columns category selection
  1000. if (isset($_POST['undo_filter'])) {
  1001. Util::jump_to($back_url);
  1002. }
  1003. //filter setting done, go to next step
  1004. if (isset($_POST['import_filter']) || isset($_POST['show_filter']) || isset($_POST['pre_filter'])) {
  1005. $temp_url = $next_url;
  1006. if (isset($_POST['pre_filter'])) $temp_url.='&show=1&nosave=1';
  1007. if (isset($_POST['show_filter'])) $temp_url.='&show=1';
  1008. Util::jump_to($temp_url);
  1009. }
  1010. $box = new ReportBox('choose_time');
  1011. $box->title = $this->lang->def('_CHOOSE_TIME');
  1012. $box->description = false;
  1013. $year = date('Y');
  1014. $dropdownyears = array(
  1015. 1 => $year,
  1016. 2 => $year.' - '.($year - 1),
  1017. 3 => $year.' - '.($year - 2),
  1018. 4 => $year.' - '.($year - 3),
  1019. 5 => $year.' - '.($year - 4),
  1020. 6 => $year.' - '.($year - 5),
  1021. 7 => $year.' - '.($year - 6),
  1022. );
  1023. $box->body .= Form::getHidden('update_tempdata', 'update_tempdata', 1);
  1024. $box->body .= Form::getDropDown($this->lang->def('_RA_CAT_TIME'), 'years', 'years', $dropdownyears, $ref['years']);
  1025. $html = $box->get();
  1026. cout($html);
  1027. }
  1028. function _get_time_query($type = 'html', $report_data = NULL, $other = '') {
  1029. require_once($GLOBALS['where_lms'].'/lib/lib.course.php');
  1030. require_once(dirname(__FILE__).'/report_tableprinter.php');
  1031. if ($report_data==NULL) $ref =& $_SESSION['report_tempdata']; else $ref =& $report_data;
  1032. $fw = $GLOBALS['prefix_fw'];
  1033. $lms = $GLOBALS['prefix_lms'];
  1034. $sel_all = $ref['rows_filter']['select_all'];
  1035. $sel_type = $ref['rows_filter']['selection_type'];
  1036. $selection = $ref['rows_filter']['selection'];
  1037. $timetype = $ref['columns_filter']['timetype'];
  1038. $years =& $ref['columns_filter']['years'];
  1039. $months =& $ref['columns_filter']['months'];
  1040. if (!$sel_all && count($selection)<=0) {
  1041. cout( '<p>'.$this->lang->def('_EMPTY_SELECTION').'</p>' );
  1042. return;
  1043. }
  1044. $acl = new DoceboACLManager();
  1045. $acl->include_suspended = true;
  1046. //admin users filter
  1047. $userlevelid = Docebo::user()->getUserLevelId();
  1048. if ( $userlevelid != ADMIN_GROUP_GODADMIN && !Docebo::user()->isAnonymous()) {
  1049. require_once(_base_.'/lib/lib.preference.php');
  1050. $adminManager = new AdminPreference();
  1051. $admin_tree = $adminManager->getAdminTree(Docebo::user()->getIdST());
  1052. $admin_users = $acl_man->getAllUsersFromIdst($admin_tree);
  1053. $admin_users = array_unique($admin_users);
  1054. }
  1055. $html = '';
  1056. $times = array();
  1057. switch ($timetype) {
  1058. case 'years': {
  1059. $now = date('Y');
  1060. for ($i = $now-$years+1; $i<=$now; $i++) { $times[] = $i; }
  1061. } break;
  1062. case 'months':{
  1063. //...
  1064. } break;
  1065. }
  1066. switch ($sel_type) {
  1067. case 'users': {
  1068. $data = array();
  1069. $users_list = ($sel_all ? $acl->getAllUsersIdst() : $acl->getAllUsersFromIdst($selection) );
  1070. $users_list = array_unique($users_list);
  1071. if ( $userlevelid != ADMIN_GROUP_GODADMIN && !Docebo::user()->isAnonymous()) $users_list = array_intersect($users_list, $admin_users);
  1072. $query = "SELECT idUser, YEAR(date_complete) as yearComplete "
  1073. ." FROM ".$lms."_courseuser "
  1074. ." WHERE status=2 "
  1075. .( $userlevelid != ADMIN_GROUP_GODADMIN && !Docebo::user()->isAnonymous()? " AND idUser IN (".implode(",", $users_list).") " : "" );
  1076. $res = sql_query($query);
  1077. while ($row = mysql_fetch_assoc($res)) {
  1078. //$data[ $row['idUser'] ][ $row['yearComplete'] ] = $row['complete'];
  1079. $idUser = $row['idUser'];
  1080. $year = $row['yearComplete'];
  1081. if (!isset($data[ $idUser ][ $year ])) $data[ $idUser ][ $year ] = 0;
  1082. $data[ $idUser ][ $year ]++;
  1083. }
  1084. $usernames = array();
  1085. $query = "SELECT idst, userid FROM ".$fw."_user WHERE idst IN (".implode(",", $users_list).")";
  1086. $res = sql_query($query);
  1087. while ($row = mysql_fetch_assoc($res)) {
  1088. $usernames[ $row['idst'] ] = $acl->relativeId( $row['userid'] );
  1089. }
  1090. //draw table
  1091. $buffer = new ReportTablePrinter($type, true);
  1092. $buffer->openTable('','');
  1093. $head = array($this->lang->def('_USER'));
  1094. foreach ($times as $time) {
  1095. $head[] = $time;
  1096. }
  1097. $head[] = $this->lang->def('_TOTAL');
  1098. $buffer->openHeader();
  1099. $buffer->addHeader($head);
  1100. $buffer->closeHeader();
  1101. $tot_total = 0;
  1102. $buffer->openBody();
  1103. foreach ($users_list as $user) {
  1104. if(!isset($usernames[$user])) break;
  1105. $line = array();
  1106. $line_total = 0;
  1107. $line[] = $usernames[$user];
  1108. foreach ($times as $time) { //years or months
  1109. switch ($timetype) {
  1110. case 'years': {
  1111. if (isset($data[$user][$time])) {
  1112. $line[] = $data[$user][$time];
  1113. $line_total += $data[$user][$time];
  1114. } else
  1115. $line[] = '0';
  1116. } break;
  1117. case 'months': {
  1118. //$year = ...
  1119. //$month = ...
  1120. //$line[] = (isset($data[$group][$year][$month]) ? $data[$group][$year][$month] : '0'); break;
  1121. }
  1122. }
  1123. }
  1124. $line[] = $line_total;
  1125. $tot_total += $line_total;
  1126. $buffer->addLine($line);
  1127. }
  1128. $buffer->closeBody();
  1129. //totals
  1130. $foot = array('');
  1131. foreach ($times as $time) {
  1132. $temp = 0;
  1133. foreach ($users_list as $user) {
  1134. if (isset($data[$user][$time])) $temp += $data[$user][$time];
  1135. }
  1136. $foot[] = $temp;
  1137. }
  1138. $foot[] = $tot_total;
  1139. $buffer->setFoot($foot);
  1140. $buffer->closeTable();
  1141. $html .= $buffer->get();
  1142. } break;
  1143. //--------------------
  1144. case 'groups': {
  1145. //retrieve all labels
  1146. $orgchart_labels = array();
  1147. $query = "SELECT * FROM ".$fw."_org_chart WHERE lang_code='".getLanguage()."'";
  1148. $res = sql_query($query);
  1149. while ($row = mysql_fetch_assoc($res)) {
  1150. $orgchart_labels[$row['id_dir']] = $row['translation'];
  1151. }
  1152. $labels = array();
  1153. //$query = "SELECT * FROM ".$fw."_group WHERE (hidden='false' OR groupid LIKE '/oc_%' OR groupid LIKE '/ocd_%') AND type='free'";
  1154. $query = "SELECT * FROM ".$fw."_group WHERE groupid LIKE '/oc\_%' OR groupid LIKE '/ocd\_%' OR hidden = 'false' ";
  1155. $res = sql_query($query);
  1156. while ($row = mysql_fetch_assoc($res)) {
  1157. if ($row['hidden']=='false') {
  1158. $labels[$row['idst']] = $acl->relativeId($row['groupid']);
  1159. } else {
  1160. $temp = explode("_", $row['groupid']); //echo '<div>'.print_r($temp,true).'</div>';
  1161. if ($temp[0]=='/oc') {
  1162. $labels[$row['idst']] = ($temp[1]!=0 ? $orgchart_labels[$temp[1]] : '');
  1163. } elseif ($temp[0]=='/ocd') {
  1164. $labels[$row['idst']] = ($temp[1]!=0 ? $orgchart_labels[$temp[1]] : '');
  1165. }
  1166. }
  1167. }
  1168. //solve groups user
  1169. $solved_groups = array();
  1170. $subgroups_list = array();
  1171. foreach ($selection as $group) {
  1172. $temp = $acl->getGroupGDescendants($group);
  1173. $temp[] = $group;
  1174. foreach ($temp as $idst_subgroup) {
  1175. $solved_groups[$idst_subgroup] = $group;
  1176. }
  1177. $subgroups_list = array_merge( $subgroups_list, $temp );
  1178. }
  1179. $query = "SELECT gm.idst as idGroup, YEAR(cu.date_complete) as yearComplete, MONTH(cu.date_complete) as monthComplete "
  1180. ." FROM ".$lms."_courseuser as cu JOIN ".$fw."_group_members as gm ON (cu.idUser=gm.idstMember) "
  1181. ." WHERE status=2 AND gm.idst IN (".implode(",", $subgroups_list).")";
  1182. $data = array();
  1183. $res = sql_query($query);
  1184. while ($row = mysql_fetch_assoc($res)) {
  1185. $idGroup = $solved_groups[ $row['idGroup'] ];
  1186. $year = $row['yearComplete'];
  1187. $month = $row['monthComplete'];
  1188. switch ($timetype) {
  1189. case 'years': {
  1190. if (!isset($data[ $idGroup ][$year])) $data[ $idGroup ][$year] = 0;
  1191. $data[ $idGroup ][$year]++;
  1192. } break;
  1193. case 'months': {
  1194. if (!isset($data[ $idGroup ][$year][$month])) $data[ $idGroup ][$year][$month] = 0;
  1195. $data[ $idGroup ][$year][$month]++;
  1196. } break;
  1197. } //end switch
  1198. }
  1199. //draw table
  1200. $buffer = new ReportTablePrinter($type, true);
  1201. $buffer->openTable('','');
  1202. $head = array($this->lang->def('_GROUPS'), $this->lang->def('_USERS'));
  1203. foreach ($times as $time) {
  1204. $head[] = $time;
  1205. }
  1206. $head[] = $this->lang->def('_TOTAL');
  1207. $buffer->openHeader();
  1208. $buffer->addHeader($head);
  1209. $buffer->closeHeader();
  1210. $tot_users = 0;
  1211. $tot_total = 0;
  1212. $buffer->openBody();
  1213. foreach ($selection as $group) {
  1214. $group_users = $acl->getGroupAllUser($group);
  1215. if ( $userlevelid != ADMIN_GROUP_GODADMIN && !Docebo::user()->isAnonymous()) { $group_users = array_intersect($group_users, $admin_users); }
  1216. $users_num = count($group_users);
  1217. $line = array();
  1218. $line_total = 0;
  1219. $line[] = $labels[$group];
  1220. $line[] = $users_num;
  1221. foreach ($times as $time) { //years or months
  1222. switch ($timetype) {
  1223. case 'years': {
  1224. if (isset($data[$group][$time])) {
  1225. $line[] = $data[$group][$time];
  1226. $line_total += $data[$group][$time];
  1227. } else
  1228. $line[] = '0';
  1229. } break;
  1230. case 'months': {
  1231. //$year = ...
  1232. //$month = ...
  1233. //$line[] = (isset($data[$group][$year][$month]) ? $data[$group][$year][$month] : '0'); break;
  1234. }
  1235. }
  1236. }
  1237. $line[] = $line_total;
  1238. $tot_users += $users_num;
  1239. $tot_total += $line_total;
  1240. $buffer->addLine($line);
  1241. }
  1242. $buffer->closeBody();
  1243. //totals
  1244. $foot = array('', $tot_users);
  1245. foreach ($times as $time) {
  1246. $temp = 0;
  1247. foreach ($selection as $group) {
  1248. if (isset($data[$group][$time])) $temp += $data[$group][$time];
  1249. }
  1250. $foot[] = $temp;
  1251. }
  1252. $foot[] = $tot_total;
  1253. $buffer->setFoot($foot);
  1254. $buffer->closeTable();
  1255. $html .= $buffer->get();
  1256. } break;
  1257. } //end switch
  1258. cout($html);
  1259. }
  1260. //----------------------------------------------------------------------------
  1261. //---- communications report part --------------------------------------------
  1262. //----------------------------------------------------------------------------
  1263. function show_report_communications($data = NULL, $other = '') {
  1264. if ($data===NULL)
  1265. cout( $this->_get_communications_query() );
  1266. else
  1267. cout( $this->_get_communications_query('html', $data, $other) );
  1268. }
  1269. function get_communications_filter() {
  1270. $back_url = $this->back_url;
  1271. $jump_url = $this->jump_url;
  1272. $next_url = $this->next_url;
  1273. //preliminary checks
  1274. if (isset($_POST['undo_filter'])) Util::jump_to($back_url);
  1275. if (!isset($_SESSION['report_tempdata']['columns_filter'])) {
  1276. $_SESSION['report_tempdata']['columns_filter'] = array(
  1277. 'comm_selection' => array(),
  1278. 'all_communications' => false,
  1279. 'comm_start_date' => '',
  1280. 'comm_end_date' => ''
  1281. );
  1282. }
  1283. $ref =& $_SESSION['report_tempdata']['columns_filter'];
  1284. if (isset($_POST['update_tempdata'])) {
  1285. $ref['all_communications'] = Get::req('all_communications', DOTY_INT, 0) > 0;
  1286. $ref['comm_selection'] = Get::req('comm_selection', DOTY_MIXED, array());
  1287. $ref['comm_start_date'] = Format::dateDb(Get::req('comm_start_date', DOTY_STRING, ''), 'date');
  1288. $ref['comm_end_date'] = Format::datedb(Get::req('comm_end_date', DOTY_STRING, ''), 'date');
  1289. } else {
  1290. //...
  1291. }
  1292. //filter setting done, go to next step
  1293. if (isset($_POST['import_filter']) || isset($_POST['show_filter']) || isset($_POST['pre_filter'])) {
  1294. $temp_url = $next_url;
  1295. if (isset($_POST['pre_filter'])) $temp_url.='&show=1&nosave=1';
  1296. if (isset($_POST['show_filter'])) $temp_url.='&show=1';
  1297. Util::jump_to($temp_url);
  1298. }
  1299. //draw filter boxes
  1300. $html = '';
  1301. //time period
  1302. $box = new ReportBox('comm_selector');
  1303. $box->title = Lang::t('_TIME_PERIOD_FILTER', 'report');
  1304. $box->description = false;
  1305. $box->body .= Form::getDatefield(Lang::t('_FROM', 'standard'), 'comm_start_date', 'comm_start_date', $ref['comm_start_date']);
  1306. $box->body .= Form::getDatefield(Lang::t('_TO', 'standard'), 'comm_end_date', 'comm_end_date', $ref['comm_end_date']);
  1307. $html = $box->get();
  1308. //communications selector
  1309. $box = new ReportBox('comm_selector');
  1310. $box->title = Lang::t('_COMMUNICATIONS', 'report');
  1311. $box->description = false;
  1312. require_once(_lms_.'/lib/lib.report.php'); //the comm. table function
  1313. $box->body .= Form::getCheckbox(Lang::t('_ALL', 'report'), 'all_communications', 'all_communications', 1, $ref['all_communications']);
  1314. $box->body .= '<br />';
  1315. $box->body .= getCommunicationsTable($ref['comm_selection']);
  1316. $box->body .= Form::getHidden('update_tempdata', 'update_tempdata', 1);
  1317. $html .= $box->get();
  1318. cout($html);
  1319. }
  1320. function _get_communications_query($type = 'html', $report_data = NULL, $other = '') {
  1321. require_once(dirname(__FILE__).'/report_tableprinter.php');
  1322. if ($report_data==NULL) $ref =& $_SESSION['report_tempdata']; else $ref =& $report_data;
  1323. $_ERR_NOUSER = Lang::t('_EMPTY_SELECTION', 'report');
  1324. $_ERR_NOCOMM = Lang::t('_EMPTY_SELECTION', 'report');
  1325. $_ERR_NODATA = Lang::t('_EMPTY_SELECTION', 'report');
  1326. $lang_type = array(
  1327. 'none' => Lang::t('_NONE', 'communication'),
  1328. 'file' => Lang::t('_LONAME_item', 'storage'),
  1329. 'scorm' => Lang::t('_LONAME_scormorg', 'storage')
  1330. );
  1331. $sel_all = $ref['rows_filter']['select_all'];
  1332. $arr_selected_users = $ref['rows_filter']['selection']; //list of users selected in the filter (users, groups and org.branches)
  1333. $comm_all = $ref['columns_filter']['all_communications'];
  1334. $arr_selected_comm = $ref['columns_filter']['comm_selection']; //list of communications selected in the filter
  1335. $start_date = isset($ref['columns_filter']['comm_start_date']) ? substr($ref['columns_filter']['comm_start_date'], 0, 10) : '';
  1336. $end_date = isset($ref['columns_filter']['comm_end_date']) ? substr($ref['columns_filter']['comm_end_date'], 0, 10) : '';
  1337. //check and validate time period dates
  1338. if (!preg_match('/^(\d{4})\D?(0[1-9]|1[0-2])\D?([12]\d|0[1-9]|3[01])$/', $start_date) || $start_date == '0000-00-00')
  1339. $start_date = '';
  1340. if (!preg_match('/^(\d{4})\D?(0[1-9]|1[0-2])\D?([12]\d|0[1-9]|3[01])$/', $end_date) || $end_date == '0000-00-00')
  1341. $end_date = '';
  1342. if ($start_date != '') $start_date .= ' 00:00:00';
  1343. if ($end_date != '') $end_date .= ' 23:59:59';
  1344. if ($start_date != '' && $end_date != '')
  1345. if ($start_date > $end_date) { //invalid time period
  1346. $start_date = '';
  1347. $end_date = '';
  1348. }
  1349. //instantiate an acl manager
  1350. $acl_man = new DoceboACLManager();
  1351. $acl_man->include_suspended = true;
  1352. //extract user idst from selection
  1353. if ($sel_all) {
  1354. $arr_selected_users = $acl_man->getAllUsersIdst();
  1355. } else {
  1356. $arr_selected_users = $acl_man->getAllUsersFromIdst($arr_selected_users);
  1357. }
  1358. //admin users filter
  1359. $userlevelid = Docebo::user()->getUserLevelId();
  1360. if ( $userlevelid != ADMIN_GROUP_GODADMIN && !Docebo::user()->isAnonymous()) {
  1361. require_once(_base_.'/lib/lib.preference.php');
  1362. $adminManager = new AdminPreference();
  1363. $admin_tree = $adminManager->getAdminTree(Docebo::user()->getIdST());
  1364. $admin_users = $acl_man->getAllUsersFromIdst($admin_tree);
  1365. $admin_users = array_unique($admin_users);
  1366. //filter users selection by admin visible users
  1367. $arr_selected_users = array_intersect($arr_selected_users, $admin_users);
  1368. //free some memory
  1369. unset($admin_tree);
  1370. unset($admin_users);
  1371. unset($adminManager);
  1372. }
  1373. //Has the "All communications" options been selected ?
  1374. if ($comm_all) {
  1375. $query = "SELECT id_comm FROM %lms_communication";
  1376. $res = $this->db->query($query);
  1377. $arr_selected_comm = array();
  1378. while (list($id_comm) = $this->db->fetch_row($res))
  1379. $arr_selected_comm[] = $id_comm;
  1380. }
  1381. //check selected users ...
  1382. //$arr_selected_users = array(); //list of users selected in the filter (users, groups and org.branches)
  1383. if ($arr_selected_users <= 0) {
  1384. cout('<p>'.$_ERR_NOUSER.'</p>');
  1385. return;
  1386. }
  1387. //$arr_selected_comm = array(); //list of communications selected in the filter
  1388. if ($arr_selected_comm <= 0) {
  1389. out('<p>'.$_ERR_NOCOMM.'</p>');
  1390. return;
  1391. }
  1392. //order selected communications by publish date
  1393. $arr_selected_comm = array_unique($arr_selected_comm);
  1394. $query = "SELECT id_comm FROM %lms_communication "
  1395. ." WHERE id_comm IN (".implode(",", $arr_selected_comm).") "
  1396. ." ORDER BY publish_date DESC, title ASC";
  1397. $res = $this->db->query($query);
  1398. if ($this->db->num_rows($res) == count($arr_selected_comm)) {
  1399. $arr_selected_comm = array();
  1400. while (list($id_comm) = $this->db->fetch_row($res)) {
  1401. $arr_selected_comm[] = $id_comm;
  1402. }
  1403. }
  1404. $arr_comm = array(); //array $id_comm => list of generic idst
  1405. foreach ($arr_selected_comm as $id_comm) $arr_comm[$id_comm] = array(); //if no users have been assigned to the games, than display as 0 - 0
  1406. $arr_idst = array(); //flat list of idst
  1407. $query = "SELECT * FROM %lms_communication_access WHERE id_comm IN (".implode(",", $arr_selected_comm).")";
  1408. $res = $this->db->query($query);
  1409. while (list($id_comm, $idst) = $this->db->fetch_row($res)) {
  1410. $arr_idst[] = $idst;
  1411. $arr_comm[$id_comm][] = $idst;
  1412. }
  1413. if (count($arr_idst) <= 0) {
  1414. cout('<p>'.$_ERR_NOUSER.'</p>');
  1415. return;
  1416. }
  1417. $arr_groups = array(); //flat list of group idst
  1418. $query = "SELECT idst FROM %adm_group WHERE idst IN (".implode(",", $arr_idst).")";
  1419. $res = $this->db->query($query);
  1420. while (list($idst) = $this->db->fetch_row($res)) {
  1421. $arr_groups[] = $idst;
  1422. }
  1423. //if any group selected, then extract users and create an array [id_group][id_user]
  1424. $arr_idst_users_flat = array();
  1425. $arr_members = array(); //array $idst group => list of idst
  1426. if (count($arr_groups) > 0) {
  1427. $query = "SELECT idst, idstMember FROM %adm_group_members WHERE "
  1428. ." idst IN (".implode(",", $arr_groups).")"
  1429. ." AND idstMember IN (".implode(",", $arr_selected_users).")";
  1430. $res = $this->db->query($query);
  1431. while (list($idst, $idstMember) = $this->db->fetch_row($res)) {
  1432. $arr_members[$idst][] = $idstMember;
  1433. $arr_idst_users_flat[] = $idstMember;
  1434. }
  1435. }
  1436. //set an array with all users idst ($_all)
  1437. $diff = array_diff($arr_selected_users, $arr_groups);
  1438. $_all_users = array_merge($arr_idst_users_flat, $diff);
  1439. unset($diff);
  1440. if (count($_all_users) <= 0) {
  1441. cout('<p>'.$_ERR_NOUSER.'</p>');
  1442. return;
  1443. }
  1444. //users have been extracted by group, now calculate report's rows ----------
  1445. //get communications info data and put it in an array by id_comm => {info}
  1446. $arr_comm_data = array();
  1447. $query = "SELECT * FROM %lms_communication WHERE id_comm IN (".implode(",", $arr_selected_comm).")";
  1448. $res = $this->db->query($query);
  1449. while ($obj = $this->db->fetch_obj($res)) {
  1450. $arr_comm_data[$obj->id_comm] = array(
  1451. 'title' => $obj->title,
  1452. 'type_of' => $obj->type_of,
  1453. 'publish_date' => $obj->publish_date
  1454. );
  1455. }
  1456. //which selected communication has been seen by selected users?
  1457. $arr_viewed = array();
  1458. $query = "SELECT idReference, COUNT(idUser) as count "
  1459. ." FROM %lms_communication_track WHERE status IN ('completed', 'passed') "
  1460. ." AND idUser IN (".implode(",", $_all_users).") "
  1461. ." AND id_comm IN (".implode(",", $arr_selected_comm).") "
  1462. .($start_date != '' ? " AND dateAttempt >= '".$start_date."' " : "")
  1463. .($end_date != '' ? " AND dateAttempt <= '".$end_date."' " : "")
  1464. ." GROUP BY id_comm";
  1465. $res = $this->db->query($query);
  1466. while ($obj = $this->db->fetch_obj($res)) {
  1467. $arr_viewed[$obj->id_comm] = $obj->count;
  1468. }
  1469. /*
  1470. //user details buffer
  1471. $acl_man = Docebo::user()->getAclManager();
  1472. $user_details = array();
  1473. $query = "SELECT idst, userid FROM %adm_user WHERE idst IN (".implode(",", $_all_users).")";
  1474. $res = $this->db->query($query);
  1475. while ($obj = $this->db->fetch_obj($res)) {
  1476. $user_details[$obj->idst] = $acl_man($obj->userid);
  1477. }
  1478. */
  1479. //set table properties and buffer
  1480. $head = array(
  1481. Lang::t('_DATE', 'report'),
  1482. Lang::t('_COMMUNICATIONS_TITLE', 'report'),
  1483. Lang::t('_COMMUNICATIONS_TYPE', 'report'),
  1484. Lang::t('_COMMUNICATIONS_SEEN', 'report'),
  1485. Lang::t('_COMMUNICATIONS_TOTAL', 'report'),
  1486. Lang::t('_PERCENTAGE', 'report')
  1487. );
  1488. $buffer = new ReportTablePrinter();
  1489. $buffer->openTable('','');
  1490. $buffer->openHeader();
  1491. $buffer->addHeader($head);
  1492. $buffer->closeHeader();
  1493. $buffer->openBody();
  1494. //rows cycle
  1495. foreach ($arr_comm as $id_comm => $comm_id_list) {
  1496. //calculate total assigned users for every communication
  1497. $count = 0;
  1498. foreach ($comm_id_list as $idst) {
  1499. if (array_key_exists($idst, $arr_members)) {
  1500. foreach ($arr_members[$idst] as $idst_user) {
  1501. $count++;
  1502. }
  1503. } else {
  1504. $count++;
  1505. }
  1506. }
  1507. //line (one per communication)
  1508. $line = array();
  1509. $type_of = $arr_comm_data[$id_comm]['type_of'];
  1510. $seen = isset($arr_viewed[$id_comm]) ? $arr_viewed[$id_comm] : 0;
  1511. $line[] = $arr_comm_data[$id_comm]['publish_date'];
  1512. $line[] = $arr_comm_data[$id_comm]['title'];
  1513. $line[] = isset($lang_type[$type_of]) ? $lang_type[$type_of] : '';
  1514. //$line[] = $arr_comm_data[$id_comm]['publish_date'];
  1515. $line[] = $seen;
  1516. $line[] = $count;
  1517. $line[] = number_format(($count > 0 ? $seen/$count : 0)*100, 2, ',', '').' %';
  1518. $buffer->addLine($line);
  1519. }
  1520. $buffer->closeBody();
  1521. $buffer->closeTable();
  1522. cout($buffer->get());
  1523. }
  1524. //----------------------------------------------------------------------------
  1525. //---- games report part --------------------------------------------
  1526. //----------------------------------------------------------------------------
  1527. function show_report_games($data = NULL, $other = '') {
  1528. if ($data===NULL)
  1529. cout( $this->_get_games_query() );
  1530. else
  1531. cout( $this->_get_games_query('html', $data, $other) );
  1532. }
  1533. function get_games_filter() {
  1534. $back_url = $this->back_url;
  1535. $jump_url = $this->jump_url;
  1536. $next_url = $this->next_url;
  1537. //preliminary checks
  1538. if (isset($_POST['undo_filter'])) Util::jump_to($back_url);
  1539. if (!isset($_SESSION['report_tempdata']['columns_filter'])) {
  1540. $_SESSION['report_tempdata']['columns_filter'] = array(
  1541. 'comp_selection' => array(),
  1542. 'all_games' => false,
  1543. 'comp_start_date' => '',
  1544. 'comp_end_date' => ''
  1545. );
  1546. }
  1547. $ref =& $_SESSION['report_tempdata']['columns_filter'];
  1548. if (isset($_POST['update_tempdata'])) {
  1549. $ref['all_games'] = Get::req('all_games', DOTY_INT, 0) > 0;
  1550. $ref['comp_selection'] = Get::req('comp_selection', DOTY_MIXED, array());
  1551. $ref['comp_start_date'] = Format::dateDb(Get::req('comp_start_date', DOTY_STRING, ''), 'date');
  1552. $ref['comp_end_date'] = Format::datedb(Get::req('comp_end_date', DOTY_STRING, ''), 'date');
  1553. } else {
  1554. //...
  1555. }
  1556. //filter setting done, go to next step
  1557. if (isset($_POST['import_filter']) || isset($_POST['show_filter']) || isset($_POST['pre_filter'])) {
  1558. $temp_url = $next_url;
  1559. if (isset($_POST['pre_filter'])) $temp_url.='&show=1&nosave=1';
  1560. if (isset($_POST['show_filter'])) $temp_url.='&show=1';
  1561. Util::jump_to($temp_url);
  1562. }
  1563. //draw filter boxes
  1564. $html = '';
  1565. //time period
  1566. $box = new ReportBox('comm_selector');
  1567. $box->title = Lang::t('_TIME_PERIOD_FILTER', 'report');
  1568. $box->description = false;
  1569. $box->body .= Form::getDatefield(Lang::t('_FROM', 'standard'), 'comp_start_date', 'comp_start_date', $ref['comp_start_date']);
  1570. $box->body .= Form::getDatefield(Lang::t('_TO', 'standard'), 'comp_end_date', 'comp_end_date', $ref['comp_end_date']);
  1571. $html .= $box->get();
  1572. //draw games selector
  1573. $box = new ReportBox('comp_selector');
  1574. $box->title = Lang::t('_CONTEST');
  1575. $box->description = false;
  1576. require_once(_lms_.'/lib/lib.report.php'); //the comm. table function
  1577. $box->body .= Form::getCheckbox(Lang::t('_ALL', 'report'), 'all_games', 'all_games', 1, $ref['all_games']);
  1578. $box->body .= '<br />';
  1579. $box->body .= getGamesTable($ref['comp_selection']);
  1580. $box->body .= Form::getHidden('update_tempdata', 'update_tempdata', 1);
  1581. $html .= $box->get();
  1582. cout($html);
  1583. }
  1584. function _get_games_query($type = 'html', $report_data = NULL, $other = '') {
  1585. require_once(dirname(__FILE__).'/report_tableprinter.php');
  1586. if ($report_data==NULL) $ref =& $_SESSION['report_tempdata']; else $ref =& $report_data;
  1587. $_ERR_NOUSER = Lang::t('_EMPTY_SELECTION', 'report');
  1588. $_ERR_NOCOMP = Lang::t('_EMPTY_SELECTION', 'report');
  1589. $_ERR_NODATA = Lang::t('_NO_CONTENT', 'report');
  1590. require_once(_lms_.'/lib/lib.report.php');
  1591. $lang_type = _getLOtranslations();
  1592. $sel_all = $ref['rows_filter']['select_all'];
  1593. $arr_selected_users = $ref['rows_filter']['selection']; //list of users selected in the filter (users, groups and org.branches)
  1594. $comp_all = $ref['columns_filter']['all_games'];
  1595. $arr_selected_comp = $ref['columns_filter']['comp_selection']; //list of communications selected in the filter
  1596. $start_date = substr($ref['columns_filter']['comp_start_date'], 0, 10);
  1597. $end_date = substr($ref['columns_filter']['comp_end_date'], 0, 10);
  1598. //check and validate time period dates
  1599. if (!preg_match('/^(\d{4})\D?(0[1-9]|1[0-2])\D?([12]\d|0[1-9]|3[01])$/', $start_date) || $start_date == '0000-00-00')
  1600. $start_date = '';
  1601. if (!preg_match('/^(\d{4})\D?(0[1-9]|1[0-2])\D?([12]\d|0[1-9]|3[01])$/', $end_date) || $end_date == '0000-00-00')
  1602. $end_date = '';
  1603. if ($start_date != '') $start_date .= ' 00:00:00';
  1604. if ($end_date != '') $end_date .= ' 23:59:59';
  1605. if ($start_date != '' && $end_date != '')
  1606. if ($start_date > $end_date) { //invalid time period
  1607. $start_date = '';
  1608. $end_date = '';
  1609. }
  1610. //instantiate acl manager
  1611. $acl_man = new DoceboACLManager();
  1612. $acl_man->include_suspended = true;
  1613. //extract user idst from selection
  1614. if ($sel_all) {
  1615. $arr_selected_users = $acl_man->getAllUsersIdst();
  1616. } else {
  1617. $arr_selected_users = $acl_man->getAllUsersFromIdst($arr_selected_users);
  1618. }
  1619. //admin users filter
  1620. $userlevelid = Docebo::user()->getUserLevelId();
  1621. if ( $userlevelid != ADMIN_GROUP_GODADMIN && !Docebo::user()->isAnonymous()) {
  1622. require_once(_base_.'/lib/lib.preference.php');
  1623. $adminManager = new AdminPreference();
  1624. $admin_tree = $adminManager->getAdminTree(Docebo::user()->getIdST());
  1625. $admin_users = $acl_man->getAllUsersFromIdst($admin_tree);
  1626. $admin_users = array_unique($admin_users);
  1627. //filter users selection by admin visible users
  1628. $arr_selected_users = array_intersect($arr_selected_users, $admin_users);
  1629. //free some memory
  1630. unset($admin_tree);
  1631. unset($admin_users);
  1632. unset($adminManager);
  1633. }
  1634. //Has the "All games" options been selected ?
  1635. if ($comp_all) {
  1636. $query = "SELECT id_game FROM %lms_games";
  1637. $res = $this->db->query($query);
  1638. $arr_selected_comp = array();
  1639. while (list($id_game) = $this->db->fetch_row($res))
  1640. $arr_selected_comp[] = $id_game;
  1641. }
  1642. //check selected users ...
  1643. //$arr_selected_users = array(); //list of users selected in the filter (users, groups and org.branches)
  1644. if ($arr_selected_users <= 0) {
  1645. cout('<p>'.$_ERR_NOUSER.'</p>');
  1646. return;
  1647. }
  1648. //$arr_selected_comp = array(); //list of communications selected in the filter
  1649. if ($arr_selected_comp <= 0) {
  1650. cout('<p>'.$_ERR_NOCOMP.'</p>');
  1651. return;
  1652. }
  1653. $arr_comp = array(); //array $id_comm => list of generic idst
  1654. foreach ($arr_selected_comp as $id_game) $arr_comp[$id_game] = array(); //if no users have been assigned to the games, than display as 0 - 0
  1655. $arr_idst = array(); //flat list of idst
  1656. $query = "SELECT * FROM %lms_games_access WHERE id_comp IN (".implode(",", $arr_selected_comp).")";
  1657. $res = $this->db->query($query);
  1658. while (list($id_game, $idst) = $this->db->fetch_row($res)) {
  1659. $arr_idst[] = $idst;
  1660. $arr_comp[$id_game][] = $idst;
  1661. }
  1662. if (count($arr_idst) <= 0) {
  1663. cout('<p>'.$_ERR_NOUSER.'</p>');
  1664. return;
  1665. }
  1666. $arr_groups = array(); //flat list of group idst
  1667. $query = "SELECT idst FROM %adm_group WHERE idst IN (".implode(",", $arr_idst).")";
  1668. $res = $this->db->query($query);
  1669. while (list($idst) = $this->db->fetch_row($res)) {
  1670. $arr_groups[] = $idst;
  1671. }
  1672. //if any group selected, then extract users and create an array [id_group][id_user]
  1673. $arr_idst_users_flat = array();
  1674. $arr_members = array(); //array $idst group => list of idst
  1675. if (count($arr_groups) > 0) {
  1676. $query = "SELECT idst, idstMember FROM %adm_group_members WHERE "
  1677. ." idst IN (".implode(",", $arr_groups).")"
  1678. ." AND idstMember IN (".implode(",", $arr_selected_users).")";
  1679. $res = $this->db->query($query);
  1680. while (list($idst, $idstMember) = $this->db->fetch_row($res)) {
  1681. $arr_members[$idst][] = $idstMember;
  1682. $arr_idst_users_flat[] = $idstMember;
  1683. }
  1684. }
  1685. //set an array with all users idst ($_all)
  1686. $diff = array_diff($arr_selected_users, $arr_groups);
  1687. $_all_users = array_merge($arr_idst_users_flat, $diff);
  1688. unset($diff);
  1689. if (count($_all_users) <= 0) {
  1690. cout('<p>'.$_ERR_NOUSER.'</p>');
  1691. return;
  1692. }
  1693. //users have been extracted by group, now calculate report's rows ----------
  1694. //get games info data and put it in an array by id_game => {info}
  1695. $arr_comp_data = array();
  1696. $query = "SELECT * FROM %lms_games WHERE id_game IN (".implode(",", $arr_selected_comp).")";
  1697. $res = $this->db->query($query);
  1698. while ($obj = $this->db->fetch_obj($res)) {
  1699. $arr_comp_data[$obj->id_game] = array(
  1700. 'title' => $obj->title,
  1701. 'type_of' => $obj->type_of,
  1702. 'start_date' => $obj->start_date,
  1703. 'end_date' => $obj->end_date
  1704. );
  1705. }
  1706. //which selected communication has been seen by selected users?
  1707. $arr_viewed = array();
  1708. $query = "SELECT idReference, COUNT(idUser) as count "
  1709. ." FROM %lms_games_track WHERE status IN ('completed', 'passed') "
  1710. ." AND idUser IN (".implode(",", $_all_users).") "
  1711. ." AND idReference IN (".implode(",", $arr_selected_comp).") "
  1712. .($start_date != '' ? " AND dateAttempt >= '".$start_date."' " : "")
  1713. .($end_date != '' ? " AND dateAttempt <= '".$end_date."' " : "")
  1714. ." GROUP BY idReference";
  1715. $res = $this->db->query($query);
  1716. while ($obj = $this->db->fetch_obj($res)) {
  1717. $arr_viewed[$obj->idReference] = $obj->count;
  1718. }
  1719. //calculate average values, no conditions on the status
  1720. $arr_average = array();
  1721. $query = "SELECT idReference, AVG(current_score) as average_current_score, "
  1722. ." AVG(max_score) as average_max_score, AVG(num_attempts) as average_num_attempts "
  1723. ." FROM %lms_games_track WHERE idUser IN (".implode(",", $_all_users).") "
  1724. ." AND idReference IN (".implode(",", $arr_selected_comp).") "
  1725. .($start_date != '' ? " AND dateAttempt >= '".$start_date."' " : "")
  1726. .($end_date != '' ? " AND dateAttempt <= '".$end_date."' " : "")
  1727. ." GROUP BY idReference";
  1728. $res = $this->db->query($query);
  1729. while ($obj = $this->db->fetch_obj($res)) {
  1730. $arr_average[$obj->idReference] = $obj;
  1731. }
  1732. /*
  1733. //user details buffer
  1734. $acl_man = Docebo::user()->getAclManager();
  1735. $user_details = array();
  1736. $query = "SELECT idst, userid FROM %adm_user WHERE idst IN (".implode(",", $_all_users).")";
  1737. $res = $this->db->query($query);
  1738. while ($obj = $this->db->fetch_obj($res)) {
  1739. $user_details[$obj->idst] = $acl_man($obj->userid);
  1740. }
  1741. */
  1742. //set table properties and buffer
  1743. $head = array(
  1744. Lang::t('_GAMES_TITLE', 'report'),
  1745. Lang::t('_GAMES_TYPE', 'report'),
  1746. Lang::t('_FROM', 'standard'),
  1747. Lang::t('_TO', 'standard'),
  1748. Lang::t('_GAMES_ATTEMPTED', 'report'),
  1749. Lang::t('_GAMES_TOTAL', 'report'),
  1750. Lang::t('_GAMES_PERCENT', 'report'),
  1751. Lang::t('_GAMES_AVG_SCORE', 'report'),
  1752. Lang::t('_GAMES_AVG_MAX_SCORE', 'report'),
  1753. Lang::t('_GAMES_AVG_NUM_ATTEMPTS', 'report'),
  1754. );
  1755. $buffer = new ReportTablePrinter();
  1756. $buffer->openTable('','');
  1757. $buffer->openHeader();
  1758. $buffer->addHeader($head);
  1759. $buffer->closeHeader();
  1760. $buffer->openBody();
  1761. //rows cycle
  1762. foreach ($arr_comp as $id_game => $comp_id_list) {
  1763. //calculate total assigned users for every communication
  1764. $count = 0;
  1765. foreach ($comp_id_list as $idst) {
  1766. if (array_key_exists($idst, $arr_members)) {
  1767. foreach ($arr_members[$idst] as $idst_user) {
  1768. $count++;
  1769. }
  1770. } else {
  1771. $count++;
  1772. }
  1773. }
  1774. //line (one per communication)
  1775. $line = array();
  1776. $type_of = $arr_comp_data[$id_game]['type_of'];
  1777. $completed_by = isset($arr_viewed[$id_game]) ? $arr_viewed[$id_game] : 0;
  1778. $line[] = $arr_comp_data[$id_game]['title'];
  1779. $line[] = isset($lang_type[$type_of]) ? $lang_type[$type_of] : '';
  1780. $line[] = Format::date($arr_comp_data[$id_game]['start_date'], 'date');
  1781. $line[] = Format::date($arr_comp_data[$id_game]['end_date'], 'date');
  1782. $line[] = $completed_by;
  1783. $line[] = $count;
  1784. $line[] = number_format(($count > 0 ? $completed_by/$count : 0)*100, 2, ',', '').' %';
  1785. $avg1 = isset($arr_average[$id_game]) ? $arr_average[$id_game]->average_current_score : '';
  1786. $avg2 = isset($arr_average[$id_game]) ? $arr_average[$id_game]->average_max_score : '';
  1787. $avg3 = isset($arr_average[$id_game]) ? $arr_average[$id_game]->average_num_attempts : '';
  1788. $line[] = number_format($avg1, 2, ',', '.');
  1789. $line[] = number_format($avg2, 2, ',', '.');
  1790. $line[] = number_format($avg3, 2, ',', '.');
  1791. $buffer->addLine($line);
  1792. }
  1793. $buffer->closeBody();
  1794. $buffer->closeTable();
  1795. cout($buffer->get());
  1796. }
  1797. }