[ Index ] |
PHP Cross Reference of Unnamed Project |
[Summary view] [Print] [Text view]
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').' '.$OUTPUT->help_icon('roleshortname', 'core_role'), $this->get_shortname_field('shortname')); 617 $this->print_field('name', get_string('customrolename', 'core_role').' '.$OUTPUT->help_icon('customrolename', 'core_role'), $this->get_name_field('name')); 618 $this->print_field('edit-description', get_string('customroledescription', 'core_role').' '.$OUTPUT->help_icon('customroledescription', 'core_role'), 619 $this->get_description_field('description')); 620 $this->print_field('menuarchetype', get_string('archetype', 'core_role').' '.$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 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
Generated: Thu Aug 11 10:00:09 2016 | Cross-referenced by PHPXref 0.7.1 |