category.class.php 81 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652
  1. <?php
  2. /* For licensing terms, see /license.txt */
  3. use Chamilo\CoreBundle\Entity\GradebookCategory;
  4. use ChamiloSession as Session;
  5. /**
  6. * Class Category
  7. * Defines a gradebook Category object
  8. * @package chamilo.gradebook
  9. */
  10. class Category implements GradebookItem
  11. {
  12. private $id;
  13. private $name;
  14. private $description;
  15. private $user_id;
  16. private $course_code;
  17. private $courseId;
  18. private $parent;
  19. private $weight;
  20. private $visible;
  21. private $certificate_min_score;
  22. private $session_id;
  23. private $skills = array();
  24. private $grade_model_id;
  25. private $generateCertificates;
  26. private $isRequirement;
  27. private $courseDependency;
  28. private $minimumToValidate;
  29. public $studentList;
  30. public $evaluations;
  31. public $links;
  32. public $subCategories;
  33. /**
  34. * Consctructor
  35. */
  36. public function __construct()
  37. {
  38. $this->id = 0;
  39. $this->name = null;
  40. $this->description = null;
  41. $this->user_id = 0;
  42. $this->course_code = '';
  43. $this->courseId = 0;
  44. $this->parent = 0;
  45. $this->weight = 0;
  46. $this->visible = false;
  47. $this->certificate_min_score = 0;
  48. $this->session_id = 0;
  49. $this->grade_model_id = 0;
  50. $this->generateCertificates = false;
  51. $this->isRequirement = false;
  52. $this->courseDependency = [];
  53. $this->minimumToValidate = null;
  54. }
  55. /**
  56. * @return int
  57. */
  58. public function get_id()
  59. {
  60. return $this->id;
  61. }
  62. /**
  63. * @return string
  64. */
  65. public function get_name()
  66. {
  67. return $this->name;
  68. }
  69. /**
  70. * @return string
  71. */
  72. public function get_description()
  73. {
  74. return $this->description;
  75. }
  76. /**
  77. * @return int
  78. */
  79. public function get_user_id()
  80. {
  81. return $this->user_id;
  82. }
  83. /**
  84. * @return integer|null
  85. */
  86. public function getCertificateMinScore()
  87. {
  88. if (!empty($this->certificate_min_score)) {
  89. return $this->certificate_min_score;
  90. } else {
  91. return null;
  92. }
  93. }
  94. /**
  95. * @return string
  96. */
  97. public function get_course_code()
  98. {
  99. return $this->course_code;
  100. }
  101. /**
  102. * @return integer
  103. */
  104. public function get_parent_id()
  105. {
  106. return $this->parent;
  107. }
  108. /**
  109. * @return integer
  110. */
  111. public function get_weight()
  112. {
  113. return $this->weight;
  114. }
  115. /**
  116. * @return bool
  117. */
  118. public function is_locked()
  119. {
  120. return isset($this->locked) && $this->locked == 1 ? true : false;
  121. }
  122. /**
  123. * @return boolean
  124. */
  125. public function is_visible()
  126. {
  127. return $this->visible;
  128. }
  129. /**
  130. * Get $isRequirement
  131. * @return int
  132. */
  133. public function getIsRequirement()
  134. {
  135. return $this->isRequirement;
  136. }
  137. /**
  138. * @param int $id
  139. */
  140. public function set_id($id)
  141. {
  142. $this->id = $id;
  143. }
  144. /**
  145. * @param string $name
  146. */
  147. public function set_name($name)
  148. {
  149. $this->name = $name;
  150. }
  151. /**
  152. * @param string $description
  153. */
  154. public function set_description($description)
  155. {
  156. $this->description = $description;
  157. }
  158. /**
  159. * @param int $user_id
  160. */
  161. public function set_user_id($user_id)
  162. {
  163. $this->user_id = $user_id;
  164. }
  165. /**
  166. * @param string $course_code
  167. */
  168. public function set_course_code($course_code)
  169. {
  170. $this->course_code = $course_code;
  171. }
  172. /**
  173. * @param float $min_score
  174. */
  175. public function set_certificate_min_score($min_score = null)
  176. {
  177. $this->certificate_min_score = $min_score;
  178. }
  179. /**
  180. * @param int $parent
  181. */
  182. public function set_parent_id($parent)
  183. {
  184. $this->parent = intval($parent);
  185. }
  186. /**
  187. * Filters to int and sets the session ID
  188. * @param int The session ID from the Dokeos course session
  189. */
  190. public function set_session_id($session_id = 0)
  191. {
  192. $this->session_id = (int) $session_id;
  193. }
  194. /**
  195. * @param $weight
  196. */
  197. public function set_weight($weight)
  198. {
  199. $this->weight = $weight;
  200. }
  201. /**
  202. * @param $visible
  203. */
  204. public function set_visible($visible)
  205. {
  206. $this->visible = $visible;
  207. }
  208. /**
  209. * @param int $id
  210. */
  211. public function set_grade_model_id($id)
  212. {
  213. $this->grade_model_id = $id;
  214. }
  215. /**
  216. * @param $locked
  217. */
  218. public function set_locked($locked)
  219. {
  220. $this->locked = $locked;
  221. }
  222. /**
  223. * Set $isRequirement
  224. * @param int $isRequirement
  225. */
  226. public function setIsRequirement($isRequirement)
  227. {
  228. $this->isRequirement = $isRequirement;
  229. }
  230. /**
  231. * @param $value
  232. */
  233. public function setCourseListDependency($value)
  234. {
  235. $result = [];
  236. if (@unserialize($value) !== false) {
  237. $result = unserialize($value);
  238. }
  239. $this->courseDependency = $result;
  240. }
  241. /**
  242. * Course id list
  243. * @return array
  244. */
  245. public function getCourseListDependency()
  246. {
  247. return $this->courseDependency;
  248. }
  249. /**
  250. * @param int $value
  251. */
  252. public function setMinimumToValidate($value)
  253. {
  254. $this->minimumToValidate = $value;
  255. }
  256. /**
  257. * @return null
  258. */
  259. public function getMinimumToValidate()
  260. {
  261. return $this->minimumToValidate;
  262. }
  263. /**
  264. * @return null|integer
  265. */
  266. public function get_grade_model_id()
  267. {
  268. if ($this->grade_model_id < 0) {
  269. return null;
  270. }
  271. return $this->grade_model_id;
  272. }
  273. /**
  274. * @return string
  275. */
  276. public function get_type()
  277. {
  278. return 'category';
  279. }
  280. /**
  281. * @param bool $from_db
  282. * @return array|resource
  283. */
  284. public function get_skills($from_db = true)
  285. {
  286. if ($from_db) {
  287. $categoryId = $this->get_id();
  288. $gradebook = new Gradebook();
  289. $skills = $gradebook->getSkillsByGradebook($categoryId);
  290. } else {
  291. $skills = $this->skills;
  292. }
  293. return $skills;
  294. }
  295. /**
  296. * @return array
  297. */
  298. public function getSkillsForSelect()
  299. {
  300. $skills = $this->get_skills();
  301. $skill_select = array();
  302. if (!empty($skills)) {
  303. foreach ($skills as $skill) {
  304. $skill_select[$skill['id']] = $skill['name'];
  305. }
  306. }
  307. return $skill_select;
  308. }
  309. /**
  310. * Set the generate_certificates value
  311. * @param int $generateCertificates
  312. */
  313. public function setGenerateCertificates($generateCertificates)
  314. {
  315. $this->generateCertificates = $generateCertificates;
  316. }
  317. /**
  318. * Get the generate_certificates value
  319. * @return int
  320. */
  321. public function getGenerateCertificates()
  322. {
  323. return $this->generateCertificates;
  324. }
  325. /**
  326. * @param int $id
  327. * @param int $session_id
  328. *
  329. * @return array
  330. */
  331. public static function loadSessionCategories(
  332. $id = null,
  333. $session_id = null
  334. ) {
  335. if (isset($id) && (int) $id === 0) {
  336. $cats = array();
  337. $cats[] = self::create_root_category();
  338. return $cats;
  339. }
  340. $courseInfo = api_get_course_info_by_id(api_get_course_int_id());
  341. $courseCode = $courseInfo['code'];
  342. $session_id = intval($session_id);
  343. if (!empty($session_id)) {
  344. $table = Database::get_main_table(TABLE_MAIN_GRADEBOOK_CATEGORY);
  345. $sql = 'SELECT id, course_code
  346. FROM '.$table.'
  347. WHERE session_id = '.$session_id;
  348. $result_session = Database::query($sql);
  349. if (Database::num_rows($result_session) > 0) {
  350. $categoryList = array();
  351. while ($data_session = Database::fetch_array($result_session)) {
  352. $parent_id = $data_session['id'];
  353. if ($data_session['course_code'] == $courseCode) {
  354. $categories = self::load($parent_id);
  355. $categoryList = array_merge($categoryList, $categories);
  356. }
  357. }
  358. return $categoryList;
  359. }
  360. }
  361. }
  362. /**
  363. * Retrieve categories and return them as an array of Category objects
  364. * @param int $id category id
  365. * @param int $user_id (category owner)
  366. * @param string $course_code
  367. * @param int $parent_id parent category
  368. * @param bool $visible
  369. * @param int $session_id (in case we are in a session)
  370. * @param bool $order_by Whether to show all "session"
  371. * categories (true) or hide them (false) in case there is no session id
  372. *
  373. * @return array
  374. */
  375. public static function load(
  376. $id = null,
  377. $user_id = null,
  378. $course_code = null,
  379. $parent_id = null,
  380. $visible = null,
  381. $session_id = null,
  382. $order_by = null
  383. ) {
  384. //if the category given is explicitly 0 (not null), then create
  385. // a root category object (in memory)
  386. if (isset($id) && (int) $id === 0) {
  387. $cats = array();
  388. $cats[] = self::create_root_category();
  389. return $cats;
  390. }
  391. $tbl_grade_categories = Database::get_main_table(TABLE_MAIN_GRADEBOOK_CATEGORY);
  392. $sql = 'SELECT * FROM '.$tbl_grade_categories;
  393. $paramcount = 0;
  394. if (isset($id)) {
  395. $sql .= ' WHERE id = '.intval($id);
  396. $paramcount++;
  397. }
  398. if (isset($user_id)) {
  399. $user_id = intval($user_id);
  400. if ($paramcount != 0) {
  401. $sql .= ' AND';
  402. } else {
  403. $sql .= ' WHERE';
  404. }
  405. $sql .= ' user_id = '.intval($user_id);
  406. $paramcount++;
  407. }
  408. if (isset($course_code)) {
  409. if ($paramcount != 0) {
  410. $sql .= ' AND';
  411. } else {
  412. $sql .= ' WHERE';
  413. }
  414. if ($course_code == '0') {
  415. $sql .= ' c_id is null ';
  416. } else {
  417. $courseInfo = api_get_course_info($course_code);
  418. if ($courseInfo) {
  419. $sql .= " c_id = '".intval($courseInfo['real_id'])."'";
  420. }
  421. }
  422. /*if ($show_session_categories !== true) {
  423. // a query on the course should show all
  424. // the categories inside sessions for this course
  425. // otherwise a special parameter is given to ask explicitely
  426. $sql .= " AND (session_id IS NULL OR session_id = 0) ";
  427. } else {*/
  428. if (empty($session_id)) {
  429. $sql .= ' AND (session_id IS NULL OR session_id = 0) ';
  430. } else {
  431. $sql .= ' AND session_id = '.(int) $session_id.' ';
  432. }
  433. //}
  434. $paramcount++;
  435. }
  436. if (isset($parent_id)) {
  437. if ($paramcount != 0) {
  438. $sql .= ' AND ';
  439. } else {
  440. $sql .= ' WHERE ';
  441. }
  442. $sql .= ' parent_id = '.intval($parent_id);
  443. $paramcount++;
  444. }
  445. if (isset($visible)) {
  446. if ($paramcount != 0) {
  447. $sql .= ' AND';
  448. } else {
  449. $sql .= ' WHERE';
  450. }
  451. $sql .= ' visible = '.intval($visible);
  452. }
  453. if (!empty($order_by)) {
  454. if (!empty($order_by) && $order_by != '') {
  455. $sql .= ' '.$order_by;
  456. }
  457. }
  458. $result = Database::query($sql);
  459. $categories = array();
  460. if (Database::num_rows($result) > 0) {
  461. $categories = self::create_category_objects_from_sql_result(
  462. $result
  463. );
  464. }
  465. return $categories;
  466. }
  467. /**
  468. * @return Category
  469. */
  470. private static function create_root_category()
  471. {
  472. $cat = new Category();
  473. $cat->set_id(0);
  474. $cat->set_name(get_lang('RootCat'));
  475. $cat->set_description(null);
  476. $cat->set_user_id(0);
  477. $cat->set_course_code(null);
  478. $cat->set_parent_id(null);
  479. $cat->set_weight(0);
  480. $cat->set_visible(1);
  481. $cat->setGenerateCertificates(0);
  482. $cat->setIsRequirement(false);
  483. return $cat;
  484. }
  485. /**
  486. * @param Doctrine\DBAL\Driver\Statement|null $result
  487. *
  488. * @return array
  489. */
  490. private static function create_category_objects_from_sql_result($result)
  491. {
  492. $categories = array();
  493. while ($data = Database::fetch_array($result)) {
  494. $cat = new Category();
  495. $cat->set_id($data['id']);
  496. $cat->set_name($data['name']);
  497. $cat->set_description($data['description']);
  498. $cat->set_user_id($data['user_id']);
  499. $courseInfo = api_get_course_info_by_id($data['c_id']);
  500. $cat->set_course_code($courseInfo['code']);
  501. $cat->setCourseId($data['c_id']);
  502. $cat->set_parent_id($data['parent_id']);
  503. $cat->set_weight($data['weight']);
  504. $cat->set_visible($data['visible']);
  505. $cat->set_session_id($data['session_id']);
  506. $cat->set_certificate_min_score($data['certif_min_score']);
  507. $cat->set_grade_model_id($data['grade_model_id']);
  508. $cat->set_locked($data['locked']);
  509. $cat->setGenerateCertificates($data['generate_certificates']);
  510. $cat->setIsRequirement($data['is_requirement']);
  511. $cat->setCourseListDependency(isset($data['depends']) ? $data['depends'] : []);
  512. $cat->setMinimumToValidate(isset($data['minimum_to_validate']) ? $data['minimum_to_validate'] : null);
  513. $categories[] = $cat;
  514. }
  515. return $categories;
  516. }
  517. /**
  518. * Create a category object from a GradebookCategory entity
  519. * @param GradebookCategory $gradebookCategory The entity
  520. * @return \Category
  521. */
  522. public static function createCategoryObjectFromEntity(
  523. GradebookCategory $gradebookCategory
  524. ) {
  525. $category = new Category();
  526. $category->set_id($gradebookCategory->getId());
  527. $category->set_name($gradebookCategory->getName());
  528. $category->set_description($gradebookCategory->getDescription());
  529. $category->set_user_id($gradebookCategory->getUserId());
  530. $category->set_course_code($gradebookCategory->getCourseCode());
  531. $category->set_parent_id($gradebookCategory->getParentId());
  532. $category->set_weight($gradebookCategory->getWeight());
  533. $category->set_visible($gradebookCategory->getVisible());
  534. $category->set_session_id($gradebookCategory->getSessionId());
  535. $category->set_certificate_min_score(
  536. $gradebookCategory->getCertifMinScore()
  537. );
  538. $category->set_grade_model_id($gradebookCategory->getGradeModelId());
  539. $category->set_locked($gradebookCategory->getLocked());
  540. $category->setGenerateCertificates(
  541. $gradebookCategory->getGenerateCertificates()
  542. );
  543. $category->setIsRequirement($gradebookCategory->getIsRequirement());
  544. return $category;
  545. }
  546. /**
  547. * Insert this category into the database
  548. */
  549. public function add()
  550. {
  551. if (isset($this->name) && '-1' == $this->name) {
  552. return false;
  553. }
  554. if (isset($this->name) && isset($this->user_id)) {
  555. $em = Database::getManager();
  556. $courseInfo = api_get_course_info($this->course_code);
  557. $course = api_get_user_course_entity($courseInfo['real_id']);
  558. $category = new GradebookCategory();
  559. $category->setName($this->name);
  560. $category->setDescription($this->description);
  561. $category->setUserId($this->user_id);
  562. $category->setCourse($course);
  563. $category->setParentId($this->parent);
  564. $category->setWeight($this->weight);
  565. $category->setVisible($this->visible);
  566. $category->setCertifMinScore($this->certificate_min_score);
  567. $category->setSessionId($this->session_id);
  568. $category->setGenerateCertificates($this->generateCertificates);
  569. $category->setGradeModelId($this->grade_model_id);
  570. $category->setIsRequirement($this->isRequirement);
  571. $category->setLocked(false);
  572. $em->persist($category);
  573. $em->flush();
  574. $id = $category->getId();
  575. $this->set_id($id);
  576. if (!empty($id)) {
  577. $parent_id = $this->get_parent_id();
  578. $grade_model_id = $this->get_grade_model_id();
  579. if ($parent_id == 0) {
  580. //do something
  581. if (isset($grade_model_id) &&
  582. !empty($grade_model_id) &&
  583. $grade_model_id != '-1'
  584. ) {
  585. $obj = new GradeModel();
  586. $components = $obj->get_components($grade_model_id);
  587. $default_weight_setting = api_get_setting('gradebook_default_weight');
  588. $default_weight = 100;
  589. if (isset($default_weight_setting)) {
  590. $default_weight = $default_weight_setting;
  591. }
  592. foreach ($components as $component) {
  593. $gradebook = new Gradebook();
  594. $params = array();
  595. $params['name'] = $component['acronym'];
  596. $params['description'] = $component['title'];
  597. $params['user_id'] = api_get_user_id();
  598. $params['parent_id'] = $id;
  599. $params['weight'] = $component['percentage'] / 100 * $default_weight;
  600. $params['session_id'] = api_get_session_id();
  601. $params['course_code'] = $this->get_course_code();
  602. $gradebook->save($params);
  603. }
  604. }
  605. }
  606. }
  607. $gradebook = new Gradebook();
  608. $gradebook->update_skills_to_gradebook(
  609. $this->id,
  610. $this->get_skills(false)
  611. );
  612. return $id;
  613. }
  614. }
  615. /**
  616. * Update the properties of this category in the database
  617. * @todo fix me
  618. */
  619. public function save()
  620. {
  621. $em = Database::getManager();
  622. /** @var GradebookCategory $gradebookCategory */
  623. $gradebookCategory = $em
  624. ->getRepository('ChamiloCoreBundle:GradebookCategory')
  625. ->find($this->id);
  626. if (empty($gradebookCategory)) {
  627. return false;
  628. }
  629. $course = api_get_user_course_entity();
  630. $gradebookCategory->setName($this->name);
  631. $gradebookCategory->setDescription($this->description);
  632. $gradebookCategory->setUserId($this->user_id);
  633. $gradebookCategory->setCourse($course);
  634. //$gradebookCategory->setCourseCode($this->course_code);
  635. $gradebookCategory->setParentId($this->parent);
  636. $gradebookCategory->setWeight($this->weight);
  637. $gradebookCategory->setVisible($this->visible);
  638. $gradebookCategory->setCertifMinScore($this->certificate_min_score);
  639. $gradebookCategory->setGenerateCertificates(
  640. $this->generateCertificates
  641. );
  642. $gradebookCategory->setGradeModelId($this->grade_model_id);
  643. $gradebookCategory->setIsRequirement($this->isRequirement);
  644. $em->merge($gradebookCategory);
  645. $em->flush();
  646. if (!empty($this->id)) {
  647. $parent_id = $this->get_parent_id();
  648. $grade_model_id = $this->get_grade_model_id();
  649. if ($parent_id == 0) {
  650. if (isset($grade_model_id) &&
  651. !empty($grade_model_id) &&
  652. $grade_model_id != '-1'
  653. ) {
  654. $obj = new GradeModel();
  655. $components = $obj->get_components($grade_model_id);
  656. $default_weight_setting = api_get_setting('gradebook_default_weight');
  657. $default_weight = 100;
  658. if (isset($default_weight_setting)) {
  659. $default_weight = $default_weight_setting;
  660. }
  661. $final_weight = $this->get_weight();
  662. if (!empty($final_weight)) {
  663. $default_weight = $this->get_weight();
  664. }
  665. foreach ($components as $component) {
  666. $gradebook = new Gradebook();
  667. $params = array();
  668. $params['name'] = $component['acronym'];
  669. $params['description'] = $component['title'];
  670. $params['user_id'] = api_get_user_id();
  671. $params['parent_id'] = $this->id;
  672. $params['weight'] = $component['percentage'] / 100 * $default_weight;
  673. $params['session_id'] = api_get_session_id();
  674. $params['course_code'] = $this->get_course_code();
  675. $gradebook->save($params);
  676. }
  677. }
  678. }
  679. }
  680. $gradebook = new Gradebook();
  681. $gradebook->update_skills_to_gradebook(
  682. $this->id,
  683. $this->get_skills(false),
  684. true
  685. );
  686. }
  687. /**
  688. * Update link weights see #5168
  689. * @param type $new_weight
  690. */
  691. public function updateChildrenWeight($new_weight)
  692. {
  693. $links = $this->get_links();
  694. $old_weight = $this->get_weight();
  695. if (!empty($links)) {
  696. foreach ($links as $link_item) {
  697. if (isset($link_item)) {
  698. $new_item_weight = $new_weight * $link_item->get_weight() / $old_weight;
  699. $link_item->set_weight($new_item_weight);
  700. $link_item->save();
  701. }
  702. }
  703. }
  704. }
  705. /**
  706. * Delete this evaluation from the database
  707. */
  708. public function delete()
  709. {
  710. $table = Database::get_main_table(TABLE_MAIN_GRADEBOOK_CATEGORY);
  711. $sql = 'DELETE FROM '.$table.' WHERE id = '.intval($this->id);
  712. Database::query($sql);
  713. }
  714. /**
  715. * Not delete this category from the database,when visible=3 is category eliminated
  716. * @param int $courseId
  717. */
  718. public function update_category_delete($courseId)
  719. {
  720. $tbl_grade_categories = Database :: get_main_table(TABLE_MAIN_GRADEBOOK_CATEGORY);
  721. $sql = 'UPDATE '.$tbl_grade_categories.' SET visible=3
  722. WHERE c_id ="'.intval($courseId).'"';
  723. Database::query($sql);
  724. }
  725. /**
  726. * Delete this category from the database
  727. * @param int $courseId
  728. */
  729. public static function deleteCategoryFromCourse($courseId)
  730. {
  731. $table = Database :: get_main_table(TABLE_MAIN_GRADEBOOK_CATEGORY);
  732. $sql = 'DELETE FROM '.$table.'
  733. WHERE c_id ="'.intval($courseId).'"';
  734. Database::query($sql);
  735. }
  736. /**
  737. * @param int $course_id
  738. * @return bool|string
  739. */
  740. public function show_message_resource_delete($course_id)
  741. {
  742. $tbl_grade_categories = Database::get_main_table(TABLE_MAIN_GRADEBOOK_CATEGORY);
  743. $sql = 'SELECT count(*) AS num
  744. FROM '.$tbl_grade_categories.'
  745. WHERE
  746. c_id = "'.Database::escape_string($course_id).'" AND
  747. visible = 3';
  748. $res = Database::query($sql);
  749. $option = Database::fetch_array($res, 'ASSOC');
  750. if ($option['num'] >= 1) {
  751. return '&nbsp;&nbsp;<span class="resource-deleted">(&nbsp;'.get_lang('ResourceDeleted').'&nbsp;)</span>';
  752. } else {
  753. return false;
  754. }
  755. }
  756. /**
  757. * Shows all information of an category
  758. */
  759. public function showAllCategoryInfo($categoryId = '')
  760. {
  761. if ($categoryId == '') {
  762. return null;
  763. } else {
  764. $table = Database::get_main_table(TABLE_MAIN_GRADEBOOK_CATEGORY);
  765. $sql = 'SELECT * FROM '.$table.'
  766. WHERE id = '.intval($categoryId);
  767. $result = Database::query($sql);
  768. $row = Database::fetch_array($result, 'ASSOC');
  769. return $row;
  770. }
  771. }
  772. /**
  773. * Check if a category name (with the same parent category) already exists
  774. * @param string $name name to check (if not given, the name property of this object will be checked)
  775. * @param int $parent parent category
  776. *
  777. * @return bool
  778. */
  779. public function does_name_exist($name, $parent)
  780. {
  781. if (!isset($name)) {
  782. $name = $this->name;
  783. $parent = $this->parent;
  784. }
  785. $tbl_grade_categories = Database::get_main_table(TABLE_MAIN_GRADEBOOK_CATEGORY);
  786. $sql = "SELECT count(id) AS number
  787. FROM $tbl_grade_categories
  788. WHERE name = '".Database::escape_string($name)."'";
  789. if (api_is_allowed_to_edit()) {
  790. $parent = self::load($parent);
  791. $code = $parent[0]->get_course_code();
  792. $courseInfo = api_get_course_info($code);
  793. $courseId = $courseInfo['real_id'];
  794. if (isset($code) && $code != '0') {
  795. $main_course_user_table = Database::get_main_table(TABLE_MAIN_COURSE_USER);
  796. $sql .= ' AND user_id IN (
  797. SELECT user_id FROM '.$main_course_user_table.'
  798. WHERE c_id = '.$courseId.' AND status = '.COURSEMANAGER.'
  799. )';
  800. } else {
  801. $sql .= ' AND user_id = '.api_get_user_id();
  802. }
  803. } else {
  804. $sql .= ' AND user_id = '.api_get_user_id();
  805. }
  806. if (!isset($parent)) {
  807. $sql .= ' AND parent_id is null';
  808. } else {
  809. $sql .= ' AND parent_id = '.intval($parent);
  810. }
  811. $result = Database::query($sql);
  812. $number = Database::fetch_row($result);
  813. return $number[0] != 0;
  814. }
  815. /**
  816. * Checks if the certificate is available for the given user in this category
  817. * @param integer $user_id User ID
  818. * @return boolean True if conditions match, false if fails
  819. */
  820. public function is_certificate_available($user_id)
  821. {
  822. $score = $this->calc_score(
  823. $user_id,
  824. null,
  825. $this->course_code,
  826. $this->session_id
  827. );
  828. if (isset($score) && isset($score[0])) {
  829. // Get a percentage score to compare to minimum certificate score
  830. // $certification_score = $score[0] / $score[1] * 100;
  831. // Get real score not a percentage.
  832. $certification_score = $score[0];
  833. if ($certification_score >= $this->certificate_min_score) {
  834. return true;
  835. }
  836. }
  837. return false;
  838. }
  839. /**
  840. * Is this category a course ?
  841. * A category is a course if it has a course code and no parent category.
  842. */
  843. public function is_course()
  844. {
  845. return (isset($this->course_code) && !empty($this->course_code)
  846. && (!isset($this->parent) || $this->parent == 0));
  847. }
  848. /**
  849. * Calculate the score of this category
  850. * @param integer $stud_id student id (default: all students - then the average is returned)
  851. * @param integer $session_id
  852. * @param string $course_code
  853. * @param int $session_id
  854. * @return array (score sum, weight sum)
  855. * or null if no scores available
  856. */
  857. public function calc_score(
  858. $stud_id = null,
  859. $type = null,
  860. $course_code = '',
  861. $session_id = null
  862. ) {
  863. // Classic
  864. if (!empty($stud_id) && $type == '') {
  865. if (!empty($course_code)) {
  866. $cats = $this->get_subcategories(
  867. $stud_id,
  868. $course_code,
  869. $session_id
  870. );
  871. $evals = $this->get_evaluations($stud_id, false, $course_code);
  872. $links = $this->get_links($stud_id, false, $course_code);
  873. } else {
  874. $cats = $this->get_subcategories($stud_id);
  875. $evals = $this->get_evaluations($stud_id);
  876. $links = $this->get_links($stud_id);
  877. }
  878. // Calculate score
  879. $count = 0;
  880. $ressum = 0;
  881. $weightsum = 0;
  882. if (!empty($cats)) {
  883. /** @var Category $cat */
  884. foreach ($cats as $cat) {
  885. $cat->set_session_id($session_id);
  886. $cat->set_course_code($course_code);
  887. $cat->setStudentList($this->getStudentList());
  888. $score = $cat->calc_score(
  889. $stud_id,
  890. null,
  891. $course_code,
  892. $session_id
  893. );
  894. $catweight = 0;
  895. if ($cat->get_weight() != 0) {
  896. $catweight = $cat->get_weight();
  897. $weightsum += $catweight;
  898. }
  899. if (isset($score) && !empty($score[1]) && !empty($catweight)) {
  900. $ressum += $score[0] / $score[1] * $catweight;
  901. }
  902. }
  903. }
  904. $students = array();
  905. if (!empty($evals)) {
  906. /** @var Evaluation $eval */
  907. foreach ($evals as $eval) {
  908. $eval->setStudentList($this->getStudentList());
  909. $evalres = $eval->calc_score($stud_id, null);
  910. if (isset($evalres) && $eval->get_weight() != 0) {
  911. $evalweight = $eval->get_weight();
  912. $weightsum += $evalweight;
  913. $count++;
  914. if (!empty($evalres[1])) {
  915. $ressum += $evalres[0] / $evalres[1] * $evalweight;
  916. }
  917. } else {
  918. if ($eval->get_weight() != 0) {
  919. $evalweight = $eval->get_weight();
  920. $weightsum += $evalweight;
  921. }
  922. }
  923. }
  924. }
  925. if (!empty($links)) {
  926. /** @var EvalLink|ExerciseLink $link */
  927. foreach ($links as $link) {
  928. $link->setStudentList($this->getStudentList());
  929. if ($session_id) {
  930. $link->set_session_id($session_id);
  931. }
  932. $linkres = $link->calc_score($stud_id, null);
  933. if (!empty($linkres) && $link->get_weight() != 0) {
  934. $students[$stud_id] = $linkres[0];
  935. $linkweight = $link->get_weight();
  936. $link_res_denom = $linkres[1] == 0 ? 1 : $linkres[1];
  937. $count++;
  938. $weightsum += $linkweight;
  939. $ressum += $linkres[0] / $link_res_denom * $linkweight;
  940. } else {
  941. // Adding if result does not exists
  942. if ($link->get_weight() != 0) {
  943. $linkweight = $link->get_weight();
  944. $weightsum += $linkweight;
  945. }
  946. }
  947. }
  948. }
  949. } else {
  950. if (!empty($course_code)) {
  951. $cats = $this->get_subcategories(
  952. null,
  953. $course_code,
  954. $session_id
  955. );
  956. $evals = $this->get_evaluations(null, false, $course_code);
  957. $links = $this->get_links(null, false, $course_code);
  958. } else {
  959. $cats = $this->get_subcategories(null);
  960. $evals = $this->get_evaluations(null);
  961. $links = $this->get_links(null);
  962. }
  963. // Calculate score
  964. $count = 0;
  965. $ressum = 0;
  966. $weightsum = 0;
  967. $bestResult = 0;
  968. if (!empty($cats)) {
  969. /** @var Category $cat */
  970. foreach ($cats as $cat) {
  971. $cat->setStudentList($this->getStudentList());
  972. $score = $cat->calc_score(
  973. null,
  974. $type,
  975. $course_code,
  976. $session_id
  977. );
  978. $catweight = 0;
  979. if ($cat->get_weight() != 0) {
  980. $catweight = $cat->get_weight();
  981. $weightsum += $catweight;
  982. }
  983. if (isset($score) && !empty($score[1]) && !empty($catweight)) {
  984. $ressum += $score[0] / $score[1] * $catweight;
  985. if ($ressum > $bestResult) {
  986. $bestResult = $ressum;
  987. }
  988. }
  989. }
  990. }
  991. if (!empty($evals)) {
  992. /** @var Evaluation $eval */
  993. foreach ($evals as $eval) {
  994. $evalres = $eval->calc_score(null, $type);
  995. $eval->setStudentList($this->getStudentList());
  996. if (isset($evalres) && $eval->get_weight() != 0) {
  997. $evalweight = $eval->get_weight();
  998. $weightsum += $evalweight;
  999. $count++;
  1000. if (!empty($evalres[1])) {
  1001. $ressum += $evalres[0] / $evalres[1] * $evalweight;
  1002. }
  1003. if ($ressum > $bestResult) {
  1004. $bestResult = $ressum;
  1005. }
  1006. } else {
  1007. if ($eval->get_weight() != 0) {
  1008. $evalweight = $eval->get_weight();
  1009. $weightsum += $evalweight;
  1010. }
  1011. }
  1012. }
  1013. }
  1014. if (!empty($links)) {
  1015. /** @var EvalLink|ExerciseLink $link */
  1016. foreach ($links as $link) {
  1017. $link->setStudentList($this->getStudentList());
  1018. if ($session_id) {
  1019. $link->set_session_id($session_id);
  1020. }
  1021. $linkres = $link->calc_score($stud_id, $type);
  1022. if (!empty($linkres) && $link->get_weight() != 0) {
  1023. $students[$stud_id] = $linkres[0];
  1024. $linkweight = $link->get_weight();
  1025. $link_res_denom = $linkres[1] == 0 ? 1 : $linkres[1];
  1026. $count++;
  1027. $weightsum += $linkweight;
  1028. $ressum += $linkres[0] / $link_res_denom * $linkweight;
  1029. if ($ressum > $bestResult) {
  1030. $bestResult = $ressum;
  1031. }
  1032. } else {
  1033. // Adding if result does not exists
  1034. if ($link->get_weight() != 0) {
  1035. $linkweight = $link->get_weight();
  1036. $weightsum += $linkweight;
  1037. }
  1038. }
  1039. }
  1040. }
  1041. }
  1042. switch ($type) {
  1043. case 'best':
  1044. if (empty($bestResult)) {
  1045. return null;
  1046. }
  1047. return array($bestResult, $weightsum);
  1048. break;
  1049. case 'average':
  1050. if (empty($ressum)) {
  1051. return null;
  1052. }
  1053. return array($ressum, $weightsum);
  1054. break;
  1055. case 'ranking':
  1056. // category ranking is calculated in gradebook_data_generator.class.php
  1057. // function get_data
  1058. return null;
  1059. return AbstractLink::getCurrentUserRanking($stud_id, array());
  1060. break;
  1061. default:
  1062. return array($ressum, $weightsum);
  1063. break;
  1064. }
  1065. }
  1066. /**
  1067. * Delete this category and every subcategory, evaluation and result inside
  1068. */
  1069. public function delete_all()
  1070. {
  1071. $cats = self::load(null, null, $this->course_code, $this->id, null);
  1072. $evals = Evaluation::load(
  1073. null,
  1074. null,
  1075. $this->course_code,
  1076. $this->id,
  1077. null
  1078. );
  1079. $links = LinkFactory::load(
  1080. null,
  1081. null,
  1082. null,
  1083. null,
  1084. $this->course_code,
  1085. $this->id,
  1086. null
  1087. );
  1088. if (!empty($cats)) {
  1089. /** @var Category $cat */
  1090. foreach ($cats as $cat) {
  1091. $cat->delete_all();
  1092. $cat->delete();
  1093. }
  1094. }
  1095. if (!empty($evals)) {
  1096. /** @var Evaluation $eval */
  1097. foreach ($evals as $eval) {
  1098. $eval->delete_with_results();
  1099. }
  1100. }
  1101. if (!empty($links)) {
  1102. /** @var AbstractLink $link */
  1103. foreach ($links as $link) {
  1104. $link->delete();
  1105. }
  1106. }
  1107. $this->delete();
  1108. }
  1109. /**
  1110. * Return array of Category objects where a student is subscribed to.
  1111. *
  1112. * @param integer $stud_id
  1113. * @param string $course_code
  1114. * @param integer $session_id
  1115. * @return array
  1116. */
  1117. public function get_root_categories_for_student(
  1118. $stud_id,
  1119. $course_code = null,
  1120. $session_id = null
  1121. ) {
  1122. $main_course_user_table = Database::get_main_table(TABLE_MAIN_COURSE_USER);
  1123. $courseTable = Database::get_main_table(TABLE_MAIN_COURSE);
  1124. $tbl_grade_categories = Database::get_main_table(TABLE_MAIN_GRADEBOOK_CATEGORY);
  1125. $course_code = Database::escape_string($course_code);
  1126. $session_id = (int) $session_id;
  1127. $sql = "SELECT * FROM $tbl_grade_categories WHERE parent_id = 0";
  1128. if (!api_is_allowed_to_edit()) {
  1129. $sql .= ' AND visible = 1';
  1130. //proceed with checks on optional parameters course & session
  1131. if (!empty($course_code)) {
  1132. // TODO: considering it highly improbable that a user would get here
  1133. // if he doesn't have the rights to view this course and this
  1134. // session, we don't check his registration to these, but this
  1135. // could be an improvement
  1136. if (!empty($session_id)) {
  1137. $sql .= " AND course_code = '".$course_code."' AND session_id = ".$session_id;
  1138. } else {
  1139. $sql .= " AND course_code = '".$course_code."' AND session_id is null OR session_id=0";
  1140. }
  1141. } else {
  1142. //no optional parameter, proceed as usual
  1143. $sql .= ' AND course_code in
  1144. (
  1145. SELECT c.code
  1146. FROM '.$main_course_user_table.' cu INNER JOIN '.$courseTable.' c
  1147. ON (cu.c_id = c.id)
  1148. WHERE cu.user_id = '.intval($stud_id).'
  1149. AND cu.status = '.STUDENT.'
  1150. )';
  1151. }
  1152. } elseif (api_is_allowed_to_edit() && !api_is_platform_admin()) {
  1153. //proceed with checks on optional parameters course & session
  1154. if (!empty($course_code)) {
  1155. // TODO: considering it highly improbable that a user would get here
  1156. // if he doesn't have the rights to view this course and this
  1157. // session, we don't check his registration to these, but this
  1158. // could be an improvement
  1159. $sql .= " AND course_code = '".$course_code."'";
  1160. if (!empty($session_id)) {
  1161. $sql .= " AND session_id = ".$session_id;
  1162. } else {
  1163. $sql .= "AND session_id IS NULL OR session_id=0";
  1164. }
  1165. } else {
  1166. $sql .= ' AND course_code IN
  1167. (
  1168. SELECT c.code
  1169. FROM '.$main_course_user_table.' cu INNER JOIN '.$courseTable.' c
  1170. ON (cu.c_id = c.id)
  1171. WHERE
  1172. cu.user_id = '.api_get_user_id().' AND
  1173. cu.status = '.COURSEMANAGER.'
  1174. )';
  1175. }
  1176. } elseif (api_is_platform_admin()) {
  1177. if (isset($session_id) && $session_id != 0) {
  1178. $sql .= ' AND session_id='.$session_id;
  1179. } else {
  1180. $sql .= ' AND coalesce(session_id,0)=0';
  1181. }
  1182. }
  1183. $result = Database::query($sql);
  1184. $cats = self::create_category_objects_from_sql_result($result);
  1185. // course independent categories
  1186. if (empty($course_code)) {
  1187. $cats = self::getIndependentCategoriesWithStudentResult(
  1188. 0,
  1189. $stud_id,
  1190. $cats
  1191. );
  1192. }
  1193. return $cats;
  1194. }
  1195. /**
  1196. * Return array of Category objects where a teacher is admin for.
  1197. *
  1198. * @param integer $user_id (to return everything, use 'null' here)
  1199. * @param string $course_code (optional)
  1200. * @param integer $session_id (optional)
  1201. * @return array
  1202. */
  1203. public function get_root_categories_for_teacher(
  1204. $user_id,
  1205. $course_code = null,
  1206. $session_id = null
  1207. ) {
  1208. if ($user_id == null) {
  1209. return self::load(null, null, $course_code, 0, null, $session_id);
  1210. }
  1211. $courseTable = Database::get_main_table(TABLE_MAIN_COURSE);
  1212. $main_course_user_table = Database::get_main_table(TABLE_MAIN_COURSE_USER);
  1213. $tbl_grade_categories = Database::get_main_table(TABLE_MAIN_GRADEBOOK_CATEGORY);
  1214. $sql = 'SELECT * FROM '.$tbl_grade_categories.'
  1215. WHERE parent_id = 0 ';
  1216. if (!empty($course_code)) {
  1217. $sql .= " AND course_code = '".Database::escape_string($course_code)."' ";
  1218. if (!empty($session_id)) {
  1219. $sql .= " AND session_id = ".(int) $session_id;
  1220. }
  1221. } else {
  1222. $sql .= ' AND course_code in
  1223. (
  1224. SELECT c.code
  1225. FROM '.$main_course_user_table.' cu
  1226. INNER JOIN '.$courseTable.' c
  1227. ON (cu.c_id = c.id)
  1228. WHERE user_id = '.intval($user_id).'
  1229. )';
  1230. }
  1231. $result = Database::query($sql);
  1232. $cats = self::create_category_objects_from_sql_result($result);
  1233. // course independent categories
  1234. if (isset($course_code)) {
  1235. $indcats = self::load(
  1236. null,
  1237. $user_id,
  1238. $course_code,
  1239. 0,
  1240. null,
  1241. $session_id
  1242. );
  1243. $cats = array_merge($cats, $indcats);
  1244. }
  1245. return $cats;
  1246. }
  1247. /**
  1248. * Can this category be moved to somewhere else ?
  1249. * The root and courses cannot be moved.
  1250. * @return bool
  1251. */
  1252. public function is_movable()
  1253. {
  1254. return !(!isset($this->id) || $this->id == 0 || $this->is_course());
  1255. }
  1256. /**
  1257. * Generate an array of possible categories where this category can be moved to.
  1258. * Notice: its own parent will be included in the list: it's up to the frontend
  1259. * to disable this element.
  1260. * @return array 2-dimensional array - every element contains 3 subelements (id, name, level)
  1261. */
  1262. public function get_target_categories()
  1263. {
  1264. // the root or a course -> not movable
  1265. if (!$this->is_movable()) {
  1266. return null;
  1267. } else {
  1268. // otherwise:
  1269. // - course independent category
  1270. // -> movable to root or other independent categories
  1271. // - category inside a course
  1272. // -> movable to root, independent categories or categories inside the course
  1273. $user = api_is_platform_admin() ? null : api_get_user_id();
  1274. $targets = array();
  1275. $level = 0;
  1276. $root = array(0, get_lang('RootCat'), $level);
  1277. $targets[] = $root;
  1278. if (isset($this->course_code) && !empty($this->course_code)) {
  1279. $crscats = self::load(null, null, $this->course_code, 0);
  1280. foreach ($crscats as $cat) {
  1281. if ($this->can_be_moved_to_cat($cat)) {
  1282. $targets[] = array(
  1283. $cat->get_id(),
  1284. $cat->get_name(),
  1285. $level + 1
  1286. );
  1287. $targets = $this->addTargetSubcategories(
  1288. $targets,
  1289. $level + 1,
  1290. $cat->get_id()
  1291. );
  1292. }
  1293. }
  1294. }
  1295. $indcats = self::load(null, $user, 0, 0);
  1296. foreach ($indcats as $cat) {
  1297. if ($this->can_be_moved_to_cat($cat)) {
  1298. $targets[] = array($cat->get_id(), $cat->get_name(), $level + 1);
  1299. $targets = $this->addTargetSubcategories(
  1300. $targets,
  1301. $level + 1,
  1302. $cat->get_id()
  1303. );
  1304. }
  1305. }
  1306. return $targets;
  1307. }
  1308. }
  1309. /**
  1310. * Internal function used by get_target_categories()
  1311. * @param array $targets
  1312. * @param integer $level
  1313. * @param int $catid
  1314. *
  1315. * @return array
  1316. */
  1317. private function addTargetSubcategories($targets, $level, $catid)
  1318. {
  1319. $subcats = self::load(null, null, null, $catid);
  1320. foreach ($subcats as $cat) {
  1321. if ($this->can_be_moved_to_cat($cat)) {
  1322. $targets[] = array(
  1323. $cat->get_id(),
  1324. $cat->get_name(),
  1325. $level + 1
  1326. );
  1327. $targets = $this->addTargetSubcategories(
  1328. $targets,
  1329. $level + 1,
  1330. $cat->get_id()
  1331. );
  1332. }
  1333. }
  1334. return $targets;
  1335. }
  1336. /**
  1337. * Internal function used by get_target_categories() and addTargetSubcategories()
  1338. * Can this category be moved to the given category ?
  1339. * Impossible when origin and target are the same... children won't be processed
  1340. * either. (a category can't be moved to one of its own children)
  1341. */
  1342. private function can_be_moved_to_cat($cat)
  1343. {
  1344. return $cat->get_id() != $this->get_id();
  1345. }
  1346. /**
  1347. * Move this category to the given category.
  1348. * If this category moves from inside a course to outside,
  1349. * its course code must be changed, as well as the course code
  1350. * of all underlying categories and evaluations. All links will
  1351. * be deleted as well !
  1352. */
  1353. public function move_to_cat($cat)
  1354. {
  1355. $this->set_parent_id($cat->get_id());
  1356. if ($this->get_course_code() != $cat->get_course_code()) {
  1357. $this->set_course_code($cat->get_course_code());
  1358. $this->applyCourseCodeToChildren();
  1359. }
  1360. $this->save();
  1361. }
  1362. /**
  1363. * Internal function used by move_to_cat()
  1364. */
  1365. private function applyCourseCodeToChildren()
  1366. {
  1367. $cats = self::load(null, null, null, $this->id, null);
  1368. $evals = Evaluation::load(null, null, null, $this->id, null);
  1369. $links = LinkFactory::load(
  1370. null,
  1371. null,
  1372. null,
  1373. null,
  1374. null,
  1375. $this->id,
  1376. null
  1377. );
  1378. /** @var Category $cat */
  1379. foreach ($cats as $cat) {
  1380. $cat->set_course_code($this->get_course_code());
  1381. $cat->save();
  1382. $cat->applyCourseCodeToChildren();
  1383. }
  1384. foreach ($evals as $eval) {
  1385. $eval->set_course_code($this->get_course_code());
  1386. $eval->save();
  1387. }
  1388. foreach ($links as $link) {
  1389. $link->delete();
  1390. }
  1391. }
  1392. /**
  1393. * Generate an array of all categories the user can navigate to
  1394. */
  1395. public function get_tree()
  1396. {
  1397. $targets = array();
  1398. $level = 0;
  1399. $root = array(0, get_lang('RootCat'), $level);
  1400. $targets[] = $root;
  1401. // course or platform admin
  1402. if (api_is_allowed_to_edit()) {
  1403. $user = api_is_platform_admin() ? null : api_get_user_id();
  1404. $cats = self::get_root_categories_for_teacher($user);
  1405. foreach ($cats as $cat) {
  1406. $targets[] = array(
  1407. $cat->get_id(),
  1408. $cat->get_name(),
  1409. $level + 1
  1410. );
  1411. $targets = self::add_subtree(
  1412. $targets,
  1413. $level + 1,
  1414. $cat->get_id(),
  1415. null
  1416. );
  1417. }
  1418. } else {
  1419. // student
  1420. $cats = self::get_root_categories_for_student(api_get_user_id());
  1421. foreach ($cats as $cat) {
  1422. $targets[] = array(
  1423. $cat->get_id(),
  1424. $cat->get_name(),
  1425. $level + 1
  1426. );
  1427. $targets = self::add_subtree(
  1428. $targets,
  1429. $level + 1,
  1430. $cat->get_id(),
  1431. 1
  1432. );
  1433. }
  1434. }
  1435. return $targets;
  1436. }
  1437. /**
  1438. * Internal function used by get_tree()
  1439. * @param integer $level
  1440. * @param null|integer $visible
  1441. * @return array
  1442. */
  1443. private function add_subtree($targets, $level, $catid, $visible)
  1444. {
  1445. $subcats = self::load(null, null, null, $catid, $visible);
  1446. if (!empty($subcats)) {
  1447. foreach ($subcats as $cat) {
  1448. $targets[] = array(
  1449. $cat->get_id(),
  1450. $cat->get_name(),
  1451. $level + 1
  1452. );
  1453. $targets = self::add_subtree(
  1454. $targets,
  1455. $level + 1,
  1456. $cat->get_id(),
  1457. $visible
  1458. );
  1459. }
  1460. }
  1461. return $targets;
  1462. }
  1463. /**
  1464. * Generate an array of courses that a teacher hasn't created a category for.
  1465. * @param integer $user_id
  1466. * @return array 2-dimensional array - every element contains 2 subelements (code, title)
  1467. */
  1468. public function get_not_created_course_categories($user_id)
  1469. {
  1470. $tbl_main_courses = Database::get_main_table(TABLE_MAIN_COURSE);
  1471. $tbl_main_course_user = Database::get_main_table(TABLE_MAIN_COURSE_USER);
  1472. $tbl_grade_categories = Database::get_main_table(TABLE_MAIN_GRADEBOOK_CATEGORY);
  1473. $sql = 'SELECT DISTINCT(code), title
  1474. FROM '.$tbl_main_courses.' cc, '.$tbl_main_course_user.' cu
  1475. WHERE
  1476. cc.id = cu.c_id AND
  1477. cu.status = '.COURSEMANAGER;
  1478. if (!api_is_platform_admin()) {
  1479. $sql .= ' AND cu.user_id = '.$user_id;
  1480. }
  1481. $sql .= ' AND cc.code NOT IN
  1482. (
  1483. SELECT course_code FROM '.$tbl_grade_categories.'
  1484. WHERE
  1485. parent_id = 0 AND
  1486. course_code IS NOT NULL
  1487. )';
  1488. $result = Database::query($sql);
  1489. $cats = array();
  1490. while ($data = Database::fetch_array($result)) {
  1491. $cats[] = array($data['code'], $data['title']);
  1492. }
  1493. return $cats;
  1494. }
  1495. /**
  1496. * Generate an array of all courses that a teacher is admin of.
  1497. * @param integer $user_id
  1498. * @return array 2-dimensional array - every element contains 2 subelements (code, title)
  1499. */
  1500. public function get_all_courses($user_id)
  1501. {
  1502. $tbl_main_courses = Database::get_main_table(TABLE_MAIN_COURSE);
  1503. $tbl_main_course_user = Database::get_main_table(TABLE_MAIN_COURSE_USER);
  1504. $sql = 'SELECT DISTINCT(code), title
  1505. FROM '.$tbl_main_courses.' cc, '.$tbl_main_course_user.' cu
  1506. WHERE cc.id = cu.c_id AND cu.status = '.COURSEMANAGER;
  1507. if (!api_is_platform_admin()) {
  1508. $sql .= ' AND cu.user_id = '.intval($user_id);
  1509. }
  1510. $result = Database::query($sql);
  1511. $cats = array();
  1512. while ($data = Database::fetch_array($result)) {
  1513. $cats[] = array($data['code'], $data['title']);
  1514. }
  1515. return $cats;
  1516. }
  1517. /**
  1518. * Apply the same visibility to every subcategory, evaluation and link
  1519. */
  1520. public function apply_visibility_to_children()
  1521. {
  1522. $cats = self::load(null, null, null, $this->id, null);
  1523. $evals = Evaluation::load(null, null, null, $this->id, null);
  1524. $links = LinkFactory::load(
  1525. null,
  1526. null,
  1527. null,
  1528. null,
  1529. null,
  1530. $this->id,
  1531. null
  1532. );
  1533. if (!empty($cats)) {
  1534. foreach ($cats as $cat) {
  1535. $cat->set_visible($this->is_visible());
  1536. $cat->save();
  1537. $cat->apply_visibility_to_children();
  1538. }
  1539. }
  1540. if (!empty($evals)) {
  1541. foreach ($evals as $eval) {
  1542. $eval->set_visible($this->is_visible());
  1543. $eval->save();
  1544. }
  1545. }
  1546. if (!empty($links)) {
  1547. foreach ($links as $link) {
  1548. $link->set_visible($this->is_visible());
  1549. $link->save();
  1550. }
  1551. }
  1552. }
  1553. /**
  1554. * Check if a category contains evaluations with a result for a given student
  1555. * @param int $studentId
  1556. * @return bool
  1557. */
  1558. public function hasEvaluationsWithStudentResults($studentId)
  1559. {
  1560. $evals = Evaluation::get_evaluations_with_result_for_student(
  1561. $this->id,
  1562. $studentId
  1563. );
  1564. if (count($evals) != 0) {
  1565. return true;
  1566. } else {
  1567. $cats = self::load(
  1568. null,
  1569. null,
  1570. null,
  1571. $this->id,
  1572. api_is_allowed_to_edit() ? null : 1
  1573. );
  1574. /** @var Category $cat */
  1575. foreach ($cats as $cat) {
  1576. if ($cat->hasEvaluationsWithStudentResults($studentId)) {
  1577. return true;
  1578. }
  1579. }
  1580. return false;
  1581. }
  1582. }
  1583. /**
  1584. * Retrieve all categories inside a course independent category
  1585. * that should be visible to a student.
  1586. * @param int $categoryId parent category
  1587. * @param int $studentId
  1588. * @param array $cats optional: if defined, the categories will be added to this array
  1589. * @return array
  1590. */
  1591. public function getIndependentCategoriesWithStudentResult(
  1592. $categoryId,
  1593. $studentId,
  1594. $cats = array()
  1595. ) {
  1596. $creator = api_is_allowed_to_edit() && !api_is_platform_admin() ? api_get_user_id() : null;
  1597. $categories = self::load(
  1598. null,
  1599. $creator,
  1600. '0',
  1601. $categoryId,
  1602. api_is_allowed_to_edit() ? null : 1
  1603. );
  1604. if (!empty($categories)) {
  1605. /** @var Category $category */
  1606. foreach ($categories as $category) {
  1607. if ($category->hasEvaluationsWithStudentResults($studentId)) {
  1608. $cats[] = $category;
  1609. }
  1610. }
  1611. }
  1612. return $cats;
  1613. }
  1614. /**
  1615. * Return the session id (in any case, even if it's null or 0)
  1616. * @return int Session id (can be null)
  1617. */
  1618. public function get_session_id()
  1619. {
  1620. return $this->session_id;
  1621. }
  1622. /**
  1623. * Get appropriate subcategories visible for the user (and optionally the course and session)
  1624. * @param int $studentId student id (default: all students)
  1625. * @param string $course_code Course code (optional)
  1626. * @param int $session_id Session ID (optional)
  1627. * @param bool $order
  1628. * @return array Array of subcategories
  1629. */
  1630. public function get_subcategories(
  1631. $studentId = null,
  1632. $course_code = null,
  1633. $session_id = null,
  1634. $order = null
  1635. ) {
  1636. if (!empty($session_id)) {
  1637. /*$tbl_grade_categories = Database::get_main_table(TABLE_MAIN_GRADEBOOK_CATEGORY);
  1638. $sql = 'SELECT id FROM '.$tbl_grade_categories. ' WHERE session_id = '.$session_id;
  1639. $result_session = Database::query($sql);
  1640. if (Database::num_rows($result_session) > 0) {
  1641. $data_session = Database::fetch_array($result_session);
  1642. $parent_id = $data_session['id'];
  1643. return self::load(null, null, null, $parent_id, null, null, $order);
  1644. }*/
  1645. }
  1646. // 1 student
  1647. if (isset($studentId)) {
  1648. // Special case: this is the root
  1649. if ($this->id == 0) {
  1650. return self::get_root_categories_for_student($studentId, $course_code, $session_id);
  1651. } else {
  1652. return self::load(
  1653. null,
  1654. null,
  1655. $course_code,
  1656. $this->id,
  1657. api_is_allowed_to_edit() ? null : 1,
  1658. $session_id,
  1659. $order
  1660. );
  1661. }
  1662. } else {
  1663. // All students
  1664. // Course admin
  1665. if (api_is_allowed_to_edit() && !api_is_platform_admin()) {
  1666. // root
  1667. if ($this->id == 0) {
  1668. return $this->get_root_categories_for_teacher(
  1669. api_get_user_id(),
  1670. $course_code,
  1671. $session_id,
  1672. false
  1673. );
  1674. // inside a course
  1675. } elseif (!empty($this->course_code)) {
  1676. return self::load(
  1677. null,
  1678. null,
  1679. $this->course_code,
  1680. $this->id,
  1681. null,
  1682. $session_id,
  1683. $order
  1684. );
  1685. } elseif (!empty($course_code)) {
  1686. return self::load(
  1687. null,
  1688. null,
  1689. $course_code,
  1690. $this->id,
  1691. null,
  1692. $session_id,
  1693. $order
  1694. );
  1695. // course independent
  1696. } else {
  1697. return self::load(
  1698. null,
  1699. api_get_user_id(),
  1700. 0,
  1701. $this->id,
  1702. null
  1703. );
  1704. }
  1705. } elseif (api_is_platform_admin()) {
  1706. // platform admin
  1707. // we explicitly avoid listing subcats from another session
  1708. return self::load(
  1709. null,
  1710. null,
  1711. $course_code,
  1712. $this->id,
  1713. null,
  1714. $session_id,
  1715. $order
  1716. );
  1717. }
  1718. }
  1719. return array();
  1720. }
  1721. /**
  1722. * Get appropriate evaluations visible for the user
  1723. * @param int $studentId student id (default: all students)
  1724. * @param boolean $recursive process subcategories (default: no recursion)
  1725. * @param string $course_code
  1726. * @param int $sessionId
  1727. *
  1728. * @return array
  1729. */
  1730. public function get_evaluations(
  1731. $studentId = null,
  1732. $recursive = false,
  1733. $course_code = '',
  1734. $sessionId = 0
  1735. ) {
  1736. $evals = array();
  1737. $course_code = empty($course_code) ? $this->get_course_code() : $course_code;
  1738. $sessionId = empty($sessionId) ? $this->get_session_id() : $sessionId;
  1739. // 1 student
  1740. if (isset($studentId) && !empty($studentId)) {
  1741. // Special case: this is the root
  1742. if ($this->id == 0) {
  1743. $evals = Evaluation::get_evaluations_with_result_for_student(
  1744. 0,
  1745. $studentId
  1746. );
  1747. } else {
  1748. $evals = Evaluation::load(
  1749. null,
  1750. null,
  1751. $course_code,
  1752. $this->id,
  1753. api_is_allowed_to_edit() ? null : 1
  1754. );
  1755. }
  1756. } else {
  1757. // All students
  1758. // course admin
  1759. if ((api_is_allowed_to_edit() || api_is_drh() || api_is_session_admin()) &&
  1760. !api_is_platform_admin()
  1761. ) {
  1762. // root
  1763. if ($this->id == 0) {
  1764. $evals = Evaluation::load(
  1765. null,
  1766. api_get_user_id(),
  1767. null,
  1768. $this->id,
  1769. null
  1770. );
  1771. } elseif (isset($this->course_code) &&
  1772. !empty($this->course_code)
  1773. ) {
  1774. // inside a course
  1775. $evals = Evaluation::load(
  1776. null,
  1777. null,
  1778. $course_code,
  1779. $this->id,
  1780. null
  1781. );
  1782. } else {
  1783. // course independent
  1784. $evals = Evaluation::load(
  1785. null,
  1786. api_get_user_id(),
  1787. null,
  1788. $this->id,
  1789. null
  1790. );
  1791. }
  1792. } else {
  1793. $evals = Evaluation::load(
  1794. null,
  1795. null,
  1796. $course_code,
  1797. $this->id,
  1798. null
  1799. );
  1800. }
  1801. }
  1802. if ($recursive) {
  1803. $subcats = $this->get_subcategories(
  1804. $studentId,
  1805. $course_code,
  1806. $sessionId
  1807. );
  1808. if (!empty($subcats)) {
  1809. foreach ($subcats as $subcat) {
  1810. $subevals = $subcat->get_evaluations(
  1811. $studentId,
  1812. true,
  1813. $course_code
  1814. );
  1815. $evals = array_merge($evals, $subevals);
  1816. }
  1817. }
  1818. }
  1819. return $evals;
  1820. }
  1821. /**
  1822. * Get appropriate links visible for the user
  1823. * @param int $studentId student id (default: all students)
  1824. * @param boolean $recursive process subcategories (default: no recursion)
  1825. * @param string $course_code
  1826. * @param int $sessionId
  1827. *
  1828. * @return array
  1829. */
  1830. public function get_links(
  1831. $studentId = null,
  1832. $recursive = false,
  1833. $course_code = '',
  1834. $sessionId = 0
  1835. ) {
  1836. $links = array();
  1837. $course_code = empty($course_code) ? $this->get_course_code() : $course_code;
  1838. $sessionId = empty($sessionId) ? $this->get_session_id() : $sessionId;
  1839. // no links in root or course independent categories
  1840. if ($this->id == 0) {
  1841. } elseif (isset($studentId)) {
  1842. // 1 student $studentId
  1843. $links = LinkFactory::load(
  1844. null,
  1845. null,
  1846. null,
  1847. null,
  1848. empty($this->course_code) ? null : $course_code,
  1849. $this->id,
  1850. api_is_allowed_to_edit() ? null : 1
  1851. );
  1852. } else {
  1853. // All students -> only for course/platform admin
  1854. $links = LinkFactory::load(
  1855. null,
  1856. null,
  1857. null,
  1858. null,
  1859. empty($this->course_code) ? null : $this->course_code,
  1860. $this->id,
  1861. null
  1862. );
  1863. }
  1864. if ($recursive) {
  1865. $subcats = $this->get_subcategories(
  1866. $studentId,
  1867. $course_code,
  1868. $sessionId
  1869. );
  1870. if (!empty($subcats)) {
  1871. /** @var Category $subcat */
  1872. foreach ($subcats as $subcat) {
  1873. $sublinks = $subcat->get_links(
  1874. $studentId,
  1875. false,
  1876. $course_code,
  1877. $sessionId
  1878. );
  1879. $links = array_merge($links, $sublinks);
  1880. }
  1881. }
  1882. }
  1883. return $links;
  1884. }
  1885. /**
  1886. * Get all the categories from with the same given direct parent
  1887. * @param int $catId Category parent ID
  1888. * @return array Array of Category objects
  1889. */
  1890. public function getCategories($catId)
  1891. {
  1892. $tblGradeCategories = Database::get_main_table(TABLE_MAIN_GRADEBOOK_CATEGORY);
  1893. $sql = 'SELECT * FROM '.$tblGradeCategories.'
  1894. WHERE parent_id = '.intval($catId);
  1895. $result = Database::query($sql);
  1896. $categories = self::create_category_objects_from_sql_result($result);
  1897. return $categories;
  1898. }
  1899. /**
  1900. * Gets the type for the current object
  1901. * @return string 'C' to represent "Category" object type
  1902. */
  1903. public function get_item_type()
  1904. {
  1905. return 'C';
  1906. }
  1907. /**
  1908. * @param array $skills
  1909. */
  1910. public function set_skills($skills)
  1911. {
  1912. $this->skills = $skills;
  1913. }
  1914. /**
  1915. * @return null
  1916. */
  1917. public function get_date()
  1918. {
  1919. return null;
  1920. }
  1921. /**
  1922. * @return string
  1923. */
  1924. public function get_icon_name()
  1925. {
  1926. return 'cat';
  1927. }
  1928. /**
  1929. * Find category by name
  1930. * @param string $name_mask search string
  1931. * @return array category objects matching the search criterium
  1932. */
  1933. public function find_category($name_mask, $allcat)
  1934. {
  1935. $categories = array();
  1936. foreach ($allcat as $search_cat) {
  1937. if (!(strpos(strtolower($search_cat->get_name()), strtolower($name_mask)) === false)) {
  1938. $categories[] = $search_cat;
  1939. }
  1940. }
  1941. return $categories;
  1942. }
  1943. /**
  1944. * This function, locks a category , only one who can unlock it is
  1945. * the platform administrator.
  1946. * @param int locked 1 or unlocked 0
  1947. * @return boolean|null
  1948. * */
  1949. public function lock($locked)
  1950. {
  1951. $table = Database::get_main_table(TABLE_MAIN_GRADEBOOK_CATEGORY);
  1952. $sql = "UPDATE $table SET locked = '".intval($locked)."'
  1953. WHERE id='".intval($this->id)."'";
  1954. Database::query($sql);
  1955. }
  1956. /**
  1957. * @param $locked
  1958. */
  1959. public function lockAllItems($locked)
  1960. {
  1961. if (api_get_setting('gradebook_locking_enabled') == 'true') {
  1962. $this->lock($locked);
  1963. $evals_to_lock = $this->get_evaluations();
  1964. if (!empty($evals_to_lock)) {
  1965. foreach ($evals_to_lock as $item) {
  1966. $item->lock($locked);
  1967. }
  1968. }
  1969. $link_to_lock = $this->get_links();
  1970. if (!empty($link_to_lock)) {
  1971. foreach ($link_to_lock as $item) {
  1972. $item->lock($locked);
  1973. }
  1974. }
  1975. $event_type = LOG_GRADEBOOK_UNLOCKED;
  1976. if ($locked == 1) {
  1977. $event_type = LOG_GRADEBOOK_LOCKED;
  1978. }
  1979. Event::addEvent($event_type, LOG_GRADEBOOK_ID, $this->id);
  1980. }
  1981. }
  1982. /**
  1983. * Generates a certificate for this user if everything matches
  1984. * @param int $category_id gradebook id
  1985. * @param int $user_id
  1986. * @param bool $sendNotification
  1987. *
  1988. * @return bool|string
  1989. */
  1990. public static function generateUserCertificate(
  1991. $category_id,
  1992. $user_id,
  1993. $sendNotification = false
  1994. ) {
  1995. $courseId = api_get_course_int_id();
  1996. $courseCode = api_get_course_id();
  1997. $sessionId = api_get_session_id();
  1998. // Generating the total score for a course
  1999. $cats_course = self::load(
  2000. $category_id,
  2001. null,
  2002. null,
  2003. null,
  2004. null,
  2005. $sessionId,
  2006. false
  2007. );
  2008. /** @var Category $category */
  2009. $category = $cats_course[0];
  2010. if (empty($category)) {
  2011. return false;
  2012. }
  2013. $sessionId = $category->get_session_id();
  2014. $courseCode = $category->get_course_code();
  2015. $courseInfo = api_get_course_info($courseCode);
  2016. $courseId = $courseInfo['real_id'];
  2017. //@todo move these in a function
  2018. $sum_categories_weight_array = array();
  2019. if (isset($cats_course) && !empty($cats_course)) {
  2020. $categories = self::load(null, null, null, $category_id);
  2021. if (!empty($categories)) {
  2022. foreach ($categories as $subCategory) {
  2023. $sum_categories_weight_array[$subCategory->get_id()] = $subCategory->get_weight();
  2024. }
  2025. } else {
  2026. $sum_categories_weight_array[$category_id] = $cats_course[0]->get_weight();
  2027. }
  2028. }
  2029. $main_weight = $cats_course[0]->get_weight();
  2030. $cattotal = self::load($category_id);
  2031. $scoretotal = $cattotal[0]->calc_score($user_id);
  2032. // Do not remove this the gradebook/lib/fe/gradebooktable.class.php
  2033. // file load this variable as a global
  2034. $scoredisplay = ScoreDisplay::instance();
  2035. $my_score_in_gradebook = $scoredisplay->display_score(
  2036. $scoretotal,
  2037. SCORE_SIMPLE
  2038. );
  2039. $userFinishedCourse = self::userFinishedCourse(
  2040. $user_id,
  2041. $cats_course[0],
  2042. true
  2043. );
  2044. if (!$userFinishedCourse) {
  2045. return false;
  2046. }
  2047. $skillToolEnabled = Skill::hasAccessToUserSkill(
  2048. api_get_user_id(),
  2049. $user_id
  2050. );
  2051. $userHasSkills = false;
  2052. if ($skillToolEnabled) {
  2053. $skill = new Skill();
  2054. $skill->addSkillToUser(
  2055. $user_id,
  2056. $category_id,
  2057. $courseId,
  2058. $sessionId
  2059. );
  2060. $objSkillRelUser = new SkillRelUser();
  2061. $userSkills = $objSkillRelUser->getUserSkills(
  2062. $user_id,
  2063. $courseId,
  2064. $sessionId
  2065. );
  2066. $userHasSkills = !empty($userSkills);
  2067. if (!$category->getGenerateCertificates() && $userHasSkills) {
  2068. return [
  2069. 'badge_link' => Display::toolbarButton(
  2070. get_lang('ExportBadges'),
  2071. api_get_path(WEB_CODE_PATH)."gradebook/get_badges.php?user=$user_id",
  2072. 'external-link'
  2073. ),
  2074. ];
  2075. }
  2076. }
  2077. $my_certificate = GradebookUtils::get_certificate_by_user_id(
  2078. $cats_course[0]->get_id(),
  2079. $user_id
  2080. );
  2081. if (empty($my_certificate)) {
  2082. GradebookUtils::registerUserInfoAboutCertificate(
  2083. $category_id,
  2084. $user_id,
  2085. $my_score_in_gradebook,
  2086. api_get_utc_datetime()
  2087. );
  2088. $my_certificate = GradebookUtils::get_certificate_by_user_id(
  2089. $cats_course[0]->get_id(),
  2090. $user_id
  2091. );
  2092. }
  2093. $html = array();
  2094. if (!empty($my_certificate)) {
  2095. $certificate_obj = new Certificate(
  2096. $my_certificate['id'],
  2097. 0,
  2098. $sendNotification
  2099. );
  2100. $fileWasGenerated = $certificate_obj->isHtmlFileGenerated();
  2101. if (!empty($fileWasGenerated)) {
  2102. $url = api_get_path(WEB_PATH).'certificates/index.php?id='.$my_certificate['id'];
  2103. $certificates = Display::toolbarButton(
  2104. get_lang('DisplayCertificate'),
  2105. $url,
  2106. 'eye',
  2107. 'primary'
  2108. );
  2109. $exportToPDF = Display::url(
  2110. Display::return_icon(
  2111. 'pdf.png',
  2112. get_lang('ExportToPDF'),
  2113. array(),
  2114. ICON_SIZE_MEDIUM
  2115. ),
  2116. "$url&action=export"
  2117. );
  2118. $hideExportLink = api_get_setting('hide_certificate_export_link');
  2119. $hideExportLinkStudent = api_get_setting('hide_certificate_export_link_students');
  2120. if ($hideExportLink === 'true' || (api_is_student() && $hideExportLinkStudent === 'true')) {
  2121. $exportToPDF = null;
  2122. }
  2123. $html = array(
  2124. 'certificate_link' => $certificates,
  2125. 'pdf_link' => $exportToPDF,
  2126. 'pdf_url' => "$url&action=export",
  2127. );
  2128. if ($skillToolEnabled && $userHasSkills) {
  2129. $html['badge_link'] = Display::toolbarButton(
  2130. get_lang('ExportBadges'),
  2131. api_get_path(WEB_CODE_PATH)."gradebook/get_badges.php?user=$user_id",
  2132. 'external-link'
  2133. );
  2134. }
  2135. }
  2136. return $html;
  2137. }
  2138. }
  2139. /**
  2140. * @param int $catId
  2141. * @param array $userList
  2142. */
  2143. public static function generateCertificatesInUserList($catId, $userList)
  2144. {
  2145. if (!empty($userList)) {
  2146. foreach ($userList as $userInfo) {
  2147. self::generateUserCertificate($catId, $userInfo['user_id']);
  2148. }
  2149. }
  2150. }
  2151. /**
  2152. * @param int $catId
  2153. * @param array $userList
  2154. */
  2155. public static function exportAllCertificates(
  2156. $catId,
  2157. $userList = array()
  2158. ) {
  2159. $orientation = api_get_configuration_value('certificate_pdf_orientation');
  2160. $params['orientation'] = 'landscape';
  2161. if (!empty($orientation)) {
  2162. $params['orientation'] = $orientation;
  2163. }
  2164. $params['left'] = 0;
  2165. $params['right'] = 0;
  2166. $params['top'] = 0;
  2167. $params['bottom'] = 0;
  2168. $page_format = $params['orientation'] == 'landscape' ? 'A4-L' : 'A4';
  2169. $pdf = new PDF($page_format, $params['orientation'], $params);
  2170. $certificate_list = GradebookUtils::get_list_users_certificates($catId, $userList);
  2171. $certificate_path_list = array();
  2172. if (!empty($certificate_list)) {
  2173. foreach ($certificate_list as $index=>$value) {
  2174. $list_certificate = GradebookUtils::get_list_gradebook_certificates_by_user_id(
  2175. $value['user_id'],
  2176. $catId
  2177. );
  2178. foreach ($list_certificate as $value_certificate) {
  2179. $certificate_obj = new Certificate($value_certificate['id']);
  2180. $certificate_obj->generate(array('hide_print_button' => true));
  2181. if ($certificate_obj->isHtmlFileGenerated()) {
  2182. $certificate_path_list[] = $certificate_obj->html_file;
  2183. }
  2184. }
  2185. }
  2186. }
  2187. if (!empty($certificate_path_list)) {
  2188. // Print certificates (without the common header/footer/watermark
  2189. // stuff) and return as one multiple-pages PDF
  2190. $pdf->html_to_pdf(
  2191. $certificate_path_list,
  2192. get_lang('Certificates'),
  2193. null,
  2194. false,
  2195. false
  2196. );
  2197. }
  2198. }
  2199. /**
  2200. * @param int $catId
  2201. */
  2202. public static function deleteAllCertificates($catId)
  2203. {
  2204. $certificate_list = GradebookUtils::get_list_users_certificates($catId);
  2205. if (!empty($certificate_list)) {
  2206. foreach ($certificate_list as $index => $value) {
  2207. $list_certificate = GradebookUtils::get_list_gradebook_certificates_by_user_id(
  2208. $value['user_id'],
  2209. $catId
  2210. );
  2211. foreach ($list_certificate as $value_certificate) {
  2212. $certificate_obj = new Certificate($value_certificate['id']);
  2213. $certificate_obj->delete(true);
  2214. }
  2215. }
  2216. }
  2217. }
  2218. /**
  2219. * Check whether a user has finished a course by its gradebook
  2220. * @param int $userId The user ID
  2221. * @param \Category $category Optional. The gradebook category.
  2222. * To check by the gradebook category
  2223. * @param boolean $recalculateScore Whether recalculate the score
  2224. * @return boolean
  2225. */
  2226. public static function userFinishedCourse(
  2227. $userId,
  2228. \Category $category,
  2229. $recalculateScore = false
  2230. ) {
  2231. if (empty($category)) {
  2232. return false;
  2233. }
  2234. $currentScore = self::getCurrentScore(
  2235. $userId,
  2236. $category,
  2237. $recalculateScore
  2238. );
  2239. $minCertificateScore = $category->getCertificateMinScore();
  2240. $passedCourse = $currentScore >= $minCertificateScore;
  2241. return $passedCourse;
  2242. }
  2243. /**
  2244. * Get the current score (as percentage) on a gradebook category for a user
  2245. * @param int $userId The user id
  2246. * @param Category $category The gradebook category
  2247. * @param bool $recalculate
  2248. *
  2249. * @return float The score
  2250. */
  2251. public static function getCurrentScore(
  2252. $userId,
  2253. $category,
  2254. $recalculate = false
  2255. ) {
  2256. if (empty($category)) {
  2257. return 0;
  2258. }
  2259. if ($recalculate) {
  2260. return self::calculateCurrentScore(
  2261. $userId,
  2262. $category
  2263. );
  2264. }
  2265. $resultData = Database::select(
  2266. '*',
  2267. Database::get_main_table(TABLE_MAIN_GRADEBOOK_SCORE_LOG),
  2268. [
  2269. 'where' => [
  2270. 'category_id = ? AND user_id = ?' => [$category->get_id(), $userId],
  2271. ],
  2272. 'order' => 'registered_at DESC',
  2273. 'limit' => '1',
  2274. ],
  2275. 'first'
  2276. );
  2277. if (empty($resultData)) {
  2278. return 0;
  2279. }
  2280. return $resultData['score'];
  2281. }
  2282. /**
  2283. * Calculate the current score on a gradebook category for a user
  2284. * @param int $userId The user id
  2285. * @param Category $category The gradebook category
  2286. * @return float The score
  2287. */
  2288. private static function calculateCurrentScore(
  2289. $userId,
  2290. $category
  2291. ) {
  2292. if (empty($category)) {
  2293. return 0;
  2294. }
  2295. $courseEvaluations = $category->get_evaluations(
  2296. $userId, true
  2297. );
  2298. $courseLinks = $category->get_links($userId, true);
  2299. $evaluationsAndLinks = array_merge($courseEvaluations, $courseLinks);
  2300. $categoryScore = 0;
  2301. for ($i = 0; $i < count($evaluationsAndLinks); $i++) {
  2302. $item = $evaluationsAndLinks[$i];
  2303. $score = $item->calc_score($userId);
  2304. $itemValue = 0;
  2305. if (!empty($score)) {
  2306. $divider = $score[1] == 0 ? 1 : $score[1];
  2307. $itemValue = $score[0] / $divider * $item->get_weight();
  2308. }
  2309. $categoryScore += $itemValue;
  2310. }
  2311. return api_float_val($categoryScore);
  2312. }
  2313. /**
  2314. * Register the current score for a user on a category gradebook
  2315. * @param float $score The achieved score
  2316. * @param int $userId The user id
  2317. * @param int $categoryId The gradebook category
  2318. * @return false|string The insert id
  2319. */
  2320. public static function registerCurrentScore($score, $userId, $categoryId)
  2321. {
  2322. return Database::insert(
  2323. Database::get_main_table(TABLE_MAIN_GRADEBOOK_SCORE_LOG),
  2324. [
  2325. 'category_id' => intval($categoryId),
  2326. 'user_id' => intval($userId),
  2327. 'score' => api_float_val($score),
  2328. 'registered_at' => api_get_utc_datetime(),
  2329. ]
  2330. );
  2331. }
  2332. /**
  2333. * @return array
  2334. */
  2335. public function getStudentList()
  2336. {
  2337. return $this->studentList;
  2338. }
  2339. /**
  2340. * @param array $list
  2341. */
  2342. public function setStudentList($list)
  2343. {
  2344. $this->studentList = $list;
  2345. }
  2346. /**
  2347. * @return string
  2348. */
  2349. public static function getUrl()
  2350. {
  2351. $url = Session::read('gradebook_dest');
  2352. if (empty($url)) {
  2353. // We guess the link
  2354. $courseInfo = api_get_course_info();
  2355. if (!empty($courseInfo)) {
  2356. return api_get_path(WEB_CODE_PATH).'gradebook/index.php?'.api_get_cidreq().'&';
  2357. } else {
  2358. return api_get_path(WEB_CODE_PATH).'gradebook/gradebook.php?';
  2359. }
  2360. }
  2361. return $url;
  2362. }
  2363. /**
  2364. * Destination is index.php or gradebook.php
  2365. * @param string $url
  2366. */
  2367. public static function setUrl($url)
  2368. {
  2369. switch ($url) {
  2370. case 'gradebook.php':
  2371. $url = api_get_path(WEB_CODE_PATH).'gradebook/gradebook.php?';
  2372. break;
  2373. case 'index.php':
  2374. $url = api_get_path(WEB_CODE_PATH).'gradebook/index.php?'.api_get_cidreq().'&';
  2375. break;
  2376. }
  2377. Session::write('gradebook_dest', $url);
  2378. }
  2379. /**
  2380. * @return int
  2381. */
  2382. public function getCourseId()
  2383. {
  2384. return $this->courseId;
  2385. }
  2386. /**
  2387. * @param int $courseId
  2388. * @return Category
  2389. */
  2390. public function setCourseId($courseId)
  2391. {
  2392. $this->courseId = $courseId;
  2393. return $this;
  2394. }
  2395. }