[ Index ]

PHP Cross Reference of moodle-2.8

title

Body

[close]

/group/ -> lib.php (source)

   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  
  18  /**
  19   * Extra library for groups and groupings.
  20   *
  21   * @copyright 2006 The Open University, J.White AT open.ac.uk, Petr Skoda (skodak)
  22   * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  23   * @package   core_group
  24   */
  25  
  26  /*
  27   * INTERNAL FUNCTIONS - to be used by moodle core only
  28   * require_once $CFG->dirroot.'/group/lib.php' must be used
  29   */
  30  
  31  /**
  32   * Adds a specified user to a group
  33   *
  34   * @param mixed $grouporid  The group id or group object
  35   * @param mixed $userorid   The user id or user object
  36   * @param string $component Optional component name e.g. 'enrol_imsenterprise'
  37   * @param int $itemid Optional itemid associated with component
  38   * @return bool True if user added successfully or the user is already a
  39   * member of the group, false otherwise.
  40   */
  41  function groups_add_member($grouporid, $userorid, $component=null, $itemid=0) {
  42      global $DB;
  43  
  44      if (is_object($userorid)) {
  45          $userid = $userorid->id;
  46          $user   = $userorid;
  47          if (!isset($user->deleted)) {
  48              $user = $DB->get_record('user', array('id'=>$userid), '*', MUST_EXIST);
  49          }
  50      } else {
  51          $userid = $userorid;
  52          $user = $DB->get_record('user', array('id'=>$userid), '*', MUST_EXIST);
  53      }
  54  
  55      if ($user->deleted) {
  56          return false;
  57      }
  58  
  59      if (is_object($grouporid)) {
  60          $groupid = $grouporid->id;
  61          $group   = $grouporid;
  62      } else {
  63          $groupid = $grouporid;
  64          $group = $DB->get_record('groups', array('id'=>$groupid), '*', MUST_EXIST);
  65      }
  66  
  67      // Check if the user a participant of the group course.
  68      $context = context_course::instance($group->courseid);
  69      if (!is_enrolled($context, $userid)) {
  70          return false;
  71      }
  72  
  73      if (groups_is_member($groupid, $userid)) {
  74          return true;
  75      }
  76  
  77      $member = new stdClass();
  78      $member->groupid   = $groupid;
  79      $member->userid    = $userid;
  80      $member->timeadded = time();
  81      $member->component = '';
  82      $member->itemid = 0;
  83  
  84      // Check the component exists if specified
  85      if (!empty($component)) {
  86          $dir = core_component::get_component_directory($component);
  87          if ($dir && is_dir($dir)) {
  88              // Component exists and can be used
  89              $member->component = $component;
  90              $member->itemid = $itemid;
  91          } else {
  92              throw new coding_exception('Invalid call to groups_add_member(). An invalid component was specified');
  93          }
  94      }
  95  
  96      if ($itemid !== 0 && empty($member->component)) {
  97          // An itemid can only be specified if a valid component was found
  98          throw new coding_exception('Invalid call to groups_add_member(). A component must be specified if an itemid is given');
  99      }
 100  
 101      $DB->insert_record('groups_members', $member);
 102  
 103      // Update group info, and group object.
 104      $DB->set_field('groups', 'timemodified', $member->timeadded, array('id'=>$groupid));
 105      $group->timemodified = $member->timeadded;
 106  
 107      // Trigger group event.
 108      $params = array(
 109          'context' => $context,
 110          'objectid' => $groupid,
 111          'relateduserid' => $userid,
 112          'other' => array(
 113              'component' => $member->component,
 114              'itemid' => $member->itemid
 115          )
 116      );
 117      $event = \core\event\group_member_added::create($params);
 118      $event->add_record_snapshot('groups', $group);
 119      $event->trigger();
 120  
 121      return true;
 122  }
 123  
 124  /**
 125   * Checks whether the current user is permitted (using the normal UI) to
 126   * remove a specific group member, assuming that they have access to remove
 127   * group members in general.
 128   *
 129   * For automatically-created group member entries, this checks with the
 130   * relevant plugin to see whether it is permitted. The default, if the plugin
 131   * doesn't provide a function, is true.
 132   *
 133   * For other entries (and any which have already been deleted/don't exist) it
 134   * just returns true.
 135   *
 136   * @param mixed $grouporid The group id or group object
 137   * @param mixed $userorid The user id or user object
 138   * @return bool True if permitted, false otherwise
 139   */
 140  function groups_remove_member_allowed($grouporid, $userorid) {
 141      global $DB;
 142  
 143      if (is_object($userorid)) {
 144          $userid = $userorid->id;
 145      } else {
 146          $userid = $userorid;
 147      }
 148      if (is_object($grouporid)) {
 149          $groupid = $grouporid->id;
 150      } else {
 151          $groupid = $grouporid;
 152      }
 153  
 154      // Get entry
 155      if (!($entry = $DB->get_record('groups_members',
 156              array('groupid' => $groupid, 'userid' => $userid), '*', IGNORE_MISSING))) {
 157          // If the entry does not exist, they are allowed to remove it (this
 158          // is consistent with groups_remove_member below).
 159          return true;
 160      }
 161  
 162      // If the entry does not have a component value, they can remove it
 163      if (empty($entry->component)) {
 164          return true;
 165      }
 166  
 167      // It has a component value, so we need to call a plugin function (if it
 168      // exists); the default is to allow removal
 169      return component_callback($entry->component, 'allow_group_member_remove',
 170              array($entry->itemid, $entry->groupid, $entry->userid), true);
 171  }
 172  
 173  /**
 174   * Deletes the link between the specified user and group.
 175   *
 176   * @param mixed $grouporid  The group id or group object
 177   * @param mixed $userorid   The user id or user object
 178   * @return bool True if deletion was successful, false otherwise
 179   */
 180  function groups_remove_member($grouporid, $userorid) {
 181      global $DB;
 182  
 183      if (is_object($userorid)) {
 184          $userid = $userorid->id;
 185      } else {
 186          $userid = $userorid;
 187      }
 188  
 189      if (is_object($grouporid)) {
 190          $groupid = $grouporid->id;
 191          $group   = $grouporid;
 192      } else {
 193          $groupid = $grouporid;
 194          $group = $DB->get_record('groups', array('id'=>$groupid), '*', MUST_EXIST);
 195      }
 196  
 197      if (!groups_is_member($groupid, $userid)) {
 198          return true;
 199      }
 200  
 201      $DB->delete_records('groups_members', array('groupid'=>$groupid, 'userid'=>$userid));
 202  
 203      // Update group info.
 204      $time = time();
 205      $DB->set_field('groups', 'timemodified', $time, array('id' => $groupid));
 206      $group->timemodified = $time;
 207  
 208      // Trigger group event.
 209      $params = array(
 210          'context' => context_course::instance($group->courseid),
 211          'objectid' => $groupid,
 212          'relateduserid' => $userid
 213      );
 214      $event = \core\event\group_member_removed::create($params);
 215      $event->add_record_snapshot('groups', $group);
 216      $event->trigger();
 217  
 218      return true;
 219  }
 220  
 221  /**
 222   * Add a new group
 223   *
 224   * @param stdClass $data group properties
 225   * @param stdClass $editform
 226   * @param array $editoroptions
 227   * @return id of group or false if error
 228   */
 229  function groups_create_group($data, $editform = false, $editoroptions = false) {
 230      global $CFG, $DB;
 231  
 232      //check that courseid exists
 233      $course = $DB->get_record('course', array('id' => $data->courseid), '*', MUST_EXIST);
 234      $context = context_course::instance($course->id);
 235  
 236      $data->timecreated  = time();
 237      $data->timemodified = $data->timecreated;
 238      $data->name         = trim($data->name);
 239      if (isset($data->idnumber)) {
 240          $data->idnumber = trim($data->idnumber);
 241          if (groups_get_group_by_idnumber($course->id, $data->idnumber)) {
 242              throw new moodle_exception('idnumbertaken');
 243          }
 244      }
 245  
 246      if ($editform and $editoroptions) {
 247          $data->description = $data->description_editor['text'];
 248          $data->descriptionformat = $data->description_editor['format'];
 249      }
 250  
 251      $data->id = $DB->insert_record('groups', $data);
 252  
 253      if ($editform and $editoroptions) {
 254          // Update description from editor with fixed files
 255          $data = file_postupdate_standard_editor($data, 'description', $editoroptions, $context, 'group', 'description', $data->id);
 256          $upd = new stdClass();
 257          $upd->id                = $data->id;
 258          $upd->description       = $data->description;
 259          $upd->descriptionformat = $data->descriptionformat;
 260          $DB->update_record('groups', $upd);
 261      }
 262  
 263      $group = $DB->get_record('groups', array('id'=>$data->id));
 264  
 265      if ($editform) {
 266          groups_update_group_icon($group, $data, $editform);
 267      }
 268  
 269      // Invalidate the grouping cache for the course
 270      cache_helper::invalidate_by_definition('core', 'groupdata', array(), array($course->id));
 271  
 272      // Trigger group event.
 273      $params = array(
 274          'context' => $context,
 275          'objectid' => $group->id
 276      );
 277      $event = \core\event\group_created::create($params);
 278      $event->add_record_snapshot('groups', $group);
 279      $event->trigger();
 280  
 281      return $group->id;
 282  }
 283  
 284  /**
 285   * Add a new grouping
 286   *
 287   * @param stdClass $data grouping properties
 288   * @param array $editoroptions
 289   * @return id of grouping or false if error
 290   */
 291  function groups_create_grouping($data, $editoroptions=null) {
 292      global $DB;
 293  
 294      $data->timecreated  = time();
 295      $data->timemodified = $data->timecreated;
 296      $data->name         = trim($data->name);
 297      if (isset($data->idnumber)) {
 298          $data->idnumber = trim($data->idnumber);
 299          if (groups_get_grouping_by_idnumber($data->courseid, $data->idnumber)) {
 300              throw new moodle_exception('idnumbertaken');
 301          }
 302      }
 303  
 304      if ($editoroptions !== null) {
 305          $data->description = $data->description_editor['text'];
 306          $data->descriptionformat = $data->description_editor['format'];
 307      }
 308  
 309      $id = $DB->insert_record('groupings', $data);
 310      $data->id = $id;
 311  
 312      if ($editoroptions !== null) {
 313          $description = new stdClass;
 314          $description->id = $data->id;
 315          $description->description_editor = $data->description_editor;
 316          $description = file_postupdate_standard_editor($description, 'description', $editoroptions, $editoroptions['context'], 'grouping', 'description', $description->id);
 317          $DB->update_record('groupings', $description);
 318      }
 319  
 320      // Invalidate the grouping cache for the course
 321      cache_helper::invalidate_by_definition('core', 'groupdata', array(), array($data->courseid));
 322  
 323      // Trigger group event.
 324      $params = array(
 325          'context' => context_course::instance($data->courseid),
 326          'objectid' => $id
 327      );
 328      $event = \core\event\grouping_created::create($params);
 329      $event->trigger();
 330  
 331      return $id;
 332  }
 333  
 334  /**
 335   * Update the group icon from form data
 336   *
 337   * @param stdClass $group group information
 338   * @param stdClass $data
 339   * @param stdClass $editform
 340   */
 341  function groups_update_group_icon($group, $data, $editform) {
 342      global $CFG, $DB;
 343      require_once("$CFG->libdir/gdlib.php");
 344  
 345      $fs = get_file_storage();
 346      $context = context_course::instance($group->courseid, MUST_EXIST);
 347  
 348      //TODO: it would make sense to allow picture deleting too (skodak)
 349      if ($iconfile = $editform->save_temp_file('imagefile')) {
 350          if (process_new_icon($context, 'group', 'icon', $group->id, $iconfile)) {
 351              $DB->set_field('groups', 'picture', 1, array('id'=>$group->id));
 352              $group->picture = 1;
 353          } else {
 354              $fs->delete_area_files($context->id, 'group', 'icon', $group->id);
 355              $DB->set_field('groups', 'picture', 0, array('id'=>$group->id));
 356              $group->picture = 0;
 357          }
 358          @unlink($iconfile);
 359          // Invalidate the group data as we've updated the group record.
 360          cache_helper::invalidate_by_definition('core', 'groupdata', array(), array($group->courseid));
 361      }
 362  }
 363  
 364  /**
 365   * Update group
 366   *
 367   * @param stdClass $data group properties (with magic quotes)
 368   * @param stdClass $editform
 369   * @param array $editoroptions
 370   * @return bool true or exception
 371   */
 372  function groups_update_group($data, $editform = false, $editoroptions = false) {
 373      global $CFG, $DB;
 374  
 375      $context = context_course::instance($data->courseid);
 376  
 377      $data->timemodified = time();
 378      if (isset($data->name)) {
 379          $data->name = trim($data->name);
 380      }
 381      if (isset($data->idnumber)) {
 382          $data->idnumber = trim($data->idnumber);
 383          if (($existing = groups_get_group_by_idnumber($data->courseid, $data->idnumber)) && $existing->id != $data->id) {
 384              throw new moodle_exception('idnumbertaken');
 385          }
 386      }
 387  
 388      if ($editform and $editoroptions) {
 389          $data = file_postupdate_standard_editor($data, 'description', $editoroptions, $context, 'group', 'description', $data->id);
 390      }
 391  
 392      $DB->update_record('groups', $data);
 393  
 394      // Invalidate the group data.
 395      cache_helper::invalidate_by_definition('core', 'groupdata', array(), array($data->courseid));
 396  
 397      $group = $DB->get_record('groups', array('id'=>$data->id));
 398  
 399      if ($editform) {
 400          groups_update_group_icon($group, $data, $editform);
 401      }
 402  
 403      // Trigger group event.
 404      $params = array(
 405          'context' => $context,
 406          'objectid' => $group->id
 407      );
 408      $event = \core\event\group_updated::create($params);
 409      $event->add_record_snapshot('groups', $group);
 410      $event->trigger();
 411  
 412      return true;
 413  }
 414  
 415  /**
 416   * Update grouping
 417   *
 418   * @param stdClass $data grouping properties (with magic quotes)
 419   * @param array $editoroptions
 420   * @return bool true or exception
 421   */
 422  function groups_update_grouping($data, $editoroptions=null) {
 423      global $DB;
 424      $data->timemodified = time();
 425      if (isset($data->name)) {
 426          $data->name = trim($data->name);
 427      }
 428      if (isset($data->idnumber)) {
 429          $data->idnumber = trim($data->idnumber);
 430          if (($existing = groups_get_grouping_by_idnumber($data->courseid, $data->idnumber)) && $existing->id != $data->id) {
 431              throw new moodle_exception('idnumbertaken');
 432          }
 433      }
 434      if ($editoroptions !== null) {
 435          $data = file_postupdate_standard_editor($data, 'description', $editoroptions, $editoroptions['context'], 'grouping', 'description', $data->id);
 436      }
 437      $DB->update_record('groupings', $data);
 438  
 439      // Invalidate the group data.
 440      cache_helper::invalidate_by_definition('core', 'groupdata', array(), array($data->courseid));
 441  
 442      // Trigger group event.
 443      $params = array(
 444          'context' => context_course::instance($data->courseid),
 445          'objectid' => $data->id
 446      );
 447      $event = \core\event\grouping_updated::create($params);
 448      $event->trigger();
 449  
 450      return true;
 451  }
 452  
 453  /**
 454   * Delete a group best effort, first removing members and links with courses and groupings.
 455   * Removes group avatar too.
 456   *
 457   * @param mixed $grouporid The id of group to delete or full group object
 458   * @return bool True if deletion was successful, false otherwise
 459   */
 460  function groups_delete_group($grouporid) {
 461      global $CFG, $DB;
 462      require_once("$CFG->libdir/gdlib.php");
 463  
 464      if (is_object($grouporid)) {
 465          $groupid = $grouporid->id;
 466          $group   = $grouporid;
 467      } else {
 468          $groupid = $grouporid;
 469          if (!$group = $DB->get_record('groups', array('id'=>$groupid))) {
 470              //silently ignore attempts to delete missing already deleted groups ;-)
 471              return true;
 472          }
 473      }
 474  
 475      // delete group calendar events
 476      $DB->delete_records('event', array('groupid'=>$groupid));
 477      //first delete usage in groupings_groups
 478      $DB->delete_records('groupings_groups', array('groupid'=>$groupid));
 479      //delete members
 480      $DB->delete_records('groups_members', array('groupid'=>$groupid));
 481      //group itself last
 482      $DB->delete_records('groups', array('id'=>$groupid));
 483  
 484      // Delete all files associated with this group
 485      $context = context_course::instance($group->courseid);
 486      $fs = get_file_storage();
 487      $fs->delete_area_files($context->id, 'group', 'description', $groupid);
 488      $fs->delete_area_files($context->id, 'group', 'icon', $groupid);
 489  
 490      // Invalidate the grouping cache for the course
 491      cache_helper::invalidate_by_definition('core', 'groupdata', array(), array($group->courseid));
 492  
 493      // Trigger group event.
 494      $params = array(
 495          'context' => $context,
 496          'objectid' => $groupid
 497      );
 498      $event = \core\event\group_deleted::create($params);
 499      $event->add_record_snapshot('groups', $group);
 500      $event->trigger();
 501  
 502      return true;
 503  }
 504  
 505  /**
 506   * Delete grouping
 507   *
 508   * @param int $groupingorid
 509   * @return bool success
 510   */
 511  function groups_delete_grouping($groupingorid) {
 512      global $DB;
 513  
 514      if (is_object($groupingorid)) {
 515          $groupingid = $groupingorid->id;
 516          $grouping   = $groupingorid;
 517      } else {
 518          $groupingid = $groupingorid;
 519          if (!$grouping = $DB->get_record('groupings', array('id'=>$groupingorid))) {
 520              //silently ignore attempts to delete missing already deleted groupings ;-)
 521              return true;
 522          }
 523      }
 524  
 525      //first delete usage in groupings_groups
 526      $DB->delete_records('groupings_groups', array('groupingid'=>$groupingid));
 527      // remove the default groupingid from course
 528      $DB->set_field('course', 'defaultgroupingid', 0, array('defaultgroupingid'=>$groupingid));
 529      // remove the groupingid from all course modules
 530      $DB->set_field('course_modules', 'groupingid', 0, array('groupingid'=>$groupingid));
 531      //group itself last
 532      $DB->delete_records('groupings', array('id'=>$groupingid));
 533  
 534      $context = context_course::instance($grouping->courseid);
 535      $fs = get_file_storage();
 536      $files = $fs->get_area_files($context->id, 'grouping', 'description', $groupingid);
 537      foreach ($files as $file) {
 538          $file->delete();
 539      }
 540  
 541      // Invalidate the grouping cache for the course
 542      cache_helper::invalidate_by_definition('core', 'groupdata', array(), array($grouping->courseid));
 543  
 544      // Trigger group event.
 545      $params = array(
 546          'context' => $context,
 547          'objectid' => $groupingid
 548      );
 549      $event = \core\event\grouping_deleted::create($params);
 550      $event->add_record_snapshot('groupings', $grouping);
 551      $event->trigger();
 552  
 553      return true;
 554  }
 555  
 556  /**
 557   * Remove all users (or one user) from all groups in course
 558   *
 559   * @param int $courseid
 560   * @param int $userid 0 means all users
 561   * @param bool $showfeedback
 562   * @return bool success
 563   */
 564  function groups_delete_group_members($courseid, $userid=0, $showfeedback=false) {
 565      global $DB, $OUTPUT;
 566  
 567      if (is_bool($userid)) {
 568          debugging('Incorrect userid function parameter');
 569          return false;
 570      }
 571  
 572      // Select * so that the function groups_remove_member() gets the whole record.
 573      $groups = $DB->get_recordset('groups', array('courseid' => $courseid));
 574      foreach ($groups as $group) {
 575          if ($userid) {
 576              $userids = array($userid);
 577          } else {
 578              $userids = $DB->get_fieldset_select('groups_members', 'userid', 'groupid = :groupid', array('groupid' => $group->id));
 579          }
 580  
 581          foreach ($userids as $id) {
 582              groups_remove_member($group, $id);
 583          }
 584      }
 585  
 586      // TODO MDL-41312 Remove events_trigger_legacy('groups_members_removed').
 587      // This event is kept here for backwards compatibility, because it cannot be
 588      // translated to a new event as it is wrong.
 589      $eventdata = new stdClass();
 590      $eventdata->courseid = $courseid;
 591      $eventdata->userid   = $userid;
 592      events_trigger_legacy('groups_members_removed', $eventdata);
 593  
 594      if ($showfeedback) {
 595          echo $OUTPUT->notification(get_string('deleted').' - '.get_string('groupmembers', 'group'), 'notifysuccess');
 596      }
 597  
 598      return true;
 599  }
 600  
 601  /**
 602   * Remove all groups from all groupings in course
 603   *
 604   * @param int $courseid
 605   * @param bool $showfeedback
 606   * @return bool success
 607   */
 608  function groups_delete_groupings_groups($courseid, $showfeedback=false) {
 609      global $DB, $OUTPUT;
 610  
 611      $groupssql = "SELECT id FROM {groups} g WHERE g.courseid = ?";
 612      $results = $DB->get_recordset_select('groupings_groups', "groupid IN ($groupssql)",
 613          array($courseid), '', 'groupid, groupingid');
 614  
 615      foreach ($results as $result) {
 616          groups_unassign_grouping($result->groupingid, $result->groupid, false);
 617      }
 618  
 619      // Invalidate the grouping cache for the course
 620      cache_helper::invalidate_by_definition('core', 'groupdata', array(), array($courseid));
 621  
 622      // TODO MDL-41312 Remove events_trigger_legacy('groups_groupings_groups_removed').
 623      // This event is kept here for backwards compatibility, because it cannot be
 624      // translated to a new event as it is wrong.
 625      events_trigger_legacy('groups_groupings_groups_removed', $courseid);
 626  
 627      // no need to show any feedback here - we delete usually first groupings and then groups
 628  
 629      return true;
 630  }
 631  
 632  /**
 633   * Delete all groups from course
 634   *
 635   * @param int $courseid
 636   * @param bool $showfeedback
 637   * @return bool success
 638   */
 639  function groups_delete_groups($courseid, $showfeedback=false) {
 640      global $CFG, $DB, $OUTPUT;
 641  
 642      $groups = $DB->get_recordset('groups', array('courseid' => $courseid));
 643      foreach ($groups as $group) {
 644          groups_delete_group($group);
 645      }
 646  
 647      // Invalidate the grouping cache for the course
 648      cache_helper::invalidate_by_definition('core', 'groupdata', array(), array($courseid));
 649  
 650      // TODO MDL-41312 Remove events_trigger_legacy('groups_groups_deleted').
 651      // This event is kept here for backwards compatibility, because it cannot be
 652      // translated to a new event as it is wrong.
 653      events_trigger_legacy('groups_groups_deleted', $courseid);
 654  
 655      if ($showfeedback) {
 656          echo $OUTPUT->notification(get_string('deleted').' - '.get_string('groups', 'group'), 'notifysuccess');
 657      }
 658  
 659      return true;
 660  }
 661  
 662  /**
 663   * Delete all groupings from course
 664   *
 665   * @param int $courseid
 666   * @param bool $showfeedback
 667   * @return bool success
 668   */
 669  function groups_delete_groupings($courseid, $showfeedback=false) {
 670      global $DB, $OUTPUT;
 671  
 672      $groupings = $DB->get_recordset_select('groupings', 'courseid = ?', array($courseid));
 673      foreach ($groupings as $grouping) {
 674          groups_delete_grouping($grouping);
 675      }
 676  
 677      // Invalidate the grouping cache for the course.
 678      cache_helper::invalidate_by_definition('core', 'groupdata', array(), array($courseid));
 679  
 680      // TODO MDL-41312 Remove events_trigger_legacy('groups_groupings_deleted').
 681      // This event is kept here for backwards compatibility, because it cannot be
 682      // translated to a new event as it is wrong.
 683      events_trigger_legacy('groups_groupings_deleted', $courseid);
 684  
 685      if ($showfeedback) {
 686          echo $OUTPUT->notification(get_string('deleted').' - '.get_string('groupings', 'group'), 'notifysuccess');
 687      }
 688  
 689      return true;
 690  }
 691  
 692  /* =================================== */
 693  /* various functions used by groups UI */
 694  /* =================================== */
 695  
 696  /**
 697   * Obtains a list of the possible roles that group members might come from,
 698   * on a course. Generally this includes only profile roles.
 699   *
 700   * @param context $context Context of course
 701   * @return Array of role ID integers, or false if error/none.
 702   */
 703  function groups_get_possible_roles($context) {
 704      $roles = get_profile_roles($context);
 705      return array_keys($roles);
 706  }
 707  
 708  
 709  /**
 710   * Gets potential group members for grouping
 711   *
 712   * @param int $courseid The id of the course
 713   * @param int $roleid The role to select users from
 714   * @param mixed $source restrict to cohort, grouping or group id
 715   * @param string $orderby The column to sort users by
 716   * @param int $notingroup restrict to users not in existing groups
 717   * @return array An array of the users
 718   */
 719  function groups_get_potential_members($courseid, $roleid = null, $source = null,
 720                                        $orderby = 'lastname ASC, firstname ASC',
 721                                        $notingroup = null) {
 722      global $DB;
 723  
 724      $context = context_course::instance($courseid);
 725  
 726      list($esql, $params) = get_enrolled_sql($context);
 727  
 728      $notingroupsql = "";
 729      if ($notingroup) {
 730          // We want to eliminate users that are already associated with a course group.
 731          $notingroupsql = "u.id NOT IN (SELECT userid
 732                                           FROM {groups_members}
 733                                          WHERE groupid IN (SELECT id
 734                                                              FROM {groups}
 735                                                             WHERE courseid = :courseid))";
 736          $params['courseid'] = $courseid;
 737      }
 738  
 739      if ($roleid) {
 740          // We are looking for all users with this role assigned in this context or higher.
 741          list($relatedctxsql, $relatedctxparams) = $DB->get_in_or_equal($context->get_parent_context_ids(true),
 742                                                                         SQL_PARAMS_NAMED,
 743                                                                         'relatedctx');
 744  
 745          $params = array_merge($params, $relatedctxparams, array('roleid' => $roleid));
 746          $where = "WHERE u.id IN (SELECT userid
 747                                     FROM {role_assignments}
 748                                    WHERE roleid = :roleid AND contextid $relatedctxsql)";
 749          $where .= $notingroup ? "AND $notingroupsql" : "";
 750      } else if ($notingroup) {
 751          $where = "WHERE $notingroupsql";
 752      } else {
 753          $where = "";
 754      }
 755  
 756      $sourcejoin = "";
 757      if (is_int($source)) {
 758          $sourcejoin .= "JOIN {cohort_members} cm ON (cm.userid = u.id AND cm.cohortid = :cohortid) ";
 759          $params['cohortid'] = $source;
 760      } else {
 761          // Auto-create groups from an existing cohort membership.
 762          if (isset($source['cohortid'])) {
 763              $sourcejoin .= "JOIN {cohort_members} cm ON (cm.userid = u.id AND cm.cohortid = :cohortid) ";
 764              $params['cohortid'] = $source['cohortid'];
 765          }
 766          // Auto-create groups from an existing group membership.
 767          if (isset($source['groupid'])) {
 768              $sourcejoin .= "JOIN {groups_members} gp ON (gp.userid = u.id AND gp.groupid = :groupid) ";
 769              $params['groupid'] = $source['groupid'];
 770          }
 771          // Auto-create groups from an existing grouping membership.
 772          if (isset($source['groupingid'])) {
 773              $sourcejoin .= "JOIN {groupings_groups} gg ON gg.groupingid = :groupingid ";
 774              $sourcejoin .= "JOIN {groups_members} gm ON (gm.userid = u.id AND gm.groupid = gg.groupid) ";
 775              $params['groupingid'] = $source['groupingid'];
 776          }
 777      }
 778  
 779      $allusernamefields = get_all_user_name_fields(true, 'u');
 780      $sql = "SELECT DISTINCT u.id, u.username, $allusernamefields, u.idnumber
 781                FROM {user} u
 782                JOIN ($esql) e ON e.id = u.id
 783         $sourcejoin
 784              $where
 785            ORDER BY $orderby";
 786  
 787      return $DB->get_records_sql($sql, $params);
 788  
 789  }
 790  
 791  /**
 792   * Parse a group name for characters to replace
 793   *
 794   * @param string $format The format a group name will follow
 795   * @param int $groupnumber The number of the group to be used in the parsed format string
 796   * @return string the parsed format string
 797   */
 798  function groups_parse_name($format, $groupnumber) {
 799      if (strstr($format, '@') !== false) { // Convert $groupnumber to a character series
 800          $letter = 'A';
 801          for($i=0; $i<$groupnumber; $i++) {
 802              $letter++;
 803          }
 804          $str = str_replace('@', $letter, $format);
 805      } else {
 806          $str = str_replace('#', $groupnumber+1, $format);
 807      }
 808      return($str);
 809  }
 810  
 811  /**
 812   * Assigns group into grouping
 813   *
 814   * @param int groupingid
 815   * @param int groupid
 816   * @param int $timeadded  The time the group was added to the grouping.
 817   * @param bool $invalidatecache If set to true the course group cache will be invalidated as well.
 818   * @return bool true or exception
 819   */
 820  function groups_assign_grouping($groupingid, $groupid, $timeadded = null, $invalidatecache = true) {
 821      global $DB;
 822  
 823      if ($DB->record_exists('groupings_groups', array('groupingid'=>$groupingid, 'groupid'=>$groupid))) {
 824          return true;
 825      }
 826      $assign = new stdClass();
 827      $assign->groupingid = $groupingid;
 828      $assign->groupid    = $groupid;
 829      if ($timeadded != null) {
 830          $assign->timeadded = (integer)$timeadded;
 831      } else {
 832          $assign->timeadded = time();
 833      }
 834      $DB->insert_record('groupings_groups', $assign);
 835  
 836      if ($invalidatecache) {
 837          // Invalidate the grouping cache for the course
 838          $courseid = $DB->get_field('groupings', 'courseid', array('id' => $groupingid));
 839          cache_helper::invalidate_by_definition('core', 'groupdata', array(), array($courseid));
 840      }
 841  
 842      return true;
 843  }
 844  
 845  /**
 846   * Unassigns group from grouping
 847   *
 848   * @param int groupingid
 849   * @param int groupid
 850   * @param bool $invalidatecache If set to true the course group cache will be invalidated as well.
 851   * @return bool success
 852   */
 853  function groups_unassign_grouping($groupingid, $groupid, $invalidatecache = true) {
 854      global $DB;
 855      $DB->delete_records('groupings_groups', array('groupingid'=>$groupingid, 'groupid'=>$groupid));
 856  
 857      if ($invalidatecache) {
 858          // Invalidate the grouping cache for the course
 859          $courseid = $DB->get_field('groupings', 'courseid', array('id' => $groupingid));
 860          cache_helper::invalidate_by_definition('core', 'groupdata', array(), array($courseid));
 861      }
 862  
 863      return true;
 864  }
 865  
 866  /**
 867   * Lists users in a group based on their role on the course.
 868   * Returns false if there's an error or there are no users in the group.
 869   * Otherwise returns an array of role ID => role data, where role data includes:
 870   * (role) $id, $shortname, $name
 871   * $users: array of objects for each user which include the specified fields
 872   * Users who do not have a role are stored in the returned array with key '-'
 873   * and pseudo-role details (including a name, 'No role'). Users with multiple
 874   * roles, same deal with key '*' and name 'Multiple roles'. You can find out
 875   * which roles each has by looking in the $roles array of the user object.
 876   *
 877   * @param int $groupid
 878   * @param int $courseid Course ID (should match the group's course)
 879   * @param string $fields List of fields from user table prefixed with u, default 'u.*'
 880   * @param string $sort SQL ORDER BY clause, default (when null passed) is what comes from users_order_by_sql.
 881   * @param string $extrawheretest extra SQL conditions ANDed with the existing where clause.
 882   * @param array $whereorsortparams any parameters required by $extrawheretest (named parameters).
 883   * @return array Complex array as described above
 884   */
 885  function groups_get_members_by_role($groupid, $courseid, $fields='u.*',
 886          $sort=null, $extrawheretest='', $whereorsortparams=array()) {
 887      global $DB;
 888  
 889      // Retrieve information about all users and their roles on the course or
 890      // parent ('related') contexts
 891      $context = context_course::instance($courseid);
 892  
 893      // We are looking for all users with this role assigned in this context or higher.
 894      list($relatedctxsql, $relatedctxparams) = $DB->get_in_or_equal($context->get_parent_context_ids(true), SQL_PARAMS_NAMED, 'relatedctx');
 895  
 896      if ($extrawheretest) {
 897          $extrawheretest = ' AND ' . $extrawheretest;
 898      }
 899  
 900      if (is_null($sort)) {
 901          list($sort, $sortparams) = users_order_by_sql('u');
 902          $whereorsortparams = array_merge($whereorsortparams, $sortparams);
 903      }
 904  
 905      $sql = "SELECT r.id AS roleid, u.id AS userid, $fields
 906                FROM {groups_members} gm
 907                JOIN {user} u ON u.id = gm.userid
 908           LEFT JOIN {role_assignments} ra ON (ra.userid = u.id AND ra.contextid $relatedctxsql)
 909           LEFT JOIN {role} r ON r.id = ra.roleid
 910               WHERE gm.groupid=:mgroupid
 911                     ".$extrawheretest."
 912            ORDER BY r.sortorder, $sort";
 913      $whereorsortparams = array_merge($whereorsortparams, $relatedctxparams, array('mgroupid' => $groupid));
 914      $rs = $DB->get_recordset_sql($sql, $whereorsortparams);
 915  
 916      return groups_calculate_role_people($rs, $context);
 917  }
 918  
 919  /**
 920   * Internal function used by groups_get_members_by_role to handle the
 921   * results of a database query that includes a list of users and possible
 922   * roles on a course.
 923   *
 924   * @param moodle_recordset $rs The record set (may be false)
 925   * @param int $context ID of course context
 926   * @return array As described in groups_get_members_by_role
 927   */
 928  function groups_calculate_role_people($rs, $context) {
 929      global $CFG, $DB;
 930  
 931      if (!$rs) {
 932          return array();
 933      }
 934  
 935      $allroles = role_fix_names(get_all_roles($context), $context);
 936  
 937      // Array of all involved roles
 938      $roles = array();
 939      // Array of all retrieved users
 940      $users = array();
 941      // Fill arrays
 942      foreach ($rs as $rec) {
 943          // Create information about user if this is a new one
 944          if (!array_key_exists($rec->userid, $users)) {
 945              // User data includes all the optional fields, but not any of the
 946              // stuff we added to get the role details
 947              $userdata = clone($rec);
 948              unset($userdata->roleid);
 949              unset($userdata->roleshortname);
 950              unset($userdata->rolename);
 951              unset($userdata->userid);
 952              $userdata->id = $rec->userid;
 953  
 954              // Make an array to hold the list of roles for this user
 955              $userdata->roles = array();
 956              $users[$rec->userid] = $userdata;
 957          }
 958          // If user has a role...
 959          if (!is_null($rec->roleid)) {
 960              // Create information about role if this is a new one
 961              if (!array_key_exists($rec->roleid, $roles)) {
 962                  $role = $allroles[$rec->roleid];
 963                  $roledata = new stdClass();
 964                  $roledata->id        = $role->id;
 965                  $roledata->shortname = $role->shortname;
 966                  $roledata->name      = $role->localname;
 967                  $roledata->users = array();
 968                  $roles[$roledata->id] = $roledata;
 969              }
 970              // Record that user has role
 971              $users[$rec->userid]->roles[$rec->roleid] = $roles[$rec->roleid];
 972          }
 973      }
 974      $rs->close();
 975  
 976      // Return false if there weren't any users
 977      if (count($users) == 0) {
 978          return false;
 979      }
 980  
 981      // Add pseudo-role for multiple roles
 982      $roledata = new stdClass();
 983      $roledata->name = get_string('multipleroles','role');
 984      $roledata->users = array();
 985      $roles['*'] = $roledata;
 986  
 987      $roledata = new stdClass();
 988      $roledata->name = get_string('noroles','role');
 989      $roledata->users = array();
 990      $roles[0] = $roledata;
 991  
 992      // Now we rearrange the data to store users by role
 993      foreach ($users as $userid=>$userdata) {
 994          $rolecount = count($userdata->roles);
 995          if ($rolecount == 0) {
 996              // does not have any roles
 997              $roleid = 0;
 998          } else if($rolecount > 1) {
 999              $roleid = '*';
1000          } else {
1001              $userrole = reset($userdata->roles);
1002              $roleid = $userrole->id;
1003          }
1004          $roles[$roleid]->users[$userid] = $userdata;
1005      }
1006  
1007      // Delete roles not used
1008      foreach ($roles as $key=>$roledata) {
1009          if (count($roledata->users)===0) {
1010              unset($roles[$key]);
1011          }
1012      }
1013  
1014      // Return list of roles containing their users
1015      return $roles;
1016  }


Generated: Fri Nov 28 20:29:05 2014 Cross-referenced by PHPXref 0.7.1