abstractlink.class.php 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798
  1. <?php
  2. /* For licensing terms, see /license.txt */
  3. /**
  4. * Class AbstractLink
  5. * Defines a gradebook AbstractLink object.
  6. * To implement specific links,
  7. * extend this class and define a type in LinkFactory.
  8. * Use the methods in LinkFactory to create link objects.
  9. *
  10. * @author Bert Steppé
  11. * @author Julio Montoya <gugli100@gmail.com> security improvements
  12. *
  13. * @package chamilo.gradebook
  14. */
  15. abstract class AbstractLink implements GradebookItem
  16. {
  17. public $course_id;
  18. public $studentList;
  19. /** @var \Chamilo\CoreBundle\Entity\GradebookLink */
  20. public $entity;
  21. protected $id;
  22. protected $type;
  23. protected $ref_id;
  24. protected $user_id;
  25. protected $course_code;
  26. /** @var Category */
  27. protected $category;
  28. protected $created_at;
  29. protected $weight;
  30. protected $visible;
  31. protected $session_id;
  32. /**
  33. * Constructor.
  34. */
  35. public function __construct()
  36. {
  37. $this->course_id = api_get_course_int_id();
  38. }
  39. /**
  40. * @return bool
  41. */
  42. abstract public function has_results();
  43. /**
  44. * @return string
  45. */
  46. abstract public function get_link();
  47. /**
  48. * @return bool
  49. */
  50. abstract public function is_valid_link();
  51. /**
  52. * @return string
  53. */
  54. abstract public function get_type_name();
  55. /**
  56. * @return bool
  57. */
  58. abstract public function needs_name_and_description();
  59. /**
  60. * @return bool
  61. */
  62. abstract public function needs_max();
  63. /**
  64. * @return bool
  65. */
  66. abstract public function needs_results();
  67. /**
  68. * @return bool
  69. */
  70. abstract public function is_allowed_to_change_name();
  71. /**
  72. * @return int
  73. */
  74. public function get_id()
  75. {
  76. return $this->id;
  77. }
  78. /**
  79. * @return string
  80. */
  81. public function get_type()
  82. {
  83. return $this->type;
  84. }
  85. /**
  86. * @return int
  87. */
  88. public function get_ref_id()
  89. {
  90. return (int) $this->ref_id;
  91. }
  92. /**
  93. * @return int
  94. */
  95. public function get_session_id()
  96. {
  97. return $this->session_id;
  98. }
  99. /**
  100. * @return int
  101. */
  102. public function get_user_id()
  103. {
  104. return $this->user_id;
  105. }
  106. /**
  107. * @return string
  108. */
  109. public function get_course_code()
  110. {
  111. return $this->course_code;
  112. }
  113. /**
  114. * @return Category
  115. */
  116. public function getCategory()
  117. {
  118. return $this->category;
  119. }
  120. /**
  121. * @param Category $category
  122. */
  123. public function setCategory($category)
  124. {
  125. $this->category = $category;
  126. }
  127. /**
  128. * @return int
  129. */
  130. public function get_category_id()
  131. {
  132. return $this->category->get_id();
  133. }
  134. /**
  135. * @param int $category_id
  136. */
  137. public function set_category_id($category_id)
  138. {
  139. $categories = Category::load($category_id);
  140. if (isset($categories[0])) {
  141. $this->setCategory($categories[0]);
  142. }
  143. }
  144. public function get_date()
  145. {
  146. return $this->created_at;
  147. }
  148. public function get_weight()
  149. {
  150. return $this->weight;
  151. }
  152. public function is_locked()
  153. {
  154. return isset($this->locked) && $this->locked == 1 ? true : false;
  155. }
  156. public function is_visible()
  157. {
  158. return $this->visible;
  159. }
  160. public function set_id($id)
  161. {
  162. $this->id = $id;
  163. }
  164. public function set_type($type)
  165. {
  166. $this->type = $type;
  167. }
  168. public function set_ref_id($ref_id)
  169. {
  170. $this->ref_id = $ref_id;
  171. }
  172. public function set_user_id($user_id)
  173. {
  174. $this->user_id = $user_id;
  175. }
  176. /**
  177. * @param string $course_code
  178. */
  179. public function set_course_code($course_code)
  180. {
  181. $courseInfo = api_get_course_info($course_code);
  182. if ($courseInfo) {
  183. $this->course_code = $course_code;
  184. $this->course_id = $courseInfo['real_id'];
  185. }
  186. }
  187. /**
  188. * @return array
  189. */
  190. public function getStudentList()
  191. {
  192. if (empty($this->studentList)) {
  193. return [];
  194. }
  195. return $this->studentList;
  196. }
  197. /**
  198. * @param array $list
  199. */
  200. public function setStudentList($list)
  201. {
  202. $this->studentList = $list;
  203. }
  204. public function set_date($date)
  205. {
  206. $this->created_at = $date;
  207. }
  208. public function set_weight($weight)
  209. {
  210. $this->weight = $weight;
  211. }
  212. public function set_visible($visible)
  213. {
  214. $this->visible = $visible;
  215. }
  216. /**
  217. * @param int $id
  218. */
  219. public function set_session_id($id)
  220. {
  221. $this->session_id = $id;
  222. }
  223. /**
  224. * @param $locked
  225. */
  226. public function set_locked($locked)
  227. {
  228. $this->locked = $locked;
  229. }
  230. /**
  231. * @return int
  232. */
  233. public function getCourseId()
  234. {
  235. return $this->course_id;
  236. }
  237. /**
  238. * Retrieve links and return them as an array of extensions of AbstractLink.
  239. * To keep consistency, do not call this method but LinkFactory::load instead.
  240. *
  241. * @param int $id
  242. * @param int $type
  243. * @param int $ref_id
  244. * @param int $user_id
  245. * @param string $course_code
  246. * @param int $category_id
  247. * @param int $visible
  248. *
  249. * @return array
  250. */
  251. public static function load(
  252. $id = null,
  253. $type = null,
  254. $ref_id = null,
  255. $user_id = null,
  256. $course_code = null,
  257. $category_id = null,
  258. $visible = null
  259. ) {
  260. $tbl_grade_links = Database::get_main_table(TABLE_MAIN_GRADEBOOK_LINK);
  261. $sql = 'SELECT * FROM '.$tbl_grade_links;
  262. $paramcount = 0;
  263. if (isset($id)) {
  264. $sql .= ' WHERE id = '.intval($id);
  265. $paramcount++;
  266. }
  267. if (isset($type)) {
  268. if ($paramcount != 0) {
  269. $sql .= ' AND';
  270. } else {
  271. $sql .= ' WHERE';
  272. }
  273. $sql .= ' type = '.intval($type);
  274. $paramcount++;
  275. }
  276. if (isset($ref_id)) {
  277. if ($paramcount != 0) {
  278. $sql .= ' AND';
  279. } else {
  280. $sql .= ' WHERE';
  281. }
  282. $sql .= ' ref_id = '.intval($ref_id);
  283. $paramcount++;
  284. }
  285. if (isset($user_id)) {
  286. if ($paramcount != 0) {
  287. $sql .= ' AND';
  288. } else {
  289. $sql .= ' WHERE';
  290. }
  291. $sql .= ' user_id = '.intval($user_id);
  292. $paramcount++;
  293. }
  294. if (isset($course_code)) {
  295. if ($paramcount != 0) {
  296. $sql .= ' AND';
  297. } else {
  298. $sql .= ' WHERE';
  299. }
  300. $sql .= " course_code = '".Database::escape_string($course_code)."'";
  301. $paramcount++;
  302. }
  303. if (isset($category_id)) {
  304. if ($paramcount != 0) {
  305. $sql .= ' AND';
  306. } else {
  307. $sql .= ' WHERE';
  308. }
  309. $sql .= ' category_id = '.intval($category_id);
  310. $paramcount++;
  311. }
  312. if (isset($visible)) {
  313. if ($paramcount != 0) {
  314. $sql .= ' AND';
  315. } else {
  316. $sql .= ' WHERE';
  317. }
  318. $sql .= ' visible = '.intval($visible);
  319. }
  320. $result = Database::query($sql);
  321. $links = self::create_objects_from_sql_result($result);
  322. return $links;
  323. }
  324. /**
  325. * Insert this link into the database.
  326. */
  327. public function add()
  328. {
  329. $this->add_linked_data();
  330. if (isset($this->type) &&
  331. isset($this->ref_id) &&
  332. isset($this->user_id) &&
  333. isset($this->course_code) &&
  334. isset($this->category) &&
  335. isset($this->weight) &&
  336. isset($this->visible)
  337. ) {
  338. $table = Database::get_main_table(TABLE_MAIN_GRADEBOOK_LINK);
  339. $sql = "SELECT count(*) count FROM $table
  340. WHERE
  341. ref_id = ".$this->get_ref_id()." AND
  342. category_id = ".$this->category->get_id()." AND
  343. course_code = '".$this->course_code."' AND
  344. type = ".$this->type;
  345. $result = Database::query($sql);
  346. $row = Database::fetch_array($result, 'ASSOC');
  347. if ($row['count'] == 0) {
  348. $params = [
  349. 'type' => $this->get_type(),
  350. 'ref_id' => $this->get_ref_id(),
  351. 'user_id' => $this->get_user_id(),
  352. 'course_code' => $this->get_course_code(),
  353. 'category_id' => $this->get_category_id(),
  354. 'weight' => $this->get_weight(),
  355. 'visible' => $this->is_visible(),
  356. 'created_at' => api_get_utc_datetime(),
  357. 'locked' => 0,
  358. ];
  359. $id = Database::insert($table, $params);
  360. $this->set_id($id);
  361. return $id;
  362. }
  363. }
  364. return false;
  365. }
  366. /**
  367. * Update the properties of this link in the database.
  368. */
  369. public function save()
  370. {
  371. $em = Database::getManager();
  372. $link = $em->find('ChamiloCoreBundle:GradebookLink', $this->id);
  373. if (!$link) {
  374. return;
  375. }
  376. self::add_link_log($this->id);
  377. $this->save_linked_data();
  378. $link
  379. ->setType($this->get_type())
  380. ->setRefId($this->get_ref_id())
  381. ->setUserId($this->get_user_id())
  382. ->setCourseCode($this->get_course_code())
  383. ->setCategoryId($this->get_category_id())
  384. ->setWeight($this->get_weight())
  385. ->setVisible($this->is_visible());
  386. $em->merge($link);
  387. $em->flush();
  388. }
  389. /**
  390. * @param int $evaluationId
  391. */
  392. public static function add_link_log($evaluationId, $nameLog = null)
  393. {
  394. $table = Database::get_main_table(TABLE_MAIN_GRADEBOOK_LINKEVAL_LOG);
  395. $dateobject = self::load($evaluationId, null, null, null, null);
  396. $now = api_get_utc_datetime();
  397. $arreval = get_object_vars($dateobject[0]);
  398. $description_log = isset($arreval['description']) ? $arreval['description'] : '';
  399. if (empty($nameLog)) {
  400. if (isset($_POST['name_link'])) {
  401. $name_log = isset($_POST['name_link']) ? $_POST['name_link'] : $arreval['course_code'];
  402. } elseif (isset($_POST['link_'.$evaluationId]) && $_POST['link_'.$evaluationId]) {
  403. $name_log = $_POST['link_'.$evaluationId];
  404. } else {
  405. $name_log = $arreval['course_code'];
  406. }
  407. } else {
  408. $name_log = $nameLog;
  409. }
  410. $params = [
  411. 'id_linkeval_log' => $arreval['id'],
  412. 'name' => $name_log,
  413. 'description' => $description_log,
  414. 'created_at' => $now,
  415. 'weight' => $arreval['weight'],
  416. 'visible' => $arreval['visible'],
  417. 'type' => 'Link',
  418. 'user_id_log' => api_get_user_id(),
  419. ];
  420. Database::insert($table, $params);
  421. }
  422. /**
  423. * Delete this link from the database.
  424. */
  425. public function delete()
  426. {
  427. $this->delete_linked_data();
  428. $table = Database::get_main_table(TABLE_MAIN_GRADEBOOK_LINK);
  429. $sql = 'DELETE FROM '.$table.'
  430. WHERE id = '.intval($this->id);
  431. Database::query($sql);
  432. }
  433. /**
  434. * Generate an array of possible categories where this link can be moved to.
  435. * Notice: its own parent will be included in the list: it's up to the frontend
  436. * to disable this element.
  437. *
  438. * @return array 2-dimensional array - every element contains 3 subelements (id, name, level)
  439. */
  440. public function get_target_categories()
  441. {
  442. // links can only be moved to categories inside this course
  443. $targets = [];
  444. $level = 0;
  445. $categories = Category::load(null, null, $this->get_course_code(), 0);
  446. foreach ($categories as $cat) {
  447. $targets[] = [$cat->get_id(), $cat->get_name(), $level + 1];
  448. $targets = $this->addTargetSubcategories(
  449. $targets,
  450. $level + 1,
  451. $cat->get_id()
  452. );
  453. }
  454. return $targets;
  455. }
  456. /**
  457. * Move this link to the given category.
  458. * If this link moves to outside a course, delete it.
  459. */
  460. public function move_to_cat($cat)
  461. {
  462. if ($this->get_course_code() != $cat->get_course_code()) {
  463. $this->delete();
  464. } else {
  465. $this->set_category_id($cat->get_id());
  466. $this->save();
  467. }
  468. }
  469. /**
  470. * Find links by name
  471. * To keep consistency, do not call this method but LinkFactory::find_links instead.
  472. *
  473. * @todo can be written more efficiently using a new (but very complex) sql query
  474. *
  475. * @param string $name_mask
  476. *
  477. * @return array
  478. */
  479. public function find_links($name_mask, $selectcat)
  480. {
  481. $rootcat = Category::load($selectcat);
  482. $links = $rootcat[0]->get_links((api_is_allowed_to_edit() ? null : api_get_user_id()), true);
  483. $foundlinks = [];
  484. foreach ($links as $link) {
  485. if (!(api_strpos(api_strtolower($link->get_name()), api_strtolower($name_mask)) === false)) {
  486. $foundlinks[] = $link;
  487. }
  488. }
  489. return $foundlinks;
  490. }
  491. /**
  492. * @return string
  493. */
  494. public function get_item_type()
  495. {
  496. return 'L';
  497. }
  498. /**
  499. * @return string
  500. */
  501. public function get_icon_name()
  502. {
  503. return 'link';
  504. }
  505. public function get_all_links()
  506. {
  507. return [];
  508. }
  509. public function add_linked_data()
  510. {
  511. }
  512. public function save_linked_data()
  513. {
  514. }
  515. public function delete_linked_data()
  516. {
  517. }
  518. /**
  519. * @param string $name
  520. */
  521. public function set_name($name)
  522. {
  523. }
  524. /**
  525. * @param string $description
  526. */
  527. public function set_description($description)
  528. {
  529. }
  530. /**
  531. * @param int $max
  532. */
  533. public function set_max($max)
  534. {
  535. }
  536. public function get_view_url($stud_id)
  537. {
  538. return null;
  539. }
  540. /**
  541. * Locks a link.
  542. *
  543. * @param int $locked 1 or unlocked 0
  544. *
  545. * */
  546. public function lock($locked)
  547. {
  548. $table = Database::get_main_table(TABLE_MAIN_GRADEBOOK_LINK);
  549. $sql = "UPDATE $table SET locked = '".intval($locked)."'
  550. WHERE id='".$this->id."'";
  551. Database::query($sql);
  552. }
  553. /**
  554. * Get current user ranking.
  555. *
  556. * @param int $userId
  557. * @param array $studentList Array with user id and scores
  558. * Example: [1 => 5.00, 2 => 8.00]
  559. *
  560. * @return array
  561. */
  562. public static function getCurrentUserRanking($userId, $studentList)
  563. {
  564. $ranking = null;
  565. $currentUserId = $userId;
  566. if (!empty($studentList) && !empty($currentUserId)) {
  567. $studentList = array_map('floatval', $studentList);
  568. asort($studentList);
  569. $ranking = $count = count($studentList);
  570. foreach ($studentList as $userId => $position) {
  571. if ($currentUserId == $userId) {
  572. break;
  573. }
  574. $ranking--;
  575. }
  576. // If no ranking was detected.
  577. if ($ranking == 0) {
  578. return [];
  579. }
  580. return [$ranking, $count];
  581. }
  582. return [];
  583. }
  584. /**
  585. * @return string
  586. */
  587. public function getSkillsFromItem()
  588. {
  589. $toolType = '';
  590. switch ($this->type) {
  591. case LINK_ATTENDANCE:
  592. $toolType = ITEM_TYPE_ATTENDANCE;
  593. break;
  594. case LINK_EXERCISE:
  595. $toolType = ITEM_TYPE_EXERCISE;
  596. break;
  597. case LINK_FORUM_THREAD:
  598. $toolType = ITEM_TYPE_FORUM_THREAD;
  599. break;
  600. case LINK_LEARNPATH:
  601. $toolType = ITEM_TYPE_LEARNPATH;
  602. break;
  603. case LINK_HOTPOTATOES:
  604. $toolType = ITEM_TYPE_HOTPOTATOES;
  605. break;
  606. case LINK_STUDENTPUBLICATION:
  607. $toolType = ITEM_TYPE_STUDENT_PUBLICATION;
  608. break;
  609. case LINK_SURVEY:
  610. $toolType = ITEM_TYPE_SURVEY;
  611. break;
  612. }
  613. $skillToString = Skill::getSkillRelItemsToString($toolType, $this->get_ref_id());
  614. return $skillToString;
  615. }
  616. /**
  617. * @param int $itemId
  618. * @param int $linkType
  619. * @param string $courseCode
  620. * @param int $sessionId
  621. *
  622. * @return array|bool|\Doctrine\DBAL\Driver\Statement
  623. */
  624. public static function getGradebookLinksFromItem($itemId, $linkType, $courseCode, $sessionId = 0)
  625. {
  626. if (empty($courseCode) || empty($itemId) || empty($linkType)) {
  627. return false;
  628. }
  629. $table = Database::get_main_table(TABLE_MAIN_GRADEBOOK_LINK);
  630. $tableCategory = Database::get_main_table(TABLE_MAIN_GRADEBOOK_CATEGORY);
  631. $itemId = (int) $itemId;
  632. $linkType = (int) $linkType;
  633. $sessionId = (int) $sessionId;
  634. $courseCode = Database::escape_string($courseCode);
  635. $sql = "SELECT DISTINCT l.*
  636. FROM $table l INNER JOIN $tableCategory c
  637. ON (c.course_code = l.course_code AND c.id = l.category_id)
  638. WHERE
  639. ref_id = $itemId AND
  640. type = $linkType AND
  641. l.course_code = '$courseCode' AND
  642. c.session_id = $sessionId";
  643. $result = Database::query($sql);
  644. if (Database::num_rows($result)) {
  645. $result = Database::store_result($result);
  646. return $result;
  647. }
  648. return false;
  649. }
  650. /**
  651. * @param Doctrine\DBAL\Driver\Statement|null $result
  652. *
  653. * @return array
  654. */
  655. private static function create_objects_from_sql_result($result)
  656. {
  657. $links = [];
  658. $allow = api_get_configuration_value('allow_gradebook_stats');
  659. if ($allow) {
  660. $em = Database::getManager();
  661. $repo = $em->getRepository('ChamiloCoreBundle:GradebookLink');
  662. }
  663. while ($data = Database::fetch_array($result)) {
  664. $link = LinkFactory::create($data['type']);
  665. $link->set_id($data['id']);
  666. $link->set_type($data['type']);
  667. $link->set_ref_id($data['ref_id']);
  668. $link->set_user_id($data['user_id']);
  669. $link->set_course_code($data['course_code']);
  670. $link->set_category_id($data['category_id']);
  671. $link->set_date($data['created_at']);
  672. $link->set_weight($data['weight']);
  673. $link->set_visible($data['visible']);
  674. $link->set_locked($data['locked']);
  675. //session id should depend of the category --> $data['category_id']
  676. $session_id = api_get_session_id();
  677. $link->set_session_id($session_id);
  678. if ($allow) {
  679. $link->entity = $repo->find($data['id']);
  680. }
  681. $links[] = $link;
  682. }
  683. return $links;
  684. }
  685. /**
  686. * Internal function used by get_target_categories().
  687. *
  688. * @param array $targets
  689. * @param int $level
  690. * @param int $catid
  691. *
  692. * @return array
  693. */
  694. private function addTargetSubcategories($targets, $level, $catid)
  695. {
  696. $subcats = Category::load(null, null, null, $catid);
  697. foreach ($subcats as $cat) {
  698. $targets[] = [$cat->get_id(), $cat->get_name(), $level + 1];
  699. $targets = $this->addTargetSubcategories(
  700. $targets,
  701. $level + 1,
  702. $cat->get_id()
  703. );
  704. }
  705. return $targets;
  706. }
  707. }