PageRenderTime 48ms CodeModel.GetById 17ms RepoModel.GetById 0ms app.codeStats 0ms

/lib/grouplib.php

https://bitbucket.org/kudutest1/moodlegit
PHP | 933 lines | 493 code | 120 blank | 320 comment | 138 complexity | 159f08395883d8b394b2fa6368472b2b MD5 | raw file
  1. <?php
  2. // This file is part of Moodle - http://moodle.org/
  3. //
  4. // Moodle is free software: you can redistribute it and/or modify
  5. // it under the terms of the GNU General Public License as published by
  6. // the Free Software Foundation, either version 3 of the License, or
  7. // (at your option) any later version.
  8. //
  9. // Moodle is distributed in the hope that it will be useful,
  10. // but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. // GNU General Public License for more details.
  13. //
  14. // You should have received a copy of the GNU General Public License
  15. // along with Moodle. If not, see <http://www.gnu.org/licenses/>.
  16. /**
  17. * @copyright 1999 onwards Martin Dougiamas {@link http://moodle.com}
  18. * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  19. * @package core_group
  20. */
  21. defined('MOODLE_INTERNAL') || die();
  22. /**
  23. * Groups not used in course or activity
  24. */
  25. define('NOGROUPS', 0);
  26. /**
  27. * Groups used, users do not see other groups
  28. */
  29. define('SEPARATEGROUPS', 1);
  30. /**
  31. * Groups used, students see other groups
  32. */
  33. define('VISIBLEGROUPS', 2);
  34. /**
  35. * Determines if a group with a given groupid exists.
  36. *
  37. * @category group
  38. * @param int $groupid The groupid to check for
  39. * @return bool True if the group exists, false otherwise or if an error
  40. * occurred.
  41. */
  42. function groups_group_exists($groupid) {
  43. global $DB;
  44. return $DB->record_exists('groups', array('id'=>$groupid));
  45. }
  46. /**
  47. * Gets the name of a group with a specified id
  48. *
  49. * @category group
  50. * @param int $groupid The id of the group
  51. * @return string The name of the group
  52. */
  53. function groups_get_group_name($groupid) {
  54. global $DB;
  55. return $DB->get_field('groups', 'name', array('id'=>$groupid));
  56. }
  57. /**
  58. * Gets the name of a grouping with a specified id
  59. *
  60. * @category group
  61. * @param int $groupingid The id of the grouping
  62. * @return string The name of the grouping
  63. */
  64. function groups_get_grouping_name($groupingid) {
  65. global $DB;
  66. return $DB->get_field('groupings', 'name', array('id'=>$groupingid));
  67. }
  68. /**
  69. * Returns the groupid of a group with the name specified for the course.
  70. * Group names should be unique in course
  71. *
  72. * @category group
  73. * @param int $courseid The id of the course
  74. * @param string $name name of group (without magic quotes)
  75. * @return int $groupid
  76. */
  77. function groups_get_group_by_name($courseid, $name) {
  78. $data = groups_get_course_data($courseid);
  79. foreach ($data->groups as $group) {
  80. if ($group->name == $name) {
  81. return $group->id;
  82. }
  83. }
  84. return false;
  85. }
  86. /**
  87. * Returns the groupid of a group with the idnumber specified for the course.
  88. * Group idnumbers should be unique within course
  89. *
  90. * @category group
  91. * @param int $courseid The id of the course
  92. * @param string $idnumber idnumber of group
  93. * @return group object
  94. */
  95. function groups_get_group_by_idnumber($courseid, $idnumber) {
  96. if (empty($idnumber)) {
  97. return false;
  98. }
  99. $data = groups_get_course_data($courseid);
  100. foreach ($data->groups as $group) {
  101. if ($group->idnumber == $idnumber) {
  102. return $group;
  103. }
  104. }
  105. return false;
  106. }
  107. /**
  108. * Returns the groupingid of a grouping with the name specified for the course.
  109. * Grouping names should be unique in course
  110. *
  111. * @category group
  112. * @param int $courseid The id of the course
  113. * @param string $name name of group (without magic quotes)
  114. * @return int $groupid
  115. */
  116. function groups_get_grouping_by_name($courseid, $name) {
  117. $data = groups_get_course_data($courseid);
  118. foreach ($data->groupings as $grouping) {
  119. if ($grouping->name == $name) {
  120. return $grouping->id;
  121. }
  122. }
  123. return false;
  124. }
  125. /**
  126. * Returns the groupingid of a grouping with the idnumber specified for the course.
  127. * Grouping names should be unique within course
  128. *
  129. * @category group
  130. * @param int $courseid The id of the course
  131. * @param string $idnumber idnumber of the group
  132. * @return grouping object
  133. */
  134. function groups_get_grouping_by_idnumber($courseid, $idnumber) {
  135. if (empty($idnumber)) {
  136. return false;
  137. }
  138. $data = groups_get_course_data($courseid);
  139. foreach ($data->groupings as $grouping) {
  140. if ($grouping->idnumber == $idnumber) {
  141. return $grouping;
  142. }
  143. }
  144. return false;
  145. }
  146. /**
  147. * Get the group object
  148. *
  149. * @category group
  150. * @param int $groupid ID of the group.
  151. * @param string $fields (default is all fields)
  152. * @param int $strictness (IGNORE_MISSING - default)
  153. * @return stdGlass group object
  154. */
  155. function groups_get_group($groupid, $fields='*', $strictness=IGNORE_MISSING) {
  156. global $DB;
  157. return $DB->get_record('groups', array('id'=>$groupid), $fields, $strictness);
  158. }
  159. /**
  160. * Get the grouping object
  161. *
  162. * @category group
  163. * @param int $groupingid ID of the group.
  164. * @param string $fields
  165. * @param int $strictness (IGNORE_MISSING - default)
  166. * @return stdClass group object
  167. */
  168. function groups_get_grouping($groupingid, $fields='*', $strictness=IGNORE_MISSING) {
  169. global $DB;
  170. return $DB->get_record('groupings', array('id'=>$groupingid), $fields, $strictness);
  171. }
  172. /**
  173. * Gets array of all groups in a specified course.
  174. *
  175. * @category group
  176. * @param int $courseid The id of the course.
  177. * @param mixed $userid optional user id or array of ids, returns only groups of the user.
  178. * @param int $groupingid optional returns only groups in the specified grouping.
  179. * @param string $fields
  180. * @return array Returns an array of the group objects (userid field returned if array in $userid)
  181. */
  182. function groups_get_all_groups($courseid, $userid=0, $groupingid=0, $fields='g.*') {
  183. global $DB;
  184. // We need to check that we each field in the fields list belongs to the group table and that it has not being
  185. // aliased. If its something else we need to avoid the cache and run the query as who knows whats going on.
  186. $knownfields = true;
  187. if ($fields !== 'g.*') {
  188. $fieldbits = explode(',', $fields);
  189. foreach ($fieldbits as $bit) {
  190. $bit = trim($bit);
  191. if (strpos($bit, 'g.') !== 0 or stripos($bit, ' AS ') !== false) {
  192. $knownfields = false;
  193. break;
  194. }
  195. }
  196. }
  197. if (empty($userid) && $knownfields) {
  198. // We can use the cache.
  199. $data = groups_get_course_data($courseid);
  200. if (empty($groupingid)) {
  201. // All groups.. Easy!
  202. $groups = $data->groups;
  203. } else {
  204. $groups = array();
  205. foreach ($data->mappings as $mapping) {
  206. if ($mapping->groupingid != $groupingid) {
  207. continue;
  208. }
  209. if (isset($data->groups[$mapping->groupid])) {
  210. $groups[$mapping->groupid] = $data->groups[$mapping->groupid];
  211. }
  212. }
  213. }
  214. // Yay! We could use the cache. One more query saved.
  215. return $groups;
  216. }
  217. if (empty($userid)) {
  218. $userfrom = "";
  219. $userwhere = "";
  220. $params = array();
  221. } else {
  222. list($usql, $params) = $DB->get_in_or_equal($userid);
  223. $userfrom = ", {groups_members} gm";
  224. $userwhere = "AND g.id = gm.groupid AND gm.userid $usql";
  225. }
  226. if (!empty($groupingid)) {
  227. $groupingfrom = ", {groupings_groups} gg";
  228. $groupingwhere = "AND g.id = gg.groupid AND gg.groupingid = ?";
  229. $params[] = $groupingid;
  230. } else {
  231. $groupingfrom = "";
  232. $groupingwhere = "";
  233. }
  234. array_unshift($params, $courseid);
  235. return $DB->get_records_sql("SELECT $fields
  236. FROM {groups} g $userfrom $groupingfrom
  237. WHERE g.courseid = ? $userwhere $groupingwhere
  238. ORDER BY name ASC", $params);
  239. }
  240. /**
  241. * Gets array of all groups in current user.
  242. *
  243. * @since Moodle 2.5
  244. * @category group
  245. * @return array Returns an array of the group objects.
  246. */
  247. function groups_get_my_groups() {
  248. global $DB, $USER;
  249. return $DB->get_records_sql("SELECT *
  250. FROM {groups_members} gm
  251. JOIN {groups} g
  252. ON g.id = gm.groupid
  253. WHERE gm.userid = ?
  254. ORDER BY name ASC", array($USER->id));
  255. }
  256. /**
  257. * Returns info about user's groups in course.
  258. *
  259. * @category group
  260. * @param int $courseid
  261. * @param int $userid $USER if not specified
  262. * @return array Array[groupingid][groupid] including grouping id 0 which means all groups
  263. */
  264. function groups_get_user_groups($courseid, $userid=0) {
  265. global $USER, $DB;
  266. if (empty($userid)) {
  267. $userid = $USER->id;
  268. }
  269. $sql = "SELECT g.id, gg.groupingid
  270. FROM {groups} g
  271. JOIN {groups_members} gm ON gm.groupid = g.id
  272. LEFT JOIN {groupings_groups} gg ON gg.groupid = g.id
  273. WHERE gm.userid = ? AND g.courseid = ?";
  274. $params = array($userid, $courseid);
  275. $rs = $DB->get_recordset_sql($sql, $params);
  276. if (!$rs->valid()) {
  277. $rs->close(); // Not going to iterate (but exit), close rs
  278. return array('0' => array());
  279. }
  280. $result = array();
  281. $allgroups = array();
  282. foreach ($rs as $group) {
  283. $allgroups[$group->id] = $group->id;
  284. if (is_null($group->groupingid)) {
  285. continue;
  286. }
  287. if (!array_key_exists($group->groupingid, $result)) {
  288. $result[$group->groupingid] = array();
  289. }
  290. $result[$group->groupingid][$group->id] = $group->id;
  291. }
  292. $rs->close();
  293. $result['0'] = array_keys($allgroups); // all groups
  294. return $result;
  295. }
  296. /**
  297. * Gets an array of all groupings in a specified course. This value is cached
  298. * for a single course (so you can call it repeatedly for the same course
  299. * without a performance penalty).
  300. *
  301. * @category group
  302. * @param int $courseid return all groupings from course with this courseid
  303. * @return array Returns an array of the grouping objects (empty if none)
  304. */
  305. function groups_get_all_groupings($courseid) {
  306. $data = groups_get_course_data($courseid);
  307. return $data->groupings;
  308. }
  309. /**
  310. * Determines if the user is a member of the given group.
  311. *
  312. * If $userid is null, use the global object.
  313. *
  314. * @category group
  315. * @param int $groupid The group to check for membership.
  316. * @param int $userid The user to check against the group.
  317. * @return bool True if the user is a member, false otherwise.
  318. */
  319. function groups_is_member($groupid, $userid=null) {
  320. global $USER, $DB;
  321. if (!$userid) {
  322. $userid = $USER->id;
  323. }
  324. return $DB->record_exists('groups_members', array('groupid'=>$groupid, 'userid'=>$userid));
  325. }
  326. /**
  327. * Determines if current or specified is member of any active group in activity
  328. *
  329. * @category group
  330. * @staticvar array $cache
  331. * @param cm_info $cm course module object
  332. * @param int $userid id of user, null means $USER->id
  333. * @return bool true if user member of at least one group used in activity
  334. */
  335. function groups_has_membership($cm, $userid=null) {
  336. global $CFG, $USER, $DB;
  337. static $cache = array();
  338. if (empty($userid)) {
  339. $userid = $USER->id;
  340. }
  341. $cachekey = $userid.'|'.$cm->course.'|'.$cm->groupingid;
  342. if (isset($cache[$cachekey])) {
  343. return($cache[$cachekey]);
  344. }
  345. if ($cm->groupingid) {
  346. // find out if member of any group in selected activity grouping
  347. $sql = "SELECT 'x'
  348. FROM {groups_members} gm, {groupings_groups} gg
  349. WHERE gm.userid = ? AND gm.groupid = gg.groupid AND gg.groupingid = ?";
  350. $params = array($userid, $cm->groupingid);
  351. } else {
  352. // no grouping used - check all groups in course
  353. $sql = "SELECT 'x'
  354. FROM {groups_members} gm, {groups} g
  355. WHERE gm.userid = ? AND gm.groupid = g.id AND g.courseid = ?";
  356. $params = array($userid, $cm->course);
  357. }
  358. $cache[$cachekey] = $DB->record_exists_sql($sql, $params);
  359. return $cache[$cachekey];
  360. }
  361. /**
  362. * Returns the users in the specified group.
  363. *
  364. * @category group
  365. * @param int $groupid The groupid to get the users for
  366. * @param int $fields The fields to return
  367. * @param int $sort optional sorting of returned users
  368. * @return array|bool Returns an array of the users for the specified
  369. * group or false if no users or an error returned.
  370. */
  371. function groups_get_members($groupid, $fields='u.*', $sort='lastname ASC') {
  372. global $DB;
  373. return $DB->get_records_sql("SELECT $fields
  374. FROM {user} u, {groups_members} gm
  375. WHERE u.id = gm.userid AND gm.groupid = ?
  376. ORDER BY $sort", array($groupid));
  377. }
  378. /**
  379. * Returns the users in the specified grouping.
  380. *
  381. * @category group
  382. * @param int $groupingid The groupingid to get the users for
  383. * @param string $fields The fields to return
  384. * @param string $sort optional sorting of returned users
  385. * @return array|bool Returns an array of the users for the specified
  386. * group or false if no users or an error returned.
  387. */
  388. function groups_get_grouping_members($groupingid, $fields='u.*', $sort='lastname ASC') {
  389. global $DB;
  390. return $DB->get_records_sql("SELECT $fields
  391. FROM {user} u
  392. INNER JOIN {groups_members} gm ON u.id = gm.userid
  393. INNER JOIN {groupings_groups} gg ON gm.groupid = gg.groupid
  394. WHERE gg.groupingid = ?
  395. ORDER BY $sort", array($groupingid));
  396. }
  397. /**
  398. * Returns effective groupmode used in course
  399. *
  400. * @category group
  401. * @param stdClass $course course object.
  402. * @return int group mode
  403. */
  404. function groups_get_course_groupmode($course) {
  405. return $course->groupmode;
  406. }
  407. /**
  408. * Returns effective groupmode used in activity, course setting
  409. * overrides activity setting if groupmodeforce enabled.
  410. *
  411. * @category group
  412. * @param cm_info $cm the course module object. Only the ->course and ->groupmode need to be set.
  413. * @param stdClass $course object optional course object to improve perf
  414. * @return int group mode
  415. */
  416. function groups_get_activity_groupmode($cm, $course=null) {
  417. global $COURSE, $DB;
  418. // get course object (reuse COURSE if possible)
  419. if (isset($course->id) and $course->id == $cm->course) {
  420. //ok
  421. } else if ($cm->course == $COURSE->id) {
  422. $course = $COURSE;
  423. } else {
  424. if (!$course = $DB->get_record('course', array('id'=>$cm->course))) {
  425. print_error('invalidcourseid');
  426. }
  427. }
  428. return empty($course->groupmodeforce) ? $cm->groupmode : $course->groupmode;
  429. }
  430. /**
  431. * Print group menu selector for course level.
  432. *
  433. * @category group
  434. * @param stdClass $course course object
  435. * @param mixed $urlroot return address. Accepts either a string or a moodle_url
  436. * @param bool $return return as string instead of printing
  437. * @return mixed void or string depending on $return param
  438. */
  439. function groups_print_course_menu($course, $urlroot, $return=false) {
  440. global $USER, $OUTPUT;
  441. if (!$groupmode = $course->groupmode) {
  442. if ($return) {
  443. return '';
  444. } else {
  445. return;
  446. }
  447. }
  448. $context = context_course::instance($course->id);
  449. $aag = has_capability('moodle/site:accessallgroups', $context);
  450. if ($groupmode == VISIBLEGROUPS or $aag) {
  451. $allowedgroups = groups_get_all_groups($course->id, 0, $course->defaultgroupingid);
  452. } else {
  453. $allowedgroups = groups_get_all_groups($course->id, $USER->id, $course->defaultgroupingid);
  454. }
  455. $activegroup = groups_get_course_group($course, true, $allowedgroups);
  456. $groupsmenu = array();
  457. if (!$allowedgroups or $groupmode == VISIBLEGROUPS or $aag) {
  458. $groupsmenu[0] = get_string('allparticipants');
  459. }
  460. if ($allowedgroups) {
  461. foreach ($allowedgroups as $group) {
  462. $groupsmenu[$group->id] = format_string($group->name);
  463. }
  464. }
  465. if ($groupmode == VISIBLEGROUPS) {
  466. $grouplabel = get_string('groupsvisible');
  467. } else {
  468. $grouplabel = get_string('groupsseparate');
  469. }
  470. if ($aag and $course->defaultgroupingid) {
  471. if ($grouping = groups_get_grouping($course->defaultgroupingid)) {
  472. $grouplabel = $grouplabel . ' (' . format_string($grouping->name) . ')';
  473. }
  474. }
  475. if (count($groupsmenu) == 1) {
  476. $groupname = reset($groupsmenu);
  477. $output = $grouplabel.': '.$groupname;
  478. } else {
  479. $select = new single_select(new moodle_url($urlroot), 'group', $groupsmenu, $activegroup, null, 'selectgroup');
  480. $select->label = $grouplabel;
  481. $output = $OUTPUT->render($select);
  482. }
  483. $output = '<div class="groupselector">'.$output.'</div>';
  484. if ($return) {
  485. return $output;
  486. } else {
  487. echo $output;
  488. }
  489. }
  490. /**
  491. * Print group menu selector for activity.
  492. *
  493. * @category group
  494. * @param stdClass $cm course module object
  495. * @param string|moodle_url $urlroot return address that users get to if they choose an option;
  496. * should include any parameters needed, e.g. "$CFG->wwwroot/mod/forum/view.php?id=34"
  497. * @param bool $return return as string instead of printing
  498. * @param bool $hideallparticipants If true, this prevents the 'All participants'
  499. * option from appearing in cases where it normally would. This is intended for
  500. * use only by activities that cannot display all groups together. (Note that
  501. * selecting this option does not prevent groups_get_activity_group from
  502. * returning 0; it will still do that if the user has chosen 'all participants'
  503. * in another activity, or not chosen anything.)
  504. * @return mixed void or string depending on $return param
  505. */
  506. function groups_print_activity_menu($cm, $urlroot, $return=false, $hideallparticipants=false) {
  507. global $USER, $OUTPUT;
  508. if ($urlroot instanceof moodle_url) {
  509. // no changes necessary
  510. } else {
  511. if (strpos($urlroot, 'http') !== 0) { // Will also work for https
  512. // Display error if urlroot is not absolute (this causes the non-JS version to break)
  513. debugging('groups_print_activity_menu requires absolute URL for ' .
  514. '$urlroot, not <tt>' . s($urlroot) . '</tt>. Example: ' .
  515. 'groups_print_activity_menu($cm, $CFG->wwwroot . \'/mod/mymodule/view.php?id=13\');',
  516. DEBUG_DEVELOPER);
  517. }
  518. $urlroot = new moodle_url($urlroot);
  519. }
  520. if (!$groupmode = groups_get_activity_groupmode($cm)) {
  521. if ($return) {
  522. return '';
  523. } else {
  524. return;
  525. }
  526. }
  527. $context = context_module::instance($cm->id);
  528. $aag = has_capability('moodle/site:accessallgroups', $context);
  529. if ($groupmode == VISIBLEGROUPS or $aag) {
  530. $allowedgroups = groups_get_all_groups($cm->course, 0, $cm->groupingid); // any group in grouping
  531. } else {
  532. $allowedgroups = groups_get_all_groups($cm->course, $USER->id, $cm->groupingid); // only assigned groups
  533. }
  534. $activegroup = groups_get_activity_group($cm, true, $allowedgroups);
  535. $groupsmenu = array();
  536. if ((!$allowedgroups or $groupmode == VISIBLEGROUPS or $aag) and !$hideallparticipants) {
  537. $groupsmenu[0] = get_string('allparticipants');
  538. }
  539. if ($allowedgroups) {
  540. foreach ($allowedgroups as $group) {
  541. $groupsmenu[$group->id] = format_string($group->name);
  542. }
  543. }
  544. if ($groupmode == VISIBLEGROUPS) {
  545. $grouplabel = get_string('groupsvisible');
  546. } else {
  547. $grouplabel = get_string('groupsseparate');
  548. }
  549. if ($aag and $cm->groupingid) {
  550. if ($grouping = groups_get_grouping($cm->groupingid)) {
  551. $grouplabel = $grouplabel . ' (' . format_string($grouping->name) . ')';
  552. }
  553. }
  554. if (count($groupsmenu) == 1) {
  555. $groupname = reset($groupsmenu);
  556. $output = $grouplabel.': '.$groupname;
  557. } else {
  558. $select = new single_select($urlroot, 'group', $groupsmenu, $activegroup, null, 'selectgroup');
  559. $select->label = $grouplabel;
  560. $output = $OUTPUT->render($select);
  561. }
  562. $output = '<div class="groupselector">'.$output.'</div>';
  563. if ($return) {
  564. return $output;
  565. } else {
  566. echo $output;
  567. }
  568. }
  569. /**
  570. * Returns group active in course, changes the group by default if 'group' page param present
  571. *
  572. * @category group
  573. * @param stdClass $course course bject
  574. * @param bool $update change active group if group param submitted
  575. * @param array $allowedgroups list of groups user may access (INTERNAL, to be used only from groups_print_course_menu())
  576. * @return mixed false if groups not used, int if groups used, 0 means all groups (access must be verified in SEPARATE mode)
  577. */
  578. function groups_get_course_group($course, $update=false, $allowedgroups=null) {
  579. global $USER, $SESSION;
  580. if (!$groupmode = $course->groupmode) {
  581. // NOGROUPS used
  582. return false;
  583. }
  584. $context = context_course::instance($course->id);
  585. if (has_capability('moodle/site:accessallgroups', $context)) {
  586. $groupmode = 'aag';
  587. }
  588. if (!is_array($allowedgroups)) {
  589. if ($groupmode == VISIBLEGROUPS or $groupmode === 'aag') {
  590. $allowedgroups = groups_get_all_groups($course->id, 0, $course->defaultgroupingid);
  591. } else {
  592. $allowedgroups = groups_get_all_groups($course->id, $USER->id, $course->defaultgroupingid);
  593. }
  594. }
  595. _group_verify_activegroup($course->id, $groupmode, $course->defaultgroupingid, $allowedgroups);
  596. // set new active group if requested
  597. $changegroup = optional_param('group', -1, PARAM_INT);
  598. if ($update and $changegroup != -1) {
  599. if ($changegroup == 0) {
  600. // do not allow changing to all groups without accessallgroups capability
  601. if ($groupmode == VISIBLEGROUPS or $groupmode === 'aag') {
  602. $SESSION->activegroup[$course->id][$groupmode][$course->defaultgroupingid] = 0;
  603. }
  604. } else {
  605. if ($allowedgroups and array_key_exists($changegroup, $allowedgroups)) {
  606. $SESSION->activegroup[$course->id][$groupmode][$course->defaultgroupingid] = $changegroup;
  607. }
  608. }
  609. }
  610. return $SESSION->activegroup[$course->id][$groupmode][$course->defaultgroupingid];
  611. }
  612. /**
  613. * Returns group active in activity, changes the group by default if 'group' page param present
  614. *
  615. * @category group
  616. * @param stdClass $cm course module object
  617. * @param bool $update change active group if group param submitted
  618. * @param array $allowedgroups list of groups user may access (INTERNAL, to be used only from groups_print_activity_menu())
  619. * @return mixed false if groups not used, int if groups used, 0 means all groups (access must be verified in SEPARATE mode)
  620. */
  621. function groups_get_activity_group($cm, $update=false, $allowedgroups=null) {
  622. global $USER, $SESSION;
  623. if (!$groupmode = groups_get_activity_groupmode($cm)) {
  624. // NOGROUPS used
  625. return false;
  626. }
  627. $context = context_module::instance($cm->id);
  628. if (has_capability('moodle/site:accessallgroups', $context)) {
  629. $groupmode = 'aag';
  630. }
  631. if (!is_array($allowedgroups)) {
  632. if ($groupmode == VISIBLEGROUPS or $groupmode === 'aag') {
  633. $allowedgroups = groups_get_all_groups($cm->course, 0, $cm->groupingid);
  634. } else {
  635. $allowedgroups = groups_get_all_groups($cm->course, $USER->id, $cm->groupingid);
  636. }
  637. }
  638. _group_verify_activegroup($cm->course, $groupmode, $cm->groupingid, $allowedgroups);
  639. // set new active group if requested
  640. $changegroup = optional_param('group', -1, PARAM_INT);
  641. if ($update and $changegroup != -1) {
  642. if ($changegroup == 0) {
  643. // allgroups visible only in VISIBLEGROUPS or when accessallgroups
  644. if ($groupmode == VISIBLEGROUPS or $groupmode === 'aag') {
  645. $SESSION->activegroup[$cm->course][$groupmode][$cm->groupingid] = 0;
  646. }
  647. } else {
  648. if ($allowedgroups and array_key_exists($changegroup, $allowedgroups)) {
  649. $SESSION->activegroup[$cm->course][$groupmode][$cm->groupingid] = $changegroup;
  650. }
  651. }
  652. }
  653. return $SESSION->activegroup[$cm->course][$groupmode][$cm->groupingid];
  654. }
  655. /**
  656. * Gets a list of groups that the user is allowed to access within the
  657. * specified activity.
  658. *
  659. * @category group
  660. * @param stdClass $cm Course-module
  661. * @param int $userid User ID (defaults to current user)
  662. * @return array An array of group objects, or false if none
  663. */
  664. function groups_get_activity_allowed_groups($cm,$userid=0) {
  665. // Use current user by default
  666. global $USER;
  667. if(!$userid) {
  668. $userid=$USER->id;
  669. }
  670. // Get groupmode for activity, taking into account course settings
  671. $groupmode=groups_get_activity_groupmode($cm);
  672. // If visible groups mode, or user has the accessallgroups capability,
  673. // then they can access all groups for the activity...
  674. $context = context_module::instance($cm->id);
  675. if ($groupmode == VISIBLEGROUPS or has_capability('moodle/site:accessallgroups', $context)) {
  676. return groups_get_all_groups($cm->course, 0, $cm->groupingid);
  677. } else {
  678. // ...otherwise they can only access groups they belong to
  679. return groups_get_all_groups($cm->course, $userid, $cm->groupingid);
  680. }
  681. }
  682. /**
  683. * Determine if a course module is currently visible to a user
  684. *
  685. * $USER If $userid is null, use the global object.
  686. *
  687. * @category group
  688. * @param stdClass $cm The course module
  689. * @param int $userid The user to check against the group.
  690. * @return bool True if the user can view the course module, false otherwise.
  691. */
  692. function groups_course_module_visible($cm, $userid=null) {
  693. global $CFG, $USER;
  694. if (empty($userid)) {
  695. $userid = $USER->id;
  696. }
  697. if (empty($CFG->enablegroupmembersonly)) {
  698. return true;
  699. }
  700. if (empty($cm->groupmembersonly)) {
  701. return true;
  702. }
  703. if (has_capability('moodle/site:accessallgroups', context_module::instance($cm->id), $userid) or groups_has_membership($cm, $userid)) {
  704. return true;
  705. }
  706. return false;
  707. }
  708. /**
  709. * Internal method, sets up $SESSION->activegroup and verifies previous value
  710. *
  711. * @param int $courseid
  712. * @param int|string $groupmode SEPARATEGROUPS, VISIBLEGROUPS or 'aag' (access all groups)
  713. * @param int $groupingid 0 means all groups
  714. * @param array $allowedgroups list of groups user can see
  715. */
  716. function _group_verify_activegroup($courseid, $groupmode, $groupingid, array $allowedgroups) {
  717. global $SESSION, $USER;
  718. // init activegroup array if necessary
  719. if (!isset($SESSION->activegroup)) {
  720. $SESSION->activegroup = array();
  721. }
  722. if (!array_key_exists($courseid, $SESSION->activegroup)) {
  723. $SESSION->activegroup[$courseid] = array(SEPARATEGROUPS=>array(), VISIBLEGROUPS=>array(), 'aag'=>array());
  724. }
  725. // make sure that the current group info is ok
  726. if (array_key_exists($groupingid, $SESSION->activegroup[$courseid][$groupmode]) and !array_key_exists($SESSION->activegroup[$courseid][$groupmode][$groupingid], $allowedgroups)) {
  727. // active group does not exist anymore or is 0
  728. if ($SESSION->activegroup[$courseid][$groupmode][$groupingid] > 0 or $groupmode == SEPARATEGROUPS) {
  729. // do not do this if all groups selected and groupmode is not separate
  730. unset($SESSION->activegroup[$courseid][$groupmode][$groupingid]);
  731. }
  732. }
  733. // set up defaults if necessary
  734. if (!array_key_exists($groupingid, $SESSION->activegroup[$courseid][$groupmode])) {
  735. if ($groupmode == 'aag') {
  736. $SESSION->activegroup[$courseid][$groupmode][$groupingid] = 0; // all groups by default if user has accessallgroups
  737. } else if ($allowedgroups) {
  738. if ($groupmode != SEPARATEGROUPS and $mygroups = groups_get_all_groups($courseid, $USER->id, $groupingid)) {
  739. $firstgroup = reset($mygroups);
  740. } else {
  741. $firstgroup = reset($allowedgroups);
  742. }
  743. $SESSION->activegroup[$courseid][$groupmode][$groupingid] = $firstgroup->id;
  744. } else {
  745. // this happen when user not assigned into group in SEPARATEGROUPS mode or groups do not exist yet
  746. // mod authors must add extra checks for this when SEPARATEGROUPS mode used (such as when posting to forum)
  747. $SESSION->activegroup[$courseid][$groupmode][$groupingid] = 0;
  748. }
  749. }
  750. }
  751. /**
  752. * Caches group data for a particular course to speed up subsequent requests.
  753. *
  754. * @param int $courseid The course id to cache data for.
  755. * @param cache $cache The cache if it has already been initialised. If not a new one will be created.
  756. * @return stdClass A data object containing groups, groupings, and mappings.
  757. */
  758. function groups_cache_groupdata($courseid, cache $cache = null) {
  759. global $DB;
  760. if ($cache === null) {
  761. // Initialise a cache if we wern't given one.
  762. $cache = cache::make('core', 'groupdata');
  763. }
  764. // Get the groups that belong to the course.
  765. $groups = $DB->get_records('groups', array('courseid' => $courseid), 'name ASC');
  766. // Get the groupings that belong to the course.
  767. $groupings = $DB->get_records('groupings', array('courseid' => $courseid), 'name ASC');
  768. if (!is_array($groups)) {
  769. $groups = array();
  770. }
  771. if (!is_array($groupings)) {
  772. $groupings = array();
  773. }
  774. if (!empty($groupings)) {
  775. // Finally get the mappings between the two.
  776. $mappings = $DB->get_records_list('groupings_groups', 'groupingid', array_keys($groupings), '', 'id,groupingid,groupid');
  777. } else {
  778. $mappings = array();
  779. }
  780. // Prepare the data array.
  781. $data = new stdClass;
  782. $data->groups = $groups;
  783. $data->groupings = $groupings;
  784. $data->mappings = $mappings;
  785. // Cache the data.
  786. $cache->set($courseid, $data);
  787. // Finally return it so it can be used if desired.
  788. return $data;
  789. }
  790. /**
  791. * Gets group data for a course.
  792. *
  793. * This returns an object with the following properties:
  794. * - groups : An array of all the groups in the course.
  795. * - groupings : An array of all the groupings within the course.
  796. * - mappings : An array of group to grouping mappings.
  797. *
  798. * @param int $courseid The course id to get data for.
  799. * @param cache $cache The cache if it has already been initialised. If not a new one will be created.
  800. * @return stdClass
  801. */
  802. function groups_get_course_data($courseid, cache $cache = null) {
  803. if ($cache === null) {
  804. // Initialise a cache if we wern't given one.
  805. $cache = cache::make('core', 'groupdata');
  806. }
  807. // Try to retrieve it from the cache.
  808. $data = $cache->get($courseid);
  809. if ($data === false) {
  810. $data = groups_cache_groupdata($courseid, $cache);
  811. }
  812. return $data;
  813. }