userportal.lib.php 107 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458
  1. <?php
  2. /* For licensing terms, see /license.txt */
  3. /**
  4. * Class IndexManager.
  5. */
  6. class IndexManager
  7. {
  8. public const VIEW_BY_DEFAULT = 0;
  9. public const VIEW_BY_SESSION = 1;
  10. // An instance of the template engine
  11. // No need to initialize because IndexManager is not static,
  12. // and the constructor immediately instantiates a Template
  13. public $tpl;
  14. public $name = '';
  15. public $home = '';
  16. public $default_home = 'home/';
  17. /**
  18. * Construct.
  19. *
  20. * @param string $title
  21. */
  22. public function __construct($title)
  23. {
  24. $this->tpl = new Template($title);
  25. $this->home = api_get_home_path();
  26. $this->user_id = api_get_user_id();
  27. $this->load_directories_preview = false;
  28. // Load footer plugins systematically
  29. /*$config = api_get_settings_params(array('subkey = ? ' => 'customfooter', ' AND category = ? ' => 'Plugins'));
  30. if (!empty($config)) {
  31. foreach ($config as $fooid => $configrecord) {
  32. $canonic = preg_replace('/^customfooter_/', '', $configrecord['variable']);
  33. $footerconfig->$canonic = $configrecord['selected_value'];
  34. }
  35. if (!empty($footerconfig->footer_left)) {
  36. $this->tpl->assign('plugin_footer_left', $footerconfig->footer_left);
  37. }
  38. if (!empty($footerconfig->footer_right)) {
  39. $this->tpl->assign('plugin_footer_right', $footerconfig->footer_right);
  40. }
  41. }*/
  42. if (api_get_setting('show_documents_preview') === 'true') {
  43. $this->load_directories_preview = true;
  44. }
  45. }
  46. /**
  47. * @param array $personal_course_list
  48. */
  49. public function return_exercise_block($personal_course_list)
  50. {
  51. $exercise_list = [];
  52. if (!empty($personal_course_list)) {
  53. foreach ($personal_course_list as $course_item) {
  54. $course_code = $course_item['c'];
  55. $session_id = $course_item['id_session'];
  56. $exercises = ExerciseLib::get_exercises_to_be_taken(
  57. $course_code,
  58. $session_id
  59. );
  60. foreach ($exercises as $exercise_item) {
  61. $exercise_item['course_code'] = $course_code;
  62. $exercise_item['session_id'] = $session_id;
  63. $exercise_item['tms'] = api_strtotime($exercise_item['end_time'], 'UTC');
  64. $exercise_list[] = $exercise_item;
  65. }
  66. }
  67. if (!empty($exercise_list)) {
  68. $exercise_list = msort($exercise_list, 'tms');
  69. $my_exercise = $exercise_list[0];
  70. $url = Display::url(
  71. $my_exercise['title'],
  72. api_get_path(
  73. WEB_CODE_PATH
  74. ).'exercise/overview.php?exerciseId='.$my_exercise['id'].'&cidReq='.$my_exercise['course_code'].'&id_session='.$my_exercise['session_id']
  75. );
  76. $this->tpl->assign('exercise_url', $url);
  77. $this->tpl->assign(
  78. 'exercise_end_date',
  79. api_convert_and_format_date($my_exercise['end_time'], DATE_FORMAT_SHORT)
  80. );
  81. }
  82. }
  83. }
  84. /**
  85. * Alias for the online_logout() function.
  86. *
  87. * @param bool $redirect Whether to ask online_logout to redirect to index.php or not
  88. * @param array $logoutInfo Information stored by local.inc.php before new context ['uid'=> x, 'cid'=>y, 'sid'=>z]
  89. */
  90. public function logout($redirect = true, $logoutInfo = [])
  91. {
  92. online_logout($this->user_id, true);
  93. Event::courseLogout($logoutInfo);
  94. }
  95. /**
  96. * This function checks if there are courses that are open to the world in the platform course categories (=faculties).
  97. *
  98. * @param string $category
  99. *
  100. * @return bool
  101. */
  102. public function category_has_open_courses($category)
  103. {
  104. $setting_show_also_closed_courses = api_get_setting('show_closed_courses') == 'true';
  105. $main_course_table = Database::get_main_table(TABLE_MAIN_COURSE);
  106. $category = Database::escape_string($category);
  107. $sql_query = "SELECT * FROM $main_course_table WHERE category_code='$category'";
  108. $sql_result = Database::query($sql_query);
  109. while ($course = Database::fetch_array($sql_result)) {
  110. if (!$setting_show_also_closed_courses) {
  111. if ((api_get_user_id() > 0 && $course['visibility'] == COURSE_VISIBILITY_OPEN_PLATFORM) ||
  112. ($course['visibility'] == COURSE_VISIBILITY_OPEN_WORLD)
  113. ) {
  114. return true; //at least one open course
  115. }
  116. } else {
  117. if (isset($course['visibility'])) {
  118. return true; // At least one course (it does not matter weither it's open or not because $setting_show_also_closed_courses = true).
  119. }
  120. }
  121. }
  122. return false;
  123. }
  124. /**
  125. * Includes a created page.
  126. *
  127. * @param bool $getIncludedFile Whether to include a file as provided in URL GET or simply the homepage
  128. *
  129. * @return string
  130. */
  131. public function return_home_page($getIncludedFile = false)
  132. {
  133. return '';
  134. $userId = api_get_user_id();
  135. // Including the page for the news
  136. $html = '';
  137. if ($getIncludedFile === true) {
  138. if (!empty($_GET['include']) && preg_match('/^[a-zA-Z0-9_-]*\.html$/', $_GET['include'])) {
  139. $open = @(string) file_get_contents($this->home.$_GET['include']);
  140. $html = api_to_system_encoding($open, api_detect_encoding(strip_tags($open)));
  141. }
  142. } else {
  143. // Hiding home top when user not connected.
  144. $hideTop = api_get_setting('hide_home_top_when_connected');
  145. if ($hideTop == 'true' && !empty($userId)) {
  146. return $html;
  147. }
  148. if (!empty($_SESSION['user_language_choice'])) {
  149. $user_selected_language = $_SESSION['user_language_choice'];
  150. } elseif (!empty($_SESSION['_user']['language'])) {
  151. $user_selected_language = $_SESSION['_user']['language'];
  152. } else {
  153. $user_selected_language = api_get_setting('platformLanguage');
  154. }
  155. $home_top_temp = '';
  156. // Try language specific home
  157. if (file_exists($this->home.'home_top_'.$user_selected_language.'.html')) {
  158. $home_top_temp = file_get_contents($this->home.'home_top_'.$user_selected_language.'.html');
  159. }
  160. // Try default language home
  161. if (empty($home_top_temp)) {
  162. if (file_exists($this->home.'home_top.html')) {
  163. $home_top_temp = file_get_contents($this->home.'home_top.html');
  164. } else {
  165. if (file_exists($this->default_home.'home_top.html')) {
  166. $home_top_temp = file_get_contents($this->default_home.'home_top.html');
  167. }
  168. }
  169. }
  170. if (trim($home_top_temp) == '' && api_is_platform_admin()) {
  171. //$home_top_temp = get_lang('<h2>Congratulations! You have successfully installed your e-learning portal!</h2> <p>You can now complete the installation by following three easy steps:<br /> <ol> <li>Configure you portal by going to the administration section, and select the Portal -> <a href="main/admin/settings.php">Configuration settings</a> entry.</li> <li>Add some life to your portal by creating users and/or training. You can do that by inviting new people to create their accounts or creating them yourself through the <a href="main/admin/">administration</a>\'s Users and Training sections.</li> <li>Edit this page through the <a href="main/admin/configure_homepage.php">Edit portal homepage</a> entry in the administration section.</li> </ol> <p>You can always find more information about this software on our website: <a href="http://www.chamilo.org">http://www.chamilo.org</a>.</p> <p>Have fun, and don't hesitate to join the community and give us feedback through <a href="http://www.chamilo.org/forum">our forum</a>.</p>');
  172. } else {
  173. $home_top_temp;
  174. }
  175. $open = str_replace('{rel_path}', api_get_path(REL_PATH), $home_top_temp);
  176. $html = api_to_system_encoding($open, api_detect_encoding(strip_tags($open)));
  177. }
  178. return $html;
  179. }
  180. /**
  181. * @return string
  182. */
  183. public function return_notice()
  184. {
  185. $user_selected_language = api_get_interface_language();
  186. // Notice
  187. $home_notice = @(string) file_get_contents($this->home.'home_notice_'.$user_selected_language.'.html');
  188. if (empty($home_notice)) {
  189. $home_notice = @(string) file_get_contents($this->home.'home_notice.html');
  190. }
  191. if (!empty($home_notice)) {
  192. $home_notice = api_to_system_encoding($home_notice, api_detect_encoding(strip_tags($home_notice)));
  193. }
  194. return $home_notice;
  195. }
  196. /**
  197. * @return string
  198. */
  199. public function return_help()
  200. {
  201. $user_selected_language = api_get_interface_language();
  202. $platformLanguage = api_get_setting('platformLanguage');
  203. // Help section.
  204. /* Hide right menu "general" and other parts on anonymous right menu. */
  205. if (!isset($user_selected_language)) {
  206. $user_selected_language = $platformLanguage;
  207. }
  208. $html = '';
  209. $home_menu = @(string) file_get_contents($this->home.'home_menu_'.$user_selected_language.'.html');
  210. if (!empty($home_menu)) {
  211. $html = api_to_system_encoding($home_menu, api_detect_encoding(strip_tags($home_menu)));
  212. }
  213. return $html;
  214. }
  215. /**
  216. * Generate the block for show a panel with links to My Certificates and Certificates Search pages.
  217. *
  218. * @return array The HTML code for the panel
  219. */
  220. public function returnSkillLinks()
  221. {
  222. $items = [];
  223. if (!api_is_anonymous() &&
  224. api_get_setting('certificate.hide_my_certificate_link') === 'false'
  225. ) {
  226. $items[] = [
  227. 'icon' => Display::return_icon('graduation.png', get_lang('My certificates')),
  228. 'link' => api_get_path(WEB_CODE_PATH).'gradebook/my_certificates.php',
  229. 'title' => get_lang('My certificates'),
  230. ];
  231. }
  232. if (api_get_setting('allow_public_certificates') == 'true') {
  233. $items[] = [
  234. 'icon' => Display::return_icon('search_graduation.png', get_lang('Search')),
  235. 'link' => api_get_path(WEB_CODE_PATH).'gradebook/search.php',
  236. 'title' => get_lang('Search'),
  237. ];
  238. }
  239. $myCertificate = GradebookUtils::get_certificate_by_user_id(
  240. +0,
  241. $this->user_id
  242. );
  243. if ($myCertificate) {
  244. $items[] = [
  245. 'icon' => Display::return_icon(
  246. 'skill-badges.png',
  247. get_lang('My global certificate'),
  248. null,
  249. ICON_SIZE_SMALL
  250. ),
  251. 'link' => api_get_path(WEB_CODE_PATH).'social/my_skills_report.php?a=generate_custom_skill',
  252. 'title' => get_lang('My global certificate'),
  253. ];
  254. }
  255. if (Skill::isAllowed(api_get_user_id(), false)) {
  256. $items[] = [
  257. 'icon' => Display::return_icon('skill-badges.png', get_lang('My skills')),
  258. 'link' => api_get_path(WEB_CODE_PATH).'social/my_skills_report.php',
  259. 'title' => get_lang('My skills'),
  260. ];
  261. $allowSkillsManagement = api_get_setting('allow_hr_skills_management') == 'true';
  262. if (($allowSkillsManagement && api_is_drh()) || api_is_platform_admin()) {
  263. $items[] = [
  264. 'icon' => Display::return_icon('edit-skill.png', get_lang('My skills')),
  265. 'link' => api_get_path(WEB_CODE_PATH).'admin/skills_wheel.php',
  266. 'title' => get_lang('Manage skills'),
  267. ];
  268. }
  269. }
  270. return $items;
  271. }
  272. /**
  273. * Reacts on a failed login:
  274. * Displays an explanation with a link to the registration form.
  275. *
  276. * @version 1.0.1
  277. */
  278. public function handle_login_failed()
  279. {
  280. return $this->tpl->handleLoginFailed();
  281. }
  282. /**
  283. * Display list of courses in a category.
  284. * (for anonymous users).
  285. *
  286. * @version 1.1
  287. *
  288. * @author Patrick Cool <patrick.cool@UGent.be>, Ghent University - refactoring and code cleaning
  289. * @author Julio Montoya <gugli100@gmail.com>, Beeznest template modifs
  290. */
  291. public function return_courses_in_categories()
  292. {
  293. $result = '';
  294. $stok = Security::get_token();
  295. // Initialization.
  296. $user_identified = (api_get_user_id() > 0 && !api_is_anonymous());
  297. $web_course_path = api_get_path(WEB_COURSE_PATH);
  298. $category = isset($_GET['category']) ? Database::escape_string($_GET['category']) : '';
  299. $setting_show_also_closed_courses = api_get_setting('show_closed_courses') == 'true';
  300. // Database table definitions.
  301. $main_course_table = Database::get_main_table(TABLE_MAIN_COURSE);
  302. $main_category_table = Database::get_main_table(TABLE_MAIN_CATEGORY);
  303. // Get list of courses in category $category.
  304. $sql = "SELECT * FROM $main_course_table cours
  305. WHERE category_code = '".$category."'
  306. ORDER BY title, UPPER(visual_code)";
  307. // Showing only the courses of the current access_url_id.
  308. if (api_is_multiple_url_enabled()) {
  309. $url_access_id = api_get_current_access_url_id();
  310. if ($url_access_id != -1) {
  311. $tbl_url_rel_course = Database::get_main_table(TABLE_MAIN_ACCESS_URL_REL_COURSE);
  312. $sql = "SELECT * FROM $main_course_table as course
  313. INNER JOIN $tbl_url_rel_course as url_rel_course
  314. ON (url_rel_course.c_id = course.id)
  315. WHERE
  316. access_url_id = $url_access_id AND
  317. category_code = '".$category."'
  318. ORDER BY title, UPPER(visual_code)";
  319. }
  320. }
  321. // Removed: AND cours.visibility='".COURSE_VISIBILITY_OPEN_WORLD."'
  322. $queryResult = Database::query($sql);
  323. while ($course_result = Database::fetch_array($queryResult)) {
  324. $course_list[] = $course_result;
  325. }
  326. $numRows = Database::num_rows($queryResult);
  327. // $setting_show_also_closed_courses
  328. if ($user_identified) {
  329. if ($setting_show_also_closed_courses) {
  330. $platform_visible_courses = '';
  331. } else {
  332. $platform_visible_courses = " AND (t3.visibility='".COURSE_VISIBILITY_OPEN_WORLD."' OR t3.visibility='".COURSE_VISIBILITY_OPEN_PLATFORM."' )";
  333. }
  334. } else {
  335. if ($setting_show_also_closed_courses) {
  336. $platform_visible_courses = '';
  337. } else {
  338. $platform_visible_courses = " AND (t3.visibility='".COURSE_VISIBILITY_OPEN_WORLD."' )";
  339. }
  340. }
  341. $sqlGetSubCatList = "
  342. SELECT t1.name,
  343. t1.code,
  344. t1.parent_id,
  345. t1.children_count,COUNT(DISTINCT t3.code) AS nbCourse
  346. FROM $main_category_table t1
  347. LEFT JOIN $main_category_table t2
  348. ON t1.code=t2.parent_id
  349. LEFT JOIN $main_course_table t3
  350. ON (t3.category_code = t1.code $platform_visible_courses)
  351. WHERE t1.parent_id ".(empty($category) ? "IS NULL" : "='$category'")."
  352. GROUP BY t1.name,t1.code,t1.parent_id,t1.children_count
  353. ORDER BY t1.tree_pos, t1.name";
  354. // Showing only the category of courses of the current access_url_id
  355. if (api_is_multiple_url_enabled()) {
  356. $table = Database::get_main_table(TABLE_MAIN_ACCESS_URL_REL_COURSE_CATEGORY);
  357. $courseCategoryCondition = " INNER JOIN $table a ON (t1.id = a.course_category_id)";
  358. $url_access_id = api_get_current_access_url_id();
  359. if ($url_access_id != -1) {
  360. $tbl_url_rel_course = Database::get_main_table(TABLE_MAIN_ACCESS_URL_REL_COURSE);
  361. $sqlGetSubCatList = "
  362. SELECT t1.name,
  363. t1.code,
  364. t1.parent_id,
  365. t1.children_count,
  366. COUNT(DISTINCT t3.code) AS nbCourse
  367. FROM $main_category_table t1
  368. $courseCategoryCondition
  369. LEFT JOIN $main_category_table t2 ON t1.code = t2.parent_id
  370. LEFT JOIN $main_course_table t3 ON (t3.category_code = t1.code $platform_visible_courses)
  371. INNER JOIN $tbl_url_rel_course as url_rel_course
  372. ON (url_rel_course.c_id = t3.id)
  373. WHERE
  374. url_rel_course.access_url_id = $url_access_id AND
  375. t1.parent_id ".(empty($category) ? "IS NULL" : "='$category'")."
  376. GROUP BY t1.name,t1.code,t1.parent_id,t1.children_count
  377. ORDER BY t1.tree_pos, t1.name";
  378. }
  379. }
  380. $resCats = Database::query($sqlGetSubCatList);
  381. $thereIsSubCat = false;
  382. $htmlTitre = '';
  383. $htmlListCat = '';
  384. if (Database::num_rows($resCats) > 0) {
  385. $htmlListCat = Display::page_header(get_lang('Categories'));
  386. $htmlListCat .= '<ul>';
  387. while ($catLine = Database::fetch_array($resCats)) {
  388. $category_has_open_courses = self::category_has_open_courses($catLine['code']);
  389. if ($category_has_open_courses) {
  390. // The category contains courses accessible to anonymous visitors.
  391. $htmlListCat .= '<li>';
  392. $htmlListCat .= '<a href="'.api_get_self(
  393. ).'?category='.$catLine['code'].'">'.$catLine['name'].'</a>';
  394. if (api_get_setting('show_number_of_courses') == 'true') {
  395. $htmlListCat .= ' ('.$catLine['nbCourse'].' '.get_lang('Courses').')';
  396. }
  397. $htmlListCat .= "</li>";
  398. $thereIsSubCat = true;
  399. } elseif ($catLine['children_count'] > 0) {
  400. // The category has children, subcategories.
  401. $htmlListCat .= '<li>';
  402. $htmlListCat .= '<a href="'.api_get_self(
  403. ).'?category='.$catLine['code'].'">'.$catLine['name'].'</a>';
  404. $htmlListCat .= "</li>";
  405. $thereIsSubCat = true;
  406. } elseif (api_get_setting('show_empty_course_categories') == 'true') {
  407. /* End changed code to eliminate the (0 courses) after empty categories. */
  408. $htmlListCat .= '<li>';
  409. $htmlListCat .= $catLine['name'];
  410. $htmlListCat .= "</li>";
  411. $thereIsSubCat = true;
  412. } // Else don't set thereIsSubCat to true to avoid printing things if not requested.
  413. // TODO: deprecate this useless feature - this includes removing system variable
  414. if (empty($htmlTitre)) {
  415. $htmlTitre = '<p>';
  416. if (api_get_setting('show_back_link_on_top_of_tree') == 'true') {
  417. $htmlTitre .= '<a href="'.api_get_self().'">&lt;&lt; '.get_lang('Categories Overview').'</a>';
  418. }
  419. $htmlTitre .= "</p>";
  420. }
  421. }
  422. $htmlListCat .= "</ul>";
  423. }
  424. $result .= $htmlTitre;
  425. if ($thereIsSubCat) {
  426. $result .= $htmlListCat;
  427. }
  428. while ($categoryName = Database::fetch_array($resCats)) {
  429. $result .= '<h3>'.$categoryName['name']."</h3>\n";
  430. }
  431. $courses_list_string = '';
  432. $courses_shown = 0;
  433. if ($numRows > 0) {
  434. $courses_list_string .= Display::page_header(get_lang('Course list'));
  435. $courses_list_string .= "<ul>";
  436. if (api_get_user_id()) {
  437. $courses_of_user = self::get_courses_of_user(api_get_user_id());
  438. }
  439. foreach ($course_list as $course) {
  440. // $setting_show_also_closed_courses
  441. if ($course['visibility'] == COURSE_VISIBILITY_HIDDEN) {
  442. continue;
  443. }
  444. if (!$setting_show_also_closed_courses) {
  445. // If we do not show the closed courses
  446. // we only show the courses that are open to the world (to everybody)
  447. // and the courses that are open to the platform (if the current user is a registered user.
  448. if (($user_identified && $course['visibility'] == COURSE_VISIBILITY_OPEN_PLATFORM) ||
  449. ($course['visibility'] == COURSE_VISIBILITY_OPEN_WORLD)
  450. ) {
  451. $courses_shown++;
  452. $courses_list_string .= "<li>";
  453. $courses_list_string .= '<a href="'.$web_course_path.$course['directory'].'/">'.$course['title'].'</a><br />';
  454. $course_details = [];
  455. if (api_get_setting('display_coursecode_in_courselist') === 'true') {
  456. $course_details[] = '('.$course['visual_code'].')';
  457. }
  458. if (api_get_setting('display_teacher_in_courselist') === 'true') {
  459. $course_details[] = CourseManager::getTeacherListFromCourseCodeToString($course['code']);
  460. }
  461. if (api_get_setting('show_different_course_language') === 'true' &&
  462. $course['course_language'] != api_get_setting('platformLanguage')
  463. ) {
  464. $course_details[] = $course['course_language'];
  465. }
  466. $courses_list_string .= implode(' - ', $course_details);
  467. $courses_list_string .= "</li>";
  468. }
  469. } else {
  470. // We DO show the closed courses.
  471. // The course is accessible if (link to the course homepage):
  472. // 1. the course is open to the world (doesn't matter if the user is logged in or not): $course['visibility'] == COURSE_VISIBILITY_OPEN_WORLD);
  473. // 2. the user is logged in and the course is open to the world or open to the platform: ($user_identified && $course['visibility'] == COURSE_VISIBILITY_OPEN_PLATFORM);
  474. // 3. the user is logged in and the user is subscribed to the course and the course visibility is not COURSE_VISIBILITY_CLOSED;
  475. // 4. the user is logged in and the user is course admin of te course (regardless of the course visibility setting);
  476. // 5. the user is the platform admin api_is_platform_admin().
  477. $courses_shown++;
  478. $courses_list_string .= "<li>";
  479. if ($course['visibility'] == COURSE_VISIBILITY_OPEN_WORLD
  480. || ($user_identified && $course['visibility'] == COURSE_VISIBILITY_OPEN_PLATFORM)
  481. || ($user_identified && array_key_exists($course['code'], $courses_of_user)
  482. && $course['visibility'] != COURSE_VISIBILITY_CLOSED)
  483. || $courses_of_user[$course['code']]['status'] == '1'
  484. || api_is_platform_admin()
  485. ) {
  486. $courses_list_string .= '<a href="'.$web_course_path.$course['directory'].'/">';
  487. }
  488. $courses_list_string .= $course['title'];
  489. if ($course['visibility'] == COURSE_VISIBILITY_OPEN_WORLD
  490. || ($user_identified && $course['visibility'] == COURSE_VISIBILITY_OPEN_PLATFORM)
  491. || ($user_identified && array_key_exists($course['code'], $courses_of_user)
  492. && $course['visibility'] != COURSE_VISIBILITY_CLOSED)
  493. || $courses_of_user[$course['code']]['status'] == '1'
  494. || api_is_platform_admin()
  495. ) {
  496. $courses_list_string .= '</a><br />';
  497. }
  498. $course_details = [];
  499. if (api_get_setting('display_coursecode_in_courselist') == 'true') {
  500. $course_details[] = '('.$course['visual_code'].')';
  501. }
  502. if (api_get_setting('display_teacher_in_courselist') === 'true') {
  503. if (!empty($course['tutor_name'])) {
  504. $course_details[] = $course['tutor_name'];
  505. }
  506. }
  507. if (api_get_setting('show_different_course_language') == 'true' &&
  508. $course['course_language'] != api_get_setting('platformLanguage')
  509. ) {
  510. $course_details[] = $course['course_language'];
  511. }
  512. $courses_list_string .= implode(' - ', $course_details);
  513. // We display a subscription link if:
  514. // 1. it is allowed to register for the course and if the course is not already in
  515. // the courselist of the user and if the user is identified
  516. // 2.
  517. if ($user_identified && !array_key_exists($course['code'], $courses_of_user)) {
  518. if ($course['subscribe'] == '1') {
  519. $courses_list_string .= '&nbsp;<a class="btn btn-primary" href="main/auth/courses.php?action=subscribe_course&sec_token='.$stok.'&subscribe_course='.$course['code'].'&category_code='.Security::remove_XSS(
  520. $_GET['category']
  521. ).'">'.get_lang('Subscribe').'</a><br />';
  522. } else {
  523. $courses_list_string .= '<br />'.get_lang('Subscribing not allowed');
  524. }
  525. }
  526. $courses_list_string .= "</li>";
  527. } //end else
  528. } // end foreach
  529. $courses_list_string .= "</ul>";
  530. }
  531. if ($courses_shown > 0) {
  532. // Only display the list of courses and categories if there was more than
  533. // 0 courses visible to the world (we're in the anonymous list here).
  534. $result .= $courses_list_string;
  535. }
  536. if ($category != '') {
  537. $result .= '<p><a href="'.api_get_self().'">'
  538. .Display:: return_icon('back.png', get_lang('Categories Overview'))
  539. .get_lang('Categories Overview').'</a></p>';
  540. }
  541. return $result;
  542. }
  543. /**
  544. * retrieves all the courses that the user has already subscribed to.
  545. *
  546. * @author Patrick Cool <patrick.cool@UGent.be>, Ghent University, Belgium
  547. *
  548. * @param int $user_id : the id of the user
  549. *
  550. * @return array an array containing all the information of the courses of the given user
  551. */
  552. public function get_courses_of_user($user_id)
  553. {
  554. $table_course = Database::get_main_table(TABLE_MAIN_COURSE);
  555. $table_course_user = Database::get_main_table(TABLE_MAIN_COURSE_USER);
  556. // Secondly we select the courses that are in a category (user_course_cat <> 0)
  557. // and sort these according to the sort of the category
  558. $user_id = intval($user_id);
  559. $sql = "SELECT
  560. course.code k,
  561. course.visual_code vc,
  562. course.subscribe subscr,
  563. course.unsubscribe unsubscr,
  564. course.title i,
  565. course.tutor_name t,
  566. course.directory dir,
  567. course_rel_user.status status,
  568. course_rel_user.sort sort,
  569. course_rel_user.user_course_cat user_course_cat
  570. FROM
  571. $table_course course,
  572. $table_course_user course_rel_user
  573. WHERE
  574. course.id = course_rel_user.c_id AND
  575. course_rel_user.user_id = '".$user_id."' AND
  576. course_rel_user.relation_type <> ".COURSE_RELATION_TYPE_RRHH."
  577. ORDER BY course_rel_user.sort ASC";
  578. $result = Database::query($sql);
  579. $courses = [];
  580. while ($row = Database::fetch_array($result)) {
  581. // We only need the database name of the course.
  582. $courses[$row['k']] = [
  583. 'code' => $row['k'],
  584. 'visual_code' => $row['vc'],
  585. 'title' => $row['i'],
  586. 'directory' => $row['dir'],
  587. 'status' => $row['status'],
  588. 'tutor' => $row['t'],
  589. 'subscribe' => $row['subscr'],
  590. 'unsubscribe' => $row['unsubscr'],
  591. 'sort' => $row['sort'],
  592. 'user_course_category' => $row['user_course_cat'],
  593. ];
  594. }
  595. return $courses;
  596. }
  597. /**
  598. * @todo use the template system
  599. *
  600. * @param $title
  601. * @param $content
  602. * @param string $id
  603. * @param array $params
  604. * @param string $idAccordion
  605. * @param string $idCollapse
  606. *
  607. * @return string
  608. */
  609. public function showRightBlock(
  610. $title,
  611. $content,
  612. $id = '',
  613. $params = [],
  614. $idAccordion = '',
  615. $idCollapse = ''
  616. ) {
  617. $html = '';
  618. if (!empty($idAccordion)) {
  619. $html = Display::panel($content, $title);
  620. } else {
  621. $html = Display::panel($content, $title);
  622. }
  623. return $html;
  624. }
  625. /**
  626. * Adds a form to let users login.
  627. *
  628. * @version 1.1
  629. */
  630. public function display_login_form()
  631. {
  632. return $this->tpl->displayLoginForm();
  633. }
  634. /**
  635. * @todo use FormValidator
  636. *
  637. * @return string
  638. */
  639. public function return_search_block()
  640. {
  641. $html = '';
  642. if (api_get_setting('search_enabled') == 'true') {
  643. $search_btn = get_lang('Search');
  644. $search_content = '<form action="main/search/" method="post">
  645. <div class="form-group">
  646. <input type="text" id="query" class="form-control" name="query" value="" />
  647. <button class="btn btn-default" type="submit" name="submit" value="'.$search_btn.'" />'.
  648. $search_btn.' </button>
  649. </div></form>';
  650. $html .= $this->showRightBlock(get_lang('Search'), $search_content, 'search_block');
  651. }
  652. return $html;
  653. }
  654. /**
  655. * @return string
  656. */
  657. public function returnClassesBlock()
  658. {
  659. if (api_get_setting('show_groups_to_users') !== 'true') {
  660. return '';
  661. }
  662. $items = [];
  663. $usergroup = new UserGroup();
  664. if (api_is_platform_admin()) {
  665. $items[] = [
  666. 'link' => api_get_path(WEB_CODE_PATH).'admin/usergroups.php?action=add',
  667. 'title' => get_lang('Add classes'),
  668. ];
  669. } else {
  670. if (api_is_teacher() && $usergroup->allowTeachers()) {
  671. $items[] = [
  672. 'link' => api_get_path(WEB_CODE_PATH).'admin/usergroups.php',
  673. 'title' => get_lang('Class list'),
  674. ];
  675. }
  676. }
  677. $usergroup_list = $usergroup->get_usergroup_by_user(api_get_user_id());
  678. if (!empty($usergroup_list)) {
  679. foreach ($usergroup_list as $group_id) {
  680. $data = $usergroup->get($group_id);
  681. $items[] = [
  682. 'link' => api_get_path(WEB_CODE_PATH).'user/classes.php?id='.$data['id'],
  683. 'title' => $data['name'],
  684. ];
  685. }
  686. }
  687. $html = $this->showRightBlock(
  688. get_lang('Classes'),
  689. self::returnRightBlockItems($items),
  690. 'classes_block'
  691. );
  692. return $html;
  693. }
  694. /**
  695. * @return string
  696. */
  697. public function return_user_image_block()
  698. {
  699. $html = '';
  700. if (!api_is_anonymous()) {
  701. $userPicture = UserManager::getUserPicture(api_get_user_id(), USER_IMAGE_SIZE_ORIGINAL);
  702. $content = null;
  703. if (api_get_setting('allow_social_tool') == 'true') {
  704. $content .= '<a style="text-align:center" href="'.api_get_path(WEB_CODE_PATH).'social/home.php">
  705. <img class="img-circle" src="'.$userPicture.'"></a>';
  706. } else {
  707. $content .= '<a style="text-align:center" href="'.api_get_path(WEB_CODE_PATH).'auth/profile.php">
  708. <img class="img-circle" title="'.get_lang('Edit profile').'" src="'.$userPicture.'"></a>';
  709. }
  710. $html = $this->showRightBlock(
  711. null,
  712. $content,
  713. 'user_image_block',
  714. ['style' => 'text-align:center;']
  715. );
  716. }
  717. return $html;
  718. }
  719. /**
  720. * @return array
  721. */
  722. public function return_profile_block()
  723. {
  724. $userInfo = api_get_user_info();
  725. $userId = api_get_user_id();
  726. if (empty($userId)) {
  727. return;
  728. }
  729. $items = [];
  730. $userGroup = new UserGroup();
  731. // @todo Add a platform setting to add the user image.
  732. if (api_get_setting('allow_message_tool') === 'true') {
  733. // New messages.
  734. $number_of_new_messages = MessageManager::getCountNewMessages();
  735. // New contact invitations.
  736. $number_of_new_messages_of_friend = SocialManager::get_message_number_invitation_by_user_id(
  737. $userId
  738. );
  739. // New group invitations sent by a moderator.
  740. $group_pending_invitations = $userGroup->get_groups_by_user(
  741. $userId,
  742. GROUP_USER_PERMISSION_PENDING_INVITATION,
  743. false
  744. );
  745. $group_pending_invitations = count($group_pending_invitations);
  746. $total_invitations = $number_of_new_messages_of_friend + $group_pending_invitations;
  747. $cant_msg = Display::badge($number_of_new_messages);
  748. $items[] = [
  749. 'class' => 'inbox-message-social',
  750. 'icon' => Display::return_icon('inbox.png', get_lang('Inbox')),
  751. 'link' => api_get_path(WEB_CODE_PATH).'messages/inbox.php',
  752. 'title' => get_lang('Inbox').$cant_msg,
  753. ];
  754. $items[] = [
  755. 'class' => 'new-message-social',
  756. 'icon' => Display::return_icon('new-message.png', get_lang('Compose')),
  757. 'link' => api_get_path(WEB_CODE_PATH).'messages/new_message.php',
  758. 'title' => get_lang('Compose'),
  759. ];
  760. if (api_get_setting('allow_social_tool') == 'true') {
  761. $total_invitations = Display::badge($total_invitations);
  762. $items[] = [
  763. 'class' => 'invitations-social',
  764. 'icon' => Display::return_icon('invitations.png', get_lang('Pending invitations')),
  765. 'link' => api_get_path(WEB_CODE_PATH).'social/invitations.php',
  766. 'title' => get_lang('Pending invitations').$total_invitations,
  767. ];
  768. }
  769. }
  770. $items[] = [
  771. 'class' => 'personal-data',
  772. 'icon' => Display::return_icon('database.png', get_lang('Personal data')),
  773. 'link' => api_get_path(WEB_CODE_PATH).'social/personal_data.php',
  774. 'title' => get_lang('Personal data'),
  775. ];
  776. if (api_get_configuration_value('allow_my_files_link_in_homepage')) {
  777. if (api_get_setting('allow_my_files') !== 'false') {
  778. $items[] = [
  779. 'class' => 'myfiles-social',
  780. 'icon' => Display::return_icon('sn-files.png', get_lang('Files')),
  781. 'link' => api_get_path(WEB_CODE_PATH).'social/myfiles.php',
  782. 'title' => get_lang('My files'),
  783. ];
  784. }
  785. }
  786. $items[] = [
  787. 'class' => 'profile-social',
  788. 'icon' => Display::return_icon('edit-profile.png', get_lang('Edit profile')),
  789. 'link' => Display::getProfileEditionLink($userId),
  790. 'title' => get_lang('Edit profile'),
  791. ];
  792. if (api_get_configuration_value('show_link_request_hrm_user') &&
  793. api_is_drh()
  794. ) {
  795. $label = get_lang('Request linking to student');
  796. $items[] = [
  797. 'icon' => Display::return_icon('new_group.png', $label),
  798. 'link' => api_get_path(WEB_CODE_PATH).'social/require_user_linking.php',
  799. 'title' => $label,
  800. ];
  801. }
  802. if (bbb::showGlobalConferenceLink($userInfo)) {
  803. $bbb = new bbb('', '', true, api_get_user_id());
  804. $url = $bbb->getListingUrl();
  805. $items[] = [
  806. 'class' => 'video-conference',
  807. 'icon' => Display::return_icon(
  808. 'bbb.png',
  809. get_lang('Videoconference')
  810. ),
  811. 'link' => $url,
  812. 'title' => get_lang('Videoconference'),
  813. ];
  814. }
  815. if (true === api_get_configuration_value('whispeak_auth_enabled')) {
  816. $itemTitle = WhispeakAuthPlugin::create()->get_title();
  817. $items[] = [
  818. 'class' => 'whispeak-enrollment',
  819. 'icon' => Display::return_icon('addworkuser.png', $itemTitle),
  820. 'link' => WhispeakAuthPlugin::getEnrollmentUrl(),
  821. 'title' => $itemTitle,
  822. ];
  823. }
  824. return $items;
  825. }
  826. /**
  827. * @return array
  828. */
  829. public function return_navigation_links()
  830. {
  831. $items = [];
  832. // Deleting the myprofile link.
  833. if (api_get_setting('allow_social_tool') == 'true') {
  834. unset($this->tpl->menu_navigation['myprofile']);
  835. }
  836. $hideMenu = api_get_configuration_value('hide_main_navigation_menu');
  837. if ($hideMenu === true) {
  838. return '';
  839. }
  840. // Main navigation section.
  841. // Tabs that are deactivated are added here.
  842. if (!empty($this->tpl->menu_navigation)) {
  843. foreach ($this->tpl->menu_navigation as $section => $navigation_info) {
  844. $items[] = [
  845. 'icon' => null,
  846. 'link' => $navigation_info['url'],
  847. 'title' => $navigation_info['title'],
  848. ];
  849. }
  850. }
  851. return $items;
  852. }
  853. /**
  854. * @return array
  855. */
  856. public function return_course_block()
  857. {
  858. if (api_get_configuration_value('hide_course_sidebar')) {
  859. return '';
  860. }
  861. $isHrm = api_is_drh();
  862. $show_create_link = false;
  863. $show_course_link = false;
  864. if (api_is_allowed_to_create_course()) {
  865. $show_create_link = true;
  866. }
  867. if (api_get_setting('allow_students_to_browse_courses') === 'true') {
  868. $show_course_link = true;
  869. }
  870. $items = [];
  871. // My account section
  872. if ($show_create_link) {
  873. if (api_get_setting('course_validation') == 'true' && !api_is_platform_admin()) {
  874. $items[] = [
  875. 'class' => 'add-course',
  876. 'icon' => Display::return_icon('new-course.png', get_lang('Create a course request')),
  877. 'link' => api_get_path(WEB_CODE_PATH).'create_course/add_course.php',
  878. 'title' => get_lang('Create a course request'),
  879. ];
  880. } else {
  881. $items[] = [
  882. 'class' => 'add-course',
  883. 'icon' => Display::return_icon('new-course.png', get_lang('Create a course')),
  884. 'link' => api_get_path(WEB_CODE_PATH).'create_course/add_course.php',
  885. 'title' => get_lang('Create a course'),
  886. ];
  887. }
  888. if (SessionManager::allowToManageSessions()) {
  889. $items[] = [
  890. 'class' => 'add-session',
  891. 'icon' => Display::return_icon('session.png', get_lang('Add a training session')),
  892. 'link' => api_get_path(WEB_CODE_PATH).'session/session_add.php',
  893. 'title' => get_lang('Add a training session'),
  894. ];
  895. }
  896. }
  897. // Sort courses
  898. if (api_get_configuration_value('view_grid_courses') != true) {
  899. $items[] = [
  900. 'class' => 'order-course',
  901. 'icon' => Display::return_icon('order-course.png', get_lang('Sort courses')),
  902. 'link' => api_get_path(WEB_CODE_PATH).'auth/sort_my_courses.php',
  903. 'title' => get_lang('Sort courses'),
  904. ];
  905. }
  906. // Session history
  907. if (isset($_GET['history']) && intval($_GET['history']) == 1) {
  908. $items[] = [
  909. 'class' => 'history-course',
  910. 'icon' => Display::return_icon('history-course.png', get_lang('Display courses list')),
  911. 'link' => api_get_path(WEB_PATH).'user_portal.php',
  912. 'title' => get_lang('Display courses list'),
  913. ];
  914. } else {
  915. $items[] = [
  916. 'class' => 'history-course',
  917. 'icon' => Display::return_icon('history-course.png', get_lang('Courses history')),
  918. 'link' => api_get_path(WEB_PATH).'user_portal.php?history=1',
  919. 'title' => get_lang('Courses history'),
  920. ];
  921. }
  922. if ($isHrm) {
  923. $items[] = [
  924. 'link' => api_get_path(WEB_CODE_PATH).'auth/hrm_courses.php',
  925. 'title' => get_lang('HrmAssignedUsersCourse list'),
  926. ];
  927. }
  928. // Course catalog
  929. if ($show_course_link) {
  930. if (!api_is_drh()) {
  931. $items[] = [
  932. 'class' => 'list-course',
  933. 'icon' => Display::return_icon('catalog-course.png', get_lang('Course catalog')),
  934. 'link' => api_get_path(WEB_CODE_PATH).'auth/courses.php',
  935. 'title' => get_lang('Course catalog'),
  936. ];
  937. } else {
  938. $items[] = [
  939. 'link' => api_get_path(WEB_CODE_PATH).'dashboard/index.php',
  940. 'title' => get_lang('Dashboard'),
  941. ];
  942. }
  943. }
  944. return $items;
  945. }
  946. /**
  947. * Prints the session and course list (user_portal.php).
  948. *
  949. * @param int $user_id
  950. * @param bool $showSessions
  951. * @param string $categoryCodeFilter
  952. * @param bool $useUserLanguageFilterIfAvailable
  953. * @param bool $loadHistory
  954. *
  955. * @return array
  956. */
  957. public function returnCoursesAndSessions(
  958. $user_id,
  959. $showSessions = true,
  960. $categoryCodeFilter = '',
  961. $useUserLanguageFilterIfAvailable = true,
  962. $loadHistory = false
  963. ) {
  964. $gameModeIsActive = api_get_setting('gamification_mode');
  965. $viewGridCourses = api_get_configuration_value('view_grid_courses');
  966. $showSimpleSessionInfo = api_get_configuration_value('show_simple_session_info');
  967. $coursesWithoutCategoryTemplate = '/user_portal/classic_courses_without_category.tpl';
  968. $coursesWithCategoryTemplate = '/user_portal/classic_courses_with_category.tpl';
  969. $showAllSessions = api_get_configuration_value('show_all_sessions_on_my_course_page') === true;
  970. if ($loadHistory) {
  971. // Load sessions in category in *history*
  972. $session_categories = UserManager::get_sessions_by_category($user_id, true);
  973. } else {
  974. // Load sessions in category
  975. $session_categories = UserManager::get_sessions_by_category($user_id, false);
  976. }
  977. $sessionCount = 0;
  978. $courseCount = 0;
  979. // Student info code check (shows student progress information on
  980. // courses list
  981. $studentInfo = api_get_configuration_value('course_student_info');
  982. $studentInfoProgress = !empty($studentInfo['progress']) && $studentInfo['progress'] === true;
  983. $studentInfoScore = !empty($studentInfo['score']) && $studentInfo['score'] === true;
  984. $studentInfoCertificate = !empty($studentInfo['certificate']) && $studentInfo['certificate'] === true;
  985. $courseCompleteList = [];
  986. $coursesInCategoryCount = 0;
  987. $coursesNotInCategoryCount = 0;
  988. $listCourse = '';
  989. $specialCourseList = '';
  990. // If we're not in the history view...
  991. if ($loadHistory === false) {
  992. // Display special courses.
  993. $specialCourses = CourseManager::returnSpecialCourses(
  994. $user_id,
  995. $this->load_directories_preview,
  996. $useUserLanguageFilterIfAvailable
  997. );
  998. // Display courses.
  999. $courses = CourseManager::returnCourses(
  1000. $user_id,
  1001. $this->load_directories_preview,
  1002. $useUserLanguageFilterIfAvailable
  1003. );
  1004. // Course option (show student progress)
  1005. // This code will add new variables (Progress, Score, Certificate)
  1006. if ($studentInfoProgress || $studentInfoScore || $studentInfoCertificate) {
  1007. if (!empty($specialCourses)) {
  1008. foreach ($specialCourses as $key => $specialCourseInfo) {
  1009. if ($studentInfoProgress) {
  1010. $progress = Tracking::get_avg_student_progress(
  1011. $user_id,
  1012. $specialCourseInfo['course_code']
  1013. );
  1014. $specialCourses[$key]['student_info']['progress'] = $progress === false ? null : $progress;
  1015. }
  1016. if ($studentInfoScore) {
  1017. $percentage_score = Tracking::get_avg_student_score(
  1018. $user_id,
  1019. $specialCourseInfo['course_code'],
  1020. []
  1021. );
  1022. $specialCourses[$key]['student_info']['score'] = $percentage_score;
  1023. }
  1024. if ($studentInfoCertificate) {
  1025. $category = Category::load(
  1026. null,
  1027. null,
  1028. $specialCourseInfo['course_code'],
  1029. null,
  1030. null,
  1031. null
  1032. );
  1033. $specialCourses[$key]['student_info']['certificate'] = null;
  1034. if (isset($category[0])) {
  1035. if ($category[0]->is_certificate_available($user_id)) {
  1036. $specialCourses[$key]['student_info']['certificate'] = Display::label(
  1037. get_lang('Yes'),
  1038. 'success'
  1039. );
  1040. } else {
  1041. $specialCourses[$key]['student_info']['certificate'] = Display::label(
  1042. get_lang('No'),
  1043. 'danger'
  1044. );
  1045. }
  1046. }
  1047. }
  1048. }
  1049. }
  1050. if (isset($courses['in_category'])) {
  1051. foreach ($courses['in_category'] as $key1 => $value) {
  1052. if (isset($courses['in_category'][$key1]['courses'])) {
  1053. foreach ($courses['in_category'][$key1]['courses'] as $key2 => $courseInCatInfo) {
  1054. $courseCode = $courseInCatInfo['course_code'];
  1055. if ($studentInfoProgress) {
  1056. $progress = Tracking::get_avg_student_progress(
  1057. $user_id,
  1058. $courseCode
  1059. );
  1060. $courses['in_category'][$key1]['courses'][$key2]['student_info']['progress'] = $progress === false ? null : $progress;
  1061. }
  1062. if ($studentInfoScore) {
  1063. $percentage_score = Tracking::get_avg_student_score(
  1064. $user_id,
  1065. $courseCode,
  1066. []
  1067. );
  1068. $courses['in_category'][$key1]['courses'][$key2]['student_info']['score'] = $percentage_score;
  1069. }
  1070. if ($studentInfoCertificate) {
  1071. $category = Category::load(
  1072. null,
  1073. null,
  1074. $courseCode,
  1075. null,
  1076. null,
  1077. null
  1078. );
  1079. $courses['in_category'][$key1]['student_info']['certificate'] = null;
  1080. $isCertificateAvailable = $category[0]->is_certificate_available($user_id);
  1081. if (isset($category[0])) {
  1082. if ($viewGridCourses) {
  1083. if ($isCertificateAvailable) {
  1084. $courses['in_category'][$key1]['student_info']['certificate'] = get_lang(
  1085. 'Yes'
  1086. );
  1087. } else {
  1088. $courses['in_category'][$key1]['student_info']['certificate'] = get_lang(
  1089. 'No'
  1090. );
  1091. }
  1092. } else {
  1093. if ($isCertificateAvailable) {
  1094. $courses['in_category'][$key1]['student_info']['certificate'] = Display::label(
  1095. get_lang('Yes'),
  1096. 'success'
  1097. );
  1098. } else {
  1099. $courses['in_category'][$key1]['student_info']['certificate'] = Display::label(
  1100. get_lang('No'),
  1101. 'danger'
  1102. );
  1103. }
  1104. }
  1105. }
  1106. }
  1107. }
  1108. }
  1109. }
  1110. }
  1111. if (isset($courses['not_category'])) {
  1112. foreach ($courses['not_category'] as $key => $courseNotInCatInfo) {
  1113. $courseCode = $courseNotInCatInfo['course_code'];
  1114. if ($studentInfoProgress) {
  1115. $progress = Tracking::get_avg_student_progress(
  1116. $user_id,
  1117. $courseCode
  1118. );
  1119. $courses['not_category'][$key]['student_info']['progress'] = $progress === false ? null : $progress;
  1120. }
  1121. if ($studentInfoScore) {
  1122. $percentage_score = Tracking::get_avg_student_score(
  1123. $user_id,
  1124. $courseCode,
  1125. []
  1126. );
  1127. $courses['not_category'][$key]['student_info']['score'] = $percentage_score;
  1128. }
  1129. if ($studentInfoCertificate) {
  1130. $category = Category::load(
  1131. null,
  1132. null,
  1133. $courseCode,
  1134. null,
  1135. null,
  1136. null
  1137. );
  1138. $courses['not_category'][$key]['student_info']['certificate'] = null;
  1139. if (isset($category[0])) {
  1140. $certificateAvailable = $category[0]->is_certificate_available($user_id);
  1141. if ($viewGridCourses) {
  1142. if ($certificateAvailable) {
  1143. $courses['not_category'][$key]['student_info']['certificate'] = get_lang('Yes');
  1144. } else {
  1145. $courses['not_category'][$key]['student_info']['certificate'] = get_lang('No');
  1146. }
  1147. } else {
  1148. if ($certificateAvailable) {
  1149. $courses['not_category'][$key]['student_info']['certificate'] = Display::label(
  1150. get_lang('Yes'),
  1151. 'success'
  1152. );
  1153. } else {
  1154. $courses['not_category'][$key]['student_info']['certificate'] = Display::label(
  1155. get_lang('No'),
  1156. 'danger'
  1157. );
  1158. }
  1159. }
  1160. }
  1161. }
  1162. }
  1163. }
  1164. }
  1165. if ($viewGridCourses) {
  1166. $coursesWithoutCategoryTemplate = '/user_portal/grid_courses_without_category.tpl';
  1167. $coursesWithCategoryTemplate = '/user_portal/grid_courses_with_category.tpl';
  1168. }
  1169. if ($specialCourses) {
  1170. if ($categoryCodeFilter) {
  1171. $specialCourses = self::filterByCategory($specialCourses, $categoryCodeFilter);
  1172. }
  1173. $this->tpl->assign('courses', $specialCourses);
  1174. $specialCourseList = $this->tpl->fetch($this->tpl->get_template($coursesWithoutCategoryTemplate));
  1175. $courseCompleteList = array_merge($courseCompleteList, $specialCourses);
  1176. }
  1177. if ($courses['in_category'] || $courses['not_category']) {
  1178. foreach ($courses['in_category'] as $courseData) {
  1179. if (!empty($courseData['courses'])) {
  1180. $coursesInCategoryCount += count($courseData['courses']);
  1181. $courseCompleteList = array_merge($courseCompleteList, $courseData['courses']);
  1182. }
  1183. }
  1184. $coursesNotInCategoryCount += count($courses['not_category']);
  1185. $courseCompleteList = array_merge($courseCompleteList, $courses['not_category']);
  1186. if ($categoryCodeFilter) {
  1187. $courses['in_category'] = self::filterByCategory(
  1188. $courses['in_category'],
  1189. $categoryCodeFilter
  1190. );
  1191. $courses['not_category'] = self::filterByCategory(
  1192. $courses['not_category'],
  1193. $categoryCodeFilter
  1194. );
  1195. }
  1196. $this->tpl->assign('courses', $courses['not_category']);
  1197. $this->tpl->assign('categories', $courses['in_category']);
  1198. $listCourse = $this->tpl->fetch($this->tpl->get_template($coursesWithCategoryTemplate));
  1199. $listCourse .= $this->tpl->fetch($this->tpl->get_template($coursesWithoutCategoryTemplate));
  1200. }
  1201. $courseCount = count($specialCourses) + $coursesInCategoryCount + $coursesNotInCategoryCount;
  1202. }
  1203. $sessions_with_category = '';
  1204. $sessions_with_no_category = '';
  1205. $collapsable = api_get_configuration_value('allow_user_session_collapsable');
  1206. $collapsableLink = '';
  1207. if ($collapsable) {
  1208. $collapsableLink = api_get_path(WEB_PATH).'user_portal.php?action=collapse_session';
  1209. }
  1210. $extraFieldValue = new ExtraFieldValue('session');
  1211. if ($showSessions) {
  1212. $coursesListSessionStyle = api_get_configuration_value('courses_list_session_title_link');
  1213. $coursesListSessionStyle = $coursesListSessionStyle === false ? 1 : $coursesListSessionStyle;
  1214. if (api_is_drh()) {
  1215. $coursesListSessionStyle = 1;
  1216. }
  1217. $portalShowDescription = api_get_setting('show_session_description') === 'true';
  1218. // Declared listSession variable
  1219. $listSession = [];
  1220. // Get timestamp in UTC to compare to DB values (in UTC by convention)
  1221. $session_now = strtotime(api_get_utc_datetime(time()));
  1222. if (is_array($session_categories)) {
  1223. foreach ($session_categories as $session_category) {
  1224. $session_category_id = $session_category['session_category']['id'];
  1225. // Sessions and courses that are not in a session category
  1226. if (empty($session_category_id) &&
  1227. isset($session_category['sessions'])
  1228. ) {
  1229. // Independent sessions
  1230. foreach ($session_category['sessions'] as $session) {
  1231. $session_id = $session['session_id'];
  1232. // Don't show empty sessions.
  1233. if (count($session['courses']) < 1) {
  1234. continue;
  1235. }
  1236. // Courses inside the current session.
  1237. $date_session_start = $session['access_start_date'];
  1238. $date_session_end = $session['access_end_date'];
  1239. $coachAccessStartDate = $session['coach_access_start_date'];
  1240. $coachAccessEndDate = $session['coach_access_end_date'];
  1241. $count_courses_session = 0;
  1242. // Loop course content
  1243. $html_courses_session = [];
  1244. $atLeastOneCourseIsVisible = false;
  1245. $markAsOld = false;
  1246. $markAsFuture = false;
  1247. foreach ($session['courses'] as $course) {
  1248. $is_coach_course = api_is_coach($session_id, $course['real_id']);
  1249. $allowed_time = 0;
  1250. $allowedEndTime = true;
  1251. if (!empty($date_session_start)) {
  1252. if ($is_coach_course) {
  1253. $allowed_time = api_strtotime($coachAccessStartDate);
  1254. } else {
  1255. $allowed_time = api_strtotime($date_session_start);
  1256. }
  1257. $endSessionToTms = null;
  1258. if (!isset($_GET['history'])) {
  1259. if (!empty($date_session_end)) {
  1260. if ($is_coach_course) {
  1261. // if coach end date is empty we use the default end date
  1262. if (empty($coachAccessEndDate)) {
  1263. $endSessionToTms = api_strtotime($date_session_end);
  1264. if ($session_now > $endSessionToTms) {
  1265. $allowedEndTime = false;
  1266. }
  1267. } else {
  1268. $endSessionToTms = api_strtotime($coachAccessEndDate);
  1269. if ($session_now > $endSessionToTms) {
  1270. $allowedEndTime = false;
  1271. }
  1272. }
  1273. } else {
  1274. $endSessionToTms = api_strtotime($date_session_end);
  1275. if ($session_now > $endSessionToTms) {
  1276. $allowedEndTime = false;
  1277. }
  1278. }
  1279. }
  1280. }
  1281. }
  1282. if ($showAllSessions) {
  1283. if ($allowed_time < $session_now && $allowedEndTime === false) {
  1284. $markAsOld = true;
  1285. }
  1286. if ($allowed_time > $session_now && $endSessionToTms > $session_now) {
  1287. $markAsFuture = true;
  1288. }
  1289. $allowedEndTime = true;
  1290. $allowed_time = 0;
  1291. }
  1292. if ($session_now >= $allowed_time && $allowedEndTime) {
  1293. // Read only and accessible.
  1294. $atLeastOneCourseIsVisible = true;
  1295. if (api_get_setting('hide_courses_in_sessions') === 'false') {
  1296. $courseUserHtml = CourseManager::get_logged_user_course_html(
  1297. $course,
  1298. $session_id,
  1299. 'session_course_item',
  1300. true,
  1301. $this->load_directories_preview
  1302. );
  1303. if (isset($courseUserHtml[1])) {
  1304. $course_session = $courseUserHtml[1];
  1305. $course_session['skill'] = isset($courseUserHtml['skill']) ? $courseUserHtml['skill'] : '';
  1306. // Course option (show student progress)
  1307. // This code will add new variables (Progress, Score, Certificate)
  1308. if ($studentInfoProgress || $studentInfoScore || $studentInfoCertificate) {
  1309. if ($studentInfoProgress) {
  1310. $progress = Tracking::get_avg_student_progress(
  1311. $user_id,
  1312. $course['course_code'],
  1313. [],
  1314. $session_id
  1315. );
  1316. $course_session['student_info']['progress'] = $progress === false ? null : $progress;
  1317. }
  1318. if ($studentInfoScore) {
  1319. $percentage_score = Tracking::get_avg_student_score(
  1320. $user_id,
  1321. $course['course_code'],
  1322. [],
  1323. $session_id
  1324. );
  1325. $course_session['student_info']['score'] = $percentage_score;
  1326. }
  1327. if ($studentInfoCertificate) {
  1328. $category = Category::load(
  1329. null,
  1330. null,
  1331. $course['course_code'],
  1332. null,
  1333. null,
  1334. $session_id
  1335. );
  1336. $course_session['student_info']['certificate'] = null;
  1337. if (isset($category[0])) {
  1338. if ($category[0]->is_certificate_available($user_id)) {
  1339. $course_session['student_info']['certificate'] = Display::label(
  1340. get_lang('Yes'),
  1341. 'success'
  1342. );
  1343. } else {
  1344. $course_session['student_info']['certificate'] = Display::label(
  1345. get_lang('No')
  1346. );
  1347. }
  1348. }
  1349. }
  1350. }
  1351. $html_courses_session[] = $course_session;
  1352. }
  1353. }
  1354. $count_courses_session++;
  1355. }
  1356. }
  1357. // No courses to show.
  1358. if ($atLeastOneCourseIsVisible === false) {
  1359. if (empty($html_courses_session)) {
  1360. continue;
  1361. }
  1362. }
  1363. if ($count_courses_session > 0) {
  1364. $params = [
  1365. 'id' => $session_id,
  1366. ];
  1367. $session_box = Display::getSessionTitleBox($session_id);
  1368. $coachId = $session_box['id_coach'];
  1369. $imageField = $extraFieldValue->get_values_by_handler_and_field_variable(
  1370. $session_id,
  1371. 'image'
  1372. );
  1373. $params['category_id'] = $session_box['category_id'];
  1374. $params['title'] = $session_box['title'];
  1375. $params['id_coach'] = $coachId;
  1376. $params['coach_url'] = api_get_path(WEB_AJAX_PATH).
  1377. 'user_manager.ajax.php?a=get_user_popup&user_id='.$coachId;
  1378. $params['coach_name'] = !empty($session_box['coach']) ? $session_box['coach'] : null;
  1379. $params['coach_avatar'] = UserManager::getUserPicture(
  1380. $coachId,
  1381. USER_IMAGE_SIZE_SMALL
  1382. );
  1383. $params['date'] = $session_box['dates'];
  1384. $params['image'] = isset($imageField['value']) ? $imageField['value'] : null;
  1385. $params['duration'] = isset($session_box['duration']) ? ' '.$session_box['duration'] : null;
  1386. $params['show_actions'] = SessionManager::cantEditSession($session_id);
  1387. if ($collapsable) {
  1388. $collapsableData = SessionManager::getCollapsableData(
  1389. $user_id,
  1390. $session_id,
  1391. $extraFieldValue,
  1392. $collapsableLink
  1393. );
  1394. $params['collapsed'] = $collapsableData['collapsed'];
  1395. $params['collapsable_link'] = $collapsableData['collapsable_link'];
  1396. }
  1397. $params['show_description'] = $session_box['show_description'] == 1 && $portalShowDescription;
  1398. $params['description'] = $session_box['description'];
  1399. $params['visibility'] = $session_box['visibility'];
  1400. $params['show_simple_session_info'] = $showSimpleSessionInfo;
  1401. $params['course_list_session_style'] = $coursesListSessionStyle;
  1402. $params['num_users'] = $session_box['num_users'];
  1403. $params['num_courses'] = $session_box['num_courses'];
  1404. $params['course_categories'] = CourseManager::getCourseCategoriesFromCourseList(
  1405. $html_courses_session
  1406. );
  1407. $params['courses'] = $html_courses_session;
  1408. $params['is_old'] = $markAsOld;
  1409. $params['is_future'] = $markAsFuture;
  1410. if ($showSimpleSessionInfo) {
  1411. $params['subtitle'] = self::getSimpleSessionDetails(
  1412. $session_box['coach'],
  1413. $session_box['dates'],
  1414. isset($session_box['duration']) ? $session_box['duration'] : null
  1415. );
  1416. }
  1417. if ($gameModeIsActive) {
  1418. $params['stars'] = GamificationUtils::getSessionStars(
  1419. $params['id'],
  1420. $this->user_id
  1421. );
  1422. $params['progress'] = GamificationUtils::getSessionProgress(
  1423. $params['id'],
  1424. $this->user_id
  1425. );
  1426. $params['points'] = GamificationUtils::getSessionPoints(
  1427. $params['id'],
  1428. $this->user_id
  1429. );
  1430. }
  1431. $listSession[] = $params;
  1432. $sessionCount++;
  1433. }
  1434. }
  1435. } else {
  1436. // All sessions included in
  1437. $count_courses_session = 0;
  1438. $html_sessions = '';
  1439. if (isset($session_category['sessions'])) {
  1440. foreach ($session_category['sessions'] as $session) {
  1441. $session_id = $session['session_id'];
  1442. // Don't show empty sessions.
  1443. if (count($session['courses']) < 1) {
  1444. continue;
  1445. }
  1446. $date_session_start = $session['access_start_date'];
  1447. $date_session_end = $session['access_end_date'];
  1448. $coachAccessStartDate = $session['coach_access_start_date'];
  1449. $coachAccessEndDate = $session['coach_access_end_date'];
  1450. $html_courses_session = [];
  1451. $count = 0;
  1452. $markAsOld = false;
  1453. $markAsFuture = false;
  1454. foreach ($session['courses'] as $course) {
  1455. $is_coach_course = api_is_coach($session_id, $course['real_id']);
  1456. $allowed_time = 0;
  1457. $allowedEndTime = true;
  1458. if (!empty($date_session_start)) {
  1459. if ($is_coach_course) {
  1460. $allowed_time = api_strtotime($coachAccessStartDate);
  1461. } else {
  1462. $allowed_time = api_strtotime($date_session_start);
  1463. }
  1464. if (!isset($_GET['history'])) {
  1465. if (!empty($date_session_end)) {
  1466. if ($is_coach_course) {
  1467. // if coach end date is empty we use the default end date
  1468. if (empty($coachAccessEndDate)) {
  1469. $endSessionToTms = api_strtotime($date_session_end);
  1470. if ($session_now > $endSessionToTms) {
  1471. $allowedEndTime = false;
  1472. }
  1473. } else {
  1474. $endSessionToTms = api_strtotime($coachAccessEndDate);
  1475. if ($session_now > $endSessionToTms) {
  1476. $allowedEndTime = false;
  1477. }
  1478. }
  1479. } else {
  1480. $endSessionToTms = api_strtotime($date_session_end);
  1481. if ($session_now > $endSessionToTms) {
  1482. $allowedEndTime = false;
  1483. }
  1484. }
  1485. }
  1486. }
  1487. }
  1488. if ($showAllSessions) {
  1489. if ($allowed_time < $session_now && $allowedEndTime == false) {
  1490. $markAsOld = true;
  1491. }
  1492. if ($allowed_time > $session_now && $endSessionToTms > $session_now) {
  1493. $markAsFuture = true;
  1494. }
  1495. $allowedEndTime = true;
  1496. $allowed_time = 0;
  1497. }
  1498. if ($session_now >= $allowed_time && $allowedEndTime) {
  1499. if (api_get_setting('hide_courses_in_sessions') === 'false') {
  1500. $c = CourseManager::get_logged_user_course_html(
  1501. $course,
  1502. $session_id,
  1503. 'session_course_item'
  1504. );
  1505. if (isset($c[1])) {
  1506. $html_courses_session[] = $c[1];
  1507. }
  1508. }
  1509. $count_courses_session++;
  1510. $count++;
  1511. }
  1512. }
  1513. $sessionParams = [];
  1514. // Category
  1515. if ($count > 0) {
  1516. $session_box = Display::getSessionTitleBox($session_id);
  1517. $sessionParams[0]['id'] = $session_id;
  1518. $sessionParams[0]['date'] = $session_box['dates'];
  1519. $sessionParams[0]['duration'] = isset($session_box['duration']) ? ' '.$session_box['duration'] : null;
  1520. $sessionParams[0]['course_list_session_style'] = $coursesListSessionStyle;
  1521. $sessionParams[0]['title'] = $session_box['title'];
  1522. $sessionParams[0]['subtitle'] = (!empty($session_box['coach']) ? $session_box['coach'].' | ' : '').$session_box['dates'];
  1523. $sessionParams[0]['show_actions'] = SessionManager::cantEditSession($session_id);
  1524. $sessionParams[0]['courses'] = $html_courses_session;
  1525. $sessionParams[0]['show_simple_session_info'] = $showSimpleSessionInfo;
  1526. $sessionParams[0]['coach_name'] = !empty($session_box['coach']) ? $session_box['coach'] : null;
  1527. $sessionParams[0]['is_old'] = $markAsOld;
  1528. $sessionParams[0]['is_future'] = $markAsFuture;
  1529. if ($collapsable) {
  1530. $collapsableData = SessionManager::getCollapsableData(
  1531. $user_id,
  1532. $session_id,
  1533. $extraFieldValue,
  1534. $collapsableLink
  1535. );
  1536. $sessionParams[0]['collapsable_link'] = $collapsableData['collapsable_link'];
  1537. $sessionParams[0]['collapsed'] = $collapsableData['collapsed'];
  1538. }
  1539. if ($showSimpleSessionInfo) {
  1540. $sessionParams[0]['subtitle'] = self::getSimpleSessionDetails(
  1541. $session_box['coach'],
  1542. $session_box['dates'],
  1543. isset($session_box['duration']) ? $session_box['duration'] : null
  1544. );
  1545. }
  1546. $this->tpl->assign('session', $sessionParams);
  1547. $this->tpl->assign('show_tutor', (api_get_setting('show_session_coach') === 'true' ? true : false));
  1548. $this->tpl->assign('gamification_mode', $gameModeIsActive);
  1549. $this->tpl->assign('remove_session_url', api_get_configuration_value('remove_session_url'));
  1550. if ($viewGridCourses) {
  1551. $html_sessions .= $this->tpl->fetch(
  1552. $this->tpl->get_template('/user_portal/grid_session.tpl')
  1553. );
  1554. } else {
  1555. $html_sessions .= $this->tpl->fetch(
  1556. $this->tpl->get_template('user_portal/classic_session.tpl')
  1557. );
  1558. }
  1559. $sessionCount++;
  1560. }
  1561. }
  1562. }
  1563. if ($count_courses_session > 0) {
  1564. $categoryParams = [
  1565. 'id' => $session_category['session_category']['id'],
  1566. 'title' => $session_category['session_category']['name'],
  1567. 'show_actions' => api_is_platform_admin(),
  1568. 'subtitle' => '',
  1569. 'sessions' => $html_sessions,
  1570. ];
  1571. $session_category_start_date = $session_category['session_category']['date_start'];
  1572. $session_category_end_date = $session_category['session_category']['date_end'];
  1573. if ($session_category_start_date == '0000-00-00') {
  1574. $session_category_start_date = '';
  1575. }
  1576. if ($session_category_end_date == '0000-00-00') {
  1577. $session_category_end_date = '';
  1578. }
  1579. if (!empty($session_category_start_date) &&
  1580. !empty($session_category_end_date)
  1581. ) {
  1582. $categoryParams['subtitle'] = sprintf(
  1583. get_lang('From %s to %s'),
  1584. $session_category_start_date,
  1585. $session_category_end_date
  1586. );
  1587. } else {
  1588. if (!empty($session_category_start_date)) {
  1589. $categoryParams['subtitle'] = get_lang('From').' '.$session_category_start_date;
  1590. }
  1591. if (!empty($session_category_end_date)) {
  1592. $categoryParams['subtitle'] = get_lang('Until').' '.$session_category_end_date;
  1593. }
  1594. }
  1595. $this->tpl->assign('session_category', $categoryParams);
  1596. $sessions_with_category .= $this->tpl->fetch(
  1597. $this->tpl->get_template('user_portal/session_category.tpl')
  1598. );
  1599. }
  1600. }
  1601. }
  1602. $allCoursesInSessions = [];
  1603. foreach ($listSession as $currentSession) {
  1604. $coursesInSessions = $currentSession['courses'];
  1605. unset($currentSession['courses']);
  1606. foreach ($coursesInSessions as $coursesInSession) {
  1607. $coursesInSession['session'] = $currentSession;
  1608. $allCoursesInSessions[] = $coursesInSession;
  1609. }
  1610. }
  1611. $this->tpl->assign('all_courses', $allCoursesInSessions);
  1612. $this->tpl->assign('session', $listSession);
  1613. $this->tpl->assign('show_tutor', (api_get_setting('show_session_coach') === 'true' ? true : false));
  1614. $this->tpl->assign('gamification_mode', $gameModeIsActive);
  1615. $this->tpl->assign('remove_session_url', api_get_configuration_value('remove_session_url'));
  1616. if ($viewGridCourses) {
  1617. $sessions_with_no_category = $this->tpl->fetch(
  1618. $this->tpl->get_template('/user_portal/grid_session.tpl')
  1619. );
  1620. } else {
  1621. $sessions_with_no_category = $this->tpl->fetch(
  1622. $this->tpl->get_template('user_portal/classic_session.tpl')
  1623. );
  1624. }
  1625. }
  1626. }
  1627. return [
  1628. 'courses' => $courseCompleteList,
  1629. 'sessions' => $session_categories,
  1630. 'html' => trim($specialCourseList.$sessions_with_category.$sessions_with_no_category.$listCourse),
  1631. 'session_count' => $sessionCount,
  1632. 'course_count' => $courseCount,
  1633. ];
  1634. }
  1635. /**
  1636. * Shows a welcome message when the user doesn't have any content in the course list.
  1637. */
  1638. public function setWelComeCourse()
  1639. {
  1640. $count_courses = CourseManager::count_courses();
  1641. $course_catalog_url = api_get_path(WEB_CODE_PATH).'auth/courses.php';
  1642. $course_list_url = api_get_path(WEB_PATH).'user_portal.php';
  1643. $this->tpl->assign('course_catalog_url', $course_catalog_url);
  1644. $this->tpl->assign('course_list_url', $course_list_url);
  1645. $this->tpl->assign('course_catalog_link', Display::url(get_lang('here'), $course_catalog_url));
  1646. $this->tpl->assign('course_list_link', Display::url(get_lang('here'), $course_list_url));
  1647. $this->tpl->assign('count_courses', $count_courses);
  1648. }
  1649. /**
  1650. * @return array
  1651. */
  1652. public function return_hot_courses()
  1653. {
  1654. return CourseManager::return_hot_courses(30, 6);
  1655. }
  1656. /**
  1657. * UserPortal view for session, return the HTML of the course list.
  1658. *
  1659. * @param $user_id
  1660. *
  1661. * @return string
  1662. */
  1663. public function returnCoursesAndSessionsViewBySession($user_id)
  1664. {
  1665. $sessionCount = 0;
  1666. $courseCount = 0;
  1667. $load_history = (isset($_GET['history']) && intval($_GET['history']) == 1) ? true : false;
  1668. if ($load_history) {
  1669. // Load sessions in category in *history*
  1670. $sessionCategories = UserManager::get_sessions_by_category($user_id, true);
  1671. } else {
  1672. // Load sessions in category
  1673. $sessionCategories = UserManager::get_sessions_by_category($user_id, false);
  1674. }
  1675. $html = '';
  1676. $loadDirs = $this->load_directories_preview;
  1677. // If we're not in the history view...
  1678. $listCoursesInfo = [];
  1679. if (!isset($_GET['history'])) {
  1680. // Display special courses
  1681. $specialCoursesResult = CourseManager::returnSpecialCourses(
  1682. $user_id,
  1683. $loadDirs
  1684. );
  1685. $specialCourses = $specialCoursesResult;
  1686. if ($specialCourses) {
  1687. $this->tpl->assign('courses', $specialCourses);
  1688. $html = $this->tpl->fetch(
  1689. $this->tpl->get_template('/user_portal/classic_courses_without_category.tpl')
  1690. );
  1691. }
  1692. // Display courses
  1693. // [code=>xxx, real_id=>000]
  1694. $listCourses = CourseManager::get_courses_list_by_user_id(
  1695. $user_id,
  1696. false
  1697. );
  1698. foreach ($listCourses as $i => $listCourseCodeId) {
  1699. if (isset($listCourseCodeId['special_course'])) {
  1700. continue;
  1701. }
  1702. $courseCategory = CourseManager::getUserCourseCategoryForCourse(
  1703. $user_id,
  1704. $listCourseCodeId['real_id']
  1705. );
  1706. $userCatTitle = '';
  1707. $userCategoryId = 0;
  1708. if ($courseCategory) {
  1709. $userCategoryId = $courseCategory['user_course_cat'];
  1710. $userCatTitle = $courseCategory['title'];
  1711. }
  1712. $listCourse = api_get_course_info_by_id($listCourseCodeId['real_id']);
  1713. $listCoursesInfo[] = [
  1714. 'course' => $listCourse,
  1715. 'code' => $listCourseCodeId['code'],
  1716. 'id' => $listCourseCodeId['real_id'],
  1717. 'title' => $listCourse['title'],
  1718. 'userCatId' => $userCategoryId,
  1719. 'userCatTitle' => $userCatTitle,
  1720. ];
  1721. $courseCount++;
  1722. }
  1723. usort($listCoursesInfo, 'self::compareByCourse');
  1724. }
  1725. $listCoursesInSession = [];
  1726. if (is_array($sessionCategories)) {
  1727. // all courses that are in a session
  1728. $listCoursesInSession = SessionManager::getNamedSessionCourseForCoach($user_id);
  1729. }
  1730. // we got all courses
  1731. // for each user category, sorted alphabetically, display courses
  1732. $listUserCategories = CourseManager::get_user_course_categories($user_id);
  1733. $listCoursesAlreadyDisplayed = [];
  1734. uasort($listUserCategories, "self::compareListUserCategory");
  1735. $listUserCategories[0] = '';
  1736. $html .= '<div class="session-view-block">';
  1737. foreach ($listUserCategories as $userCategoryId => $userCat) {
  1738. // add user category
  1739. $userCategoryHtml = '';
  1740. if ($userCategoryId != 0) {
  1741. $userCategoryHtml = '<div class="session-view-well ">';
  1742. $userCategoryHtml .= self::getHtmlForUserCategory($userCategoryId, $userCat['title']);
  1743. }
  1744. // look for course in this userCat in session courses : $listCoursesInSession
  1745. $htmlCategory = '';
  1746. if (isset($listCoursesInSession[$userCategoryId])) {
  1747. // list of courses in this user cat
  1748. foreach ($listCoursesInSession[$userCategoryId]['courseInUserCatList'] as $i => $listCourse) {
  1749. // add course
  1750. $listCoursesAlreadyDisplayed[$listCourse['courseId']] = 1;
  1751. $coursesInfo = $listCourse['course'];
  1752. $htmlCategory .= self::getHtmlForCourse(
  1753. $coursesInfo,
  1754. $userCategoryId,
  1755. 1,
  1756. $loadDirs
  1757. );
  1758. // list of session category
  1759. $htmlSessionCategory = '<div class="session-view-row" style="display:none;" id="courseblock-'.$coursesInfo['real_id'].'">';
  1760. foreach ($listCourse['sessionCatList'] as $listCategorySession) {
  1761. // add session category
  1762. $htmlSessionCategory .= self::getHtmlSessionCategory(
  1763. $listCategorySession['catSessionId'],
  1764. $listCategorySession['catSessionName']
  1765. );
  1766. // list of session
  1767. $htmlSession = ''; // start
  1768. foreach ($listCategorySession['sessionList'] as $listSession) {
  1769. // add session
  1770. $htmlSession .= '<div class="session-view-row">';
  1771. $htmlSession .= self::getHtmlForSession(
  1772. $listSession['sessionId'],
  1773. $listSession['sessionName'],
  1774. $listCategorySession['catSessionId'],
  1775. $coursesInfo
  1776. );
  1777. $htmlSession .= '</div>';
  1778. $sessionCount++;
  1779. }
  1780. $htmlSession .= ''; // end session block
  1781. $htmlSessionCategory .= $htmlSession;
  1782. }
  1783. $htmlSessionCategory .= '</div>'; // end session cat block
  1784. $htmlCategory .= Display::panel($htmlSessionCategory, '');
  1785. }
  1786. $userCategoryHtml .= $htmlCategory;
  1787. }
  1788. // look for courses in this userCat in not in session courses : $listCoursesInfo
  1789. // if course not already added
  1790. $htmlCategory = '';
  1791. foreach ($listCoursesInfo as $i => $listCourse) {
  1792. if ($listCourse['userCatId'] == $userCategoryId &&
  1793. !isset($listCoursesAlreadyDisplayed[$listCourse['id']])
  1794. ) {
  1795. $body = self::getHtmlForCourse(
  1796. $listCourse['course'],
  1797. $userCategoryId,
  1798. 0,
  1799. $loadDirs
  1800. );
  1801. $htmlCategory .= Display::panel($body, '');
  1802. }
  1803. }
  1804. $htmlCategory .= '';
  1805. $userCategoryHtml .= $htmlCategory; // end user cat block
  1806. if ($userCategoryId != 0) {
  1807. $userCategoryHtml .= '</div>';
  1808. }
  1809. $html .= $userCategoryHtml;
  1810. }
  1811. $html .= '</div>';
  1812. return [
  1813. 'html' => $html,
  1814. 'sessions' => $sessionCategories,
  1815. 'courses' => $listCoursesInfo,
  1816. 'session_count' => $sessionCount,
  1817. 'course_count' => $courseCount,
  1818. ];
  1819. }
  1820. /**
  1821. * @param $listA
  1822. * @param $listB
  1823. *
  1824. * @return int
  1825. */
  1826. public static function compareListUserCategory($listA, $listB)
  1827. {
  1828. if ($listA['title'] == $listB['title']) {
  1829. return 0;
  1830. }
  1831. if ($listA['title'] > $listB['title']) {
  1832. return 1;
  1833. }
  1834. return -1;
  1835. }
  1836. /**
  1837. * @param $view
  1838. * @param $userId
  1839. */
  1840. public static function setDefaultMyCourseView($view, $userId)
  1841. {
  1842. //setcookie('defaultMyCourseView'.$userId, $view);
  1843. }
  1844. /**
  1845. * @param int $userId
  1846. *
  1847. * @return array
  1848. */
  1849. public function returnCourseCategoryListFromUser($userId)
  1850. {
  1851. $sessionCount = 0;
  1852. $courseList = CourseManager::get_courses_list_by_user_id($userId);
  1853. $categoryCodes = CourseManager::getCourseCategoriesFromCourseList($courseList);
  1854. $categories = [];
  1855. foreach ($categoryCodes as $categoryCode) {
  1856. $categories[] = CourseCategory::getCategory($categoryCode);
  1857. }
  1858. $template = new Template('', false, false, false, true, false, false);
  1859. $layout = $template->get_template('user_portal/course_categories.tpl');
  1860. $template->assign('course_categories', $categories);
  1861. return [
  1862. 'courses' => $courseList,
  1863. 'html' => $template->fetch($layout),
  1864. 'course_count' => count($courseList),
  1865. 'session_count' => $sessionCount,
  1866. ];
  1867. }
  1868. /**
  1869. * Set grade book dependency progress bar see BT#13099.
  1870. *
  1871. * @param $userId
  1872. *
  1873. * @return bool
  1874. */
  1875. public function setGradeBookDependencyBar($userId)
  1876. {
  1877. $allow = api_get_configuration_value('gradebook_dependency');
  1878. if (api_is_anonymous()) {
  1879. return false;
  1880. }
  1881. if ($allow) {
  1882. $courseAndSessions = $this->returnCoursesAndSessions(
  1883. $userId,
  1884. false,
  1885. '',
  1886. false,
  1887. false
  1888. );
  1889. $courseList = api_get_configuration_value('gradebook_dependency_mandatory_courses');
  1890. $courseList = isset($courseList['courses']) ? $courseList['courses'] : [];
  1891. $mandatoryCourse = [];
  1892. if (!empty($courseList)) {
  1893. foreach ($courseList as $courseId) {
  1894. $courseInfo = api_get_course_info_by_id($courseId);
  1895. $mandatoryCourse[] = $courseInfo['code'];
  1896. }
  1897. }
  1898. // @todo improve calls of course info
  1899. $subscribedCourses = !empty($courseAndSessions['courses']) ? $courseAndSessions['courses'] : [];
  1900. $mainCategoryList = [];
  1901. foreach ($subscribedCourses as $courseInfo) {
  1902. $courseCode = $courseInfo['code'];
  1903. $categories = Category::load(null, null, $courseCode);
  1904. /** @var Category $category */
  1905. $category = !empty($categories[0]) ? $categories[0] : [];
  1906. if (!empty($category)) {
  1907. $mainCategoryList[] = $category;
  1908. }
  1909. }
  1910. $result20 = 0;
  1911. $result80 = 0;
  1912. $countCoursesPassedNoDependency = 0;
  1913. /** @var Category $category */
  1914. foreach ($mainCategoryList as $category) {
  1915. $userFinished = Category::userFinishedCourse(
  1916. $userId,
  1917. $category,
  1918. true
  1919. );
  1920. if ($userFinished) {
  1921. if (in_array($category->get_course_code(), $mandatoryCourse)) {
  1922. if ($result20 < 20) {
  1923. $result20 += 10;
  1924. }
  1925. } else {
  1926. $countCoursesPassedNoDependency++;
  1927. if ($result80 < 80) {
  1928. $result80 += 10;
  1929. }
  1930. }
  1931. }
  1932. }
  1933. $finalResult = $result20 + $result80;
  1934. $gradeBookList = api_get_configuration_value('gradebook_badge_sidebar');
  1935. $gradeBookList = isset($gradeBookList['gradebooks']) ? $gradeBookList['gradebooks'] : [];
  1936. $badgeList = [];
  1937. foreach ($gradeBookList as $id) {
  1938. $categories = Category::load($id);
  1939. /** @var Category $category */
  1940. $category = !empty($categories[0]) ? $categories[0] : [];
  1941. $badgeList[$id]['name'] = $category->get_name();
  1942. $badgeList[$id]['finished'] = false;
  1943. $badgeList[$id]['skills'] = [];
  1944. if (!empty($category)) {
  1945. $minToValidate = $category->getMinimumToValidate();
  1946. $dependencies = $category->getCourseListDependency();
  1947. $gradeBooksToValidateInDependence = $category->getGradeBooksToValidateInDependence();
  1948. $countDependenciesPassed = 0;
  1949. foreach ($dependencies as $courseId) {
  1950. $courseInfo = api_get_course_info_by_id($courseId);
  1951. $courseCode = $courseInfo['code'];
  1952. $categories = Category::load(null, null, $courseCode);
  1953. $subCategory = !empty($categories[0]) ? $categories[0] : null;
  1954. if (!empty($subCategory)) {
  1955. $score = Category::userFinishedCourse(
  1956. $userId,
  1957. $subCategory,
  1958. true
  1959. );
  1960. if ($score) {
  1961. $countDependenciesPassed++;
  1962. }
  1963. }
  1964. }
  1965. $userFinished =
  1966. $countDependenciesPassed >= $gradeBooksToValidateInDependence &&
  1967. $countCoursesPassedNoDependency >= $minToValidate;
  1968. if ($userFinished) {
  1969. $badgeList[$id]['finished'] = true;
  1970. }
  1971. $objSkill = new Skill();
  1972. $skills = $category->get_skills();
  1973. $skillList = [];
  1974. foreach ($skills as $skill) {
  1975. $skillList[] = $objSkill->get($skill['id']);
  1976. }
  1977. $badgeList[$id]['skills'] = $skillList;
  1978. }
  1979. }
  1980. $this->tpl->assign(
  1981. 'grade_book_sidebar',
  1982. true
  1983. );
  1984. $this->tpl->assign(
  1985. 'grade_book_progress',
  1986. $finalResult
  1987. );
  1988. $this->tpl->assign('grade_book_badge_list', $badgeList);
  1989. return true;
  1990. }
  1991. return false;
  1992. }
  1993. /**
  1994. * Generate the HTML code for items when displaying the right-side blocks.
  1995. *
  1996. * @param array $items
  1997. *
  1998. * @return string
  1999. */
  2000. private static function returnRightBlockItems(array $items)
  2001. {
  2002. $my_account_content = '';
  2003. foreach ($items as $item) {
  2004. if (empty($item['link']) && empty($item['title'])) {
  2005. continue;
  2006. }
  2007. $my_account_content .= '<li class="list-group-item '.(empty($item['class']) ? '' : $item['class']).'">'
  2008. .(empty($item['icon']) ? '' : '<span class="item-icon">'.$item['icon'].'</span>')
  2009. .'<a href="'.$item['link'].'">'.$item['title'].'</a>'
  2010. .'</li>';
  2011. }
  2012. return '<ul class="list-group">'.$my_account_content.'</ul>';
  2013. }
  2014. /**
  2015. * Return HTML code for personal user course category.
  2016. *
  2017. * @param $id
  2018. * @param $title
  2019. *
  2020. * @return string
  2021. */
  2022. private static function getHtmlForUserCategory($id, $title)
  2023. {
  2024. if ($id == 0) {
  2025. return '';
  2026. }
  2027. $icon = Display::return_icon(
  2028. 'folder_yellow.png',
  2029. $title,
  2030. ['class' => 'sessionView'],
  2031. ICON_SIZE_LARGE
  2032. );
  2033. return "<div class='session-view-user-category'>$icon<span>$title</span></div>";
  2034. }
  2035. /**
  2036. * return HTML code for course display in session view.
  2037. *
  2038. * @param array $courseInfo
  2039. * @param $userCategoryId
  2040. * @param bool $displayButton
  2041. * @param $loadDirs
  2042. *
  2043. * @return string
  2044. */
  2045. private static function getHtmlForCourse(
  2046. $courseInfo,
  2047. $userCategoryId,
  2048. $displayButton = false,
  2049. $loadDirs
  2050. ) {
  2051. if (empty($courseInfo)) {
  2052. return '';
  2053. }
  2054. $id = $courseInfo['real_id'];
  2055. $title = $courseInfo['title'];
  2056. $code = $courseInfo['code'];
  2057. $class = 'session-view-lvl-6';
  2058. if ($userCategoryId != 0 && !$displayButton) {
  2059. $class = 'session-view-lvl-7';
  2060. }
  2061. $class2 = 'session-view-lvl-6';
  2062. if ($displayButton || $userCategoryId != 0) {
  2063. $class2 = 'session-view-lvl-7';
  2064. }
  2065. $button = '';
  2066. if ($displayButton) {
  2067. $button = '<input id="session-view-button-'.intval(
  2068. $id
  2069. ).'" class="btn btn-default btn-sm" type="button" onclick="hideUnhide(\'courseblock-'.intval(
  2070. $id
  2071. ).'\', \'session-view-button-'.intval($id).'\', \'+\', \'-\')" value="+" />';
  2072. }
  2073. $icon = Display::return_icon(
  2074. 'blackboard.png',
  2075. $title,
  2076. ['class' => 'sessionView'],
  2077. ICON_SIZE_LARGE
  2078. );
  2079. $courseLink = $courseInfo['course_public_url'].'?id_session=0';
  2080. // get html course params
  2081. $courseParams = CourseManager::getCourseParamsForDisplay($id, $loadDirs);
  2082. $teachers = '';
  2083. $rightActions = '';
  2084. // teacher list
  2085. if (!empty($courseParams['teachers'])) {
  2086. $teachers = '<p class="'.$class2.' view-by-session-teachers">'.$courseParams['teachers'].'</p>';
  2087. }
  2088. // notification
  2089. if (!empty($courseParams['right_actions'])) {
  2090. $rightActions = '<div class="pull-right">'.$courseParams['right_actions'].'</div>';
  2091. }
  2092. $notifications = isset($courseParams['notifications']) ? $courseParams['notifications'] : '';
  2093. return "<div>
  2094. $button
  2095. <span class='$class'>$icon
  2096. <a class='sessionView' href='$courseLink'>$title</a>
  2097. </span>
  2098. $notifications
  2099. $rightActions
  2100. </div>
  2101. $teachers";
  2102. }
  2103. /**
  2104. * return HTML code for session category.
  2105. *
  2106. * @param $id
  2107. * @param $title
  2108. *
  2109. * @return string
  2110. */
  2111. private static function getHtmlSessionCategory($id, $title)
  2112. {
  2113. if ($id == 0) {
  2114. return '';
  2115. }
  2116. $icon = Display::return_icon(
  2117. 'folder_blue.png',
  2118. $title,
  2119. ['class' => 'sessionView'],
  2120. ICON_SIZE_LARGE
  2121. );
  2122. return "<div class='session-view-session-category'>
  2123. <span class='session-view-lvl-2'>
  2124. $icon
  2125. <span>$title</span>
  2126. </span>
  2127. </div>";
  2128. }
  2129. /**
  2130. * return HTML code for session.
  2131. *
  2132. * @param int $id session id
  2133. * @param string $title session title
  2134. * @param int $categorySessionId
  2135. * @param array $courseInfo
  2136. *
  2137. * @return string
  2138. */
  2139. private static function getHtmlForSession($id, $title, $categorySessionId, $courseInfo)
  2140. {
  2141. $html = '';
  2142. if ($categorySessionId == 0) {
  2143. $class1 = 'session-view-lvl-2'; // session
  2144. $class2 = 'session-view-lvl-4'; // got to course in session link
  2145. } else {
  2146. $class1 = 'session-view-lvl-3'; // session
  2147. $class2 = 'session-view-lvl-5'; // got to course in session link
  2148. }
  2149. $icon = Display::return_icon(
  2150. 'session.png',
  2151. $title,
  2152. ['class' => 'sessionView'],
  2153. ICON_SIZE_LARGE
  2154. );
  2155. $courseLink = $courseInfo['course_public_url'].'?id_session='.intval($id);
  2156. $html .= "<span class='$class1 session-view-session'>$icon$title</span>";
  2157. $html .= '<div class="'.$class2.' session-view-session-go-to-course-in-session">
  2158. <a class="" href="'.$courseLink.'">'.get_lang('Go to course within session').'</a></div>';
  2159. return '<div>'.$html.'</div>';
  2160. }
  2161. /**
  2162. * @param $listA
  2163. * @param $listB
  2164. *
  2165. * @return int
  2166. */
  2167. private static function compareByCourse($listA, $listB)
  2168. {
  2169. if ($listA['userCatTitle'] == $listB['userCatTitle']) {
  2170. if ($listA['title'] == $listB['title']) {
  2171. return 0;
  2172. }
  2173. if ($listA['title'] > $listB['title']) {
  2174. return 1;
  2175. }
  2176. return -1;
  2177. }
  2178. if ($listA['userCatTitle'] > $listB['userCatTitle']) {
  2179. return 1;
  2180. }
  2181. return -1;
  2182. }
  2183. /**
  2184. * Get the session coach name, duration or dates
  2185. * when $_configuration['show_simple_session_info'] is enabled.
  2186. *
  2187. * @param string $coachName
  2188. * @param string $dates
  2189. * @param string|null $duration Optional
  2190. *
  2191. * @return string
  2192. */
  2193. private static function getSimpleSessionDetails($coachName, $dates, $duration = null)
  2194. {
  2195. $strDetails = [];
  2196. if (!empty($coachName)) {
  2197. $strDetails[] = $coachName;
  2198. }
  2199. $strDetails[] = !empty($duration) ? $duration : $dates;
  2200. return implode(' | ', $strDetails);
  2201. }
  2202. /**
  2203. * Filter the course list by category code.
  2204. *
  2205. * @param array $courseList course list
  2206. * @param string $categoryCode
  2207. *
  2208. * @return array
  2209. */
  2210. private static function filterByCategory($courseList, $categoryCode)
  2211. {
  2212. return array_filter(
  2213. $courseList,
  2214. function ($courseInfo) use ($categoryCode) {
  2215. if (isset($courseInfo['category_code']) &&
  2216. $courseInfo['category_code'] === $categoryCode
  2217. ) {
  2218. return true;
  2219. }
  2220. return false;
  2221. }
  2222. );
  2223. }
  2224. }