learnpath_functions.inc.php 102 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748
  1. <?php
  2. /*
  3. ==============================================================================
  4. Dokeos - elearning and course management software
  5. Copyright (c) 2004-2005 Dokeos S.A.
  6. Copyright (c) 2003 Ghent University (UGent)
  7. Copyright (c) 2001 Universite catholique de Louvain (UCL)
  8. Copyright (c) Denes Nagy
  9. Copyright (c) Yannick Warnier
  10. For a full list of contributors, see "credits.txt".
  11. The full license can be read in "license.txt".
  12. This program is free software; you can redistribute it and/or
  13. modify it under the terms of the GNU General Public License
  14. as published by the Free Software Foundation; either version 2
  15. of the License, or (at your option) any later version.
  16. See the GNU General Public License for more details.
  17. Contact address: Dokeos, 44 rue des palais, B-1030 Brussels, Belgium
  18. Mail: info@dokeos.com
  19. ==============================================================================
  20. */
  21. /**
  22. ==============================================================================
  23. * This is a function library for the learning path.
  24. *
  25. * Due to the face that the learning path has been built upon the resoucelinker,
  26. * naming conventions have changed at least 2 times. You can see here in order the :
  27. * 1. name used in the first version of the resourcelinker
  28. * 2. name used in the first version of the LP
  29. * 3. name used in the second (current) version of the LP
  30. *
  31. * 1. 2. 3.
  32. * Category = Chapter = Module
  33. * Item (?) = Item = Step
  34. *
  35. * @author Denes Nagy <darkden@evk.bke.hu>, main author
  36. * @author Roan Embrechts, some code cleaning
  37. * @author Yannick Warnier <yannick.warnier@dokeos.com>, multi-level learnpath behaviour + new SCORM tool
  38. * @access public
  39. * @package dokeos.learnpath
  40. * @todo rename functions to coding conventions: not deleteitem but delete_item, etc
  41. * @todo rewrite functions to comply with phpDocumentor
  42. * @todo remove code duplication
  43. ==============================================================================
  44. */
  45. /**
  46. * This function deletes an item
  47. * @param integer $id: the item we want to delete
  48. * @return boolean True if item was deleted, false if not found or error
  49. **/
  50. function deleteitem($id)
  51. {
  52. $tbl_learnpath_item = Database :: get_course_table(LEARNPATH_ITEM_TABLE);
  53. $tbl_learnpath_chapter = Database :: get_course_table(LEARNPATH_CHAPTER_TABLE);
  54. //get the display order for this item before it is deleted
  55. $sql = "SELECT display_order, parent_item_id FROM $tbl_lp_item WHERE id=$id";
  56. $result = api_sql_query($sql, __FILE__, __LINE__);
  57. if (mysql_num_rows($result) == 0)
  58. {
  59. return false;
  60. }
  61. $row = mysql_fetch_row($result);
  62. $display_order = $row[0];
  63. $parent_item_id = $row[1];
  64. // delete the item
  65. $sql = "DELETE FROM $tbl_learnpath_item WHERE id='$id'";
  66. $result = api_sql_query($sql, __FILE__, __LINE__);
  67. if ($result === false)
  68. {
  69. return false;
  70. }
  71. // update the other items and chapters
  72. $sql = "UPDATE $tbl_learnpath_item SET display_order = display_order-1 WHERE display_order > $display_order AND parent_item_id = $parent_item_id";
  73. $result = api_sql_query($sql, __FILE__, __LINE__);
  74. $sql = "UPDATE $tbl_learnpath_chapter SET display_order = display_order-1 WHERE display_order > $display_order AND parent_item_id = $parent_item_id";
  75. $result = api_sql_query($sql, __FILE__, __LINE__);
  76. //return
  77. return true;
  78. }
  79. /**
  80. * This function deletes a module(chapter) and all its steps(items).
  81. *
  82. * @param integer id of the chapter we want to delete
  83. * @return boolean True on success and false if not found or error
  84. **/
  85. function deletemodule($parent_item_id)
  86. {
  87. global $learnpath_id;
  88. $tbl_learnpath_item = Database :: get_course_table(LEARNPATH_ITEM_TABLE);
  89. $tbl_learnpath_chapter = Database :: get_course_table(LEARNPATH_CHAPTER_TABLE);
  90. //Added for multi-level behaviour - slightly recursive
  91. $sql = "SELECT * FROM $tbl_learnpath_chapter WHERE lp_id=$learnpath_id";
  92. $result = api_sql_query($sql, __FILE__, __LINE__);
  93. while ($row = mysql_fetch_array($result))
  94. {
  95. if ($row['parent_item_id'] == $parent_item_id)
  96. {
  97. //delete every subchapter
  98. if (deletemodule($row['id']) === false)
  99. {
  100. return false;
  101. }
  102. }
  103. }
  104. //get this chapter's display order
  105. $sql = "SELECT display_order, parent_item_id FROM $tbl_learnpath_chapter WHERE id=$parent_item_id and lp_id=$learnpath_id";
  106. $result = api_sql_query($sql, __FILE__, __LINE__);
  107. if (mysql_num_rows($result) == 0)
  108. {
  109. return false;
  110. }
  111. $row = mysql_fetch_row($result);
  112. $display_order = $row[0];
  113. $parent_id = $row[1];
  114. //delete the chapter itself
  115. $sql = "DELETE FROM $tbl_learnpath_chapter WHERE (id=$parent_item_id and lp_id=$learnpath_id)";
  116. $result = api_sql_query($sql, __FILE__, __LINE__);
  117. //delete items from that chapter
  118. $sql2 = "DELETE FROM $tbl_learnpath_item WHERE parent_item_id=$parent_item_id";
  119. $result = api_sql_query($sql2, __FILE__, __LINE__);
  120. //update all other chapters accordingly
  121. $sql = "UPDATE $tbl_learnpath_item SET display_order = display_order-1 WHERE display_order > $display_order AND parent_item_id = $parent_id";
  122. $result = api_sql_query($sql, __FILE__, __LINE__);
  123. $sql = "UPDATE $tbl_learnpath_chapter SET display_order = display_order-1 WHERE display_order > $display_order AND parent_item_id = $parent_id";
  124. $result = api_sql_query($sql, __FILE__, __LINE__);
  125. return true;
  126. }
  127. /**
  128. * This function deletes an entire path.
  129. *
  130. * @param integer $id: the path we want to delete
  131. * @return void
  132. **/
  133. function deletepath($path_id)
  134. {
  135. $tbl_learnpath_main = Database :: get_course_table(LEARNPATH_MAIN_TABLE);
  136. $tbl_learnpath_item = Database :: get_course_table(LEARNPATH_ITEM_TABLE);
  137. $tbl_learnpath_chapter = Database :: get_course_table(LEARNPATH_CHAPTER_TABLE);
  138. $sql = "DELETE FROM $tbl_learnpath_main WHERE lp_id='$path_id'";
  139. $result = api_sql_query($sql, __FILE__, __LINE__);
  140. //@TODO check how this function is used before uncommenting the following
  141. //also delete all elements inside that path
  142. $sql = "SELECT * FROM $tbl_learnpath_chapter WHERE lp_id=$path_id";
  143. $result = api_sql_query($sql, __FILE__, __LINE__);
  144. while ($row = mysql_fetch_array($result))
  145. {
  146. deletemodule($row['id']);
  147. }
  148. }
  149. /**
  150. * This function moves an item.
  151. *
  152. * @param string $direction: move the given chapter up or down
  153. * @param integer Item ID
  154. * @param integer $moduleid: the id of the chapter the element resides in
  155. * @return boolean Returns false on error
  156. * @note With this new version, the moveitem deals with items AND directories (not the base-level modules). This is a lot more complicated but is a temporary step towards new database structure as 'everything is an item'
  157. **/
  158. function moveitem($direction, $id, $moduleid, $type = 'item')
  159. {
  160. global $learnpath_id;
  161. $tbl_learnpath_item = Database::get_course_table(LEARNPATH_ITEM_TABLE);
  162. $tbl_learnpath_chapter = Database::get_course_table(LEARNPATH_CHAPTER_TABLE);
  163. $tree = get_learnpath_tree($learnpath_id);
  164. $orig_order = 0;
  165. $orig_type = '';
  166. $orig_id = $id;
  167. foreach ($tree[$moduleid] as $row)
  168. {
  169. //if this is the element we want (be it a chapter or an item), get its data
  170. if (($row['id'] == $id) && ($row['type'] == $type))
  171. {
  172. $orig_order = $row['display_order'];
  173. $orig_type = $row['type'];
  174. break;
  175. }
  176. }
  177. $dest_order = 0;
  178. $dest_type = '';
  179. $dest_id = 0;
  180. if ($direction == "up")
  181. {
  182. if (!empty ($tree[$moduleid][$orig_order -1]))
  183. {
  184. $dest_order = $orig_order -1;
  185. $dest_type = $tree[$moduleid][$orig_order -1]['type'];
  186. $dest_id = $tree[$moduleid][$orig_order -1]['id'];
  187. }
  188. else
  189. {
  190. return false;
  191. }
  192. }
  193. else
  194. {
  195. //move down
  196. if (!empty ($tree[$moduleid][$orig_order +1]))
  197. {
  198. $dest_order = $orig_order +1;
  199. $dest_type = $tree[$moduleid][$orig_order +1]['type'];
  200. $dest_id = $tree[$moduleid][$orig_order +1]['id'];
  201. }
  202. else
  203. {
  204. return false;
  205. }
  206. }
  207. $sql1 = '';
  208. $sql2 = '';
  209. if ($orig_type == 'chapter')
  210. {
  211. $sql1 = "UPDATE $tbl_learnpath_chapter SET display_order = ".$dest_order." WHERE (id=$orig_id and parent_item_id=$moduleid)";
  212. }
  213. elseif ($orig_type == 'item')
  214. {
  215. $sql1 = "UPDATE $tbl_learnpath_item SET display_order = ".$dest_order." WHERE (id=$orig_id and parent_item_id=$moduleid)";
  216. }
  217. else
  218. {
  219. return false;
  220. }
  221. if ($dest_type == 'chapter')
  222. {
  223. $sql2 = "UPDATE $tbl_learnpath_chapter SET display_order = ".$orig_order." WHERE (id='$dest_id' and parent_item_id=$moduleid)";
  224. }
  225. elseif ($dest_type == 'item')
  226. {
  227. $sql2 = "UPDATE $tbl_learnpath_item SET display_order = ".$orig_order." WHERE (id='$dest_id' and parent_item_id=$moduleid)";
  228. }
  229. else
  230. {
  231. return false;
  232. }
  233. api_sql_query($sql1, __FILE__, __LINE__);
  234. api_sql_query($sql2, __FILE__, __LINE__);
  235. }
  236. /**
  237. * This function moves a module (also called chapter or category).
  238. *
  239. * @param string $direction: move the given chapter up or down
  240. * @param integer $id: the id of the chapter we want to move
  241. * @return void
  242. **/
  243. function movemodule($direction, $id)
  244. {
  245. global $learnpath_id;
  246. $tbl_learnpath_chapter = Database :: get_course_learnpath_chapter_table();
  247. if ($direction == "up")
  248. {
  249. $sortDirection = "DESC";
  250. }
  251. else
  252. {
  253. $sortDirection = "ASC";
  254. }
  255. // Select all chapters of first level (parent_item_id = 0)
  256. $sql = "SELECT * FROM $tbl_learnpath_chapter where (lp_id=$learnpath_id AND parent_item_id = 0) ORDER BY display_order $sortDirection";
  257. $result = api_sql_query($sql, __FILE__, __LINE__);
  258. $previousrow = "";
  259. // see similar comment in moveitem() function
  260. // @TODO: this only works for chapters in multi-level mode. Why not gather
  261. // this function and moveitem to keep only one multi-uses function?
  262. while ($row = mysql_fetch_array($result))
  263. {
  264. // step 2: performing the move (only happens when passed trhough step 1 at least once)
  265. if (!empty ($this_cat_order))
  266. {
  267. $next_cat_order = $row["display_order"];
  268. $next_cat_id = $row["id"];
  269. $sql1 = "UPDATE $tbl_learnpath_chapter SET display_order = '$next_cat_order' WHERE (id='$this_cat_id' and lp_id=$learnpath_id)";
  270. $sql2 = "UPDATE $tbl_learnpath_chapter SET display_order = '$this_cat_order' WHERE (id='$next_cat_id' and lp_id=$learnpath_id)";
  271. api_sql_query($sql1, __FILE__, __LINE__);
  272. api_sql_query($sql2, __FILE__, __LINE__);
  273. unset ($this_cat_order);
  274. unset ($this_cat_id);
  275. unset ($next_cat_order);
  276. unset ($next_cat_id);
  277. break;
  278. }
  279. // step 1: looking for the order of the row we want to move
  280. if ($row["id"] == $id)
  281. {
  282. $this_cat_order = $row["display_order"];
  283. $this_cat_id = $id;
  284. }
  285. }
  286. }
  287. /**
  288. * Inserts a new element in a learnpath table (item or chapter)
  289. * @param string Element type ('chapter' or 'item')
  290. * @param string Chapter name
  291. * @param string Chapter description (optional)
  292. * @param integer Parent chapter ID (default: 0)
  293. * @param integer Learnpath ID
  294. * @param mixed If type 'item', then array(prereq_id=>value, prereq_..)
  295. * @return integer The new chapter ID, or false on failure
  296. * @TODO Finish this function before it is used. Currently only chapters can be added using it.
  297. * @note This function is currently never used!
  298. */
  299. function insert_item($type = 'item', $name, $chapter_description = '', $parent_id = 0, $learnpath_id = 0, $params = null)
  300. {
  301. $tbl_learnpath_chapter = Database :: get_course_table(LEARNPATH_CHAPTER_TABLE);
  302. $tbl_learnpath_item = Database :: get_course_table(LEARNPATH_ITEM_TABLE);
  303. // getting the last order number from the chapters table, in this learnpath, for the parent chapter given
  304. $sql = "SELECT * FROM $tbl_learnpath_chapter
  305. WHERE lp_id=$learnpath_id
  306. AND parent_item_id = $parent_id
  307. ORDER BY display_order DESC";
  308. $result = api_sql_query($sql, __FILE__, __LINE__);
  309. $row = mysql_fetch_array($result);
  310. $last_chapter_order = $row["display_order"];
  311. // getting the last order number of the items
  312. $sql = "SELECT * FROM $tbl_learnpath_item
  313. AND parent_item_id = $parent_id
  314. ORDER BY display_order DESC";
  315. $result = api_sql_query($sql, __FILE__, __LINE__);
  316. $row = mysql_fetch_array($result);
  317. $last_item_order = $row["display_order"];
  318. $new_order = max($last_chapter_order, $last_item_order) + 1;
  319. if ($type === 'chapter')
  320. {
  321. $sql = "INSERT INTO $tbl_learnpath_chapter
  322. (lp_id, chapter_name, chapter_description, display_order)
  323. VALUES ('".domesticate($learnpath_id)."',
  324. '".domesticate(htmlspecialchars($chapter_name))."',
  325. '".domesticate(htmlspecialchars($chapter_description))."',
  326. $new_order )";
  327. $result = api_sql_query($sql, __FILE__, __LINE__);
  328. if ($result === false)
  329. {
  330. return false;
  331. }
  332. $id = Database :: get_last_insert_id();
  333. }
  334. elseif ($type === 'item')
  335. {
  336. $sql = "INSERT INTO $tbl_learnpath_item
  337. (parent_item_id, item_type, item_id, display_order)
  338. VALUES ('".domesticate($parent_id)."',
  339. '".domesticate(htmlspecialchars($item_type))."',
  340. '".domesticate(htmlspecialchars($item_id))."',
  341. $new_order )";
  342. $result = api_sql_query($sql, __FILE__, __LINE__);
  343. if ($result === false)
  344. {
  345. return false;
  346. }
  347. $id = Database :: get_last_insert_id();
  348. }
  349. return $id;
  350. }
  351. /**
  352. * This function returns an array with all the learnpath categories/chapters
  353. * @return array List of learnpath chapter titles
  354. **/
  355. function array_learnpath_categories()
  356. {
  357. #global $tbl_learnpath_chapter;
  358. global $learnpath_id;
  359. $tbl_learnpath_chapter = Database :: get_course_table(LEARNPATH_CHAPTER_TABLE);
  360. $sql = "SELECT * FROM $tbl_learnpath_chapter WHERE (lp_id=$learnpath_id) ORDER BY display_order ASC";
  361. $result = api_sql_query($sql, __FILE__, __LINE__);
  362. while ($row = mysql_fetch_array($result))
  363. {
  364. $array_learnpath_categories[] = array ($row["id"], $row["chapter_name"]);
  365. }
  366. //$array_learnpath_categories=array($array_learnpath_categories_name,$array_learnpath_categories_id);
  367. return $array_learnpath_categories;
  368. }
  369. /**
  370. * Displays the learnpath chapters(=modules,categories) and their contents.
  371. * @param integer Chapter ID to display now (enables recursive behaviour)
  372. * @param array The array as returned by get_learnpath_tree, with all the elements of a learnpath compiled and structured into the array, by chapter id
  373. * @param integer Level (the depth of the call - helps in display)
  374. * @todo eliminate all global $lang declarations, use get_lang, improve structure.
  375. * @author Denes Nagy
  376. * @author Roan Embrechts
  377. * @author Yannick Warnier <yannick.warnier@dokeos.com> - complete redesign for multi-level learnpath chapters
  378. */
  379. function display_learnpath_chapters($parent_item_id = 0, $tree = array (), $level = 0)
  380. {
  381. //error_log('New LP - In learnpath_functions::display_learnpath_chapters',0);
  382. global $color2;
  383. global $xml_output;
  384. global $learnpath_id;
  385. $tbl_lp_item = Database::get_course_table('lp_item');
  386. $lang_move_down = get_lang('_move_down');
  387. $lang_move_up = get_lang('lang_move_up');
  388. $lang_edit_learnpath_module = get_lang('lang_edit_learnpath_module');
  389. $lang_delete_learnpath_module = get_lang('lang_delete_learnpath_module');
  390. $lang_nochapters = get_lang('lang_nochapters');
  391. $lang_prerequisites = get_lang('lang_prerequisites');
  392. $lang_prerequisites_limit = get_lang('lang_prerequisites_limit');
  393. $lang_add_learnpath_item = get_lang('lang_add_learnpath_item');
  394. $lang_add_item = get_lang('lang_add_item');
  395. $lang_title_and_desc = get_lang('lang_title_and_desc');
  396. $lang_change_order = get_lang('lang_change_order');
  397. $lang_add_prereqi = get_lang('lang_add_prereqi');
  398. $lang_add_title_and_desc = get_lang('lang_add_title_and_desc');
  399. $lang_delete = get_lang('lang_delete');
  400. if ($parent_item_id === 0)
  401. {
  402. // this is the first time we use the function, define the tree and display learnpath name
  403. $tree = get_learnpath_tree($learnpath_id);
  404. $num_modules = count($tree);
  405. //$num_modules=mysql_num_rows($result);
  406. if ($num_modules == 0)
  407. {
  408. // do not diplay useless information
  409. //echo "<tr><td>&nbsp;$lang_nochapters</td></tr>";
  410. }
  411. else
  412. {
  413. echo " <tr align='center' valign='top'>\n"." <td><b>&nbsp;$lang_title_and_desc </b></td>\n"." <td><b>&nbsp;$lang_add_item </b></td>\n";
  414. if (is_prereq($learnpath_id))
  415. {
  416. echo " <td bgcolor='#ddddee'><b>&nbsp;$lang_prerequisites_limit </b></td>\n";
  417. }
  418. else
  419. echo " <td><b>&nbsp;$lang_prerequisites </b></td>\n";
  420. echo " <td colspan='2'><b>&nbsp;$lang_change_order </b></td><td><b>&nbsp;$lang_add_prereqi </b></td>\n"." <td><b>&nbsp;$lang_add_title_and_desc </b></td><td><b>&nbsp;$lang_delete </b></td>\n"." </tr>\n";
  421. }
  422. }
  423. $i = 1;
  424. $counter = 0;
  425. $num_modules = count($tree[$parent_item_id]);
  426. //while ($row=mysql_fetch_array($result))
  427. if (isset ($tree[$parent_item_id]))
  428. {
  429. foreach ($tree[$parent_item_id] as $row)
  430. {
  431. if ($row['item_type'] === 'dokeos_chapter')
  432. {
  433. $xml_output .= "<chapter>";
  434. $xml_output .= "<chaptertitle>".$row["title"]."</chaptertitle>";
  435. $xml_output .= "<chapterdescription>".$row["description"]."</chapterdescription>";
  436. $counter ++;
  437. if (($counter % 2) == 0)
  438. {
  439. $oddclass = "row_odd";
  440. }
  441. else
  442. {
  443. $oddclass = "row_even";
  444. }
  445. //echo '<tr class="'.$oddclass.'">'."\n".' <td>'.str_repeat("&nbsp;&gt;", $level)."<img src='../img/documents.gif' alt='folder'/><a href='".$_SERVER['PHP_SELF']."?lp_id=$learnpath_id&item_id={$row['id']}&action=add&type=learnpathitem&SQMSESSID=36812c2dea7d8d6e708d5e6a2f09b0b9'><b>&nbsp;".$row['title']."</b></a>"."<br /><i><div align='justify'>&nbsp;".str_repeat("&nbsp;&nbsp;&nbsp;", $level)."</i></td>\n".' <td align="center"><a href="'.$_SERVER['PHP_SELF']."?lp_id=$learnpath_id&item_id={$row['id']}&action=add&type=learnpathitem&SQMSESSID=36812c2dea7d8d6e708d5e6a2f09b0b9"><img src='../img/0.gif' width='13' height='13' border='0' title='$lang_add_learnpath_item'></a></td>\n"." <td";
  446. echo '<tr class="'.$oddclass.'">'."\n".' <td>'.str_repeat("&nbsp;&gt;", $level)."<img src='../img/documents.gif' alt='folder'/><a href='".$_SERVER['PHP_SELF']."?lp_id=$learnpath_id&parent_item_id=".$row['id']."&action=add_sub_item'><b>&nbsp;".$row['title']."</b></a>"."<br /><i><div align='justify'>&nbsp;".str_repeat("&nbsp;&nbsp;&nbsp;", $level)."</i></td>\n".' <td align="center"><a href="'.$_SERVER['PHP_SELF']."?lp_id=$learnpath_id&parent_item_id=".$row['id']."&action=add_sub_item\"><img src='../img/0.gif' width='13' height='13' border='0' title='$lang_add_learnpath_item'></a></td>\n"." <td";
  447. if (is_prereq($learnpath_id))
  448. {
  449. echo " bgcolor='#ddddee'";
  450. }
  451. echo ">".$row['prerequisite']."</td>\n";
  452. // showing the edit, delete and move icons
  453. if (is_allowed_to_edit())
  454. {
  455. $myaction = 'move_item';
  456. if ($i < $num_modules)
  457. {
  458. // if we are still under the number of chapters in this section, show "move down"
  459. //echo " <td align=center>"."<a href='".$_SERVER['PHP_SELF']."?lp_id=$learnpath_id&amp;action=".$myaction."&amp;direction=down&amp;moduleid=".$parent_item_id."&amp;id=".$row["id"]."'&SQMSESSID=36812c2dea7d8d6e708d5e6a2f09b0b9>"."<img src=\"../img/down.gif\" border=\"0\" title=\"$lang_move_down\">"."</a></td>\n";
  460. echo " <td align=center>"."<a href='".$_SERVER['PHP_SELF']."?lp_id=$learnpath_id&action=".$myaction."&direction=down&moduleid=".$parent_item_id."&id=".$row["id"]."'>"."<img src=\"../img/down.gif\" border=\"0\" title=\"$lang_move_down\">"."</a></td>\n";
  461. }
  462. else
  463. {
  464. echo ' <td align="center">&nbsp;</td>'."\n";
  465. }
  466. if ($i > 1)
  467. {
  468. //echo ' <td align="center">'."<a href='".$_SERVER['PHP_SELF']."?lp_id=$learnpath_id&amp;action=".$myaction."&amp;direction=up&amp;moduleid=".$parent_item_id."&amp;id=".$row["id"]."'&SQMSESSID=36812c2dea7d8d6e708d5e6a2f09b0b9>"."<img src=\"../img/up.gif\" border=\"0\" title=\"$lang_move_up\">"."</a>"."</td>\n";
  469. echo ' <td align="center">'."<a href='".$_SERVER['PHP_SELF']."?lp_id=$learnpath_id&action=".$myaction."&direction=up&moduleid=".$parent_item_id."&id=".$row["id"]."'>"."<img src=\"../img/up.gif\" border=\"0\" title=\"$lang_move_up\">"."</a>"."</td>\n";
  470. }
  471. else
  472. {
  473. echo ' <td align="center">&nbsp;</td>'."\n";
  474. }
  475. echo " <td align='center'>&nbsp;</td>\n";
  476. //echo " <td align='center'>"."<a href='".$_SERVER['PHP_SELF']."?lp_id=$learnpath_id&amp;action=editmodule&amp;id=".$row["id"]."'&SQMSESSID=36812c2dea7d8d6e708d5e6a2f09b0b9>"."<img src=\"../img/edit.gif\" border=\"0\" title=\"$lang_edit_learnpath_module\">"."</a>"."</td>\n";
  477. echo " <td align='center'>"."<a href='".$_SERVER['PHP_SELF']."?lp_id=$learnpath_id&action=edititem&id=".$row["id"]."'>"."<img src=\"../img/edit.gif\" border=\"0\" title=\"$lang_edit_learnpath_module\">"."</a>"."</td>\n";
  478. //echo " <td align='center'>"."<a href='".$_SERVER['PHP_SELF']."?lp_id=$learnpath_id&amp;action=deletemodule&amp;id=".$row["id"]."'&SQMSESSID=36812c2dea7d8d6e708d5e6a2f09b0b9 onclick=\"return confirmation('".$row['chapter_name']."');\">"."<img src=\"../img/delete.gif\" border=\"0\" title=\"$lang_delete_learnpath_module\">"."</a>"."</td>\n";
  479. echo " <td align='center'>"."<a href='".$_SERVER['PHP_SELF']."?lp_id=$learnpath_id&action=delete_item&id=".$row["id"]."' onclick=\"return confirmation('".$row['title']."');\">"."<img src=\"../img/delete.gif\" border=\"0\" title=\"$lang_delete_learnpath_module\">"."</a>"."</td>\n";
  480. }
  481. echo "</tr>\n";
  482. $i ++;
  483. $xml_output .= "<items>";
  484. #display_learnpath_items($row["id"]);
  485. display_learnpath_chapters($row['id'], $tree, $level +1);
  486. $xml_output .= "</items>";
  487. $xml_output .= "</chapter>";
  488. }
  489. else //if //($row['item_type'] === 'item')
  490. {
  491. $row_items = $row;
  492. echo "<tr>\n <td colspan='2' valign='top'>";
  493. //require('resourcelinker.inc.php');
  494. display_addedresource_link_in_learnpath($row_items["item_type"], $row_items["ref"], '', $row_items["id"], 'builder', 'icon', $level);
  495. if ($row_items["description"])
  496. {
  497. echo "<div align='justify'><font color='#999999'>&nbsp;&nbsp;&nbsp;{$row_items['description']}</font>";
  498. }
  499. echo "</td>";
  500. if (is_prereq($learnpath_id))
  501. {
  502. echo '<td bgcolor="#EEEEFF">';
  503. }
  504. else
  505. {
  506. echo "<td>";
  507. }
  508. if (is_allowed_to_edit())
  509. {
  510. if ($row_items["prerequisite"] <> '')
  511. {
  512. $prereq = $row_items["prerequisite"];
  513. //if ($row_items["prereq_type"] == 'i')
  514. //{
  515. //item
  516. $sql_items2 = "SELECT * FROM $tbl_lp_item WHERE id='$prereq'"; //check if prereq has been deleted
  517. $result_items2 = api_sql_query($sql_items2, __FILE__, __LINE__);
  518. $number_items2 = Database::num_rows($result_items2);
  519. if ($number_items2 == 0)
  520. {
  521. echo "<font color='red'>$lang_prereq_deleted_error</font>";
  522. }
  523. $row_items2 = mysql_fetch_array($result_items2);
  524. display_addedresource_link_in_learnpath($row_items2["item_type"], $row_items2["ref"], '', $row_items2["id"], 'builder', '', 0);
  525. if ((($row_items2["item_type"] == TOOL_QUIZ) or ($row_items2["item_type"] == 'HotPotatoes')) and ($row_items['prerequisite']))
  526. {
  527. //echo "&nbsp;({$row_items2['title']})";
  528. }
  529. //}
  530. /*
  531. if ($row_items["prereq_type"] == 'c')
  532. {
  533. //chapter
  534. $sql_items2 = "SELECT * FROM $tbl_lp_item WHERE id='$prereq' AND item_type='dokeos_chapter'"; //check if prereq has been deleted
  535. $result_items2 = api_sql_query($sql_items2, __FILE__, __LINE__);
  536. $number_items2 = Database::num_rows($result_items2);
  537. if ($number_items2 == 0)
  538. {
  539. echo "<font color='red'>$lang_prereq_deleted_error</font>";
  540. }
  541. $row_items2 = mysql_fetch_array($result_items2);
  542. echo " {$row_items2['title']}";
  543. }*/
  544. }
  545. echo "</font></td>";
  546. $xml_output .= "<element_type>".$row_items["item_type"]."</element_type>";
  547. $xml_output .= "<element_id>".$row_items["item_id"]."</element_id>";
  548. // move
  549. if ($i < $num_modules)
  550. {
  551. echo "<td align='center'>"."<a href='".$_SERVER['PHP_SELF']."?lp_id=$learnpath_id&amp;action=moveitem&amp;type=item&amp;direction=down&amp;moduleid=".$parent_item_id."&amp;id=".$row_items["id"]."'&SQMSESSID=36812c2dea7d8d6e708d5e6a2f09b0b9>"."<img src=\"../img/down.gif\" border=\"0\" title=\"$lang_move_down\">"."</a>"."</td>";
  552. }
  553. else
  554. {
  555. echo "<td width='30' align='center'>&nbsp;</td>";
  556. }
  557. if ($i > 1)
  558. {
  559. echo "<td align='center'>"."<a href='".$_SERVER['PHP_SELF']."?lp_id=$learnpath_id&amp;action=moveitem&amp;type=item&amp;direction=up&amp;moduleid=".$parent_item_id."&amp;id=".$row_items["id"]."'&SQMSESSID=36812c2dea7d8d6e708d5e6a2f09b0b9>"."<img src=\"../img/up.gif\" border=\"0\" title=\"$lang_move_up\">"."</a>";
  560. }
  561. else
  562. {
  563. echo "<td width='30' align='center'>&nbsp;</td>";
  564. }
  565. echo "</td>"."<td align='center'>";
  566. // edit prereq
  567. echo "<a href='".$_SERVER['PHP_SELF']."?lp_id=$learnpath_id&amp;action=edititemprereq&amp;id=".$row_items["id"]."'&SQMSESSID=36812c2dea7d8d6e708d5e6a2f09b0b9>"."<img src=\"../img/scormpre.gif\" border=\"0\" title=\"$lang_add_prereq\">"."</a>"."</td>";
  568. // edit
  569. echo "<td align='center'>"."<a href='".$_SERVER['PHP_SELF']."?lp_id=$learnpath_id&amp;action=edititem&amp;id=".$row_items["id"]."'&SQMSESSID=36812c2dea7d8d6e708d5e6a2f09b0b9>"."<img src=\"../img/edit.gif\" border=\"0\" title=\"$lang_edit_learnpath_item\">"."</a>"."</td>";
  570. // delete
  571. echo "<td align='center'>"."<a href='".$_SERVER['PHP_SELF']."?lp_id=$learnpath_id&action=deleteitem&id=".$row_items["id"]."'&SQMSESSID=36812c2dea7d8d6e708d5e6a2f09b0b9>"."<img src=\"../img/delete.gif\" border=\"0\" title=\"$lang_delete_learnpath_item\" onclick=\"return confirmation('".$row_items["item_type"]."');\">"."</a>";
  572. }
  573. $i ++;
  574. echo "</td></tr>";
  575. }
  576. }
  577. }
  578. }
  579. /**
  580. * Displays all learning paths.
  581. * @return void
  582. * @todo eliminate all global $lang declarations, use get_lang, improve structure.
  583. */
  584. function display_all_learnpath()
  585. {
  586. global $tbl_tool, $color2;
  587. global $xml_output, $lang_edit_learnpath, $lang_delete_learnpath, $lang_publish, $lang_no_publish, $lang_add_learnpath_chapter_to_path;
  588. $tbl_learnpath_main = Database :: get_course_table(LEARNPATH_MAIN_TABLE);
  589. $sql = "SELECT * FROM $tbl_learnpath_main ORDER BY learnpath_name";
  590. $result = api_sql_query($sql, __FILE__, __LINE__);
  591. $i = 1;
  592. $num_modules = mysql_num_rows($result);
  593. while ($row = mysql_fetch_array($result))
  594. {
  595. //other grey color : #E6E6E6
  596. echo "<tr><td bgcolor=\"$color2\" width=400><b>&nbsp;";
  597. echo "<a href='learnpath_handler.php?&lp_id={$row['lp_id']}'&SQMSESSID=36812c2dea7d8d6e708d5e6a2f09b0b9>{$row['learnpath_name']}</a>";
  598. echo "</b><br><i><div class=text align=justify>{$row['learnpath_description']}</div></i></td>";
  599. // showing the edit, delete and publish icons
  600. if (is_allowed_to_edit())
  601. {
  602. echo "<td bgcolor=\"$color2\" align=center><a href='learnpath_handler.php?lp_id={$row['lp_id']}&action=add&type=learnpathcategory'&SQMSESSID=36812c2dea7d8d6e708d5e6a2f09b0b9><img src='../img/0.gif' width='13' height='13' border='0' title='$lang_add_learnpath_chapter_to_path'></a></td>";
  603. echo "<td bgcolor=\"$color2\" align=center><a href='".$_SERVER['PHP_SELF']."?action=editpath&id=".$row["lp_id"]."'&SQMSESSID=36812c2dea7d8d6e708d5e6a2f09b0b9><img src=\"../img/edit.gif\" border=\"0\" title=\"$lang_edit_learnpath\"></a></td>";
  604. echo "<td bgcolor=\"$color2\" align=center><a href='".$_SERVER['PHP_SELF']."?action=deletepath&id=".$row["lp_id"]."'&SQMSESSID=36812c2dea7d8d6e708d5e6a2f09b0b9><img src=\"../img/delete.gif\" border=\"0\" title=\"$lang_delete_learnpath\" onclick=\"return confirmation('".$row2['learnpath_name']."');\"></a></td>";
  605. $id = $row["lp_id"];
  606. $sql2 = "SELECT * FROM $tbl_learnpath_main where lp_id=$id";
  607. $result2 = api_sql_query($sql2, __FILE__, __LINE__);
  608. $row2 = mysql_fetch_array($result2);
  609. $name = $row2['learnpath_name'];
  610. $sql3 = "SELECT * FROM $tbl_tool where (name=\"$name\" and image='scormbuilder.gif')";
  611. $result3 = api_sql_query($sql3, __FILE__, __LINE__);
  612. $row3 = mysql_fetch_array($result3);
  613. if (($row3["visibility"]) == '1')
  614. {
  615. echo "<td bgcolor=\"$color2\" align=center><a href='".$_SERVER['PHP_SELF']."?action=publishpath&set=i&id=".$row["lp_id"]."'&SQMSESSID=36812c2dea7d8d6e708d5e6a2f09b0b9><img src=\"../img/visible.gif\" border=\"0\" title=\"$lang_no_publish\"></a></td>";
  616. }
  617. else
  618. {
  619. echo "<td bgcolor=\"$color2\" align=center><a href='".$_SERVER['PHP_SELF']."?action=publishpath&set=v&id=".$row["lp_id"]."'&SQMSESSID=36812c2dea7d8d6e708d5e6a2f09b0b9><img src=\"../img/invisible.gif\" border=\"0\" title=\"$lang_publish\"></a></td>";
  620. }
  621. }
  622. $i ++;
  623. echo "<tr><td>&nbsp;</td></tr>";
  624. }
  625. }
  626. /**
  627. * Displays the learning path items/steps.
  628. * @param integer Category ID
  629. * @return void
  630. * @todo eliminate all global $lang declarations, use get_lang, improve structure.
  631. */
  632. function display_learnpath_items($categoryid)
  633. {
  634. global $xml_output;
  635. global $lang_prerequisites, $lang_move_down, $lang_move_up, $lang_edit_learnpath_item, $lang_delete_learnpath_item, $learnpath_id, $lang_add_prereq, $lang_prereq_deleted_error, $lang_pre_short, $langThisItem;
  636. $tbl_lp_item = Database::get_course_table('lp_item');
  637. $sql_items = "SELECT * FROM $tbl_lp_item WHERE parent_item_id='$categoryid' ORDER BY display_order ASC";
  638. $result_items = api_sql_query($sql_items,__FILE__,__LINE__);
  639. $number_items = Database::num_rows($result_items);
  640. $i = 1;
  641. error_log('Selected item under '.$categoryid,0);
  642. while ($row_items = Database::fetch_array($result_items))
  643. {
  644. echo "<tr><td colspan='2' valign='top'>";
  645. display_addedresource_link_in_learnpath($row_items["item_type"], $row_items["ref"], '', $row_items["id"], 'builder', 'icon');
  646. if ($row_items["description"])
  647. {
  648. echo "<div align='justify'><font color='#999999'>&nbsp;&nbsp;&nbsp;{$row_items['description']}</font>";
  649. }
  650. echo "</td>";
  651. if (is_prereq($learnpath_id))
  652. {
  653. echo '<td bgcolor="#EEEEFF">';
  654. }
  655. else
  656. {
  657. echo "<td>";
  658. }
  659. if (is_allowed_to_edit())
  660. {
  661. error_log('Is allowed to edit item'.$row_items['id'],0);
  662. //TODO: fix by adding true prerequisites parsing (and cycle through)
  663. //Over simplification here, we transform prereq_id field into prerequisite field
  664. if ($row_items["prerequisite"] <> '')
  665. {
  666. $prereq = $row_items["prerequisite"];
  667. //if ($row_items["prereq_type"] == 'i')
  668. //{
  669. //item
  670. $sql_items2 = "SELECT * FROM $tbl_lp_item WHERE id='$prereq'"; //check if prereq has been deleted
  671. $result_items2 = api_sql_query($sql_items2);
  672. $number_items2 = Database::num_rows($result_items2);
  673. if ($number_items2 == 0)
  674. {
  675. echo "<font color=red>$lang_prereq_deleted_error</font>";
  676. }
  677. $row_items2 = Database::fetch_array($result_items2);
  678. display_addedresource_link_in_learnpath($row_items2["item_type"], $row_items2["ref"], '', $row_items2["id"], 'builder', '');
  679. if ((($row_items2["item_type"] == 'Exercise') or ($row_items2["item_type"] == 'HotPotatoes')) and ($row_items['prerequisites']))
  680. {
  681. echo "&nbsp;({$row_items2['title']})";
  682. }
  683. //}
  684. /*if ($row_items["prereq_type"] == 'c')
  685. {
  686. //chapter
  687. $sql_items2 = "SELECT * FROM $tbl_learnpath_chapter WHERE id='$prereq'"; //check if prereq has been deleted
  688. $result_items2 = api_sql_query($sql_items2,__FILE__,__LINE__);
  689. $number_items2 = Database::num_rows($result_items2);
  690. if ($number_items2 == 0)
  691. {
  692. echo "<font color=red>$lang_prereq_deleted_error</font>";
  693. }
  694. $row_items2 = Database::fetch_array($result_items2);
  695. echo " {$row_items2['chapter_name']}";
  696. }*/
  697. }
  698. echo "</font></td>";
  699. $xml_output .= "<element_type>".$row_items["item_type"]."</element_type>";
  700. $xml_output .= "<element_id>".$row_items["id"]."</element_id>";
  701. // move
  702. if ($i < $number_items)
  703. {
  704. echo "<td align='center'><a href='".$_SERVER['PHP_SELF']."?lp_id=$learnpath_id&action=moveitem&direction=down&moduleid=".$categoryid."&id=".$row_items["id"]."'&SQMSESSID=36812c2dea7d8d6e708d5e6a2f09b0b9><img src=\"../img/down.gif\" border=\"0\" title=\"$lang_move_down\"></a></td>";
  705. }
  706. else
  707. {
  708. echo "<td width='30' align='center'>&nbsp;</td>";
  709. }
  710. if ($i > 1)
  711. {
  712. echo "<td align='center'><a href='".$_SERVER['PHP_SELF']."?lp_id=$learnpath_id&action=moveitem&direction=up&moduleid=".$categoryid."&id=".$row_items["id"]."'&SQMSESSID=36812c2dea7d8d6e708d5e6a2f09b0b9><img src=\"../img/up.gif\" border=\"0\" title=\"$lang_move_up\"></a>";
  713. }
  714. else
  715. {
  716. echo "<td width='30' align='center'>&nbsp;</td>";
  717. }
  718. echo "</td><td align='center'>";
  719. // edit prereq
  720. echo "<a href='".$_SERVER['PHP_SELF']."?lp_id=$learnpath_id&action=edititemprereq&id=".$row_items["id"]."'&SQMSESSID=36812c2dea7d8d6e708d5e6a2f09b0b9><img src=\"../img/scormpre.gif\" border=\"0\" title=\"$lang_add_prereq\"></a></td>";
  721. // edit
  722. echo "<td align='center'><a href='".$_SERVER['PHP_SELF']."?lp_id=$learnpath_id&action=edititem&id=".$row_items["id"]."'&SQMSESSID=36812c2dea7d8d6e708d5e6a2f09b0b9><img src=\"../img/edit.gif\" border=\"0\" title=\"$lang_edit_learnpath_item\"></a></td>";
  723. // delete
  724. echo "<td align='center'>";
  725. echo "<a href='".$_SERVER['PHP_SELF']."?lp_id=$learnpath_id&action=deleteitem&id=".$row_items["id"]."'&SQMSESSID=36812c2dea7d8d6e708d5e6a2f09b0b9><img src=\"../img/delete.gif\" border=\"0\" title=\"$lang_delete_learnpath_item\" onclick=\"return confirmation('".$langThisItem."');\"></a>";
  726. }
  727. $i ++;
  728. echo "</td></tr>";
  729. }
  730. }
  731. /**
  732. * This function returns the items belonging to the chapter that contains the given item (brother items)
  733. * @param integer Item id
  734. * @return array Table containing the items
  735. */
  736. function learnpath_items($itemid)
  737. {
  738. global $xml_output;
  739. $tbl_learnpath_item = Database :: get_course_table(LEARNPATH_ITEM_TABLE);
  740. $sql_items = "SELECT parent_item_id FROM $tbl_lp_item WHERE id='$itemid'";
  741. $moduleid_sql = api_sql_query($sql_items);
  742. $moduleid_array = mysql_fetch_array($moduleid_sql); //first row of the results
  743. $moduleid = $moduleid_array["parent_item_id"];
  744. $sql_items = "SELECT * FROM $tbl_lp_item WHERE parent_item_id='$moduleid' ORDER BY display_order ASC";
  745. $result_items = api_sql_query($sql_items);
  746. $ar = mysql_fetch_array($result_items);
  747. while ($ar != '')
  748. {
  749. $result[] = $ar;
  750. $ar = mysql_fetch_array($result_items);
  751. }
  752. return $result;
  753. }
  754. /**
  755. * This function returns the chapters belonging to the path that contais the given chapter (brother chapters)
  756. * @param integer Learnpath id
  757. * @return array Table containing the chapters
  758. */
  759. function learnpath_chapters($learnpath_id)
  760. {
  761. global $xml_output, $learnpath_id;
  762. //$tbl_learnpath_chapter = Database :: get_course_table(LEARNPATH_CHAPTER_TABLE);
  763. $tbl_lp_item = Database::get_course_table('lp_item');
  764. $sql_items = "SELECT * FROM $tbl_lp_item WHERE lp_id='$learnpath_id' AND item_type='dokeos_chapter' ORDER BY display_order ASC";
  765. //$sql_items = "SELECT * FROM $tbl_learnpath_chapter WHERE lp_id='$learnpath_id' ORDER BY display_order ASC";
  766. $result_items = api_sql_query($sql_items, __FILE__, __LINE__);
  767. $ar = mysql_fetch_array($result_items);
  768. while ($ar != '')
  769. {
  770. $result[] = $ar;
  771. $ar = mysql_fetch_array($result_items);
  772. }
  773. return $result;
  774. }
  775. /**
  776. * This function tells if a learnpath contains items which are prerequisite to other items
  777. * @param integer Learnpath id
  778. * @return boolean True if this learnpath contains an item which is a prerequisite to something
  779. */
  780. function is_prereq($learnpath_id)
  781. {
  782. global $xml_output;
  783. $tbl_lp_item = Database::get_course_table('lp_item');
  784. $prereq = false;
  785. $sql_items = "SELECT * FROM $tbl_lp_item WHERE lp_id='$learnpath_id' AND parent_item_id=0 ORDER BY display_order ASC";
  786. $result_items = api_sql_query($sql_items,__FILE__,__LINE__);
  787. while ($ar = Database::fetch_array($result_items))
  788. {
  789. $c = $ar['id'];
  790. $sql_items2 = "SELECT * FROM $tbl_lp_item WHERE lp_id = $learnpath_id AND parent_item_id='$c' ORDER BY display_order ASC";
  791. $result_items2 = api_sql_query($sql_items2,__FILE__,__LINE__);
  792. while ($ar2 = Database::fetch_array($result_items2))
  793. {
  794. if ($ar2['prerequisite'] != '')
  795. {
  796. $prereq = true;
  797. }
  798. }
  799. }
  800. return ($prereq);
  801. }
  802. /**
  803. * This function returns the prerequisite sentence
  804. * @param integer Item ID
  805. * @return string Prerequisite warning text
  806. */
  807. function prereqcheck($id_in_path)
  808. {
  809. //1 Initialise and import working vars
  810. global $learnpath_id, $_uid;
  811. global $langPrereqToEnter, $langPrereqTestLimit1, $langPrereqTestLimit2, $langPrereqTestLimitNow, $langPrereqFirstNeedTo, $langPrereqModuleMinimum1, $langPrereqModuleMinimum2;
  812. $tbl_learnpath_user = Database :: get_course_table(LEARNPATH_USER_TABLE);
  813. $tbl_learnpath_item = Database :: get_course_table(LEARNPATH_ITEM_TABLE);
  814. $tbl_learnpath_chapter = Database :: get_course_table(LEARNPATH_CHAPTER_TABLE);
  815. //2 Initialise return value
  816. $prereq = false;
  817. //3 Get item data from the database
  818. $sql_items = "SELECT * FROM $tbl_learnpath_item WHERE id='$id_in_path'";
  819. $result_items = api_sql_query($sql_items);
  820. $row = mysql_fetch_array($result_items);
  821. //4 Check prerequisite's type
  822. if ($row['prereq_type'] == 'i')
  823. {
  824. //4.a If prerequisite is of type 'i' (item)
  825. //4.a.1 Get data ready for use
  826. $id_in_path3 = $row['prereq_id'];
  827. $prereq_limit = $row['prereq_completion_limit'];
  828. //4.a.2 Get data from the user-item relation
  829. if ($_uid == '')
  830. {
  831. $user_id = '0';
  832. }
  833. else
  834. {
  835. $user_id = $_uid;
  836. }
  837. $sql_items3 = "SELECT * FROM $tbl_learnpath_user WHERE (learnpath_item_id='$id_in_path3' and user_id=$user_id)";
  838. $result_items3 = api_sql_query($sql_items3);
  839. $row3 = mysql_fetch_array($result_items3);
  840. //4.a.3 Get the link that needs to be shown for the current item (not the prereq)
  841. $stepname = display_addedresource_link_in_learnpath($row['item_type'], $row['ref'], '', $id_in_path, 'builder', 'nolink');
  842. //this is the step we want to open
  843. $stepname = trim($stepname); //to remove occasional line breaks and white spaces
  844. //4.a.4 Get the prerequisite item
  845. $sql6 = "SELECT * FROM $tbl_learnpath_item WHERE (id='$id_in_path3')";
  846. $result6 = api_sql_query($sql6);
  847. $row6 = mysql_fetch_array($result6);
  848. //4.a.5 Get a link to the prerequisite item
  849. $prereqname = display_addedresource_link_in_learnpath($row6['item_type'], $row6['ref'], '', $id_in_path3, 'builder', 'nolink'); //this is the prereq of the step we want to open
  850. //4.a.5 Initialise limit value
  851. $limitok = true;
  852. //4.a.6 Get prerequisite limit
  853. if ($prereq_limit)
  854. {
  855. //4.a.6.a If the completion limit exists
  856. if ($row3['score'] < $prereq_limit)
  857. {
  858. //4.a.6.a.a If the completion limit hasn't been reached, then display the corresponding message
  859. $prereq = $langPrereqToEnter.$stepname.$langPrereqTestLimit1."$prereq_limit".$langPrereqTestLimit2.$prereqname.". (".$langPrereqTestLimitNow.$row3['score'].")";
  860. }
  861. else
  862. {
  863. //4.a.6.a.b The completion limit has been reached. Prepare to return false (no prereq hanging)
  864. $prereq = false;
  865. }
  866. }
  867. else
  868. {
  869. //4.a.6.b If the completion limit doesn't exist
  870. if ($row3['status'] == "completed" or $row3['status'] == 'passed')
  871. {
  872. //4.a.6.b.a If the prerequisite status is 'completed'
  873. $prereq = false;
  874. }
  875. else
  876. {
  877. //4.a.6.b.b The prerequisite status is not 'completed', return corresponding message
  878. $prereq = $langPrereqToEnter.$stepname.$langPrereqFirstNeedTo.$prereqname.'.';
  879. }
  880. }
  881. }
  882. elseif ($row['prereq_type'] == 'c')
  883. {
  884. //4.b If prerequisite is of type 'c' (chapter)
  885. //4.b.1 Get data ready to use
  886. $id_in_path2 = $row['prereq_id'];
  887. //4.b.2 Get all items in the prerequisite chapter
  888. $sql_items3 = "SELECT * FROM $tbl_lp_item WHERE parent_item_id='$id_in_path2'";
  889. $result_items3 = api_sql_query($sql_items3);
  890. $allcompleted = true;
  891. while ($row3 = mysql_fetch_array($result_items3))
  892. {
  893. //4.b.3 Cycle through items in the prerequisite chapter
  894. //4.b.3.1 Get data ready to use
  895. $id_in_path4 = $row3['id'];
  896. if ($_uid == '')
  897. {
  898. $user_id = '0';
  899. }
  900. else
  901. {
  902. $user_id = $_uid;
  903. }
  904. //4.b.3.2 Get user-item relation
  905. $sql_items4 = "SELECT * FROM $tbl_learnpath_user WHERE (learnpath_item_id='$id_in_path4' and user_id=$user_id)";
  906. $result_items4 = api_sql_query($sql_items4);
  907. $row4 = mysql_fetch_array($result_items4);
  908. //4.b.3.3 If any of these elements is not 'completed', the overall completion status is false
  909. if ($row4['status'] != "completed" and $row4['status'] != 'passed')
  910. {
  911. $allcompleted = false;
  912. }
  913. }
  914. if ($allcompleted)
  915. {
  916. //4.b.4.a All items were completed, prepare to return that there is no prerequisite blocking the way
  917. $prereq = false;
  918. }
  919. else
  920. {
  921. //4.b.4.b Something was not completed. Return corresponding message
  922. $sql5 = "SELECT * FROM $tbl_learnpath_chapter WHERE (lp_id='$learnpath_id' and id='$id_in_path2')";
  923. $result5 = api_sql_query($sql5);
  924. $row5 = mysql_fetch_array($result5);
  925. $prereqmodulename = trim($row5['chapter_name']);
  926. $prereq = $langPrereqModuleMinimum1.$prereqmodulename.$langPrereqModuleMinimum2;
  927. }
  928. }
  929. else
  930. {
  931. //5 If prerequisite type undefined, no prereq
  932. $prereq = false;
  933. }
  934. //6 Return the message (or false if no prerequisite waiting)
  935. return ($prereq);
  936. }
  937. /**
  938. * Constructs the tree that will be used to build the learnpath structure
  939. * @params integer Learnpath_id
  940. * @return array Tree of the learnpath structure
  941. * @author Yannick Warnier <yannick.warnier@dokeos.com>
  942. * @comment This is a temporary function, which exists while the chapters and items
  943. * are still in separate tables in the database. This function gathers the data in a unique tree.
  944. **/
  945. function get_learnpath_tree($learnpath_id)
  946. {
  947. //error_log('New LP - In learnpath_functions::get_learnpath_tree',0);
  948. //init elems
  949. #global $tbl_learnpath_item, $tbl_learnpath_chapter;
  950. /*
  951. $tbl_learnpath_item = Database :: get_course_table(LEARNPATH_ITEM_TABLE);
  952. $tbl_learnpath_chapter = Database :: get_course_table(LEARNPATH_CHAPTER_TABLE);
  953. */
  954. $tbl_lp_item = Database::get_course_table('lp_item');
  955. $tree = array ();
  956. $chapters = array ();
  957. //$chapters = array();
  958. //$chapters_by_parent = array();
  959. //$items = array();
  960. //$items_by_chapter = array();
  961. $all_items_by_chapter = array ();
  962. $sql = "SELECT * FROM $tbl_lp_item WHERE lp_id = ".$learnpath_id." AND item_type='dokeos_chapter' ORDER BY display_order";
  963. //error_log('New LP - learnpath_functions - get_learnpath_tree: '.$sql,0);
  964. $res = api_sql_query($sql, __FILE__, __LINE__);
  965. // format the $chapters_by_parent array so we have a suitable structure to work with
  966. while ($row = Database::fetch_array($res))
  967. {
  968. $chapters[] = $row;
  969. //shouldn't be necessary (check no null value)
  970. if (empty ($row['parent_item_id']))
  971. {
  972. $row['parent_item_id'] = 0;
  973. }
  974. //$chapters_by_parent[$row['parent_item_id']][$row['previous_item_id']] = $row;
  975. $all_items_by_chapter[$row['parent_item_id']][$row['display_order']] = $row;
  976. $all_items_by_chapter[$row['parent_item_id']][$row['display_order']]['type'] = 'dokeos_chapter';
  977. }
  978. // now for every item in each chapter, get a suitable structure too
  979. foreach ($chapters as $row)
  980. {
  981. // select items from this chapter
  982. $sql = "SELECT * FROM $tbl_lp_item WHERE lp_id = $learnpath_id AND parent_item_id = ".$row['id']." ORDER BY display_order";
  983. //error_log('New LP - learnpath_functions - get_learnpath_tree: '.$sql,0);
  984. $res = api_sql_query($sql, __FILE__, __LINE__);
  985. //error_log('New LP - learnpath_functions - get_learnpath_tree: Found '.Database::num_rows($res).' results',0);
  986. while ($myrow = mysql_fetch_array($res, MYSQL_ASSOC))
  987. {
  988. //$items[] = $myrow;
  989. //$items_by_chapter[$myrow['parent_item_id']][$myrow['display_order']] = $myrow;
  990. $all_items_by_chapter[$row['id']][$myrow['display_order']] = $myrow;
  991. $all_items_by_chapter[$row['id']][$myrow['display_order']]['type'] = 'item';
  992. }
  993. }
  994. //array_multisort($all_items_by_chapter[0], SORT_ASC, SORT_NUMERIC);
  995. foreach ($all_items_by_chapter as $key => $subrow)
  996. {
  997. ksort($all_items_by_chapter[$key]);
  998. }
  999. //all items should now be well-ordered
  1000. //error_log('New LP - In get_learnpath_tree, returning '.print_r($all_items_by_chapter,true),0);
  1001. return $all_items_by_chapter;
  1002. }
  1003. /**
  1004. * Gives a list of sequencial elements IDs for next/previous actions
  1005. * @param array The elements tree as returned by get_learnpath_tree()
  1006. * @param integer The chapter id to start from
  1007. * @param boolean Whether to include chapters or not
  1008. * @return array List of elements in the first to last order
  1009. * @author Yannick Warnier <yannick.warnier@dokeos.com>
  1010. **/
  1011. function get_ordered_items_list($tree, $chapter = 0, $include_chapters = false)
  1012. {
  1013. $list = array ();
  1014. foreach ($tree[$chapter] as $order => $elem)
  1015. {
  1016. if ($elem['type'] == 'chapter')
  1017. {
  1018. if ($include_chapters === true)
  1019. {
  1020. $list[] = array ('id' => $elem['id'], 'type' => $elem['type']);
  1021. }
  1022. $res = get_ordered_items_list($tree, $elem['id'], $include_chapters);
  1023. foreach ($res as $elem)
  1024. {
  1025. $list[] = $elem;
  1026. }
  1027. }
  1028. elseif ($elem['type'] == 'item')
  1029. {
  1030. $list[] = array ('id' => $elem['id'], 'type' => $elem['type'], 'item_type' => $elem['item_type'], 'parent_item_id' => $elem['parent_item_id'], 'item_id' => $elem['item_id']);
  1031. }
  1032. }
  1033. return $list;
  1034. }
  1035. /**
  1036. * Displays the structure of a chapter recursively. Takes the result of get_learnpath_tree as argument
  1037. * @param array Chapter structure
  1038. * @param integer Chapter ID (start point in the tree)
  1039. * @param integer Learnpath ID
  1040. * @param integer User ID
  1041. * @param boolean Indicates if the style is wrapped (true) or extended (false)
  1042. * @param integer Level reached so far in the tree depth (enables recursive behaviour)
  1043. * @return array Number of items, Number of items completed
  1044. * @author Many changes by Yannick Warnier <yannick.warnier@dokeos.com>
  1045. **/
  1046. function display_toc_chapter_contents($tree, $parent_item_id = 0, $learnpath_id, $uid, $wrap, $level = 0)
  1047. {
  1048. #global $tbl_learnpath_user;
  1049. $tbl_learnpath_user = Database :: get_course_table(LEARNPATH_USER_TABLE);
  1050. $num = 0;
  1051. $num_completed = 0;
  1052. foreach ($tree[$parent_item_id] as $order => $elem)
  1053. {
  1054. $bold = false;
  1055. if (!empty ($_SESSION['cur_open']) && ($elem['id'] == $_SESSION['cur_open']))
  1056. {
  1057. $bold = true;
  1058. }
  1059. if ($elem['type'] === 'chapter')
  1060. {
  1061. if ($wrap)
  1062. {
  1063. echo str_repeat("&nbsp;&nbsp;", $level).shorten(strip_tags($elem['chapter_name']), (35 - 3 * $level))."<br />\n";
  1064. }
  1065. else
  1066. {
  1067. echo "<tr><td colspan='3'>".str_repeat("&nbsp;&nbsp;", $level).shorten($elem['chapter_name'], (35 - 3 * $level))."</td></tr>\n";
  1068. }
  1069. if ($wrap)
  1070. {
  1071. if ($elem['chapter_description'] != '')
  1072. {
  1073. echo "<div class='description'>".str_repeat("&nbsp;&nbsp;", $level)."&nbsp;".shorten($elem['chapter_description'], (35 - 3 * $level))."</div>\n";
  1074. }
  1075. }
  1076. else
  1077. {
  1078. if ($elem['chapter_description'] != '')
  1079. {
  1080. echo "<tr><td colspan='3'><div class='description'>".str_repeat("&nbsp;&nbsp;", $level)."&nbsp;".shorten($elem['chapter_description'], (35 - 3 * $level))."</div></td></tr>\n";
  1081. }
  1082. }
  1083. list ($a, $b) = display_toc_chapter_contents($tree, $elem['id'], $learnpath_id, $uid, $wrap, $level +1);
  1084. $num += $a;
  1085. $num_completed += $b;
  1086. }
  1087. elseif ($elem['type'] === 'item')
  1088. {
  1089. // If this element is an item (understand: not a directory/module)
  1090. $sql0 = "SELECT * FROM $tbl_learnpath_user WHERE (user_id='".$uid."' and learnpath_item_id='".$elem['id']."' and lp_id='".$learnpath_id."')";
  1091. $result0 = api_sql_query($sql0, __FILE__, __LINE__);
  1092. $row0 = mysql_fetch_array($result0);
  1093. $completed = '';
  1094. if (($row0['status'] == 'completed') or ($row0['status'] == 'passed'))
  1095. {
  1096. $completed = 'completed';
  1097. $num_completed ++;
  1098. }
  1099. if ($wrap)
  1100. {
  1101. echo str_repeat("&nbsp;&nbsp;", $level)."<a name='{$elem['id']}' />\n";
  1102. }
  1103. else
  1104. {
  1105. echo "<tr><td>".str_repeat("&nbsp;&nbsp;", $level-1)."<a name='{$elem['id']}' />\n";
  1106. }
  1107. if ($wrap)
  1108. {
  1109. $icon = 'wrap';
  1110. }
  1111. if ($bold)
  1112. {
  1113. echo "<b>";
  1114. }
  1115. display_addedresource_link_in_learnpath($elem['item_type'], $elem['ref'], $completed, $elem['id'], 'player', $icon);
  1116. if ($bold)
  1117. {
  1118. echo "</b>";
  1119. }
  1120. if ($wrap)
  1121. {
  1122. echo "<br />\n";
  1123. }
  1124. else
  1125. {
  1126. echo "</td></tr>\n";
  1127. }
  1128. $num ++;
  1129. }
  1130. }
  1131. return array ($num, $num_completed);
  1132. }
  1133. /**
  1134. * Returns a string to display in the tracking frame within the contents.php page (for example)
  1135. * @param integer Learnpath id
  1136. * @param integer Current user id
  1137. * @param integer Starting chapter id
  1138. * @param array Tree of elements as returned by get_learnpath_tree()
  1139. * @param integer Level of recursivity we have reached
  1140. * @param integer Counter of elements already displayed
  1141. * @author Yannick Warnier <yannick.warnier@dokeos.com>
  1142. * @note : forced display because of display_addedresource_link_in_learnpath behaviour (outputing a string would be better)
  1143. **/
  1144. function get_tracking_table($learnpath_id, $user_id, $parent_item_id = 0, $tree = false, $level = 0, $counter = 0)
  1145. {
  1146. $tbl_learnpath_chapter = Database :: get_course_learnpath_chapter_table();
  1147. $tbl_learnpath_item = Database :: get_course_learnpath_item_table();
  1148. $tbl_learnpath_user = Database :: get_course_learnpath_user_table();
  1149. //$mytable = '';
  1150. $include_chapters = true;
  1151. if (!is_array($tree))
  1152. {
  1153. //get a tree of the current learnpath elements
  1154. $tree = get_learnpath_tree($learnpath_id);
  1155. }
  1156. foreach ($tree[$parent_item_id] as $order => $elem)
  1157. {
  1158. if (($counter % 2) == 0)
  1159. {
  1160. $oddclass = 'row_odd';
  1161. }
  1162. else
  1163. {
  1164. $oddclass = 'row_even';
  1165. }
  1166. if ($elem['type'] == 'chapter')
  1167. {
  1168. if ($include_chapters === true)
  1169. {
  1170. //$mytable .= "<tr class='$oddclass'><td colspan = '3'>".str_repeat('&nbsp;',$level*2+2).$elem['chapter_name']."</td></tr>\n";
  1171. echo "<tr class='$oddclass'><td colspan = '3'>".str_repeat('&nbsp;', $level * 2 + 2).$elem['chapter_name']."</td></tr>\n";
  1172. }
  1173. $counter ++;
  1174. //$mytable .= get_tracking_table($learnpath_id, $user_id, $elem['id'], $tree, $level + 1, $counter );
  1175. get_tracking_table($learnpath_id, $user_id, $elem['id'], $tree, $level +1, $counter);
  1176. }
  1177. elseif ($elem['type'] == 'item')
  1178. {
  1179. $sql = "SELECT * FROM $tbl_learnpath_user "."WHERE user_id = $user_id "."AND lp_id = $learnpath_id "."AND learnpath_item_id = ".$elem['id'];
  1180. $res = api_sql_query($sql, __FILE__, __LINE__);
  1181. $myrow = mysql_fetch_array($res);
  1182. if (($myrow['status'] == 'completed') || ($myrow['status'] == 'passed'))
  1183. {
  1184. $color = 'blue';
  1185. $statusmessage = get_lang('Complete');
  1186. }
  1187. else
  1188. {
  1189. $color = 'black';
  1190. $statusmessage = get_lang('Incomplete');
  1191. }
  1192. $link = get_addedresource_link_in_learnpath($elem['item_type'], $elem['id'], $elem['item_id']);
  1193. //$link = display_addedresource_link_in_learnpath($elem['item_type'], $elem['id'], $row['status'], $elem['item_id'], 'player', 'none');
  1194. //$mytable .= "<tr class='$oddclass'>"
  1195. echo "<tr class='$oddclass'>"."<td class='mystatus'>".str_repeat("&nbsp;", $level * 2 + 2);
  1196. //."<a href='$link?SQMSESSID=36812c2dea7d8d6e708d5e6a2f09b0b9' target='toc'>hop</a>"
  1197. display_addedresource_link_in_learnpath($elem['item_type'], $elem['ref'], $myrow['status'], $elem['id'], 'player', 'wrap');
  1198. //we should also add the total score here
  1199. echo "<td>"."<font color='$color'><div class='mystatus'>".$statusmessage."</div></font>"."</td>"."<td>"."<div class='mystatus' align='center'>". ($myrow['score'] == 0 ? '-' : $myrow['score'])."</div>"."</td>"."</tr>\n";
  1200. $counter ++;
  1201. }
  1202. }
  1203. //return $mytable;
  1204. return true;
  1205. }
  1206. /**
  1207. * This function returns false if there is at least one item in the path
  1208. * @param Learnpath ID
  1209. * @return boolean True if nothing was found, false otherwise
  1210. */
  1211. function is_empty($id)
  1212. {
  1213. $tbl_learnpath_item = Database :: get_course_table(LEARNPATH_ITEM_TABLE);
  1214. $tbl_learnpath_chapter = Database :: get_course_table(LEARNPATH_CHAPTER_TABLE);
  1215. $sql = "SELECT * FROM $tbl_learnpath_chapter WHERE lp_id=$id ORDER BY display_order ASC";
  1216. $result = api_sql_query($sql, __FILE__, __LINE__);
  1217. $num_modules = mysql_num_rows($result);
  1218. $empty = true;
  1219. if ($num_modules != 0)
  1220. {
  1221. while ($row = mysql_fetch_array($result))
  1222. {
  1223. $num_items = 0;
  1224. $parent_item_id = $row['id'];
  1225. $sql2 = "SELECT * FROM $tbl_learnpath_item WHERE (parent_item_id=$parent_item_id) ORDER BY display_order ASC";
  1226. $result2 = api_sql_query($sql2, __FILE__, __LINE__);
  1227. $num_items = mysql_num_rows($result2);
  1228. if ($num_items > 0)
  1229. {
  1230. $empty = false;
  1231. }
  1232. }
  1233. }
  1234. return ($empty);
  1235. }
  1236. /**
  1237. * This function writes $content to $filename
  1238. * @param string Destination filename
  1239. * @param string Learnpath name
  1240. * @param integer Learnpath ID
  1241. * @param string Content to write
  1242. * @return void
  1243. */
  1244. function exporttofile($filename, $LPname, $LPid, $content)
  1245. {
  1246. global $circle1_files; //this keeps all the files which are exported [0]:filename [1]:LP name
  1247. //the $circle1_files variable is going to be used to a deep extent in the imsmanifest.xml
  1248. global $expdir;
  1249. if (!$handle = fopen($expdir.'/'.$filename, 'w'))
  1250. {
  1251. echo "Cannot open file ($filename)";
  1252. }
  1253. if (fwrite($handle, $content) === FALSE)
  1254. {
  1255. echo "Cannot write to file ($filename)";
  1256. exit;
  1257. }
  1258. fclose($handle);
  1259. $circle1_files[0][] = $filename;
  1260. $circle1_files[1][] = $LPname;
  1261. $circle1_files[2][] = $LPid;
  1262. }
  1263. /**
  1264. * This function exports the given Dokeos test
  1265. * @param integer Test ID
  1266. * @return string The test itself as an HTML string
  1267. */
  1268. function export_exercise($item_id)
  1269. {
  1270. global $expdir, $_course, $statsDbName, $_SESSION, $_SERVER, $language_interface, $langExerciseNotFound, $langQuestion, $langOk;
  1271. $exerciseId = $item_id;
  1272. require_once ('../exercice/exercise.class.php');
  1273. require_once ('../exercice/question.class.php');
  1274. require_once ('../exercice/answer.class.php');
  1275. require_once ('../exercice/exercise.lib.php');
  1276. // answer types
  1277. define('UNIQUE_ANSWER', 1);
  1278. define('MULTIPLE_ANSWER', 2);
  1279. define('FILL_IN_BLANKS', 3);
  1280. define('MATCHING', 4);
  1281. define('FREE_ANSWER', 5);
  1282. include_once (api_get_path(LIBRARY_PATH).'/text.lib.php');
  1283. $TBL_EXERCISES = Database :: get_course_table(QUIZ_TEST_TABLE);
  1284. /*******************************/
  1285. /* Clears the exercise session */
  1286. /*******************************/
  1287. if (isset ($_SESSION['objExercise']))
  1288. {
  1289. api_session_unregister('objExercise');
  1290. unset ($objExercise);
  1291. }
  1292. if (isset ($_SESSION['objQuestion']))
  1293. {
  1294. api_session_unregister('objQuestion');
  1295. unset ($objQuestion);
  1296. }
  1297. if (isset ($_SESSION['objAnswer']))
  1298. {
  1299. api_session_unregister('objAnswer');
  1300. unset ($objAnswer);
  1301. }
  1302. if (isset ($_SESSION['questionList']))
  1303. {
  1304. api_session_unregister('questionList');
  1305. unset ($questionList);
  1306. }
  1307. if (isset ($_SESSION['exerciseResult']))
  1308. {
  1309. api_session_unregister('exerciseResult');
  1310. unset ($exerciseResult);
  1311. }
  1312. // if the object is not in the session
  1313. if (!isset ($_SESSION['objExercise']))
  1314. {
  1315. // construction of Exercise
  1316. $objExercise = new Exercise();
  1317. $sql = "SELECT title,description,sound,type,random,active FROM $TBL_EXERCISES WHERE id='$exerciseId'";
  1318. // if the specified exercise doesn't exist or is disabled
  1319. if (!$objExercise->read($exerciseId) || (!$objExercise->selectStatus() && !$is_allowedToEdit && ($origin != 'learnpath')))
  1320. {
  1321. die($langExerciseNotFound);
  1322. }
  1323. // saves the object into the session
  1324. api_session_register('objExercise');
  1325. }
  1326. $exerciseTitle = $objExercise->selectTitle();
  1327. $exerciseDescription = $objExercise->selectDescription();
  1328. $exerciseSound = $objExercise->selectSound();
  1329. $randomQuestions = $objExercise->isRandom();
  1330. $exerciseType = $objExercise->selectType();
  1331. if (!isset ($_SESSION['questionList']))
  1332. {
  1333. // selects the list of question ID
  1334. $questionList = $randomQuestions ? $objExercise->selectRandomList() : $objExercise->selectQuestionList();
  1335. // saves the question list into the session
  1336. api_session_register('questionList');
  1337. }
  1338. $nbrQuestions = sizeof($questionList);
  1339. // if questionNum comes from POST and not from GET
  1340. if (!$questionNum || $_POST['questionNum'])
  1341. {
  1342. // only used for sequential exercises (see $exerciseType)
  1343. if (!$questionNum)
  1344. {
  1345. $questionNum = 1;
  1346. }
  1347. else
  1348. {
  1349. $questionNum ++;
  1350. }
  1351. }
  1352. $exerciseTitle = api_parse_tex($exerciseTitle);
  1353. $test .= "<h3>".$exerciseTitle."</h3>";
  1354. if (!empty ($exerciseSound))
  1355. {
  1356. $test .= "<a href=\"../document/download.php?doc_url=%2Faudio%2F".$exerciseSound."\"&SQMSESSID=36812c2dea7d8d6e708d5e6a2f09b0b9 target=\"_blank\"><img src=\"../img/sound.gif\" border=\"0\" align=\"absmiddle\" alt=".get_lang("Sound")."\" /></a>";
  1357. }
  1358. $exerciseDescription = api_parse_tex($exerciseDescription);
  1359. // --------- writing the .js file with to check the correct answers begin -----------------------
  1360. $scriptfilename = "Exercice".$item_id.".js";
  1361. $s = "<script type=\"text/javascript\" src='../js/".$scriptfilename."'></script>";
  1362. $test .= $s;
  1363. $content = "function evaluate() {
  1364. alert('Test evaluated.');
  1365. }
  1366. ";
  1367. if (!$handle = fopen($expdir.'/js/'.$scriptfilename, 'w'))
  1368. {
  1369. echo "Cannot open file ($scriptfilename)";
  1370. }
  1371. if (fwrite($handle, $content) === FALSE)
  1372. {
  1373. echo "Cannot write to file ($filename)";
  1374. exit;
  1375. }
  1376. fclose($handle);
  1377. // --------- writing the .js file with to check the correct answers end -----------------------
  1378. $s = "
  1379. <p>$exerciseDescription</p>
  1380. <table width='100%' border='0' cellpadding='1' cellspacing='0'>
  1381. <form method='post' action=''><input type=\"hidden\" name=\"SQMSESSID\" value=\"36812c2dea7d8d6e708d5e6a2f09b0b9\" />
  1382. <input type='hidden' name='formSent' value='1' />
  1383. <input type='hidden' name='exerciseType' value='".$exerciseType."' />
  1384. <input type='hidden' name='questionNum' value='".$questionNum."' />
  1385. <input type='hidden' name='nbrQuestions' value='".$nbrQuestions."' />
  1386. <tr>
  1387. <td>
  1388. <table width='100%' cellpadding='4' cellspacing='2' border='0'>";
  1389. $exerciseType = 1; //so to list all questions in one page
  1390. $test .= $s;
  1391. $i = 0;
  1392. foreach ($questionList as $questionId)
  1393. {
  1394. $i ++;
  1395. // for sequential exercises
  1396. if ($exerciseType == 2)
  1397. {
  1398. // if it is not the right question, goes to the next loop iteration
  1399. if ($questionNum != $i)
  1400. {
  1401. continue;
  1402. }
  1403. else
  1404. {
  1405. // if the user has already answered this question
  1406. if (isset ($exerciseResult[$questionId]))
  1407. {
  1408. // construction of the Question object
  1409. $objQuestionTmp = new Question();
  1410. // reads question informations
  1411. $objQuestionTmp->read($questionId);
  1412. $questionName = $objQuestionTmp->selectTitle();
  1413. // destruction of the Question object
  1414. unset ($objQuestionTmp);
  1415. $test .= '<tr><td>'.get_lang("AlreadyAnswered").' &quot;'.$questionName.'&quot;</td></tr>';
  1416. break;
  1417. }
  1418. }
  1419. }
  1420. $s = "<tr bgcolor='#e6e6e6'><td valign='top' colspan='2'>".$langQuestion." ";
  1421. $s .= $i;
  1422. if ($exerciseType == 2)
  1423. $s .= ' / '.$nbrQuestions;
  1424. $s .= '</td></tr>';
  1425. $test .= $s;
  1426. //Call the showQuestion() function from exercise.lib.php. This basically displays the question in a table
  1427. $test .= showQuestion($questionId, false, 'export');
  1428. } // end foreach()
  1429. $s = "</table></td></tr><tr><td><br/><input type='button' value='".$langOk."' onClick=\"javascript:evaluate();alert('Evaluated.');\">";
  1430. $s .= "</td></tr></form></table>";
  1431. $s .= "<script type='text/javascript'> loadPage(); </script>";
  1432. $b = 2;
  1433. $test .= $s;
  1434. return ($test);
  1435. }
  1436. /**
  1437. * This function exports the given item
  1438. * @param integer Id from learnpath_items table
  1439. * @param integer Item id
  1440. * @param string Itm type
  1441. * @param boolean Shall the SCORM communications features be added? (true). Default: false.
  1442. * @return void (outputs a zip file)
  1443. * @todo Try using the SCORM communications addition (adding a button and several javascript calls to the SCORM API) elsewhere than just in the export feature, so it doesn't look like an incoherent feature
  1444. */
  1445. function exportitem($id, $item_id, $item_type, $add_scorm_communications = false)
  1446. {
  1447. global $circle1_files, $expdir, $_course, $_SESSION, $GLOBALS;
  1448. global $timeNoSecFormat, $dateFormatLong, $language_interface, $langPubl, $langDone, $langThisCourseDescriptionIsEmpty, $lang_course_description, $lang_introduction_text, $_cid, $langHotPotatoesFinished, $lang_author, $lang_date, $lang_groups, $lang_users, $lang_ass, $lang_dropbox, $test, $langQuestion;
  1449. // $_course=$_SESSION['course'];
  1450. require_once (api_get_path(LIBRARY_PATH)."database.lib.php");
  1451. //$tbl_learnpath_item = Database::get_course_learnpath_item_table();
  1452. include_once ('exercise.class.php');
  1453. include_once ('question.class.php');
  1454. include_once ('answer.class.php');
  1455. include_once ('exercise.lib.php');
  1456. include_once ('../lang/english/announcements.inc.php'); //this line is here only for $langPubl in announcements
  1457. include_once ("../lang/".$language_interface."/announcements.inc.php"); //this line is here only for $langPubl in announcements
  1458. include_once ('../lang/english/course_description.inc.php'); //this line is here only for $langThisCourseDescriptionIsEmpty
  1459. include_once ("../lang/".$language_interface."/course_description.inc.php"); // -||-
  1460. include_once ('../lang/english/resourcelinker.inc.php');
  1461. include_once ("../lang/".$language_interface."/resourcelinker.inc.php");
  1462. include_once ('../lang/english/learnpath.inc.php');
  1463. include_once ("../lang/".$language_interface."/learnpath.inc.php");
  1464. include_once ('../lang/english/exercice.inc.php');
  1465. include_once ("../lang/".$language_interface."/exercice.inc.php");
  1466. include_once (api_get_path(LIBRARY_PATH).'text.lib.php');
  1467. include_once ("../resourcelinker/resourcelinker.inc.php");
  1468. include_once (api_get_path(LIBRARY_PATH)."events.lib.inc.php");
  1469. $LPname = display_addedresource_link_in_learnpath($item_type, $item_id, '', $id, 'builder', 'nolink');
  1470. $expcontent = "<!--
  1471. This is an exported file from Dokeos Learning Path belonging to a Scorm compliant content package.
  1472. Do not modify or replace individually.
  1473. Export module author : Denes Nagy <darkden@evk.bke.hu>
  1474. -->
  1475. ";
  1476. //files needed for communicating with the scos
  1477. $scocomfiles = "<script type='text/javascript' src='../js/APIWrapper.js'></script>"."<script type='text/javascript' src='../js/SCOFunctions.js'></script>";
  1478. $expcontent .= '<html><head><link rel="stylesheet" href="../css/default.css" type="text/css" media="screen,projection" />'.$scocomfiles.'</head><body>';
  1479. $donebutton .= "<script type='text/javascript'>
  1480. /* <![CDATA[ */
  1481. loadPage();
  1482. var studentName = '!';
  1483. var lmsStudentName = doLMSGetValue( 'cmi.core.student_name' );
  1484. if ( lmsStudentName != '' )
  1485. {
  1486. studentName = ' ' + lmsStudentName + '!';
  1487. }
  1488. /* ]]> */
  1489. </script>
  1490. <br /><br />
  1491. <form><input type=\"hidden\" name=\"SQMSESSID\" value=\"36812c2dea7d8d6e708d5e6a2f09b0b9\" />
  1492. <table cols='3' width='100%' align='center'>
  1493. <tr>
  1494. <td align='middle'><input type = 'button' value = ' ".$langDone." ' onclick = \"doQuit('completed')\" id='button2' name='button2'></td>
  1495. </tr>
  1496. </table>
  1497. </form>";
  1498. /**
  1499. * switch between the different element types, namely:
  1500. * - Agenda
  1501. * - Ad_Valvas
  1502. * - Course_description
  1503. * - Document
  1504. * - Introduction_text
  1505. * - HotPotatoes
  1506. * - Exercise
  1507. * - Post
  1508. * - Forum ]
  1509. * - Thread ]
  1510. * - Dropbox ]
  1511. * - Assignments ] Theses elements are all replaced by a simple message in the exported document
  1512. * - Groups ]
  1513. * - Users ]
  1514. * - Link _self
  1515. * - Link _blank
  1516. */
  1517. switch ($item_type)
  1518. {
  1519. //------------------------AGENDA BEGIN-------------------
  1520. case "Agenda" :
  1521. //1 Get agenda event data from the database table
  1522. $TABLEAGENDA = Database :: get_course_table(AGENDA_TABLE);
  1523. $sql = "SELECT * FROM ".$TABLEAGENDA." where (id=$item_id)";
  1524. $result = api_sql_query($sql, __FILE__, __LINE__);
  1525. //2 Prepare table output
  1526. $expcontent .= "<table id=\"agenda_list\" >";
  1527. $barreMois = "";
  1528. //3 For each event corresponding to this agenda, do the following:
  1529. while ($myrow = mysql_fetch_array($result))
  1530. {
  1531. //3.1 Make the blue month bar appear only once.
  1532. if ($barreMois != date("m", strtotime($myrow["start_date"])))
  1533. {
  1534. //3.1.1 Update the check value for the month bar
  1535. $barreMois = date("m", strtotime($myrow["start_date"]));
  1536. //3.1.2 Display the month bar
  1537. $expcontent .= "<tr><td id=\"title\" colspan=\"2\" class=\"month\" valign=\"top\">".ucfirst(format_locale_date("%B %Y", strtotime($myrow["start_date"])))."</td></tr>";
  1538. }
  1539. //3.2 Display the agenda items (of this month): the date, hour and title
  1540. $db_date = (int) date(d, strtotime($myrow["start_date"]));
  1541. if ($_GET["day"] <> $db_date)
  1542. { //3.2.1.a If the day given in the URL (might not be set) is different from this element's day, use style 'data'
  1543. $expcontent .= "<tr><td class=\"data\" colspan='2'>";
  1544. }
  1545. else
  1546. { //3.2.1.b Else (same day) use style 'datanow'
  1547. $expcontent .= "<tr><td class=\"datanow\" colspan='2'>";
  1548. }
  1549. //3.2.2 Mark an anchor for this date
  1550. $expcontent .= "<a name=\"".(int) date(d, strtotime($myrow["start_date"]))."\"></a>"; // anchoring
  1551. //3.2.3 Write the date and time of this event to the export string
  1552. $expcontent .= ucfirst(format_locale_date($dateFormatLong, strtotime($myrow["start_date"])))."&nbsp;&nbsp;&nbsp;";
  1553. $expcontent .= ucfirst(strftime($timeNoSecFormat, strtotime($myrow["start_time"])))."";
  1554. //3.2.4 If a duration is set, write it, otherwise ignore
  1555. if ($myrow["duration"] == "")
  1556. {
  1557. $expcontent .= "<br />";
  1558. }
  1559. else
  1560. {
  1561. $expcontent .= " / ".$lang_lasting." ".$myrow["duration"]."<br/>";
  1562. }
  1563. //3.2.5 Write the title
  1564. $expcontent .= $myrow["title"];
  1565. $expcontent .= "</td></tr>";
  1566. //3.2.6 Prepare the content of the agenda item
  1567. $content = $myrow["content"];
  1568. //3.2.7 Make clickable???
  1569. $content = make_clickable($content);
  1570. $content = api_parse_tex($content);
  1571. //3.2.8 Write the prepared content to the export string
  1572. $expcontent .= "<tr><td class=\"text\" colspan='2'>";
  1573. $expcontent .= $content;
  1574. $expcontent .= "</td></tr>";
  1575. // displaying the agenda item of this month: the added resources
  1576. // this part is not included into LP export
  1577. /*if (check_added_resources("Agenda", $myrow["id"]))
  1578. {
  1579. $content.= "<tr><td colspan='2'>";
  1580. $content.= "<i>".get_lang('AddedResources')."</i><br/>";
  1581. display_added_resources("Agenda", $myrow["id"]);
  1582. $content.= "</td></tr>";
  1583. }*/
  1584. }
  1585. //4 Finish the export string
  1586. $expcontent .= "<tr></table>";
  1587. break;
  1588. //------------------------ANNOUNCEMENT BEGIN-------------------
  1589. case "Ad_Valvas" :
  1590. //1 Get the announcement data from the database
  1591. $tbl_announcement = Database :: get_course_announcement_table();
  1592. $sql = "SELECT * FROM $tbl_announcement where id='$item_id'";
  1593. $result = api_sql_query($sql, __FILE__, __LINE__);
  1594. //2 Initialise export string
  1595. $expcontent .= "<table class=\"data_table\">";
  1596. //3 For each announcement matching the query
  1597. while ($myrow = mysql_fetch_array($result))
  1598. {
  1599. //3.1 Get the __ field data
  1600. $content = $myrow[1];
  1601. //$content = nl2br($content);
  1602. //3.2 Prepare the data for export
  1603. $content = make_clickable($content);
  1604. $content = api_parse_tex($content);
  1605. //3.3 Get a UNIX(?<-mktime) Timestamp of the end_date for this announcement
  1606. $last_post_datetime = $myrow['end_date']; // post time format datetime de mysql
  1607. list ($last_post_date, $last_post_time) = split(" ", $last_post_datetime);
  1608. list ($year, $month, $day) = explode("-", $last_post_date);
  1609. list ($hour, $min) = explode(":", $last_post_time);
  1610. $announceDate = mktime($hour, $min, 0, $month, $day, $year);
  1611. //3.4 Compare the end date to the last login date of the user (mark it in red if he has not already read it)
  1612. if ($announceDate > $_SESSION['user_last_login_datetime'])
  1613. {
  1614. $colorBecauseNew = " color=\"red\" ";
  1615. }
  1616. else
  1617. {
  1618. $colorBecauseNew = " ";
  1619. }
  1620. //3.5 Write this content to the export string (formatted HTML array)
  1621. $expcontent .= "<tr>\n"."<td class=\"cell_header\">\n"."<font ".$colorBecauseNew.">".$langPubl." : ".ucfirst(format_locale_date($dateFormatLong, strtotime($last_post_date)))."</font>\n"."</td>\n"."</tr>\n"."<tr>\n"."<td>\n".$content."</td>\n"."</tr>\n";
  1622. } // while loop
  1623. //4 Finish the export string
  1624. $expcontent .= "</table>";
  1625. break;
  1626. //------------------------Course_description BEGIN-------------------
  1627. case "Course_description" :
  1628. //1 Get course description data from database
  1629. $tbl_course_description = Database :: get_course_description_table();
  1630. $result = api_sql_query("SELECT id, title, content FROM ".$tbl_course_description." ORDER BY id", __FILE__, __LINE__);
  1631. //2 Check this element
  1632. if (mysql_num_rows($result))
  1633. {
  1634. //2.a This course has one (or more) description in the database
  1635. $expcontent .= "<hr noshade=\"noshade\" size=\"1\" />";
  1636. //2.a.1 For each description available for this course
  1637. while ($row = mysql_fetch_array($result))
  1638. {
  1639. //2.a.1.1 Write title to export string
  1640. $expcontent .= "<h4>".$row['title']."</h4>";
  1641. //2.a.1.2 Prepare content
  1642. $content = make_clickable(nl2br($row['content']));
  1643. $content = api_parse_tex($content);
  1644. //2.a.1.3 Write content to the export string
  1645. $expcontent .= $content;
  1646. }
  1647. }
  1648. else
  1649. {
  1650. //2.b This course has no description available
  1651. $expcontent .= "<br /><h4>$langThisCourseDescriptionIsEmpty</h4>";
  1652. }
  1653. break;
  1654. //------------------------DOCUMENT BEGIN-------------------
  1655. case "Document" :
  1656. //1 Get the document data from the database
  1657. $tbl_document = Database :: get_course_document_table();
  1658. $sql_query = "SELECT * FROM $tbl_document WHERE id=$item_id";
  1659. $sql_result = api_sql_query($sql_query, __FILE__, __LINE__);
  1660. $myrow = mysql_fetch_array($sql_result);
  1661. //2 Get the origin path of the document to treat it internally
  1662. $orig = api_get_path(SYS_COURSE_PATH).$_course['path'].'/document'.$myrow["path"];
  1663. //3 Make some kind of strange transformation to get the destination filepath ???
  1664. $pathname = explode("/", $myrow["path"]);
  1665. $last = count($pathname) - 1;
  1666. $filename = 'data/'.$filename.$pathname[$last];
  1667. $copyneeded = true;
  1668. //htm files do not need to be copied as the ok button is inserted into them,
  1669. //so don't copy directly
  1670. $extension = explode(".", $pathname[$last]);
  1671. //This old condition was WRONG for names like design.html.old. Instead, we now get the extension
  1672. // by using preg_match to match case-insensitive (probably faster than 4 conditions)
  1673. //if (($extension[1]=='htm') or ($extension[1]=='html') or ($extension[1]=='HTM') or ($extension[1]=='HTML')) {
  1674. //4 Check the file extension
  1675. if (preg_match('/.*(\.htm(l)?)$/i', $pathname[$last]))
  1676. {
  1677. //4.a If this file ends with ".htm(l)", we consider it's an HTML file
  1678. //src tag check begin
  1679. //we now check if there is any src attribute in htm(l) files, if yes, we have to also export
  1680. //the target file (swf, mp3, video,...) of that src tag
  1681. //In case of absolute links (http://) this is not neccessary, but makes no error.
  1682. //however still missing : relative links case with subdirs -> the necessary dirs are not created in the exported package
  1683. //4.a.1 Get the file contents into $file
  1684. $file = file_get_contents($orig);
  1685. //4.a.2 Get all the src links in this file
  1686. //preg_match_all("|((?i)src=\".*\" )|U",$file,$match);
  1687. $match = GetSRCTags($orig);
  1688. //4.a.3 For each src tag found, do the following:
  1689. for ($i = 0; $i < count($match); $i ++)
  1690. {
  1691. //4.a.3.1 Get the tag (split from the key)
  1692. list ($key, $srctag) = each($match);
  1693. $src = $srctag;
  1694. //4.a.3.2 Check the link kind (web or absolute/relative)
  1695. if (stristr($src, "http") === false)
  1696. {
  1697. //4.a.3.2.a Do something only if relative (otherwise the user will be able to see it too anyway)
  1698. //4.a.3.2.a.1 Get a proper URL and remove all './'
  1699. $src = urldecode($src); //mp3
  1700. //$src=str_replace('./','',$src);
  1701. $src = preg_replace('/^\.\//', '', $src);
  1702. //4.a.3.2.a.2 Remove the player link from the URL (only use the mp3 file)
  1703. $src = str_replace('mp3player.swf?son=', '', $src); //mp3
  1704. //4.a.3.2.a.3 Remove funny link parts
  1705. $src = str_replace('?0', '', $src); //mp3
  1706. //the previous lines are used when creating docs with Dokeos Document tool's htmlarea
  1707. //rows marked by 'mp3' are needed because the mp3 plugin inserts the swf-mp3 links in a very strange way
  1708. //and we can decode them with those 3 lines, hoping this will not cause errors in case of other htmls,
  1709. //created by any other software
  1710. //4.a.3.2.a.4 Prepare source and destination paths
  1711. $source = api_get_path(SYS_COURSE_PATH).$_course['path'].'/document'.dirname($myrow['path']).'/'.$src;
  1712. $dest = $expdir.'/data/'.$src;
  1713. //CopyNCreate($source,$dest);
  1714. rcopy($source, $dest);
  1715. } //else...?
  1716. }
  1717. //src tag check end
  1718. //sco communication insertion begin
  1719. //4.a.4 If we want to add SCORM actions and a "Done" button, do the following:
  1720. if ($add_scorm_communications === true)
  1721. {
  1722. if ($bodyclose = strpos($file, '</body>'))
  1723. {
  1724. $file = substr_replace($file, $scocomfiles.$donebutton, $bodyclose, 7);
  1725. }
  1726. elseif ($htmlclose = strpos($file, '</html>'))
  1727. {
  1728. $file = substr_replace($file, $scocomfiles.$donebutton, $htmlclose, 7);
  1729. $file .= '</html>';
  1730. }
  1731. else
  1732. {
  1733. $file .= $scocomfiles.$donebutton;
  1734. }
  1735. } //sco communication insertion end
  1736. //4.a.5 Replace the file's name by adding the element's ID before htm
  1737. // This will not work with uppercase HTML though. Maybe use the preg_replace syntax proposed...
  1738. $filename = str_replace('.htm', $id.'.htm', $filename);
  1739. //$filename=preg_replace('/.*(\.htm(l)?)$/i',$id.$1,$filename);
  1740. //4.a.6 Export these contents to a file and set the circle1_files array for later reuse
  1741. exporttofile($filename, $LPname, $id, $file);
  1742. //The file has been copied, so ask not to copy it again
  1743. $copyneeded = false;
  1744. } //if (htm(l) files) end
  1745. //5 If we still need to copy the file (e.g. it was not an HTML file), then copy and set circle1_files for later reuse
  1746. if ($copyneeded)
  1747. {
  1748. copy($orig, $expdir.'/'.$filename);
  1749. $circle1_files[0][] = $filename;
  1750. $circle1_files[1][] = $LPname;
  1751. $circle1_files[2][] = $id;
  1752. }
  1753. //echo $orig;
  1754. return;
  1755. //------------------------Introduction_text BEGIN-------------------
  1756. case "Introduction_text" :
  1757. //1 Get the introduction text data from the database
  1758. $TBL_INTRO = Database :: get_course_tool_intro_table();
  1759. $result = api_sql_query("SELECT * FROM ".$TBL_INTRO." WHERE id=1");
  1760. $myrow = mysql_fetch_array($result);
  1761. $intro = $myrow["intro_text"];
  1762. //2 Write introduction text to the export string
  1763. $expcontent .= "<br />".$intro;
  1764. break;
  1765. //------------------------HotPotatoes BEGIN-------------------
  1766. case "HotPotatoes" :
  1767. //1 Get HotPotatoes data from the document table
  1768. $tbl_document = Database :: get_course_document_table();
  1769. $result = api_sql_query("SELECT * FROM $tbl_document WHERE id=$item_id", __FILE__, __LINE__);
  1770. $myrow = mysql_fetch_array($result);
  1771. //2 Get the document path
  1772. $testfile = api_get_path(SYS_COURSE_PATH).$_course['path']."/document".urldecode($myrow['path']);
  1773. //3 Get the document contents into a string
  1774. $content = file_get_contents($testfile);
  1775. //4 Get the document filename (just the file, no path) - would probably be better to use PHP native function
  1776. $pathname = explode("/", $myrow["path"]);
  1777. $last = count($pathname) - 1;
  1778. $filename = 'data/'.$filename.$pathname[$last];
  1779. //4beta - get all linked files and copy them (procedure copied from documents type)
  1780. //Get all the src links in this file
  1781. $match = GetSRCTags($testfile);
  1782. //For each src tag found, do the following:
  1783. foreach ($match as $src)
  1784. {
  1785. //Check the link kind (web or absolute/relative)
  1786. if (stristr($src, "http") === false)
  1787. {
  1788. //Do something only if relative (otherwise the user will be able to see it too anyway)
  1789. //Get a proper URL and remove all './'
  1790. $src = urldecode($src); //mp3
  1791. $src = str_replace('./', '', $src);
  1792. //Remove the player link from the URL (only use the mp3 file)
  1793. $src = str_replace('mp3player.swf?son=', '', $src); //mp3
  1794. //Remove funny link parts
  1795. $src = str_replace('?0', '', $src); //mp3
  1796. //The previous lines are used when creating docs with Dokeos Document tool's htmlarea
  1797. //rows marked by 'mp3' are needed because the mp3 plugin inserts the swf-mp3 links in a very strange way
  1798. //and we can decode them with those 3 lines, hoping this will not cause errors in case of other htmls,
  1799. //created by any other software
  1800. //Prepare source and destination paths
  1801. $source = api_get_path(SYS_COURSE_PATH).$_course['path'].'/document'.dirname($myrow['path']).'/'.$src;
  1802. $dest = $expdir.'/data/'.$src;
  1803. //CopyNCreate($source,$dest);
  1804. rcopy($source, $dest);
  1805. } //else...?
  1806. }
  1807. //5 Prepare the special "close window" for this test
  1808. $closewindow = "<html><head><link rel='stylesheet' type='text/css' href='../css/default.css'></head><body>"."<br /><div class='message'>$langHotPotatoesFinished</div></body></html>";
  1809. //Finish is the function of HP to save scores, we insert our scorm function calls to its beginning
  1810. //'Score' is the variable that tracks the score in HP tests
  1811. //6
  1812. $mit = "function Finish(){";
  1813. $js_content = "var SaveScoreVariable = 0; // This variable is included by Dokeos LP export\n"."function mySaveScore() // This function is included by Dokeos LP export\n"."{\n"." if (SaveScoreVariable==0)\n"." {\n"." SaveScoreVariable = 1;\n".
  1814. //the following function are implemented in SCOFunctions.js
  1815. " exitPageStatus = true;\n"." computeTime();\n"." doLMSSetValue( 'cmi.core.score.raw', Score );\n"." doLMSSetValue( 'cmi.core.lesson_status', 'completed' );\n"." doLMSCommit();\n"." doLMSFinish();\n".
  1816. // " document.write('".$closewindow."');\n".
  1817. //if you insert the previous row, the test does not appear correctly !!!!
  1818. " }\n"."}\n"."function Finish(){\n"." mySaveScore();";
  1819. $start = "<script type='text/javascript'> loadPage(); </script>";
  1820. //7 Replace the current MIT function call by our set of functions. In clear, transform HP to SCORM
  1821. $content = str_replace($mit, $js_content, $content);
  1822. //8 Finally, add the API loading calls (although that might have been done first)
  1823. $content = str_replace("</script>", "</script>".$scocomfiles.$start, $content);
  1824. //9 Change the filename to add the database ID and export to a new file,
  1825. // setting the circle1_files array for later reuse
  1826. $filename = str_replace('.htm', $id.'.htm', $filename);
  1827. exporttofile($filename, $LPname, $id, $content);
  1828. return;
  1829. //------------------------Dokeos test BEGIN-------------------
  1830. case "Exercise" :
  1831. //1 Use the export_exercise() function to do the job of constructing the question's HTML table
  1832. $expcontent .= export_exercise($item_id);
  1833. break;
  1834. //------------------------POST BEGIN---------------------------------------
  1835. case "Post" :
  1836. //1 Get the forum post data from the database
  1837. $tbl_posts =Database::get_course_table(FORUM_POST_TABLE);
  1838. $tbl_posts_text =Database::get_course_table(FORUM_POST_TEXT_TABLE);
  1839. $result = api_sql_query("SELECT * FROM $tbl_posts where post_id=$item_id", __FILE__, __LINE__);
  1840. $myrow = mysql_fetch_array($result);
  1841. // grabbing the title of the post
  1842. $sql_titel = "SELECT * FROM $tbl_posts_text WHERE post_id=".$myrow["post_id"];
  1843. $result_titel = api_sql_query($sql_titel, __FILE__, __LINE__);
  1844. $myrow_titel = mysql_fetch_array($result_titel);
  1845. $posternom = $myrow['nom'];
  1846. $posterprenom = $myrow['prenom'];
  1847. $posttime = $myrow['post_time'];
  1848. $posttext = $myrow_titel['post_text'];
  1849. $posttitle = $myrow_titel['post_title'];
  1850. $posttext = str_replace('"', "'", $posttext);
  1851. //2 Export contents as an HTML table
  1852. $expcontent .= "<table border='0' cellpadding='3' cellspacing='1' width='100%'>
  1853. <tr>
  1854. <td colspan='2' bgcolor='#e6e6e6'><b>$posttitle</b><br />$posttext</td>
  1855. </tr>
  1856. <tr>
  1857. <td colspan='2'></td>
  1858. </tr>
  1859. <tr>
  1860. <td bgcolor='#cccccc' align='left'>$lang_author : $posterprenom $posternom</td>
  1861. <td align='right' bgcolor='#cccccc'>$lang_date : $posttime</td>
  1862. </tr>
  1863. <tr><td colspan='2' height='10'></td></tr>
  1864. </table>";
  1865. break;
  1866. //------------------------NOT IMPLEMENTED ITEMS BEGIN-------------------
  1867. case "Forum" :
  1868. case "Thread" :
  1869. case "Dropbox" :
  1870. case "Assignments" :
  1871. case "Groups" :
  1872. case "Users" :
  1873. //1 Instead of building something, put an info message
  1874. $langItemMissing1 = "There was a ";
  1875. $langItemMissing2 = "page (step) here in the original Dokeos Learning Path.";
  1876. $expcontent .= "<div class='message'>$langItemMissing1 $item_type $langItemMissing2</div>";
  1877. break;
  1878. //------------------------Link BEGIN-------------------------------------
  1879. case "Link _self" :
  1880. case "Link _blank" :
  1881. //1 Get the link data from the database
  1882. $TABLETOOLLINK = Database :: get_course_link_table();
  1883. $result = api_sql_query("SELECT * FROM $TABLETOOLLINK WHERE id=$item_id", __FILE__, __LINE__);
  1884. $myrow = mysql_fetch_array($result);
  1885. $thelink = $myrow["url"];
  1886. //2 Check the link type (open in blank page or in current page)
  1887. if ($item_type == "Link _blank")
  1888. {
  1889. $target = "_blank";
  1890. }
  1891. //3 Write the link to the export string
  1892. $expcontent .= "<a href='$thelink?SQMSESSID=36812c2dea7d8d6e708d5e6a2f09b0b9' target='".$target."'>$LPname</a>";
  1893. //4 Change the element type for later changes (this is lost, however, so useless here)
  1894. $item_type = "Link"; //to put this to the filename
  1895. //$LPname="<a href='$thelink?SQMSESSID=36812c2dea7d8d6e708d5e6a2f09b0b9' target=".$target.">$LPname</a>";
  1896. //i am still not sure about Link export : to export them as files or they can appear in the TOC at once ?
  1897. //to enable the second possibility, unrem the row $LPname=...
  1898. break;
  1899. }
  1900. //now we add the Done button and the initialize function : loadpage()
  1901. //not in the case of Documents, HotP
  1902. if ($item_type != 'Exercise' and ($add_scorm_communications === true))
  1903. {
  1904. $expcontent .= $donebutton;
  1905. }
  1906. //End the export string with valid HTML tags
  1907. $expcontent .= "</body></html>";
  1908. //Prepare new file name
  1909. $filename = $item_type.$id.".htm";
  1910. //Write the export content to the new file
  1911. exporttofile('data/'.$filename, $LPname, $id, $expcontent);
  1912. }
  1913. /**
  1914. * This function exports the given item's description into a separate file
  1915. * @param integer Item id
  1916. * @param string Item type
  1917. * @param string Description
  1918. * @return void
  1919. */
  1920. function exportdescription($id, $item_type, $description)
  1921. {
  1922. global $expdir;
  1923. $filename = $item_type.$id.".desc";
  1924. $expcontent = $description;
  1925. exporttofile($expdir.$filename, 'description_of_'.$item_type.$id, 'description_of_item_'.$id, $expcontent);
  1926. }
  1927. /**
  1928. * This function deletes an entire directory
  1929. * @param string The directory path
  1930. * @return boolean True on success, false on failure
  1931. */
  1932. function deldir($dir)
  1933. {
  1934. $dh = opendir($dir);
  1935. while ($file = readdir($dh))
  1936. {
  1937. if ($file != "." && $file != "..")
  1938. {
  1939. $fullpath = $dir."/".$file;
  1940. if (!is_dir($fullpath))
  1941. {
  1942. unlink($fullpath);
  1943. }
  1944. else
  1945. {
  1946. deldir($fullpath);
  1947. }
  1948. }
  1949. }
  1950. closedir($dh);
  1951. if (rmdir($dir))
  1952. {
  1953. return true;
  1954. }
  1955. else
  1956. {
  1957. return false;
  1958. }
  1959. }
  1960. /**
  1961. * This functions exports the given path. This is the opener function, which is called first
  1962. * @param integer The path id
  1963. * @return resource A zip file, containing a hopefully Scorm compliant course made from the LP. This might happen when we don't actually exit the function first :-)
  1964. */
  1965. function exportpath($learnpath_id)
  1966. {
  1967. //1 Initialise variables
  1968. global $_course, $circle1_files, $LPnamesafe, $LPname, $expdir;
  1969. //$tbl_learnpath_main, $tbl_learnpath_chapter, $tbl_learnpath_item,
  1970. $tbl_learnpath_main = Database :: get_course_table(LEARNPATH_MAIN_TABLE);
  1971. $tbl_learnpath_item = Database :: get_course_table(LEARNPATH_ITEM_TABLE);
  1972. $tbl_learnpath_chapter = Database :: get_course_table(LEARNPATH_CHAPTER_TABLE);
  1973. //where applicable, add a scorm "Done" button at the end of all contents
  1974. $add_scorm_button = true;
  1975. //2 Get the name of the LP
  1976. include_once (api_get_path(LIBRARY_PATH)."fileUpload.lib.php");
  1977. $sql = "SELECT * FROM $tbl_learnpath_main WHERE (lp_id=$learnpath_id)";
  1978. $result = api_sql_query($sql, __FILE__, __LINE__);
  1979. $row = mysql_fetch_array($result);
  1980. $LPname = $row['learnpath_name'];
  1981. $LPnamesafe = replace_dangerous_char($LPname, 'strict');
  1982. //3 Get a temporary dir for creating the zip file
  1983. $expdir = api_get_path('SYS_COURSE_PATH').$_course['path']."/temp/".$LPnamesafe;
  1984. $fromdir = '../scorm/export/'; //this dir contains some standard files
  1985. deldir($expdir); //make sure the temp dir is cleared
  1986. mkdir($expdir);
  1987. mkdir($expdir.'/css');
  1988. mkdir($expdir.'/data');
  1989. mkdir($expdir.'/js');
  1990. mkdir($expdir.'/data/images');
  1991. mkdir($expdir.'/data/audio');
  1992. mkdir($expdir.'/data/videos');
  1993. $circle1 = array (//this array contains the types of elements we want to export
  1994. 'Chapter', 'Agenda', 'Ad_Valvas', 'Course_description', 'Document', 'Introduction_text', 'Link _self', 'Link _blank', 'Forum', 'Thread', 'Post', 'Exercise', 'HotPotatoes', 'Assignments', 'Dropbox', 'Users', 'Groups');
  1995. //$circle2=array('');
  1996. //4 Get the first level chapters - YW added parent_item_id condition for multi-level paths
  1997. $sql = "SELECT * FROM $tbl_learnpath_chapter
  1998. WHERE (lp_id=$learnpath_id and parent_item_id=0)
  1999. ORDER BY display_order ASC";
  2000. //to get all the elements, we should use the function that builds the table of content get_learnpath_tree
  2001. //WHERE (lp_id=$learnpath_id)
  2002. //ORDER BY parent_item_id, display_order ASC";
  2003. $result = api_sql_query($sql, __FILE__, __LINE__);
  2004. //5 export the items listed in Circle I one by one
  2005. while ($row = mysql_fetch_array($result))
  2006. {
  2007. //5.1 Get items data from the database for this chapter
  2008. $parent_item_id = $row['id'];
  2009. //$sql2a="SELECT * FROM $tbl_learnpath_chapter WHERE (lp_id=$learnpath_id and parent_item_id=$parent_item_id) ORDER BY display_order ASC";
  2010. //$result2a=api_sql_query($sql,__FILE__,__LINE__);
  2011. $sql2b = "SELECT * FROM $tbl_learnpath_item WHERE (parent_item_id=$parent_item_id) ORDER BY display_order ASC";
  2012. $result2b = api_sql_query($sql2b, __FILE__, __LINE__);
  2013. while ($row2 = mysql_fetch_array($result2b))
  2014. {
  2015. //5.1.1 Check if the element is in the circle1 array
  2016. $tobeexported = false;
  2017. for ($i = 0; $i < count($circle1) && !$tobeexported; $i ++)
  2018. {
  2019. //if the type is found in the circle1 array, ask for export
  2020. if ($circle1[$i] == $row2['item_type'])
  2021. {
  2022. $tobeexported = true;
  2023. }
  2024. }
  2025. //5.1.2 If applicable, export the item to an HTML file (see exportitem function for more details)
  2026. if ($tobeexported)
  2027. {
  2028. exportitem($row2['id'], $row2['item_id'], $row2['item_type'], $add_scorm_button);
  2029. /*if ($row2['description']) { //put the description of items to a separate file (.desc)
  2030. exportdescription($row2['id'],$row2['item_type'],$row2['description']);
  2031. }*/
  2032. }
  2033. } //end of items loop
  2034. } //end of first-level chapters loop
  2035. //6 export the other necceassary files
  2036. $filename = 'default.css';
  2037. copy('../css/'.$filename, $expdir.'/css/'.$filename);
  2038. $filename = 'ims_xml.xsd';
  2039. copy($fromdir.$filename, $expdir.'/'.$filename);
  2040. $filename = 'imscp_v1p1.xsd';
  2041. copy($fromdir.$filename, $expdir.'/'.$filename);
  2042. $filename = 'imsmd_v1p2.xsd';
  2043. copy($fromdir.$filename, $expdir.'/'.$filename);
  2044. $filename = 'APIWrapper.js';
  2045. copy($fromdir.$filename, $expdir.'/js/'.$filename);
  2046. $filename = 'SCOFunctions.js';
  2047. copy($fromdir.$filename, $expdir.'/js/'.$filename);
  2048. //in case circle1_files is not defined, build it
  2049. //$circle1_files
  2050. //7 create imsmanifest.xml
  2051. createimsmanifest($circle1_files, $learnpath_id);
  2052. //8 put the files in the exportdir into a zip and force download
  2053. include_once (api_get_path(LIBRARY_PATH)."pclzip/pclzip.lib.php");
  2054. //create zipfile of given directory
  2055. $zip_folder = new PclZip(api_get_path('SYS_COURSE_PATH').$_course['path']."/temp/".$LPnamesafe.".zip");
  2056. $zip_folder->create(api_get_path('SYS_COURSE_PATH').$_course['path']."/temp/".$LPnamesafe."/", PCLZIP_OPT_REMOVE_PATH, api_get_path('SYS_COURSE_PATH').$_course['path']."/temp/");
  2057. //api_get_path('SYS_COURSE_PATH').$_course['path']."/temp/".$LPnamesafe); // whitout folder
  2058. // modified by imandak80
  2059. /* copy(api_get_path('SYS_COURSE_PATH').$_course['path']."/temp/".$LPnamesafe.".zip",
  2060. api_get_path('SYS_COURSE_PATH').$_course['path']."/document/".$LPnamesafe.".zip");
  2061. */
  2062. $zipfoldername = api_get_path('SYS_COURSE_PATH').$_course['path']."/temp/".$LPnamesafe;
  2063. $zipfilename = $zipfoldername.".zip";
  2064. DocumentManager :: file_send_for_download($zipfilename, false, basename($LPnamesafe.".zip"));
  2065. //9 Delete the temporary zip file and directory
  2066. include_once (api_get_path(LIBRARY_PATH)."fileManage.lib.php");
  2067. // in fileManage.lib.php
  2068. my_delete($zipfilename);
  2069. my_delete($zipfoldername);
  2070. //exit;
  2071. //0 Return the circle_files hash (array)
  2072. return ($circle1_files); //has been used before...
  2073. }
  2074. /**
  2075. * Export SCORM content into a zip file
  2076. *
  2077. * Basically, all this function does is put the scorm directory back into a zip file (like the one
  2078. * that was most probably used to import the course at first)
  2079. * @param string Name of the SCORM path (or the directory under which it resides)
  2080. * @param array Not used right now. Should replace the use of global $_course
  2081. * @return void
  2082. * @author imandak80
  2083. */
  2084. function exportSCORM($scormname, $course)
  2085. {
  2086. global $_course;
  2087. //initialize
  2088. $tmpname = api_get_path('SYS_COURSE_PATH').$_course['path']."/scorm";
  2089. $zipfoldername = $tmpname.$scormname;
  2090. $zipfilename = $zipfoldername.".zip";
  2091. //create zipfile of given directory
  2092. include_once (api_get_path(LIBRARY_PATH)."pclzip/pclzip.lib.php");
  2093. $zip_folder = new PclZip($zipfilename);
  2094. $list = 1;
  2095. //$list = $zip_folder->create($zipfoldername."/",PCLZIP_OPT_REMOVE_PATH,$tmpname.$scormname."/"); // whitout folder
  2096. $list = $zip_folder->create($zipfoldername."/", PCLZIP_OPT_REMOVE_PATH, $tmpname);
  2097. if ($list == 0)
  2098. {
  2099. // echo "Error : ".$zip_folder->errorInfo(true);
  2100. }
  2101. //send to client
  2102. DocumentManager :: file_send_for_download($zipfilename, false, basename($scormname.".zip"));
  2103. //clear
  2104. include_once (api_get_path(LIBRARY_PATH)."fileManage.lib.php");
  2105. my_delete($zipfilename);
  2106. }
  2107. /**
  2108. * This function returns an xml tag
  2109. * $data behaves as the content in case of full tags
  2110. * $data is an array of attributes in case of returning an opening tag
  2111. * @param string
  2112. * @param string
  2113. * @param array
  2114. * @param string
  2115. * @return string
  2116. */
  2117. function xmltagwrite($tagname, $which, $data, $linebreak = "yes")
  2118. {
  2119. switch ($which)
  2120. {
  2121. case "open" :
  2122. $tag = "<".$tagname;
  2123. $i = 0;
  2124. while ($data[0][$i])
  2125. {
  2126. $tag .= " ".$data[0][$i]."=\"".$data[1][$i]."\"";
  2127. $i ++;
  2128. }
  2129. if ($tagname == 'file')
  2130. {
  2131. $closing = '/';
  2132. }
  2133. $tag .= $closing.">";
  2134. if ($linebreak != 'no_linebreak')
  2135. {
  2136. $tag .= "\n";
  2137. }
  2138. break;
  2139. case "close" :
  2140. $tag = "</".$tagname.">";
  2141. if ($linebreak != 'no_linebreak')
  2142. {
  2143. $tag .= "\n";
  2144. }
  2145. break;
  2146. case "full" :
  2147. $tag = "<".$tagname;
  2148. $tag .= ">".$data."</".$tagname.">";
  2149. if ($linebreak != 'no_linebreak')
  2150. {
  2151. $tag .= "\n";
  2152. }
  2153. break;
  2154. }
  2155. return $tag;
  2156. }
  2157. /**
  2158. * This function writes the imsmanifest.xml and exports the chapter names
  2159. * @param array Array containing filenames
  2160. * @param integer Learnpath_id
  2161. * @return void
  2162. */
  2163. function createimsmanifest($circle1_files, $learnpath_id)
  2164. {
  2165. global $_course, $LPname, $expdir, $LPnamesafe;
  2166. //$tbl_learnpath_main, $tbl_learnpath_chapter, $tbl_learnpath_item,
  2167. $tbl_learnpath_main = Database :: get_course_table(LEARNPATH_MAIN_TABLE);
  2168. $tbl_learnpath_item = Database :: get_course_table(LEARNPATH_ITEM_TABLE);
  2169. $tbl_learnpath_chapter = Database :: get_course_table(LEARNPATH_CHAPTER_TABLE);
  2170. include_once ('../metadata/md_funcs.php'); // RH: export metadata
  2171. //1.1 header
  2172. /*
  2173. $header='<?xml version="1.0" encoding="UTF-8"?><manifest identifier="'.$LPnamesafe.'" xmlns="http://www.imsglobal.org/xsd/imscp_v1p1" xmlns:imsmd="http://www.imsglobal.org/xsd/imsmd_v1p2" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.imsglobal.org/xsd/imscp_v1p1 imscp_v1p1.xsd http://www.imsglobal.org/xsd/imsmd_v1p2 imsmd_v1p2.xsd" version="IMS CP 1.1.3">'."\n";
  2174. */
  2175. //1.2
  2176. //charset should be dependent on content
  2177. $mycharset = 'ISO-8859-1';
  2178. $header = '<?xml version="1.0" encoding="'.$mycharset.'"?>'."\n<manifest identifier='".$LPnamesafe."' version='1.1'\n xmlns='http://www.imsproject.org/xsd/imscp_rootv1p1p2'\n xmlns:adlcp='http://www.adlnet.org/xsd/adlcp_rootv1p2'\n xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance'\n xsi:schemaLocation='http://www.imsproject.org/xsd/imscp_rootv1p1p2 imscp_rootv1p1p2.xsd\n http://www.imsglobal.org/xsd/imsmd_rootv1p2p1 imsmd_rootv1p2p1.xsd\n http://www.adlnet.org/xsd/adlcp_rootv1p2 adlcp_rootv1p2.xsd'>\n";
  2179. $org .= xmltagwrite('metadata', 'open');
  2180. $org .= " ".xmltagwrite('schema', 'full', 'ADL SCORM');
  2181. $org .= " ".xmltagwrite('schemaversion', 'full', '1.2');
  2182. $org .= xmltagwrite('metadata', 'close');
  2183. $defaultorgname = 'default_org';
  2184. $attributes[0][0] = 'default';
  2185. $attributes[1][0] = $defaultorgname;
  2186. $org .= xmltagwrite('organizations', 'open', $attributes);
  2187. $attributes[0][0] = 'identifier';
  2188. $attributes[1][0] = $defaultorgname;
  2189. $org .= " ".xmltagwrite('organization', 'open', $attributes);
  2190. $org .= " ".xmltagwrite('title', 'full', $LPname);
  2191. //items list
  2192. $i = 0;
  2193. $previous_item_id = '00';
  2194. while ($circle1_files[0][$i])
  2195. {
  2196. //check whether we are in the border of two chapters
  2197. //if (!$desc=strpos($circle1_files[2][$i],'scription')) { //this is is needed if the descriptions are exported to file
  2198. $sql = "SELECT * FROM $tbl_learnpath_item WHERE (id=".$circle1_files[2][$i].")";
  2199. $result = api_sql_query($sql, __FILE__, __LINE__);
  2200. $row = mysql_fetch_array($result);
  2201. $parent_item_id = $row['parent_item_id'];
  2202. if ($parent_item_id != $previous_item_id)
  2203. {
  2204. //we create the item tag for the chapter (without indifierref)
  2205. $sql2 = "SELECT * FROM $tbl_learnpath_chapter WHERE (id=".$parent_item_id.")";
  2206. $result2 = api_sql_query($sql2, __FILE__, __LINE__);
  2207. $row2 = mysql_fetch_array($result2);
  2208. $chapter_name = $row2['chapter_name'];
  2209. $attributes = '';
  2210. $attributes[0][] = 'identifier';
  2211. $attributes[1][] = 'chapter_'.$row2['id'];
  2212. $attributes[0][] = 'isvisible';
  2213. $attributes[1][] = '1';
  2214. if ($previous_item_id != '00')
  2215. {
  2216. $org .= " ".xmltagwrite('item', 'close');
  2217. }
  2218. $org .= " ".xmltagwrite('item', 'open', $attributes);
  2219. $org .= " ".xmltagwrite('title', 'full', $chapter_name);
  2220. if ($row2['chapter_description'] != '')
  2221. {
  2222. //chapter description
  2223. $attributes = '';
  2224. $attributes[0][] = 'identifier';
  2225. $attributes[1][] = 'chapter_'.$row2['id'].'_desc';
  2226. $attributes[0][] = 'isvisible';
  2227. $attributes[1][] = '1';
  2228. $org .= " ".xmltagwrite('item', 'open', $attributes);
  2229. $org .= " ".xmltagwrite('title', 'full', ' '.$row2['chapter_description']);
  2230. $org .= " ".xmltagwrite('item', 'close');
  2231. }
  2232. }
  2233. $previous_item_id = $parent_item_id;
  2234. //}
  2235. $attributes = ''; //item output
  2236. $attributes[0][] = 'identifier';
  2237. $attributes[1][] = 'item_'.$circle1_files[2][$i];
  2238. $attributes[0][] = 'identifierref';
  2239. $attributes[1][] = 'item_ref_'.$circle1_files[2][$i];
  2240. $attributes[0][] = 'isvisible';
  2241. $attributes[1][] = '1';
  2242. $org .= " ".xmltagwrite('item', 'open', $attributes);
  2243. $org .= " ".xmltagwrite('title', 'full', $circle1_files[1][$i]);
  2244. if ($row['prereq_id'] != '')
  2245. { //item prerequisites
  2246. $attributes = '';
  2247. $attributes[0][] = 'type';
  2248. $attributes[1][] = 'aicc_script';
  2249. $org .= " ".xmltagwrite('adlcp:prerequisites', 'open', $attributes, "no_linebreak");
  2250. if ($row['prereq_type'] == 'i')
  2251. {
  2252. $org .= 'item_'.$row['prereq_id'];
  2253. }
  2254. if ($row['prereq_type'] == 'c')
  2255. {
  2256. $org .= 'chapter_'.$row['prereq_id'];
  2257. }
  2258. $org .= xmltagwrite('adlcp:prerequisites', 'close', $attributes);
  2259. }
  2260. if ($row['description'] != '')
  2261. {
  2262. //item description
  2263. $attributes = '';
  2264. $attributes[0][] = 'identifier';
  2265. $attributes[1][] = 'item_'.$circle1_files[2][$i].'_desc';
  2266. $attributes[0][] = 'isvisible';
  2267. $attributes[1][] = '1';
  2268. $org .= " ".xmltagwrite('item', 'open', $attributes);
  2269. $org .= " ".xmltagwrite('title', 'full', ' '.$row['description']);
  2270. $org .= " ".xmltagwrite('item', 'close');
  2271. }
  2272. $mds = new mdstore(TRUE); // RH: export metadata; if no table, create it
  2273. if (($mdt = $mds->mds_get($row['item_type'].'.'.$row['item_id'])))
  2274. if (($mdo = strpos($mdt, '<metadata>')) && ($mdc = strpos($mdt, '</metadata>')))
  2275. $org .= " ".substr($mdt, $mdo, $mdc - $mdo +11)."\n";
  2276. $org .= " ".xmltagwrite('item', 'close');
  2277. $i ++;
  2278. }
  2279. if ($circle1_files)
  2280. {
  2281. $org .= " ".xmltagwrite('item', 'close');
  2282. } //not needed in case of a blank path
  2283. $org .= " ".xmltagwrite('organization', 'close');
  2284. $org .= xmltagwrite('organizations', 'close');
  2285. $org .= xmltagwrite('resources', 'open');
  2286. //resources list
  2287. $i = 0;
  2288. while ($circle1_files[0][$i])
  2289. {
  2290. $attributes = '';
  2291. $attributes[0][] = 'identifier';
  2292. $attributes[1][] = 'item_ref_'.$circle1_files[2][$i];
  2293. $attributes[0][] = 'type';
  2294. $attributes[1][] = 'webcontent';
  2295. $attributes[0][] = 'adlcp:scormtype';
  2296. $attributes[1][] = 'sco';
  2297. $attributes[0][] = 'href';
  2298. $attributes[1][] = $circle1_files[0][$i];
  2299. $org .= " ".xmltagwrite('resource', 'open', $attributes);
  2300. $org .= " ".xmltagwrite('metadata', 'open');
  2301. $org .= " ".xmltagwrite('schema', 'full', 'ADL SCORM');
  2302. $org .= " ".xmltagwrite('schemaversion', 'full', '1.2');
  2303. $org .= " ".xmltagwrite('metadata', 'close');
  2304. $attributes = '';
  2305. $attributes[0][] = 'href';
  2306. $attributes[1][] = $circle1_files[0][$i];
  2307. $org .= " ".xmltagwrite('file', 'open', $attributes);
  2308. $org .= " ".xmltagwrite('resource', 'close');
  2309. $i ++;
  2310. }
  2311. $org .= xmltagwrite('resources', 'close');
  2312. $org .= xmltagwrite('manifest', 'close');
  2313. $manifest = $header.$org;
  2314. exporttofile('imsmanifest.xml', 'Manifest file', '0', $manifest);
  2315. }
  2316. /**
  2317. * Gets the tags of the file given as parameter
  2318. *
  2319. * if $filename is not found, GetSRCTags(filename) will return FALSE
  2320. * @param string file path
  2321. * @return mixed array of strings on success, false on failure
  2322. * @author unknown
  2323. * @author included by imandak80
  2324. */
  2325. function GetSRCTags($fileName)
  2326. {
  2327. if (!($fp = fopen($fileName, "r")))
  2328. {
  2329. //if file can't be opened, return false
  2330. return false;
  2331. }
  2332. //read file contents
  2333. $contents = fread($fp, filesize($fileName));
  2334. fclose($fp);
  2335. $matches = array ();
  2336. $srcList = array ();
  2337. //get all src tags contents in this file. Use multi-line search.
  2338. preg_match_all('/src(\s)*=(\s)*[\'"]([^\'"]*)[\'"]/mi', $contents, $matches); //get the img src as contained between " or '
  2339. foreach ($matches[3] as $match)
  2340. {
  2341. if (!in_array($match, $srcList))
  2342. {
  2343. $srcList[] = $match;
  2344. }
  2345. }
  2346. if (count($srcList) == 0)
  2347. {
  2348. return false;
  2349. }
  2350. return $srcList;
  2351. }
  2352. /**
  2353. * Copy file and create directories in the path if needed.
  2354. *
  2355. * @param string $source Source path
  2356. * @param string $dest Destination path
  2357. * @return boolean true on success, false on failure
  2358. */
  2359. function CopyNCreate($source, $dest)
  2360. {
  2361. if (strcmp($source, $dest) == 0)
  2362. return false;
  2363. $dir = "";
  2364. $tdest = explode('/', $dest);
  2365. for ($i = 0; $i < sizeof($tdest) - 1; $i ++)
  2366. {
  2367. $dir = $dir.$tdest[$i]."/";
  2368. if (!is_dir($dir))
  2369. if (!mkdir($dir))
  2370. return false;
  2371. }
  2372. if (!copy($source, $dest))
  2373. return false;
  2374. return true;
  2375. }
  2376. function rcopy($source, $dest)
  2377. {
  2378. //error_log($source." -> ".$dest,0);
  2379. if (!file_exists($source))
  2380. {
  2381. //error_log($source." does not exist",0);
  2382. return false;
  2383. }
  2384. if (is_dir($source))
  2385. {
  2386. //error_log($source." is a dir",0);
  2387. //this is a directory
  2388. //remove trailing '/'
  2389. if (strrpos($source, '/') == sizeof($source) - 1)
  2390. {
  2391. $source = substr($source, 0, size_of($source) - 1);
  2392. }
  2393. if (strrpos($dest, '/') == sizeof($dest) - 1)
  2394. {
  2395. $dest = substr($dest, 0, size_of($dest) - 1);
  2396. }
  2397. if (!is_dir($dest))
  2398. {
  2399. $res = @ mkdir($dest);
  2400. if ($res === true)
  2401. {
  2402. return true;
  2403. }
  2404. else
  2405. {
  2406. //remove latest part of path and try creating that
  2407. if (rcopy(substr($source, 0, strrpos($source, '/')), substr($dest, 0, strrpos($dest, '/'))))
  2408. {
  2409. return @ mkdir($dest);
  2410. }
  2411. else
  2412. {
  2413. return false;
  2414. }
  2415. }
  2416. }
  2417. return true;
  2418. }
  2419. else
  2420. {
  2421. //this is presumably a file
  2422. //error_log($source." is a file",0);
  2423. if (!@ copy($source, $dest))
  2424. {
  2425. //error_log("Could not simple-copy $source",0);
  2426. $res = rcopy(dirname($source), dirname($dest));
  2427. if ($res === true)
  2428. {
  2429. //error_log("Welcome dir created",0);
  2430. return @ copy($source, $dest);
  2431. }
  2432. else
  2433. {
  2434. return false;
  2435. //error_log("Error creating path",0);
  2436. }
  2437. }
  2438. else
  2439. {
  2440. //error_log("Could well simple-copy $source",0);
  2441. return true;
  2442. }
  2443. }
  2444. }
  2445. ?>