flatviewtable.class.php 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513
  1. <?php
  2. /* For licensing terms, see /license.txt */
  3. set_time_limit(0);
  4. use CpChart\Cache as pCache;
  5. use CpChart\Data as pData;
  6. use CpChart\Image as pImage;
  7. /**
  8. * Class FlatViewTable
  9. * Table to display flat view (all evaluations and links for all students)
  10. * @author Stijn Konings
  11. * @author Bert Steppé - (refactored, optimised)
  12. * @author Julio Montoya Armas - Gradebook Graphics
  13. *
  14. * @package chamilo.gradebook
  15. */
  16. class FlatViewTable extends SortableTable
  17. {
  18. public $datagen;
  19. private $selectcat;
  20. private $limit_enabled;
  21. private $offset;
  22. private $mainCourseCategory;
  23. /**
  24. * @param Category $selectcat
  25. * @param array $users
  26. * @param array $evals
  27. * @param array $links
  28. * @param bool $limit_enabled
  29. * @param int $offset
  30. * @param null $addparams
  31. * @param Category $mainCourseCategory
  32. */
  33. public function __construct(
  34. $selectcat,
  35. $users = array(),
  36. $evals = array(),
  37. $links = array(),
  38. $limit_enabled = false,
  39. $offset = 0,
  40. $addparams = null,
  41. $mainCourseCategory = null
  42. ) {
  43. parent:: __construct(
  44. 'flatviewlist',
  45. null,
  46. null,
  47. api_is_western_name_order() ? 1 : 0
  48. );
  49. $this->selectcat = $selectcat;
  50. $this->datagen = new FlatViewDataGenerator(
  51. $users,
  52. $evals,
  53. $links,
  54. array('only_subcat' => $this->selectcat->get_id()),
  55. $mainCourseCategory
  56. );
  57. $this->limit_enabled = $limit_enabled;
  58. $this->offset = $offset;
  59. if (isset($addparams)) {
  60. $this->set_additional_parameters($addparams);
  61. }
  62. // step 2: generate rows: students
  63. $this->datagen->category = $this->selectcat;
  64. $this->mainCourseCategory = $mainCourseCategory;
  65. }
  66. /**
  67. * @param bool $value
  68. */
  69. public function setLimitEnabled($value)
  70. {
  71. $this->limit_enabled = (bool) $value;
  72. }
  73. /**
  74. * @return Category
  75. */
  76. public function getMainCourseCategory()
  77. {
  78. return $this->mainCourseCategory;
  79. }
  80. /**
  81. * Display gradebook graphs
  82. */
  83. public function display_graph_by_resource()
  84. {
  85. $headerName = $this->datagen->get_header_names();
  86. $total_users = $this->datagen->get_total_users_count();
  87. $displayscore = ScoreDisplay::instance();
  88. $customdisplays = $displayscore->get_custom_score_display_settings();
  89. if (empty($customdisplays)) {
  90. echo get_lang('ToViewGraphScoreRuleMustBeEnabled');
  91. return '';
  92. }
  93. $user_results = $this->datagen->get_data_to_graph2(false);
  94. if (empty($user_results) || empty($total_users)) {
  95. echo get_lang('NoResults');
  96. return '';
  97. }
  98. // Removing first name
  99. array_shift($headerName);
  100. // Removing last name
  101. array_shift($headerName);
  102. $pre_result = $new_result = array();
  103. foreach ($user_results as $result) {
  104. for ($i = 0; $i < count($headerName); $i++) {
  105. if (isset($result[$i + 1])) {
  106. $pre_result[$i + 3][] = $result[$i + 1];
  107. }
  108. }
  109. }
  110. $i = 0;
  111. $resource_list = array();
  112. $pre_result2 = array();
  113. foreach ($pre_result as $key => $res_array) {
  114. rsort($res_array);
  115. $pre_result2[] = $res_array;
  116. }
  117. //@todo when a display custom does not exist the order of the color does not match
  118. //filling all the answer that are not responded with 0
  119. rsort($customdisplays);
  120. if ($total_users > 0) {
  121. foreach ($pre_result2 as $key => $res_array) {
  122. $key_list = array();
  123. foreach ($res_array as $user_result) {
  124. $userResult = isset($user_result[1]) ? $user_result[1] : null;
  125. if (!isset($resource_list[$key][$userResult])) {
  126. $resource_list[$key][$userResult] = 0;
  127. }
  128. $resource_list[$key][$userResult] += 1;
  129. $key_list[] = $userResult;
  130. }
  131. foreach ($customdisplays as $display) {
  132. if (!in_array($display['display'], $key_list)) {
  133. $resource_list[$key][$display['display']] = 0;
  134. }
  135. }
  136. $i++;
  137. }
  138. }
  139. //fixing $resource_list
  140. $max = 0;
  141. $new_list = array();
  142. foreach ($resource_list as $key => $value) {
  143. $new_value = array();
  144. foreach ($customdisplays as $item) {
  145. if ($value[$item['display']] > $max) {
  146. $max = $value[$item['display']];
  147. }
  148. $new_value[$item['display']] = strip_tags($value[$item['display']]);
  149. }
  150. $new_list[] = $new_value;
  151. }
  152. $resource_list = $new_list;
  153. $i = 1;
  154. foreach ($resource_list as $key => $resource) {
  155. // Reverse array, otherwise we get highest values first
  156. $resource = array_reverse($resource, true);
  157. $dataSet = new pData();
  158. $dataSet->addPoints($resource, 'Serie');
  159. $dataSet->addPoints(array_keys($resource), 'Labels');
  160. $dataSet->setSerieDescription('Labels', strip_tags($headerName[$i - 1]));
  161. $dataSet->setAbscissa('Labels');
  162. $dataSet->setAbscissaName(get_lang('GradebookSkillsRanking'));
  163. $dataSet->setAxisName(0, get_lang('Students'));
  164. $palette = array(
  165. '0' => array('R' => 186, 'G' => 206, 'B' => 151, 'Alpha' => 100),
  166. '1' => array('R' => 210, 'G' => 148, 'B' => 147, 'Alpha' => 100),
  167. '2' => array('R' => 148, 'G' => 170, 'B' => 208, 'Alpha' => 100),
  168. '3' => array('R' => 221, 'G' => 133, 'B' => 61, 'Alpha' => 100),
  169. '4' => array('R' => 65, 'G' => 153, 'B' => 176, 'Alpha' => 100),
  170. '5' => array('R' => 114, 'G' => 88, 'B' => 144, 'Alpha' => 100),
  171. '6' => array('R' => 138, 'G' => 166, 'B' => 78, 'Alpha' => 100),
  172. '7' => array('R' => 171, 'G' => 70, 'B' => 67, 'Alpha' => 100),
  173. '8' => array('R' => 69, 'G' => 115, 'B' => 168, 'Alpha' => 100),
  174. );
  175. // Cache definition
  176. $cachePath = api_get_path(SYS_ARCHIVE_PATH);
  177. $myCache = new pCache(array('CacheFolder' => substr($cachePath, 0, strlen($cachePath) - 1)));
  178. $chartHash = $myCache->getHash($dataSet);
  179. if ($myCache->isInCache($chartHash)) {
  180. $imgPath = api_get_path(SYS_ARCHIVE_PATH).$chartHash;
  181. $myCache->saveFromCache($chartHash, $imgPath);
  182. $imgPath = api_get_path(WEB_ARCHIVE_PATH).$chartHash;
  183. } else {
  184. /* Create the pChart object */
  185. $widthSize = 480;
  186. $heightSize = 250;
  187. $myPicture = new pImage($widthSize, $heightSize, $dataSet);
  188. /* Turn of Antialiasing */
  189. $myPicture->Antialias = false;
  190. /* Add a border to the picture */
  191. $myPicture->drawRectangle(
  192. 0,
  193. 0,
  194. $widthSize - 1,
  195. $heightSize - 1,
  196. array(
  197. 'R' => 0,
  198. 'G' => 0,
  199. 'B' => 0
  200. )
  201. );
  202. /* Set the default font */
  203. $myPicture->setFontProperties(
  204. array(
  205. 'FontName' => api_get_path(SYS_FONTS_PATH).'opensans/OpenSans-Regular.ttf',
  206. 'FontSize' => 10
  207. )
  208. );
  209. /* Write the chart title */
  210. $myPicture->drawText(
  211. 250,
  212. 30,
  213. strip_tags($headerName[$i - 1]),
  214. array(
  215. 'FontSize' => 12,
  216. 'Align' => TEXT_ALIGN_BOTTOMMIDDLE
  217. )
  218. );
  219. /* Define the chart area */
  220. $myPicture->setGraphArea(50, 40, $widthSize - 20, $heightSize - 50);
  221. /* Draw the scale */
  222. $scaleSettings = array(
  223. 'GridR' => 200,
  224. 'GridG' => 200,
  225. 'GridB' => 200,
  226. 'DrawSubTicks' => true,
  227. 'CycleBackground' => true,
  228. 'Mode' => SCALE_MODE_START0
  229. );
  230. $myPicture->drawScale($scaleSettings);
  231. /* Turn on shadow computing */
  232. $myPicture->setShadow(
  233. true,
  234. array(
  235. 'X' => 1,
  236. 'Y' => 1,
  237. 'R' => 0,
  238. 'G' => 0,
  239. 'B' => 0,
  240. 'Alpha' => 10
  241. )
  242. );
  243. /* Draw the chart */
  244. $myPicture->setShadow(
  245. true,
  246. array(
  247. 'X' => 1,
  248. 'Y' => 1,
  249. 'R' => 0,
  250. 'G' => 0,
  251. 'B' => 0,
  252. 'Alpha' => 10
  253. )
  254. );
  255. $settings = array(
  256. 'OverrideColors' => $palette,
  257. 'Gradient' => false,
  258. 'GradientMode' => GRADIENT_SIMPLE,
  259. 'DisplayPos' => LABEL_POS_TOP,
  260. 'DisplayValues' => true,
  261. 'DisplayR' => 0,
  262. 'DisplayG' => 0,
  263. 'DisplayB' => 0,
  264. 'DisplayShadow' => true,
  265. 'Surrounding' => 10,
  266. );
  267. $myPicture->drawBarChart($settings);
  268. /* Render the picture (choose the best way) */
  269. $myCache->writeToCache($chartHash, $myPicture);
  270. $imgPath = api_get_path(SYS_ARCHIVE_PATH).$chartHash;
  271. $myCache->saveFromCache($chartHash, $imgPath);
  272. $imgPath = api_get_path(WEB_ARCHIVE_PATH).$chartHash;
  273. }
  274. echo '<img src="'.$imgPath.'" >';
  275. if ($i % 2 == 0 && $i != 0) {
  276. echo '<br /><br />';
  277. } else {
  278. echo '&nbsp;&nbsp;&nbsp;';
  279. }
  280. $i++;
  281. }
  282. }
  283. /**
  284. * Function used by SortableTable to get total number of items in the table
  285. */
  286. public function get_total_number_of_items()
  287. {
  288. return $this->datagen->get_total_users_count();
  289. }
  290. /**
  291. * Function used by SortableTable to generate the data to display
  292. */
  293. public function get_table_data(
  294. $from = 1,
  295. $per_page = null,
  296. $column = null,
  297. $direction = null,
  298. $sort = null
  299. ) {
  300. $is_western_name_order = api_is_western_name_order();
  301. // create page navigation if needed
  302. $totalitems = $this->datagen->get_total_items_count();
  303. if ($this->limit_enabled && $totalitems > GRADEBOOK_ITEM_LIMIT) {
  304. $selectlimit = GRADEBOOK_ITEM_LIMIT;
  305. } else {
  306. $selectlimit = $totalitems;
  307. }
  308. $header = null;
  309. if ($this->limit_enabled && $totalitems > GRADEBOOK_ITEM_LIMIT) {
  310. $header .= '<table style="width: 100%; text-align: right; margin-left: auto; margin-right: auto;" border="0" cellpadding="2">'
  311. . '<tbody>'
  312. . '<tr>';
  313. // previous X
  314. $header .= '<td style="width:100%;">';
  315. if ($this->offset >= GRADEBOOK_ITEM_LIMIT) {
  316. $header .= '<a href="'.api_get_self()
  317. . '?selectcat='.Security::remove_XSS($_GET['selectcat'])
  318. . '&offset='.(($this->offset) - GRADEBOOK_ITEM_LIMIT)
  319. . (isset($_GET['search']) ? '&search='.Security::remove_XSS($_GET['search']) : '').'">'
  320. .Display::return_icon(
  321. 'action_prev.png',
  322. get_lang('PreviousPage'),
  323. array(),
  324. ICON_SIZE_MEDIUM
  325. )
  326. . '</a>';
  327. } else {
  328. $header .= Display::return_icon(
  329. 'action_prev_na.png',
  330. get_lang('PreviousPage'),
  331. array(),
  332. ICON_SIZE_MEDIUM
  333. );
  334. }
  335. $header .= ' ';
  336. // next X
  337. $calcnext = (($this->offset + (2 * GRADEBOOK_ITEM_LIMIT)) > $totalitems) ?
  338. ($totalitems - (GRADEBOOK_ITEM_LIMIT + $this->offset)) : GRADEBOOK_ITEM_LIMIT;
  339. if ($calcnext > 0) {
  340. $header .= '<a href="'.api_get_self()
  341. . '?selectcat='.Security::remove_XSS($_GET['selectcat'])
  342. . '&offset='.($this->offset + GRADEBOOK_ITEM_LIMIT)
  343. . (isset($_GET['search']) ? '&search='.Security::remove_XSS($_GET['search']) : '').'">'
  344. . Display::return_icon('action_next.png', get_lang('NextPage'), array(), ICON_SIZE_MEDIUM)
  345. . '</a>';
  346. } else {
  347. $header .= Display::return_icon(
  348. 'action_next_na.png',
  349. get_lang('NextPage'),
  350. array(),
  351. ICON_SIZE_MEDIUM
  352. );
  353. }
  354. $header .= '</td>';
  355. $header .= '</tbody></table>';
  356. echo $header;
  357. }
  358. // retrieve sorting type
  359. if ($is_western_name_order) {
  360. $users_sorting = ($this->column == 0 ? FlatViewDataGenerator::FVDG_SORT_FIRSTNAME : FlatViewDataGenerator::FVDG_SORT_LASTNAME);
  361. } else {
  362. $users_sorting = ($this->column == 0 ? FlatViewDataGenerator::FVDG_SORT_LASTNAME : FlatViewDataGenerator::FVDG_SORT_FIRSTNAME);
  363. }
  364. if ($this->direction == 'DESC') {
  365. $users_sorting |= FlatViewDataGenerator::FVDG_SORT_DESC;
  366. } else {
  367. $users_sorting |= FlatViewDataGenerator::FVDG_SORT_ASC;
  368. }
  369. // step 1: generate columns: evaluations and links
  370. $header_names = $this->datagen->get_header_names($this->offset, $selectlimit);
  371. $userRowSpan = false;
  372. foreach ($header_names as $item) {
  373. if (is_array($item)) {
  374. $userRowSpan = true;
  375. break;
  376. }
  377. }
  378. $thAttributes = '';
  379. if ($userRowSpan) {
  380. $thAttributes = 'rowspan=2';
  381. }
  382. $this->set_header(0, $header_names[0], true, $thAttributes);
  383. $this->set_header(1, $header_names[1], true, $thAttributes);
  384. $column = 2;
  385. $firstHeader = [];
  386. while ($column < count($header_names)) {
  387. $headerData = $header_names[$column];
  388. if (is_array($headerData)) {
  389. $countItems = count($headerData['items']);
  390. $this->set_header(
  391. $column,
  392. $headerData['header'],
  393. false,
  394. 'colspan="'.$countItems.'"'
  395. );
  396. foreach ($headerData['items'] as $item) {
  397. $firstHeader[] = '<center>'.$item.'</center>';
  398. }
  399. } else {
  400. $this->set_header($column, $headerData, false, $thAttributes);
  401. }
  402. $column++;
  403. }
  404. $data_array = $this->datagen->get_data(
  405. $users_sorting,
  406. $from,
  407. $this->per_page,
  408. $this->offset,
  409. $selectlimit
  410. );
  411. $table_data = array();
  412. if (!empty($firstHeader)) {
  413. $table_data[] = $firstHeader;
  414. }
  415. foreach ($data_array as $user_row) {
  416. $user_id = $user_row[0];
  417. unset($user_row[0]);
  418. $userInfo = api_get_user_info($user_id);
  419. if ($is_western_name_order) {
  420. $user_row[1] = $this->build_name_link(
  421. $user_id,
  422. $userInfo['firstname']
  423. );
  424. $user_row[2] = $this->build_name_link(
  425. $user_id,
  426. $userInfo['lastname']
  427. );
  428. } else {
  429. $user_row[1] = $this->build_name_link(
  430. $user_id,
  431. $userInfo['lastname']
  432. );
  433. $user_row[2] = $this->build_name_link(
  434. $user_id,
  435. $userInfo['firstname']
  436. );
  437. }
  438. $user_row = array_values($user_row);
  439. $table_data[] = $user_row;
  440. }
  441. return $table_data;
  442. }
  443. /**
  444. * @param $userId
  445. * @param $name
  446. *
  447. * @return string
  448. */
  449. private function build_name_link($userId, $name)
  450. {
  451. return '<a href="user_stats.php?userid='.$userId.'&selectcat='.$this->selectcat->get_id().'&'.api_get_cidreq().'">'.$name.'</a>';
  452. }
  453. }