PageRenderTime 63ms CodeModel.GetById 35ms RepoModel.GetById 0ms app.codeStats 0ms

/availability/condition/group/classes/condition.php

https://github.com/arborrow/moodle
PHP | 270 lines | 166 code | 30 blank | 74 comment | 31 complexity | bf24ed0dd50dad29c2f18cf82c66eaae 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. * Condition main class.
  18. *
  19. * @package availability_group
  20. * @copyright 2014 The Open University
  21. * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  22. */
  23. namespace availability_group;
  24. defined('MOODLE_INTERNAL') || die();
  25. /**
  26. * Condition main class.
  27. *
  28. * @package availability_group
  29. * @copyright 2014 The Open University
  30. * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  31. */
  32. class condition extends \core_availability\condition {
  33. /** @var array Array from group id => name */
  34. protected static $groupnames = array();
  35. /** @var int ID of group that this condition requires, or 0 = any group */
  36. protected $groupid;
  37. /**
  38. * Constructor.
  39. *
  40. * @param \stdClass $structure Data structure from JSON decode
  41. * @throws \coding_exception If invalid data structure.
  42. */
  43. public function __construct($structure) {
  44. // Get group id.
  45. if (!property_exists($structure, 'id')) {
  46. $this->groupid = 0;
  47. } else if (is_int($structure->id)) {
  48. $this->groupid = $structure->id;
  49. } else {
  50. throw new \coding_exception('Invalid ->id for group condition');
  51. }
  52. }
  53. public function save() {
  54. $result = (object)array('type' => 'group');
  55. if ($this->groupid) {
  56. $result->id = $this->groupid;
  57. }
  58. return $result;
  59. }
  60. public function is_available($not, \core_availability\info $info, $grabthelot, $userid) {
  61. $course = $info->get_course();
  62. $context = \context_course::instance($course->id);
  63. $allow = true;
  64. if (!has_capability('moodle/site:accessallgroups', $context, $userid)) {
  65. // Get all groups the user belongs to.
  66. $groups = $info->get_modinfo()->get_groups();
  67. if ($this->groupid) {
  68. $allow = in_array($this->groupid, $groups);
  69. } else {
  70. // No specific group. Allow if they belong to any group at all.
  71. $allow = $groups ? true : false;
  72. }
  73. // The NOT condition applies before accessallgroups (i.e. if you
  74. // set something to be available to those NOT in group X,
  75. // people with accessallgroups can still access it even if
  76. // they are in group X).
  77. if ($not) {
  78. $allow = !$allow;
  79. }
  80. }
  81. return $allow;
  82. }
  83. public function get_description($full, $not, \core_availability\info $info) {
  84. global $DB;
  85. if ($this->groupid) {
  86. // Need to get the name for the group. Unfortunately this requires
  87. // a database query. To save queries, get all groups for course at
  88. // once in a static cache.
  89. $course = $info->get_course();
  90. if (!array_key_exists($this->groupid, self::$groupnames)) {
  91. $coursegroups = $DB->get_records(
  92. 'groups', array('courseid' => $course->id), '', 'id, name');
  93. foreach ($coursegroups as $rec) {
  94. self::$groupnames[$rec->id] = $rec->name;
  95. }
  96. }
  97. // If it still doesn't exist, it must have been misplaced.
  98. if (!array_key_exists($this->groupid, self::$groupnames)) {
  99. $name = get_string('missing', 'availability_group');
  100. } else {
  101. $context = \context_course::instance($course->id);
  102. $name = format_string(self::$groupnames[$this->groupid], true,
  103. array('context' => $context));
  104. }
  105. } else {
  106. return get_string($not ? 'requires_notanygroup' : 'requires_anygroup',
  107. 'availability_group');
  108. }
  109. return get_string($not ? 'requires_notgroup' : 'requires_group',
  110. 'availability_group', $name);
  111. }
  112. protected function get_debug_string() {
  113. return $this->groupid ? '#' . $this->groupid : 'any';
  114. }
  115. public function update_after_restore($restoreid, $courseid, \base_logger $logger, $name) {
  116. global $DB;
  117. if (!$this->groupid) {
  118. return false;
  119. }
  120. $rec = \restore_dbops::get_backup_ids_record($restoreid, 'group', $this->groupid);
  121. if (!$rec || !$rec->newitemid) {
  122. // If we are on the same course (e.g. duplicate) then we can just
  123. // use the existing one.
  124. if ($DB->record_exists('groups',
  125. array('id' => $this->groupid, 'courseid' => $courseid))) {
  126. return false;
  127. }
  128. // Otherwise it's a warning.
  129. $this->groupid = -1;
  130. $logger->process('Restored item (' . $name .
  131. ') has availability condition on group that was not restored',
  132. \backup::LOG_WARNING);
  133. } else {
  134. $this->groupid = (int)$rec->newitemid;
  135. }
  136. return true;
  137. }
  138. public function update_dependency_id($table, $oldid, $newid) {
  139. if ($table === 'groups' && (int)$this->groupid === (int)$oldid) {
  140. $this->groupid = $newid;
  141. return true;
  142. } else {
  143. return false;
  144. }
  145. }
  146. /**
  147. * Wipes the static cache used to store grouping names.
  148. */
  149. public static function wipe_static_cache() {
  150. self::$groupnames = array();
  151. }
  152. public function is_applied_to_user_lists() {
  153. // Group conditions are assumed to be 'permanent', so they affect the
  154. // display of user lists for activities.
  155. return true;
  156. }
  157. public function filter_user_list(array $users, $not, \core_availability\info $info,
  158. \core_availability\capability_checker $checker) {
  159. global $CFG, $DB;
  160. // If the array is empty already, just return it.
  161. if (!$users) {
  162. return $users;
  163. }
  164. require_once($CFG->libdir . '/grouplib.php');
  165. $course = $info->get_course();
  166. // List users for this course who match the condition.
  167. if ($this->groupid) {
  168. $groupusers = groups_get_members($this->groupid, 'u.id', 'u.id ASC');
  169. } else {
  170. $groupusers = $DB->get_records_sql("
  171. SELECT DISTINCT gm.userid
  172. FROM {groups} g
  173. JOIN {groups_members} gm ON gm.groupid = g.id
  174. WHERE g.courseid = ?", array($course->id));
  175. }
  176. // List users who have access all groups.
  177. $aagusers = $checker->get_users_by_capability('moodle/site:accessallgroups');
  178. // Filter the user list.
  179. $result = array();
  180. foreach ($users as $id => $user) {
  181. // Always include users with access all groups.
  182. if (array_key_exists($id, $aagusers)) {
  183. $result[$id] = $user;
  184. continue;
  185. }
  186. // Other users are included or not based on group membership.
  187. $allow = array_key_exists($id, $groupusers);
  188. if ($not) {
  189. $allow = !$allow;
  190. }
  191. if ($allow) {
  192. $result[$id] = $user;
  193. }
  194. }
  195. return $result;
  196. }
  197. /**
  198. * Returns a JSON object which corresponds to a condition of this type.
  199. *
  200. * Intended for unit testing, as normally the JSON values are constructed
  201. * by JavaScript code.
  202. *
  203. * @param int $groupid Required group id (0 = any group)
  204. * @return stdClass Object representing condition
  205. */
  206. public static function get_json($groupid = 0) {
  207. return (object)array('type' => 'group', 'id' => (int)$groupid);
  208. }
  209. public function get_user_list_sql($not, \core_availability\info $info, $onlyactive) {
  210. global $DB;
  211. // Get enrolled users with access all groups. These always are allowed.
  212. list($aagsql, $aagparams) = get_enrolled_sql(
  213. $info->get_context(), 'moodle/site:accessallgroups', 0, $onlyactive);
  214. // Get all enrolled users.
  215. list ($enrolsql, $enrolparams) =
  216. get_enrolled_sql($info->get_context(), '', 0, $onlyactive);
  217. // Condition for specified or any group.
  218. $matchparams = array();
  219. if ($this->groupid) {
  220. $matchsql = "SELECT 1
  221. FROM {groups_members} gm
  222. WHERE gm.userid = userids.id
  223. AND gm.groupid = " .
  224. self::unique_sql_parameter($matchparams, $this->groupid);
  225. } else {
  226. $matchsql = "SELECT 1
  227. FROM {groups_members} gm
  228. JOIN {groups} g ON g.id = gm.groupid
  229. WHERE gm.userid = userids.id
  230. AND g.courseid = " .
  231. self::unique_sql_parameter($matchparams, $info->get_course()->id);
  232. }
  233. // Overall query combines all this.
  234. $condition = $not ? 'NOT' : '';
  235. $sql = "SELECT userids.id
  236. FROM ($enrolsql) userids
  237. WHERE (userids.id IN ($aagsql)) OR $condition EXISTS ($matchsql)";
  238. return array($sql, array_merge($enrolparams, $aagparams, $matchparams));
  239. }
  240. }