[ Index ]

PHP Cross Reference of Unnamed Project

title

Body

[close]

/admin/roles/classes/ -> define_role_table_advanced.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   * Advanced role definition form.
  19   *
  20   * @package    core_role
  21   * @copyright  1999 onwards Martin Dougiamas (http://dougiamas.com)
  22   * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  23   */
  24  
  25  defined('MOODLE_INTERNAL') || die();
  26  
  27  
  28  /**
  29   * As well as tracking the permissions information about the role we are creating
  30   * or editing, we also track the other information about the role. (This class is
  31   * starting to be more and more like a formslib form in some respects.)
  32   */
  33  class core_role_define_role_table_advanced extends core_role_capability_table_with_risks {
  34      /** @var stdClass Used to store other information (besides permissions) about the role we are creating/editing. */
  35      protected $role;
  36      /** @var array Used to store errors found when validating the data. */
  37      protected $errors;
  38      protected $contextlevels;
  39      protected $allcontextlevels;
  40      protected $disabled = '';
  41  
  42      protected $allowassign;
  43      protected $allowoverride;
  44      protected $allowswitch;
  45  
  46      public function __construct($context, $roleid) {
  47          $this->roleid = $roleid;
  48          parent::__construct($context, 'defineroletable', $roleid);
  49          $this->displaypermissions = $this->allpermissions;
  50          $this->strperms[$this->allpermissions[CAP_INHERIT]] = get_string('notset', 'core_role');
  51  
  52          $this->allcontextlevels = array();
  53          $levels = context_helper::get_all_levels();
  54          foreach ($levels as $level => $classname) {
  55              $this->allcontextlevels[$level] = context_helper::get_level_name($level);
  56          }
  57      }
  58  
  59      protected function load_current_permissions() {
  60          global $DB;
  61          if ($this->roleid) {
  62              if (!$this->role = $DB->get_record('role', array('id' => $this->roleid))) {
  63                  throw new moodle_exception('invalidroleid');
  64              }
  65              $contextlevels = get_role_contextlevels($this->roleid);
  66              // Put the contextlevels in the array keys, as well as the values.
  67              if (!empty($contextlevels)) {
  68                  $this->contextlevels = array_combine($contextlevels, $contextlevels);
  69              } else {
  70                  $this->contextlevels = array();
  71              }
  72              $this->allowassign = array_keys($this->get_allow_roles_list('assign'));
  73              $this->allowoverride = array_keys($this->get_allow_roles_list('override'));
  74              $this->allowswitch = array_keys($this->get_allow_roles_list('switch'));
  75  
  76          } else {
  77              $this->role = new stdClass;
  78              $this->role->name = '';
  79              $this->role->shortname = '';
  80              $this->role->description = '';
  81              $this->role->archetype = '';
  82              $this->contextlevels = array();
  83              $this->allowassign = array();
  84              $this->allowoverride = array();
  85              $this->allowswitch = array();
  86          }
  87          parent::load_current_permissions();
  88      }
  89  
  90      public function read_submitted_permissions() {
  91          global $DB;
  92          $this->errors = array();
  93  
  94          // Role short name. We clean this in a special way. We want to end up
  95          // with only lowercase safe ASCII characters.
  96          $shortname = optional_param('shortname', null, PARAM_RAW);
  97          if (!is_null($shortname)) {
  98              $this->role->shortname = $shortname;
  99              $this->role->shortname = core_text::specialtoascii($this->role->shortname);
 100              $this->role->shortname = core_text::strtolower(clean_param($this->role->shortname, PARAM_ALPHANUMEXT));
 101              if (empty($this->role->shortname)) {
 102                  $this->errors['shortname'] = get_string('errorbadroleshortname', 'core_role');
 103              }
 104          }
 105          if ($DB->record_exists_select('role', 'shortname = ? and id <> ?', array($this->role->shortname, $this->roleid))) {
 106              $this->errors['shortname'] = get_string('errorexistsroleshortname', 'core_role');
 107          }
 108  
 109          // Role name.
 110          $name = optional_param('name', null, PARAM_TEXT);
 111          if (!is_null($name)) {
 112              $this->role->name = $name;
 113              // Hack: short names of standard roles are equal to archetypes, empty name means localised via lang packs.
 114              $archetypes = get_role_archetypes();
 115              if (!isset($archetypes[$shortname]) and html_is_blank($this->role->name)) {
 116                  $this->errors['name'] = get_string('errorbadrolename', 'core_role');
 117              }
 118          }
 119          if ($this->role->name !== '' and $DB->record_exists_select('role', 'name = ? and id <> ?', array($this->role->name, $this->roleid))) {
 120              $this->errors['name'] = get_string('errorexistsrolename', 'core_role');
 121          }
 122  
 123          // Description.
 124          $description = optional_param('description', null, PARAM_RAW);
 125          if (!is_null($description)) {
 126              $this->role->description = $description;
 127          }
 128  
 129          // Legacy type.
 130          $archetype = optional_param('archetype', null, PARAM_RAW);
 131          if (isset($archetype)) {
 132              $archetypes = get_role_archetypes();
 133              if (isset($archetypes[$archetype])) {
 134                  $this->role->archetype = $archetype;
 135              } else {
 136                  $this->role->archetype = '';
 137              }
 138          }
 139  
 140          // Assignable context levels.
 141          foreach ($this->allcontextlevels as $cl => $notused) {
 142              $assignable = optional_param('contextlevel' . $cl, null, PARAM_BOOL);
 143              if (!is_null($assignable)) {
 144                  if ($assignable) {
 145                      $this->contextlevels[$cl] = $cl;
 146                  } else {
 147                      unset($this->contextlevels[$cl]);
 148                  }
 149              }
 150          }
 151  
 152          // Allowed roles.
 153          $allow = optional_param_array('allowassign', null, PARAM_INT);
 154          if (!is_null($allow)) {
 155              $this->allowassign = $allow;
 156          }
 157          $allow = optional_param_array('allowoverride', null, PARAM_INT);
 158          if (!is_null($allow)) {
 159              $this->allowoverride = $allow;
 160          }
 161          $allow = optional_param_array('allowswitch', null, PARAM_INT);
 162          if (!is_null($allow)) {
 163              $this->allowswitch = $allow;
 164          }
 165  
 166          // Now read the permissions for each capability.
 167          parent::read_submitted_permissions();
 168      }
 169  
 170      public function is_submission_valid() {
 171          return empty($this->errors);
 172      }
 173  
 174      /**
 175       * Call this after the table has been initialised,
 176       * this resets everything to that role.
 177       *
 178       * @param int $roleid role id or 0 for no role
 179       * @param array $options array with following keys:
 180       *      'name', 'shortname', 'description', 'permissions', 'archetype',
 181       *      'contextlevels', 'allowassign', 'allowoverride', 'allowswitch'
 182       */
 183      public function force_duplicate($roleid, array $options) {
 184          global $DB;
 185  
 186          if ($roleid == 0) {
 187              // This means reset to nothing == remove everything.
 188  
 189              if ($options['shortname']) {
 190                  $this->role->shortname = '';
 191              }
 192  
 193              if ($options['name']) {
 194                  $this->role->name = '';
 195              }
 196  
 197              if ($options['description']) {
 198                  $this->role->description = '';
 199              }
 200  
 201              if ($options['archetype']) {
 202                  $this->role->archetype = '';
 203              }
 204  
 205              if ($options['contextlevels']) {
 206                  $this->contextlevels = array();
 207              }
 208  
 209              if ($options['allowassign']) {
 210                  $this->allowassign = array();
 211              }
 212              if ($options['allowoverride']) {
 213                  $this->allowoverride = array();
 214              }
 215              if ($options['allowswitch']) {
 216                  $this->allowswitch = array();
 217              }
 218  
 219              if ($options['permissions']) {
 220                  foreach ($this->capabilities as $capid => $cap) {
 221                      $this->permissions[$cap->name] = CAP_INHERIT;
 222                  }
 223              }
 224  
 225              return;
 226          }
 227  
 228          $role = $DB->get_record('role', array('id'=>$roleid), '*', MUST_EXIST);
 229  
 230          if ($options['shortname']) {
 231              $this->role->shortname = $role->shortname;
 232          }
 233  
 234          if ($options['name']) {
 235              $this->role->name = $role->name;
 236          }
 237  
 238          if ($options['description']) {
 239              $this->role->description = $role->description;
 240          }
 241  
 242          if ($options['archetype']) {
 243              $this->role->archetype = $role->archetype;
 244          }
 245  
 246          if ($options['contextlevels']) {
 247              $this->contextlevels = array();
 248              $levels = get_role_contextlevels($roleid);
 249              foreach ($levels as $cl) {
 250                  $this->contextlevels[$cl] = $cl;
 251              }
 252          }
 253  
 254          if ($options['allowassign']) {
 255              $this->allowassign = array_keys($this->get_allow_roles_list('assign', $roleid));
 256          }
 257          if ($options['allowoverride']) {
 258              $this->allowoverride = array_keys($this->get_allow_roles_list('override', $roleid));
 259          }
 260          if ($options['allowswitch']) {
 261              $this->allowswitch = array_keys($this->get_allow_roles_list('switch', $roleid));
 262          }
 263  
 264          if ($options['permissions']) {
 265              $this->permissions = $DB->get_records_menu('role_capabilities',
 266                  array('roleid' => $roleid, 'contextid' => context_system::instance()->id),
 267                  '', 'capability,permission');
 268  
 269              foreach ($this->capabilities as $capid => $cap) {
 270                  if (!isset($this->permissions[$cap->name])) {
 271                      $this->permissions[$cap->name] = CAP_INHERIT;
 272                  }
 273              }
 274          }
 275      }
 276  
 277      /**
 278       * Change the role definition to match given archetype.
 279       *
 280       * @param string $archetype
 281       * @param array $options array with following keys:
 282       *      'name', 'shortname', 'description', 'permissions', 'archetype',
 283       *      'contextlevels', 'allowassign', 'allowoverride', 'allowswitch'
 284       */
 285      public function force_archetype($archetype, array $options) {
 286          $archetypes = get_role_archetypes();
 287          if (!isset($archetypes[$archetype])) {
 288              throw new coding_exception('Unknown archetype: '.$archetype);
 289          }
 290  
 291          if ($options['shortname']) {
 292              $this->role->shortname = '';
 293          }
 294  
 295          if ($options['name']) {
 296              $this->role->name = '';
 297          }
 298  
 299          if ($options['description']) {
 300              $this->role->description = '';
 301          }
 302  
 303          if ($options['archetype']) {
 304              $this->role->archetype = $archetype;
 305          }
 306  
 307          if ($options['contextlevels']) {
 308              $this->contextlevels = array();
 309              $defaults = get_default_contextlevels($archetype);
 310              foreach ($defaults as $cl) {
 311                  $this->contextlevels[$cl] = $cl;
 312              }
 313          }
 314  
 315          if ($options['allowassign']) {
 316              $this->allowassign = get_default_role_archetype_allows('assign', $archetype);
 317          }
 318          if ($options['allowoverride']) {
 319              $this->allowoverride = get_default_role_archetype_allows('override', $archetype);
 320          }
 321          if ($options['allowswitch']) {
 322              $this->allowswitch = get_default_role_archetype_allows('switch', $archetype);
 323          }
 324  
 325          if ($options['permissions']) {
 326              $defaultpermissions = get_default_capabilities($archetype);
 327              foreach ($this->permissions as $k => $v) {
 328                  if (isset($defaultpermissions[$k])) {
 329                      $this->permissions[$k] = $defaultpermissions[$k];
 330                      continue;
 331                  }
 332                  $this->permissions[$k] = CAP_INHERIT;
 333              }
 334          }
 335      }
 336  
 337      /**
 338       * Change the role definition to match given preset.
 339       *
 340       * @param string $xml
 341       * @param array $options array with following keys:
 342       *      'name', 'shortname', 'description', 'permissions', 'archetype',
 343       *      'contextlevels', 'allowassign', 'allowoverride', 'allowswitch'
 344       */
 345      public function force_preset($xml, array $options) {
 346          if (!$info = core_role_preset::parse_preset($xml)) {
 347              throw new coding_exception('Invalid role preset');
 348          }
 349  
 350          if ($options['shortname']) {
 351              if (isset($info['shortname'])) {
 352                  $this->role->shortname = $info['shortname'];
 353              }
 354          }
 355  
 356          if ($options['name']) {
 357              if (isset($info['name'])) {
 358                  $this->role->name = $info['name'];
 359              }
 360          }
 361  
 362          if ($options['description']) {
 363              if (isset($info['description'])) {
 364                  $this->role->description = $info['description'];
 365              }
 366          }
 367  
 368          if ($options['archetype']) {
 369              if (isset($info['archetype'])) {
 370                  $this->role->archetype = $info['archetype'];
 371              }
 372          }
 373  
 374          if ($options['contextlevels']) {
 375              if (isset($info['contextlevels'])) {
 376                  $this->contextlevels = $info['contextlevels'];
 377              }
 378          }
 379  
 380          foreach (array('assign', 'override', 'switch') as $type) {
 381              if ($options['allow'.$type]) {
 382                  if (isset($info['allow'.$type])) {
 383                      $this->{'allow'.$type} = $info['allow'.$type];
 384                  }
 385              }
 386          }
 387  
 388          if ($options['permissions']) {
 389              foreach ($this->permissions as $k => $v) {
 390                  // Note: do not set everything else to CAP_INHERIT here
 391                  //       because the xml file might not contain all capabilities.
 392                  if (isset($info['permissions'][$k])) {
 393                      $this->permissions[$k] = $info['permissions'][$k];
 394                  }
 395              }
 396          }
 397      }
 398  
 399      public function get_role_name() {
 400          return $this->role->name;
 401      }
 402  
 403      public function get_role_id() {
 404          return $this->role->id;
 405      }
 406  
 407      public function get_archetype() {
 408          return $this->role->archetype;
 409      }
 410  
 411      protected function load_parent_permissions() {
 412          $this->parentpermissions = get_default_capabilities($this->role->archetype);
 413      }
 414  
 415      public function save_changes() {
 416          global $DB, $CFG;
 417  
 418          if (!$this->roleid) {
 419              // Creating role.
 420              $this->role->id = create_role($this->role->name, $this->role->shortname, $this->role->description, $this->role->archetype);
 421              $this->roleid = $this->role->id; // Needed to make the parent::save_changes(); call work.
 422          } else {
 423              // Updating role.
 424              $DB->update_record('role', $this->role);
 425  
 426              // This will ensure the course contacts cache is purged so name changes get updated in
 427              // the UI. It would be better to do this only when we know that fields affected are
 428              // updated. But thats getting into the weeds of the coursecat cache and role edits
 429              // should not be that frequent, so here is the ugly brutal approach.
 430              require_once($CFG->libdir . '/coursecatlib.php');
 431              coursecat::role_assignment_changed($this->role->id, context_system::instance());
 432          }
 433  
 434          // Assignable contexts.
 435          set_role_contextlevels($this->role->id, $this->contextlevels);
 436  
 437          // Set allowed roles.
 438          $this->save_allow('assign');
 439          $this->save_allow('override');
 440          $this->save_allow('switch');
 441  
 442          // Permissions.
 443          parent::save_changes();
 444      }
 445  
 446      protected function save_allow($type) {
 447          global $DB;
 448  
 449          $current = array_keys($this->get_allow_roles_list($type));
 450          $wanted = $this->{'allow'.$type};
 451  
 452          $addfunction = 'allow_'.$type;
 453          $deltable = 'role_allow_'.$type;
 454          $field = 'allow'.$type;
 455  
 456          foreach ($current as $roleid) {
 457              if (!in_array($roleid, $wanted)) {
 458                  $DB->delete_records($deltable, array('roleid'=>$this->roleid, $field=>$roleid));
 459                  continue;
 460              }
 461              $key = array_search($roleid, $wanted);
 462              unset($wanted[$key]);
 463          }
 464  
 465          foreach ($wanted as $roleid) {
 466              if ($roleid == -1) {
 467                  $roleid = $this->roleid;
 468              }
 469              $addfunction($this->roleid, $roleid);
 470          }
 471      }
 472  
 473      protected function get_name_field($id) {
 474          return '<input type="text" id="' . $id . '" name="' . $id . '" maxlength="254" value="' . s($this->role->name) . '" />';
 475      }
 476  
 477      protected function get_shortname_field($id) {
 478          return '<input type="text" id="' . $id . '" name="' . $id . '" maxlength="254" value="' . s($this->role->shortname) . '" />';
 479      }
 480  
 481      protected function get_description_field($id) {
 482          return '<textarea class="form-textarea" id="'. s($id) .'" name="description" rows="10" cols="50">' .
 483              htmlspecialchars($this->role->description) .
 484              '</textarea>';
 485      }
 486  
 487      protected function get_archetype_field($id) {
 488          $options = array();
 489          $options[''] = get_string('none');
 490          foreach (get_role_archetypes() as $type) {
 491              $options[$type] = get_string('archetype'.$type, 'role');
 492          }
 493          return html_writer::select($options, 'archetype', $this->role->archetype, false);
 494      }
 495  
 496      protected function get_assignable_levels_control() {
 497          $output = '';
 498          foreach ($this->allcontextlevels as $cl => $clname) {
 499              $extraarguments = $this->disabled;
 500              if (in_array($cl, $this->contextlevels)) {
 501                  $extraarguments .= 'checked="checked" ';
 502              }
 503              if (!$this->disabled) {
 504                  $output .= '<input type="hidden" name="contextlevel' . $cl . '" value="0" />';
 505              }
 506              $output .= '<input type="checkbox" id="cl' . $cl . '" name="contextlevel' . $cl .
 507                  '" value="1" ' . $extraarguments . '/> ';
 508              $output .= '<label for="cl' . $cl . '">' . $clname . "</label><br />\n";
 509          }
 510          return $output;
 511      }
 512  
 513      /**
 514       * Returns an array of roles of the allowed type.
 515       *
 516       * @param string $type Must be one of: assign, switch, or override.
 517       * @param int $roleid (null means current role)
 518       * @return array
 519       */
 520      protected function get_allow_roles_list($type, $roleid = null) {
 521          global $DB;
 522  
 523          if ($type !== 'assign' and $type !== 'switch' and $type !== 'override') {
 524              debugging('Invalid role allowed type specified', DEBUG_DEVELOPER);
 525              return array();
 526          }
 527  
 528          if ($roleid === null) {
 529              $roleid = $this->roleid;
 530          }
 531  
 532          if (empty($roleid)) {
 533              return array();
 534          }
 535  
 536          $sql = "SELECT r.*
 537                    FROM {role} r
 538                    JOIN {role_allow_{$type}} a ON a.allow{$type} = r.id
 539                   WHERE a.roleid = :roleid
 540                ORDER BY r.sortorder ASC";
 541          return $DB->get_records_sql($sql, array('roleid'=>$roleid));
 542      }
 543  
 544      /**
 545       * Returns an array of roles with the allowed type.
 546       *
 547       * @param string $type Must be one of: assign, switch, or override.
 548       * @return array Am array of role names with the allowed type
 549       */
 550      protected function get_allow_role_control($type) {
 551          if ($type !== 'assign' and $type !== 'switch' and $type !== 'override') {
 552              debugging('Invalid role allowed type specified', DEBUG_DEVELOPER);
 553              return '';
 554          }
 555  
 556          $property = 'allow'.$type;
 557          $selected = $this->$property;
 558  
 559          $options = array();
 560          foreach (role_get_names(null, ROLENAME_ALIAS) as $role) {
 561              $options[$role->id] = $role->localname;
 562          }
 563          if ($this->roleid == 0) {
 564              $options[-1] = get_string('thisnewrole', 'core_role');
 565          }
 566          return html_writer::select($options, 'allow'.$type.'[]', $selected, false, array('multiple'=>'multiple', 'size'=>10));
 567      }
 568  
 569      /**
 570       * Returns information about the risks associated with a role.
 571       *
 572       * @return string
 573       */
 574      protected function get_role_risks_info() {
 575          return '';
 576      }
 577  
 578      protected function print_field($name, $caption, $field) {
 579          global $OUTPUT;
 580          // Attempt to generate HTML like formslib.
 581          echo '<div class="fitem">';
 582          echo '<div class="fitemtitle">';
 583          if ($name) {
 584              echo '<label for="' . $name . '">';
 585          }
 586          echo $caption;
 587          if ($name) {
 588              echo "</label>\n";
 589          }
 590          echo '</div>';
 591          if (isset($this->errors[$name])) {
 592              $extraclass = ' error';
 593          } else {
 594              $extraclass = '';
 595          }
 596          echo '<div class="felement' . $extraclass . '">';
 597          echo $field;
 598          if (isset($this->errors[$name])) {
 599              echo $OUTPUT->error_text($this->errors[$name]);
 600          }
 601          echo '</div>';
 602          echo '</div>';
 603      }
 604  
 605      protected function print_show_hide_advanced_button() {
 606          echo '<p class="definenotice">' . get_string('highlightedcellsshowdefault', 'core_role') . ' </p>';
 607          echo '<div class="advancedbutton">';
 608          echo '<input type="submit" name="toggleadvanced" value="' . get_string('hideadvanced', 'form') . '" />';
 609          echo '</div>';
 610      }
 611  
 612      public function display() {
 613          global $OUTPUT;
 614          // Extra fields at the top of the page.
 615          echo '<div class="topfields clearfix">';
 616          $this->print_field('shortname', get_string('roleshortname', 'core_role').'&nbsp;'.$OUTPUT->help_icon('roleshortname', 'core_role'), $this->get_shortname_field('shortname'));
 617          $this->print_field('name', get_string('customrolename', 'core_role').'&nbsp;'.$OUTPUT->help_icon('customrolename', 'core_role'), $this->get_name_field('name'));
 618          $this->print_field('edit-description', get_string('customroledescription', 'core_role').'&nbsp;'.$OUTPUT->help_icon('customroledescription', 'core_role'),
 619              $this->get_description_field('description'));
 620          $this->print_field('menuarchetype', get_string('archetype', 'core_role').'&nbsp;'.$OUTPUT->help_icon('archetype', 'core_role'), $this->get_archetype_field('archetype'));
 621          $this->print_field('', get_string('maybeassignedin', 'core_role'), $this->get_assignable_levels_control());
 622          $this->print_field('menuallowassign', get_string('allowassign', 'core_role'), $this->get_allow_role_control('assign'));
 623          $this->print_field('menuallowoverride', get_string('allowoverride', 'core_role'), $this->get_allow_role_control('override'));
 624          $this->print_field('menuallowswitch', get_string('allowswitch', 'core_role'), $this->get_allow_role_control('switch'));
 625          if ($risks = $this->get_role_risks_info()) {
 626              $this->print_field('', get_string('rolerisks', 'core_role'), $risks);
 627          }
 628          echo "</div>";
 629  
 630          $this->print_show_hide_advanced_button();
 631  
 632          // Now the permissions table.
 633          parent::display();
 634      }
 635  
 636      protected function add_permission_cells($capability) {
 637          // One cell for each possible permission.
 638          $content = '';
 639          foreach ($this->displaypermissions as $perm => $permname) {
 640              $strperm = $this->strperms[$permname];
 641              $extraclass = '';
 642              if ($perm == $this->parentpermissions[$capability->name]) {
 643                  $extraclass = ' capdefault';
 644              }
 645              $checked = '';
 646              if ($this->permissions[$capability->name] == $perm) {
 647                  $checked = 'checked="checked" ';
 648              }
 649              $content .= '<td class="' . $permname . $extraclass . '">';
 650              $content .= '<label><input type="radio" name="' . $capability->name .
 651                  '" value="' . $perm . '" ' . $checked . '/> ';
 652              $content .= '<span class="note">' . $strperm . '</span>';
 653              $content .= '</label></td>';
 654          }
 655          return $content;
 656      }
 657  }


Generated: Thu Aug 11 10:00:09 2016 Cross-referenced by PHPXref 0.7.1