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