CourseBuilder.class.php 42 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069
  1. <?php
  2. /* For licensing terms, see /license.txt */
  3. // @todo autoloader?
  4. require_once 'Course.class.php';
  5. require_once 'Event.class.php';
  6. require_once 'Link.class.php';
  7. require_once 'ToolIntro.class.php';
  8. require_once 'Document.class.php';
  9. require_once 'ScormDocument.class.php';
  10. require_once 'LinkCategory.class.php';
  11. require_once 'CourseDescription.class.php';
  12. require_once 'ForumPost.class.php';
  13. require_once 'ForumTopic.class.php';
  14. require_once 'Forum.class.php';
  15. require_once 'ForumCategory.class.php';
  16. require_once 'Quiz.class.php';
  17. require_once 'QuizQuestion.class.php';
  18. require_once 'CourseCopyLearnpath.class.php';
  19. require_once 'Survey.class.php';
  20. require_once 'SurveyQuestion.class.php';
  21. require_once 'Glossary.class.php';
  22. require_once 'CourseSession.class.php';
  23. require_once 'wiki.class.php';
  24. require_once 'Thematic.class.php';
  25. require_once 'Attendance.class.php';
  26. /**
  27. * Class which can build a course-object from a Chamilo-course.
  28. * @author Bart Mollet <bart.mollet@hogent.be>
  29. * @package chamilo.backup
  30. */
  31. class CourseBuilder
  32. {
  33. /** Course */
  34. public $course;
  35. /* With this array you can filter the tools you want to be parsed by default all tools are included*/
  36. public $tools_to_build = array(
  37. 'announcements',
  38. 'attendance',
  39. 'course_descriptions',
  40. 'documents',
  41. 'events',
  42. 'forum_category',
  43. 'forums',
  44. 'forum_topics',
  45. 'glossary',
  46. 'quizzes',
  47. 'learnpaths',
  48. 'links',
  49. 'surveys',
  50. 'tool_intro',
  51. 'thematic',
  52. 'wiki'
  53. );
  54. /* With this array you can filter wich elements of the tools are going to be added in the course obj (only works with LPs) */
  55. public $specific_id_list = array();
  56. /**
  57. * Create a new CourseBuilder
  58. */
  59. public function __construct($type='', $course = null)
  60. {
  61. $_course = api_get_course_info();
  62. if (!empty($course['official_code'])){
  63. $_course = $course;
  64. }
  65. $this->course = new Course();
  66. $this->course->code = $_course['official_code'];
  67. $this->course->type = $type;
  68. $this->course->path = api_get_path(SYS_COURSE_PATH).$_course['path'].'/';
  69. $this->course->backup_path = api_get_path(SYS_COURSE_PATH).$_course['path'];
  70. $this->course->encoding = api_get_system_encoding(); //current platform encoding
  71. $this->course->db_name = $_course['dbName'];
  72. $this->course->info = $_course;
  73. }
  74. /**
  75. *
  76. * @param type $array
  77. */
  78. function set_tools_to_build($array)
  79. {
  80. $this->tools_to_build = $array;
  81. }
  82. /**
  83. *
  84. * @param type $array
  85. */
  86. function set_tools_specific_id_list($array)
  87. {
  88. $this->specific_id_list = $array;
  89. }
  90. /**
  91. * Get the created course
  92. * @return course The course
  93. */
  94. function get_course()
  95. {
  96. return $this->course;
  97. }
  98. /**
  99. * Build the course-object
  100. *
  101. * @param int session_id
  102. * @param string course_code
  103. * @param bool true if you want to get the elements that exists in the course and
  104. * in the session, (session_id = 0 or session_id = X)
  105. */
  106. function build($session_id = 0, $course_code = '', $with_base_content = false)
  107. {
  108. $table_link = Database :: get_course_table(TABLE_LINKED_RESOURCES);
  109. $table_properties = Database :: get_course_table(TABLE_ITEM_PROPERTY);
  110. $course_info = api_get_course_info($course_code);
  111. $course_id = $course_info['real_id'];
  112. foreach ($this->tools_to_build as $tool) {
  113. $function_build = 'build_'.$tool;
  114. $specificIdList = isset($this->specific_id_list[$tool]) ? $this->specific_id_list[$tool] : null;
  115. $this->$function_build($session_id, $course_code, $with_base_content, $specificIdList);
  116. }
  117. if (!empty($session_id) && !empty($course_code)) {
  118. /*$this->build_documents($session_id, $course_code, $with_base_content);
  119. $this->build_quizzes($session_id, $course_code, $with_base_content);
  120. $this->build_glossary($session_id, $course_code, $with_base_content);
  121. $this->build_learnpaths($session_id, $course_code,$with_base_content);
  122. $this->build_links($session_id, $course_code, $with_base_content);
  123. $this->build_course_descriptions($session_id, $course_code, $with_base_content);
  124. $this->build_wiki($session_id, $course_code, $with_base_content);
  125. //$this->build_thematic($session_id, $course_code, $with_base_content);
  126. $this->build_thematic();
  127. $this->build_attendance();*/
  128. } else {
  129. /*$this->build_events();
  130. $this->build_announcements();
  131. $this->build_links();
  132. $this->build_tool_intro();
  133. $this->build_documents();
  134. $this->build_course_descriptions();
  135. $this->build_wiki();
  136. $this->build_quizzes();
  137. $this->build_learnpaths();
  138. $this->build_surveys();
  139. $this->build_glossary();
  140. $this->build_thematic();
  141. $this->build_attendance();*/
  142. }
  143. //TABLE_LINKED_RESOURCES is the "resource" course table, which is deprecated, apparently
  144. foreach ($this->course->resources as $type => $resources) {
  145. foreach ($resources as $id => $resource) {
  146. $sql = "SELECT * FROM ".$table_link." WHERE c_id = $course_id AND source_type = '".$resource->get_type()."' AND source_id = '".$resource->get_id()."'";
  147. $res = Database::query($sql);
  148. while ($link = Database::fetch_object($res)) {
  149. $this->course->resources[$type][$id]->add_linked_resource($link->resource_type, $link->resource_id);
  150. }
  151. }
  152. }
  153. // Once we've built the resouces array a bit more, try to get items
  154. // from the item_propry table and order them in the "resources" array
  155. foreach ($this->course->resources as $type => $resources) {
  156. foreach ($resources as $id => $resource) {
  157. $tool = $resource->get_tool();
  158. if ($tool != null) {
  159. $sql = "SELECT * FROM $table_properties WHERE c_id = $course_id AND TOOL = '".$tool."' AND ref='".$resource->get_id()."'";
  160. $res = Database::query($sql);
  161. $all_properties = array ();
  162. while ($item_property = Database::fetch_array($res)) {
  163. $all_properties[]= $item_property;
  164. }
  165. $this->course->resources[$type][$id]->item_properties = $all_properties;
  166. }
  167. }
  168. }
  169. return $this->course;
  170. }
  171. /**
  172. * Build the documents
  173. */
  174. function build_documents($session_id = 0, $course_code = '', $with_base_content = false, $id_list = array())
  175. {
  176. $course_info = api_get_course_info($course_code);
  177. $course_id = $course_info['real_id'];
  178. $table_doc = Database::get_course_table(TABLE_DOCUMENT);
  179. $table_prop = Database::get_course_table(TABLE_ITEM_PROPERTY);
  180. //Remove chat_files and shared_folder files
  181. $avoid_paths = " path NOT LIKE '/shared_folder%' AND
  182. path NOT LIKE '/chat_files%' ";
  183. //$avoid_paths = " 1 = 1 ";
  184. if (!empty($course_code) && !empty($session_id)) {
  185. $session_id = intval($session_id);
  186. if ($with_base_content) {
  187. $session_condition = api_get_session_condition($session_id, true, true);
  188. } else {
  189. $session_condition = api_get_session_condition($session_id, true);
  190. }
  191. if (!empty($this->course->type) && $this->course->type=='partial') {
  192. $sql = "SELECT d.id, d.path, d.comment, d.title, d.filetype, d.size FROM $table_doc d, $table_prop p
  193. WHERE d.c_id = $course_id AND
  194. p.c_id = $course_id AND
  195. tool = '".TOOL_DOCUMENT."' AND
  196. p.ref = d.id AND
  197. p.visibility != 2 AND
  198. path NOT LIKE '/images/gallery%' AND
  199. $avoid_paths
  200. $session_condition
  201. ORDER BY path";
  202. } else {
  203. $sql = "SELECT d.id, d.path, d.comment, d.title, d.filetype, d.size FROM $table_doc d, $table_prop p
  204. WHERE d.c_id = $course_id AND
  205. p.c_id = $course_id AND
  206. tool = '".TOOL_DOCUMENT."' AND
  207. $avoid_paths AND
  208. p.ref = d.id AND
  209. p.visibility != 2 $session_condition
  210. ORDER BY path";
  211. }
  212. $db_result = Database::query($sql);
  213. while ($obj = Database::fetch_object($db_result)) {
  214. $doc = new Document($obj->id, $obj->path, $obj->comment, $obj->title, $obj->filetype, $obj->size);
  215. $this->course->add_resource($doc);
  216. }
  217. } else {
  218. if (!empty($this->course->type) && $this->course->type=='partial')
  219. $sql = 'SELECT d.id, d.path, d.comment, d.title, d.filetype, d.size FROM '.$table_doc.' d, '.$table_prop.' p
  220. WHERE d.c_id = '.$course_id.' AND
  221. p.c_id = '.$course_id.' AND
  222. tool = \''.TOOL_DOCUMENT.'\' AND
  223. p.ref = d.id AND
  224. p.visibility != 2 AND
  225. path NOT LIKE \'/images/gallery%\' AND
  226. '.$avoid_paths.'AND
  227. d.session_id = 0
  228. ORDER BY path';
  229. else
  230. $sql = 'SELECT d.id, d.path, d.comment, d.title, d.filetype, d.size
  231. FROM '.$table_doc.' d, '.$table_prop.' p
  232. WHERE d.c_id = '.$course_id.' AND
  233. p.c_id = '.$course_id.' AND
  234. tool = \''.TOOL_DOCUMENT.'\' AND
  235. p.ref = d.id AND
  236. p.visibility != 2 AND
  237. '.$avoid_paths.' AND
  238. d.session_id = 0
  239. ORDER BY path';
  240. $db_result = Database::query($sql);
  241. while ($obj = Database::fetch_object($db_result)) {
  242. $doc = new Document($obj->id, $obj->path, $obj->comment, $obj->title, $obj->filetype, $obj->size);
  243. $this->course->add_resource($doc);
  244. }
  245. }
  246. }
  247. /**
  248. * Build the forums
  249. */
  250. function build_forums($session_id = 0, $course_code = null, $with_base_content = false, $id_list = array())
  251. {
  252. $course_info = api_get_course_info($course_code);
  253. $course_id = $course_info['real_id'];
  254. $table = Database :: get_course_table(TABLE_FORUM);
  255. $sql = "SELECT * FROM $table WHERE c_id = $course_id ";
  256. $sql .= " ORDER BY forum_title, forum_category";
  257. $db_result = Database::query($sql);
  258. while ($obj = Database::fetch_object($db_result)) {
  259. $forum = new Forum($obj);
  260. $this->course->add_resource($forum);
  261. }
  262. }
  263. /**
  264. * Build a forum-category
  265. */
  266. function build_forum_category($session_id = 0, $course_code = null, $with_base_content = false, $id_list = array())
  267. {
  268. $table = Database :: get_course_table(TABLE_FORUM_CATEGORY);
  269. $course_info = api_get_course_info($course_code);
  270. $course_id = $course_info['real_id'];
  271. $sql = "SELECT * FROM $table WHERE c_id = $course_id ORDER BY cat_title";
  272. $db_result = Database::query($sql);
  273. while ($obj = Database::fetch_object($db_result)) {
  274. $forum_category = new ForumCategory($obj);
  275. $this->course->add_resource($forum_category);
  276. }
  277. }
  278. /**
  279. * Build the forum-topics
  280. */
  281. function build_forum_topics($session_id = 0, $course_code = null, $with_base_content = false, $id_list = array())
  282. {
  283. $table = Database :: get_course_table(TABLE_FORUM_THREAD);
  284. $course_info = api_get_course_info($course_code);
  285. $course_id = $course_info['real_id'];
  286. $sql = "SELECT * FROM $table WHERE c_id = $course_id
  287. ORDER BY thread_title ";
  288. $db_result = Database::query($sql);
  289. while ($obj = Database::fetch_object($db_result)) {
  290. $forum_topic = new ForumTopic($obj);
  291. $this->course->add_resource($forum_topic);
  292. $this->build_forum_posts($obj->thread_id, $obj->forum_id, true);
  293. }
  294. }
  295. /**
  296. * Build the forum-posts
  297. * TODO: All tree structure of posts should be built, attachments for example.
  298. */
  299. function build_forum_posts($thread_id = null, $forum_id = null, $only_first_post = false)
  300. {
  301. $table = Database :: get_course_table(TABLE_FORUM_POST);
  302. $course_id = api_get_course_int_id();
  303. $sql = "SELECT * FROM $table WHERE c_id = $course_id ";
  304. if (!empty($thread_id) && !empty($forum_id)) {
  305. $forum_id = intval($forum_id);
  306. $thread_id = intval($thread_id);
  307. $sql .= " AND thread_id = $thread_id AND forum_id = $forum_id ";
  308. }
  309. $sql .= " ORDER BY post_id ASC LIMIT 1";
  310. $db_result = Database::query($sql);
  311. while ($obj = Database::fetch_object($db_result)) {
  312. $forum_post = new ForumPost($obj);
  313. $this->course->add_resource($forum_post);
  314. }
  315. }
  316. /**
  317. * Build the links
  318. */
  319. function build_links($session_id = 0, $course_code = '', $with_base_content = false, $id_list = array())
  320. {
  321. $course_info = api_get_course_info($course_code);
  322. $course_id = $course_info['real_id'];
  323. $table = Database :: get_course_table(TABLE_LINK);
  324. $table_prop = Database :: get_course_table(TABLE_ITEM_PROPERTY);
  325. if (!empty($session_id) && !empty($course_code)) {
  326. $session_id = intval($session_id);
  327. if ($with_base_content) {
  328. $session_condition = api_get_session_condition($session_id, true, true);
  329. } else {
  330. $session_condition = api_get_session_condition($session_id, true);
  331. }
  332. $sql = "SELECT l.id, l.title, l.url, l.description, l.category_id, l.on_homepage
  333. FROM $table l, $table_prop p
  334. WHERE l.c_id = $course_id AND p.c_id = $course_id AND p.ref=l.id AND p.tool = '".TOOL_LINK."' AND p.visibility != 2 $session_condition
  335. ORDER BY l.display_order";
  336. } else {
  337. $sql = "SELECT l.id, l.title, l.url, l.description, l.category_id, l.on_homepage
  338. FROM $table l, $table_prop p
  339. WHERE l.c_id = $course_id AND p.c_id = $course_id AND p.ref=l.id AND p.tool = '".TOOL_LINK."' AND p.visibility != 2 AND l.session_id = 0
  340. ORDER BY l.display_order";
  341. }
  342. $db_result = Database::query($sql);
  343. while ($obj = Database::fetch_object($db_result)) {
  344. $link = new Link($obj->id, $obj->title, $obj->url, $obj->description, $obj->category_id, $obj->on_homepage);
  345. $this->course->add_resource($link);
  346. if (!empty($course_code)) {
  347. $res = $this->build_link_category($obj->category_id,$course_code);
  348. } else {
  349. $res = $this->build_link_category($obj->category_id);
  350. }
  351. if($res > 0) {
  352. $this->course->resources[RESOURCE_LINK][$obj->id]->add_linked_resource(RESOURCE_LINKCATEGORY, $obj->category_id);
  353. }
  354. }
  355. }
  356. /**
  357. * Build tool intro
  358. */
  359. function build_tool_intro($session_id = 0, $course_code = '', $with_base_content = false, $id_list = array())
  360. {
  361. $table = Database :: get_course_table(TABLE_TOOL_INTRO);
  362. $course_id = api_get_course_int_id();
  363. $sql = "SELECT * FROM $table WHERE c_id = $course_id ";
  364. $db_result = Database::query($sql);
  365. while ($obj = Database::fetch_object($db_result)) {
  366. $tool_intro = new ToolIntro($obj->id, $obj->intro_text);
  367. $this->course->add_resource($tool_intro);
  368. }
  369. }
  370. /**
  371. * Build a link category
  372. */
  373. function build_link_category($id, $course_code = '')
  374. {
  375. $course_info = api_get_course_info($course_code);
  376. $course_id = $course_info['real_id'];
  377. $link_cat_table = Database :: get_course_table(TABLE_LINK_CATEGORY);
  378. $sql = "SELECT * FROM $link_cat_table WHERE c_id = $course_id AND id = $id";
  379. $db_result = Database::query($sql);
  380. while ($obj = Database::fetch_object($db_result)) {
  381. $link_category = new LinkCategory($obj->id, $obj->category_title, $obj->description, $obj->display_order);
  382. $this->course->add_resource($link_category);
  383. return $id;
  384. }
  385. return 0;
  386. }
  387. /**
  388. * Build the Quizzes
  389. */
  390. function build_quizzes($session_id = 0, $course_code = '', $with_base_content = false, $id_list = array())
  391. {
  392. $course_info = api_get_course_info($course_code);
  393. $table_qui = Database :: get_course_table(TABLE_QUIZ_TEST);
  394. $table_rel = Database :: get_course_table(TABLE_QUIZ_TEST_QUESTION);
  395. $table_doc = Database :: get_course_table(TABLE_DOCUMENT);
  396. $course_id = $course_info['real_id'];
  397. if (!empty($course_code) && !empty($session_id)) {
  398. $session_id = intval($session_id);
  399. if ($with_base_content) {
  400. $session_condition = api_get_session_condition($session_id, true, true);
  401. } else {
  402. $session_condition = api_get_session_condition($session_id, true);
  403. }
  404. $sql = "SELECT * FROM $table_qui WHERE c_id = $course_id AND active >=0 $session_condition"; //select only quizzes with active = 0 or 1 (not -1 which is for deleted quizzes)
  405. } else {
  406. $sql = "SELECT * FROM $table_qui WHERE c_id = $course_id AND active >=0 AND session_id = 0"; //select only quizzes with active = 0 or 1 (not -1 which is for deleted quizzes)
  407. }
  408. $db_result = Database::query($sql);
  409. while ($obj = Database::fetch_object($db_result)) {
  410. if (strlen($obj->sound) > 0) {
  411. $sql = "SELECT id FROM $table_doc WHERE c_id = $course_id AND path = '/audio/".$obj->sound."'";
  412. $res = Database::query($sql);
  413. $doc = Database::fetch_object($res);
  414. $obj->sound = $doc->id;
  415. }
  416. $exercise_obj = new Exercise($course_id);
  417. $exercise_obj->read($obj->iid);
  418. $categories = $exercise_obj->get_categories_with_name_in_exercise();
  419. $obj->categories = $categories;
  420. $quiz = new Quiz($obj);
  421. $sql = 'SELECT * FROM '.$table_rel.' WHERE c_id = '.$course_id.' AND exercice_id = '.$obj->iid;
  422. $db_result2 = Database::query($sql);
  423. while ($obj2 = Database::fetch_object($db_result2)) {
  424. $quiz->add_question($obj2->question_id, $obj2->question_order);
  425. }
  426. $this->course->add_resource($quiz);
  427. }
  428. if (!empty($course_code)) {
  429. $this->build_quiz_questions($course_code);
  430. } else {
  431. $this->build_quiz_questions();
  432. }
  433. }
  434. /**
  435. * Build the Quiz-Questions
  436. */
  437. function build_quiz_questions($course_code = null)
  438. {
  439. $course_info = api_get_course_info($course_code);
  440. $course_id = $course_info['real_id'];
  441. $table_qui = Database :: get_course_table(TABLE_QUIZ_TEST);
  442. $table_rel = Database :: get_course_table(TABLE_QUIZ_TEST_QUESTION);
  443. $table_que = Database :: get_course_table(TABLE_QUIZ_QUESTION);
  444. $table_ans = Database :: get_course_table(TABLE_QUIZ_ANSWER);
  445. // Building normal tests.
  446. $sql = "SELECT * FROM $table_que WHERE c_id = $course_id ";
  447. $db_result = Database::query($sql);
  448. while ($obj = Database::fetch_object($db_result)) {
  449. $categories = Testcategory::getCategoryForQuestionWithCategoryData($obj->iid, $course_id, true);
  450. $parent_info = array();
  451. if (isset($obj->parent_id) && !empty($obj->parent_id)) {
  452. $parent_info = (array)Question::read($obj->parent_id, $course_id);
  453. }
  454. $question = new QuizQuestion($obj->iid, $obj->question, $obj->description, $obj->ponderation, $obj->type, $obj->position, $obj->picture, $obj->level, $obj->extra, $parent_info, $categories);
  455. $sql = 'SELECT * FROM '.$table_ans.' WHERE question_id = '.$obj->iid;
  456. $db_result2 = Database::query($sql);
  457. while ($obj2 = Database::fetch_object($db_result2)) {
  458. $question->add_answer($obj2->iid, $obj2->answer, $obj2->correct, $obj2->comment, $obj2->ponderation, $obj2->position, $obj2->hotspot_coordinates, $obj2->hotspot_type);
  459. if ($obj->type == MULTIPLE_ANSWER_TRUE_FALSE) {
  460. $table_options = Database::get_course_table(TABLE_QUIZ_QUESTION_OPTION);
  461. $sql = 'SELECT * FROM '.$table_options.' WHERE c_id = '.$course_id.' AND question_id = '.$obj->iid;
  462. $db_result3 = Database::query($sql);
  463. while ($obj3 = Database::fetch_object($db_result3)) {
  464. $question_option = new QuizQuestionOption($obj3);
  465. $question->add_option($question_option);
  466. }
  467. }
  468. }
  469. $this->course->add_resource($question);
  470. }
  471. // Building a fictional test for collecting orphan questions.
  472. $build_orphan_questions = !empty($_POST['recycle_option']); // When a course is emptied this option should be activated (true).
  473. //@todo fix query in order to use iid
  474. /*$sql = "SELECT questions.*
  475. FROM $table_que as questions
  476. LEFT JOIN $table_rel as quizz_questions
  477. ON (questions.id = quizz_questions.question_id AND questions.c_id = $course_id AND quizz_questions.c_id = $course_id)
  478. LEFT JOIN $table_qui as exercices
  479. ON (exercice_id = exercices.id AND exercices.c_id = $course_id AND questions.c_id = $course_id)
  480. WHERE questions.c_id = $course_id AND
  481. exercices.c_id = $course_id AND
  482. (quizz_questions.exercice_id IS NULL OR exercices.active = -1) "; // active = -1 means "deleted" test.
  483. */
  484. //1st union gets the orphan questions from deleted exercises
  485. //2nd union gets the orphan questions from question that were deleted in a exercise.
  486. $sql = " (
  487. SELECT q.* FROM $table_que q INNER JOIN $table_rel r
  488. ON (q.c_id = r.c_id AND q.iid = r.question_id)
  489. INNER JOIN $table_qui ex
  490. ON (ex.iid = r.exercice_id AND ex.c_id = r.c_id )
  491. WHERE ex.c_id = $course_id AND ex.active = '-1'
  492. )
  493. UNION
  494. (
  495. SELECT q.* FROM $table_que q left
  496. OUTER JOIN $table_rel r
  497. ON (q.c_id = r.c_id AND q.iid = r.question_id)
  498. WHERE q.c_id = $course_id AND r.question_id is null
  499. )
  500. UNION
  501. (
  502. SELECT q.* FROM $table_que q
  503. INNER JOIN $table_rel r
  504. ON (q.c_id = r.c_id AND q.iid = r.question_id)
  505. WHERE r.c_id = $course_id AND r.exercice_id = '-1' OR r.exercice_id = '0'
  506. )
  507. ";
  508. $db_result = Database::query($sql);
  509. if (Database::num_rows($db_result) > 0) {
  510. $build_orphan_questions = true;
  511. $orphanQuestionIds = array();
  512. while ($obj = Database::fetch_object($db_result)) {
  513. $categories = Testcategory::getCategoryForQuestionWithCategoryData($obj->iid, $course_id, true);
  514. $parent_info = array();
  515. if (isset($obj->parent_id) && !empty($obj->parent_id)) {
  516. $parent_info = (array)Question::read($obj->parent_id, $course_id);
  517. }
  518. //Avoid adding the same question twice
  519. if (!isset($this->course->resources[$obj->iid])) {
  520. $question = new QuizQuestion($obj->iid, $obj->question, $obj->description, $obj->ponderation, $obj->type, $obj->position, $obj->picture,$obj->level, $obj->extra, $parent_info, $categories);
  521. $sql = "SELECT * FROM $table_ans WHERE c_id = $course_id AND question_id = ".$obj->iid;
  522. $db_result2 = Database::query($sql);
  523. if (Database::num_rows($db_result2)) {
  524. while ($obj2 = Database::fetch_object($db_result2)) {
  525. $question->add_answer($obj2->iid, $obj2->answer, $obj2->correct, $obj2->comment, $obj2->ponderation, $obj2->position, $obj2->hotspot_coordinates, $obj2->hotspot_type);
  526. $orphanQuestionIds[] = $obj2->iid;
  527. }
  528. }
  529. $this->course->add_resource($question);
  530. }
  531. }
  532. }
  533. if ($build_orphan_questions) {
  534. $obj = array(
  535. 'iid' => -1,
  536. 'title' => get_lang('OrphanQuestions', ''),
  537. 'type' => 2
  538. );
  539. $newQuiz = new Quiz((object)$obj);
  540. if (!empty($orphanQuestionIds)) {
  541. foreach($orphanQuestionIds as $index => $orphanId) {
  542. $order = $index +1;
  543. $newQuiz->add_question($orphanId, $order);
  544. }
  545. }
  546. $this->course->add_resource($newQuiz);
  547. }
  548. }
  549. /**
  550. * Build the orphan questions
  551. */
  552. function build_quiz_orphan_questions()
  553. {
  554. $table_qui = Database :: get_course_table(TABLE_QUIZ_TEST);
  555. $table_rel = Database :: get_course_table(TABLE_QUIZ_TEST_QUESTION);
  556. $table_que = Database :: get_course_table(TABLE_QUIZ_QUESTION);
  557. $table_ans = Database :: get_course_table(TABLE_QUIZ_ANSWER);
  558. $course_id = api_get_course_int_id();
  559. $sql = 'SELECT *
  560. FROM '.$table_que.' as questions
  561. LEFT JOIN '.$table_rel.' as quizz_questions
  562. ON questions.id=quizz_questions.question_id
  563. LEFT JOIN '.$table_qui.' as exercices
  564. ON exercice_id=exercices.id
  565. WHERE questions.c_id = '.$course_id.' AND
  566. quizz_questions.c_id = '.$course_id.' AND
  567. exercices.c_id = '.$course_id.' AND
  568. (quizz_questions.exercice_id IS NULL OR
  569. exercices.active = -1)';
  570. $db_result = Database::query($sql);
  571. if (Database::num_rows($db_result) > 0) {
  572. // This is the fictional test for collecting orphan questions.
  573. $orphan_questions = new Quiz(-1, get_lang('OrphanQuestions', ''), '', 0, 0, 1, '', 0);
  574. $this->course->add_resource($orphan_questions);
  575. while ($obj = Database::fetch_object($db_result)) {
  576. $question = new QuizQuestion($obj->iid, $obj->question, $obj->description, $obj->ponderation, $obj->type, $obj->position, $obj->picture,$obj->level,$obj->extra);
  577. $sql = 'SELECT * FROM '.$table_ans.' WHERE question_id = '.$obj->iid;
  578. $db_result2 = Database::query($sql);
  579. while ($obj2 = Database::fetch_object($db_result2)) {
  580. $question->add_answer($obj2->iid, $obj2->answer, $obj2->correct, $obj2->comment, $obj2->ponderation, $obj2->position, $obj2->hotspot_coordinates, $obj2->hotspot_type);
  581. }
  582. $this->course->add_resource($question);
  583. }
  584. }
  585. }
  586. /**
  587. * Build the Surveys
  588. */
  589. function build_surveys($session_id = 0, $course_code = '', $with_base_content = false, $id_list = array())
  590. {
  591. $table_survey = Database :: get_course_table(TABLE_SURVEY);
  592. $table_question = Database :: get_course_table(TABLE_SURVEY_QUESTION);
  593. $course_id = api_get_course_int_id();
  594. $sql = 'SELECT * FROM '.$table_survey.' WHERE c_id = '.$course_id.' AND session_id = 0 ';
  595. $db_result = Database::query($sql);
  596. while ($obj = Database::fetch_object($db_result)) {
  597. $survey = new Survey($obj->survey_id, $obj->code,$obj->title,
  598. $obj->subtitle, $obj->author, $obj->lang,
  599. $obj->avail_from, $obj->avail_till, $obj->is_shared,
  600. $obj->template, $obj->intro, $obj->surveythanks,
  601. $obj->creation_date, $obj->invited, $obj->answered,
  602. $obj->invite_mail, $obj->reminder_mail);
  603. $sql = 'SELECT * FROM '.$table_question.' WHERE c_id = '.$course_id.' AND survey_id = '.$obj->survey_id;
  604. $db_result2 = Database::query($sql);
  605. while ($obj2 = Database::fetch_object($db_result2)){
  606. $survey->add_question($obj2->question_id);
  607. }
  608. $this->course->add_resource($survey);
  609. }
  610. $this->build_survey_questions();
  611. }
  612. /**
  613. * Build the Survey Questions
  614. */
  615. function build_survey_questions() {
  616. $table_que = Database :: get_course_table(TABLE_SURVEY_QUESTION);
  617. $table_opt = Database :: get_course_table(TABLE_SURVEY_QUESTION_OPTION);
  618. $course_id = api_get_course_int_id();
  619. $sql = 'SELECT * FROM '.$table_que.' WHERE c_id = '.$course_id.' ';
  620. $db_result = Database::query($sql);
  621. while ($obj = Database::fetch_object($db_result)){
  622. $question = new SurveyQuestion($obj->question_id, $obj->survey_id,
  623. $obj->survey_question, $obj->survey_question_comment,
  624. $obj->type, $obj->display, $obj->sort,
  625. $obj->shared_question_id, $obj->max_value);
  626. $sql = 'SELECT * FROM '.$table_opt.' WHERE c_id = '.$course_id.' AND question_id = '.$obj->question_id;
  627. $db_result2 = Database::query($sql);
  628. while ($obj2 = Database::fetch_object($db_result2)) {
  629. $question->add_answer($obj2->option_text, $obj2->sort);
  630. }
  631. $this->course->add_resource($question);
  632. }
  633. }
  634. /**
  635. * Build the announcements
  636. */
  637. function build_announcements($session_id = 0, $course_code = '', $with_base_content = false, $id_list = array()) {
  638. $table = Database :: get_course_table(TABLE_ANNOUNCEMENT);
  639. $course_id = api_get_course_int_id();
  640. $sql = 'SELECT * FROM '.$table.' WHERE c_id = '.$course_id.' AND session_id = 0';
  641. $db_result = Database::query($sql);
  642. $table_attachment = Database :: get_course_table(TABLE_ANNOUNCEMENT_ATTACHMENT);
  643. while ($obj = Database::fetch_object($db_result)) {
  644. $sql = 'SELECT path, comment, filename, size FROM '.$table_attachment.' WHERE c_id = '.$course_id.' AND announcement_id = '.$obj->id.'';
  645. $result = Database::query($sql);
  646. $attachment_obj = Database::fetch_object($result);
  647. $att_path = $att_filename = $att_size = $atth_comment = '';
  648. if (!empty($attachment_obj)) {
  649. $att_path = $attachment_obj->path;
  650. $att_filename = $attachment_obj->filename;
  651. $att_size = $attachment_obj->size;
  652. $atth_comment = $attachment_obj->comment;
  653. }
  654. $announcement = new Announcement($obj->id, $obj->title, $obj->content, $obj->end_date,$obj->display_order,$obj->email_sent, $att_path, $att_filename, $att_size, $atth_comment);
  655. $this->course->add_resource($announcement);
  656. }
  657. }
  658. /**
  659. * Build the events
  660. */
  661. function build_events($session_id = 0, $course_code = '', $with_base_content = false, $id_list = array()) {
  662. $table = Database :: get_course_table(TABLE_AGENDA);
  663. $course_id = api_get_course_int_id();
  664. $sql = 'SELECT * FROM '.$table.' WHERE c_id = '.$course_id.' AND session_id = 0';
  665. $db_result = Database::query($sql);
  666. while ($obj = Database::fetch_object($db_result)) {
  667. $table_attachment = Database :: get_course_table(TABLE_AGENDA_ATTACHMENT);
  668. $sql = 'SELECT path, comment, filename, size FROM '.$table_attachment.' WHERE c_id = '.$course_id.' AND agenda_id = '.$obj->id.'';
  669. $result = Database::query($sql);
  670. $attachment_obj = Database::fetch_object($result);
  671. $att_path = $att_filename = $att_size = $atth_comment = '';
  672. if (!empty($attachment_obj)) {
  673. $att_path = $attachment_obj->path;
  674. $att_filename = $attachment_obj->filename;
  675. $att_size = $attachment_obj->size;
  676. $atth_comment = $attachment_obj->comment;
  677. }
  678. $event = new Event($obj->id, $obj->title, $obj->content, $obj->start_date, $obj->end_date, $att_path, $att_filename, $att_size, $atth_comment, $obj->all_day);
  679. $this->course->add_resource($event);
  680. }
  681. }
  682. /**
  683. * Build the course-descriptions
  684. */
  685. function build_course_descriptions($session_id = 0, $course_code = '', $with_base_content = false, $id_list = array()) {
  686. $course_info = api_get_course_info($course_code);
  687. $course_id = $course_info['real_id'];
  688. $table = Database :: get_course_table(TABLE_COURSE_DESCRIPTION);
  689. if (!empty($session_id) && !empty($course_code)) {
  690. $session_id = intval($session_id);
  691. if ($with_base_content) {
  692. $session_condition = api_get_session_condition($session_id, true, true);
  693. } else {
  694. $session_condition = api_get_session_condition($session_id, true);
  695. }
  696. $sql = 'SELECT * FROM '.$table. ' WHERE c_id = '.$course_id.' '.$session_condition;
  697. } else {
  698. $table = Database :: get_course_table(TABLE_COURSE_DESCRIPTION);
  699. $sql = 'SELECT * FROM '.$table. ' WHERE c_id = '.$course_id.' AND session_id = 0';
  700. }
  701. $db_result = Database::query($sql);
  702. while ($obj = Database::fetch_object($db_result)) {
  703. $cd = new CourseDescription($obj->id, $obj->title, $obj->content, $obj->description_type);
  704. $this->course->add_resource($cd);
  705. }
  706. }
  707. /**
  708. * Build the learnpaths
  709. */
  710. function build_learnpaths($session_id = 0, $course_code = '', $with_base_content = false, $id_list = array()) {
  711. $course_info = api_get_course_info($course_code);
  712. $course_id = $course_info['real_id'];
  713. $table_main = Database::get_course_table(TABLE_LP_MAIN);
  714. $table_item = Database::get_course_table(TABLE_LP_ITEM);
  715. $table_tool = Database::get_course_table(TABLE_TOOL_LIST);
  716. if (!empty($session_id) && !empty($course_code)) {
  717. $session_id = intval($session_id);
  718. if ($with_base_content) {
  719. $session_condition = api_get_session_condition($session_id, true, true);
  720. } else {
  721. $session_condition = api_get_session_condition($session_id, true);
  722. }
  723. $sql = 'SELECT * FROM '.$table_main.' WHERE c_id = '.$course_id.' '.$session_condition;
  724. } else {
  725. $sql = 'SELECT * FROM '.$table_main.' WHERE c_id = '.$course_id.' AND session_id = 0';
  726. }
  727. if (!empty($id_list)) {
  728. $id_list = array_map('intval', $id_list);
  729. $sql .=" AND id IN (".implode(', ', $id_list).") ";
  730. }
  731. $db_result = Database::query($sql);
  732. if ($db_result)
  733. while ($obj = Database::fetch_object($db_result)) {
  734. $items = array();
  735. $sql_items = "SELECT * FROM ".$table_item." WHERE c_id = '$course_id' AND lp_id = ".$obj->id;
  736. $db_items = Database::query($sql_items);
  737. while ($obj_item = Database::fetch_object($db_items)) {
  738. $item['id'] = $obj_item->id;
  739. $item['item_type'] = $obj_item->item_type;
  740. $item['ref'] = $obj_item->ref;
  741. $item['title'] = $obj_item->title;
  742. $item['description'] = $obj_item->description;
  743. $item['path'] = $obj_item->path;
  744. $item['min_score'] = $obj_item->min_score;
  745. $item['max_score'] = $obj_item->max_score;
  746. $item['mastery_score'] = $obj_item->mastery_score;
  747. $item['parent_item_id'] = $obj_item->parent_item_id;
  748. $item['previous_item_id'] = $obj_item->previous_item_id;
  749. $item['next_item_id'] = $obj_item->next_item_id;
  750. $item['display_order'] = $obj_item->display_order;
  751. $item['prerequisite'] = $obj_item->prerequisite;
  752. $item['parameters'] = $obj_item->parameters;
  753. $item['launch_data'] = $obj_item->launch_data;
  754. $item['audio'] = $obj_item->audio;
  755. $items[] = $item;
  756. }
  757. $sql_tool = "SELECT id FROM $table_tool
  758. WHERE c_id = $course_id AND
  759. (link LIKE '%lp_controller.php%lp_id=".$obj->id."%' AND image='scormbuilder.gif') AND
  760. visibility = '1' ";
  761. $db_tool = Database::query($sql_tool);
  762. if(Database::num_rows($db_tool)) {
  763. $visibility='1';
  764. } else {
  765. $visibility='0';
  766. }
  767. $lp = new CourseCopyLearnpath(
  768. $obj->id,
  769. $obj->lp_type,
  770. $obj->name,
  771. $obj->path,
  772. $obj->ref,
  773. $obj->description,
  774. $obj->content_local,
  775. $obj->default_encoding,
  776. $obj->default_view_mod,
  777. $obj->prevent_reinit,
  778. $obj->force_commit,
  779. $obj->content_maker,
  780. $obj->display_order,
  781. $obj->js_lib,
  782. $obj->content_license,
  783. $obj->debug,
  784. $visibility,
  785. $obj->author,
  786. $obj->preview_image,
  787. $obj->use_max_score,
  788. $obj->autolunch,
  789. $obj->created_on,
  790. $obj->modified_on,
  791. $obj->publicated_on,
  792. $obj->expired_on,
  793. $obj->session_id,
  794. $items);
  795. $this->course->add_resource($lp);
  796. }
  797. //save scorm directory (previously build_scorm_documents())
  798. $i = 1;
  799. if ($dir=@opendir($this->course->backup_path.'/scorm')) {
  800. while($file=readdir($dir)) {
  801. if(is_dir($this->course->backup_path.'/scorm/'.$file) && !in_array($file,array('.','..'))) {
  802. $doc = new ScormDocument($i++, '/'.$file, $file);
  803. $this->course->add_resource($doc);
  804. }
  805. }
  806. closedir($dir);
  807. }
  808. }
  809. /**
  810. * Build the glossarys
  811. */
  812. function build_glossary($session_id = 0, $course_code = '', $with_base_content = false, $id_list = array()) {
  813. $course_info = api_get_course_info($course_code);
  814. $table_glossary = Database :: get_course_table(TABLE_GLOSSARY);
  815. $course_id = $course_info['real_id'];
  816. if (!empty($session_id) && !empty($course_code)) {
  817. $session_id = intval($session_id);
  818. if ($with_base_content) {
  819. $session_condition = api_get_session_condition($session_id, true, true);
  820. } else {
  821. $session_condition = api_get_session_condition($session_id, true);
  822. }
  823. //@todo check this queries are the same ...
  824. if (!empty($this->course->type) && $this->course->type=='partial') {
  825. $sql = 'SELECT * FROM '.$table_glossary.' g WHERE g.c_id = '.$course_id.' '.$session_condition;
  826. } else {
  827. $sql = 'SELECT * FROM '.$table_glossary.' g WHERE g.c_id = '.$course_id.' '.$session_condition;
  828. }
  829. } else {
  830. $table_glossary = Database :: get_course_table(TABLE_GLOSSARY);
  831. //@todo check this queries are the same ... ayayay
  832. if (!empty($this->course->type) && $this->course->type=='partial') {
  833. $sql = 'SELECT * FROM '.$table_glossary.' g WHERE g.c_id = '.$course_id.' AND session_id = 0';
  834. } else {
  835. $sql = 'SELECT * FROM '.$table_glossary.' g WHERE g.c_id = '.$course_id.' AND session_id = 0';
  836. }
  837. }
  838. $db_result = Database::query($sql);
  839. while ($obj = Database::fetch_object($db_result)) {
  840. $doc = new Glossary($obj->glossary_id, $obj->name, $obj->description, $obj->display_order);
  841. $this->course->add_resource($doc);
  842. }
  843. }
  844. /*
  845. * build session course by jhon
  846. * */
  847. function build_session_course(){
  848. $tbl_session = Database::get_main_table(TABLE_MAIN_SESSION);
  849. $tbl_session_course = Database::get_main_table(TABLE_MAIN_SESSION_COURSE);
  850. $list_course = CourseManager::get_course_list();
  851. $list = array();
  852. foreach($list_course as $_course) {
  853. $this->course = new Course();
  854. $this->course->code = $_course['code'];
  855. $this->course->type = 'partial';
  856. $this->course->path = api_get_path(SYS_COURSE_PATH).$_course['directory'].'/';
  857. $this->course->backup_path = api_get_path(SYS_COURSE_PATH).$_course['directory'];
  858. $this->course->encoding = api_get_system_encoding(); //current platform encoding
  859. //$code_course = $_course['code'];
  860. $courseId = $_course['real_id'];
  861. $sql_session = "SELECT id, name, c_id
  862. FROM $tbl_session_course INNER JOIN $tbl_session ON id_session = id
  863. WHERE c_id = '$courseId' ";
  864. $query_session = Database::query($sql_session);
  865. while ($rows_session = Database::fetch_assoc($query_session)) {
  866. $session = new CourseSession($rows_session['id'], $rows_session['name']);
  867. $this->course->add_resource($session);
  868. }
  869. $list[] = $this->course;
  870. }
  871. return $list;
  872. }
  873. function build_wiki($session_id = 0, $course_code = '', $with_base_content = false, $id_list = array()) {
  874. $course_info = api_get_course_info($course_code);
  875. $tbl_wiki = Database::get_course_table(TABLE_WIKI);
  876. $course_id = $course_info['real_id'];
  877. if (!empty($session_id) && !empty($course_code)) {
  878. $session_id = intval($session_id);
  879. if ($with_base_content) {
  880. $session_condition = api_get_session_condition($session_id, true, true);
  881. } else {
  882. $session_condition = api_get_session_condition($session_id, true);
  883. }
  884. $sql = 'SELECT * FROM ' . $tbl_wiki . ' WHERE c_id = '.$course_id.' '.$session_condition;
  885. } else {
  886. $tbl_wiki = Database::get_course_table(TABLE_WIKI);
  887. $sql = 'SELECT * FROM ' . $tbl_wiki . ' WHERE c_id = '.$course_id.' AND session_id = 0';
  888. }
  889. $db_result = Database::query($sql);
  890. while ($obj = Database::fetch_object($db_result)) {
  891. $wiki = new Wiki($obj->id, $obj->page_id, $obj->reflink, $obj->title, $obj->content, $obj->user_id, $obj->group_id, $obj->dtime, $obj->progress, $obj->version);
  892. $this->course->add_resource($wiki);
  893. }
  894. }
  895. /**
  896. * Build the Surveys
  897. */
  898. function build_thematic($session_id = 0, $course_code = '', $with_base_content = false, $id_list = array())
  899. {
  900. $table_thematic = Database :: get_course_table(TABLE_THEMATIC);
  901. $table_thematic_advance = Database :: get_course_table(TABLE_THEMATIC_ADVANCE);
  902. $table_thematic_plan = Database :: get_course_table(TABLE_THEMATIC_PLAN);
  903. $session_id = intval($session_id);
  904. if ($with_base_content) {
  905. $session_condition = api_get_session_condition($session_id, true, true);
  906. } else {
  907. $session_condition = api_get_session_condition($session_id, true);
  908. }
  909. $course_id = api_get_course_int_id();
  910. $courseInfo = api_get_course_info();
  911. $sql = "SELECT * FROM $table_thematic WHERE c_id = $course_id $session_condition ";
  912. $db_result = Database::query($sql);
  913. while ($row = Database::fetch_array($db_result,'ASSOC')) {
  914. $thematic = new Thematic($courseInfo);
  915. $sql = 'SELECT * FROM '.$table_thematic_advance.' WHERE c_id = '.$course_id.' AND thematic_id = '.$row['id'];
  916. $result = Database::query($sql);
  917. while ($sub_row = Database::fetch_array($result,'ASSOC')) {
  918. $thematic->add_thematic_advance($sub_row);
  919. }
  920. $items = api_get_item_property_by_tool('thematic_plan', api_get_course_id(), $session_id);
  921. //$items_from_session = api_get_item_property_by_tool('thematic_plan', api_get_course_id(), api_get_session_id());
  922. $thematic_plan_id_list = array();
  923. if (!empty($items)) {
  924. foreach($items as $item) {
  925. $thematic_plan_id_list[] = $item['ref'];
  926. //$thematic_plan_complete_list[$item['ref']] = $item;
  927. }
  928. }
  929. //$sql = 'SELECT * FROM '.$table_thematic_plan.' WHERE c_id = '.$course_id.' AND thematic_id = '.$row['id'];
  930. $sql = "SELECT tp.*
  931. FROM $table_thematic_plan tp
  932. INNER JOIN $table_thematic t ON (t.id=tp.thematic_id)
  933. WHERE t.c_id = $course_id AND
  934. tp.c_id = $course_id AND
  935. thematic_id = {$row['id']} AND
  936. tp.id IN (".implode(', ', $thematic_plan_id_list).") ";
  937. $result = Database::query($sql);
  938. while ($sub_row = Database::fetch_array($result,'ASSOC')) {
  939. $thematic->add_thematic_plan($sub_row);
  940. }
  941. $this->course->add_resource($thematic);
  942. }
  943. }
  944. /**
  945. * Build the Surveys
  946. */
  947. function build_attendance($session_id = 0, $course_code = '', $with_base_content = false, $id_list = array()) {
  948. $table_attendance = Database :: get_course_table(TABLE_ATTENDANCE);
  949. $table_attendance_calendar = Database :: get_course_table(TABLE_ATTENDANCE_CALENDAR);
  950. $course_id = api_get_course_int_id();
  951. $sql = 'SELECT * FROM '.$table_attendance.' WHERE c_id = '.$course_id.' AND session_id = 0 ';
  952. $db_result = Database::query($sql);
  953. while ($row = Database::fetch_array($db_result,'ASSOC')) {
  954. $obj = new CourseCopyAttendance($row);
  955. $sql = 'SELECT * FROM '.$table_attendance_calendar.' WHERE c_id = '.$course_id.' AND attendance_id = '.$row['id'];
  956. $result = Database::query($sql);
  957. while ($sub_row = Database::fetch_array($result,'ASSOC')) {
  958. $obj->add_attendance_calendar($sub_row);
  959. }
  960. $this->course->add_resource($obj);
  961. }
  962. }
  963. }