Merge branch 'MDL-57282-master' of https://github.com/xow/moodle
[moodle.git] / enrol / renderer.php
blob2e867ab99fcb5e1d0bfe60449ac954bcbc02bc33
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.
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/>.
17 /**
18 * This is the main renderer for the enrol section.
20 * @package core_enrol
21 * @copyright 2010 Sam Hemelryk
22 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
25 /**
26 * This is the core renderer
28 * @copyright 2010 Sam Hemelryk
29 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
31 class core_enrol_renderer extends plugin_renderer_base {
33 /**
34 * Renders a course enrolment table
36 * @param course_enrolment_table $table
37 * @param moodleform $mform Form that contains filter controls
38 * @return string
40 public function render_course_enrolment_users_table(course_enrolment_users_table $table,
41 moodleform $mform) {
43 $table->initialise_javascript();
45 $buttons = $table->get_manual_enrol_buttons();
46 $buttonhtml = '';
47 if (count($buttons) > 0) {
48 $buttonhtml .= html_writer::start_tag('div', array('class' => 'enrol_user_buttons enrol-users-page-action'));
49 foreach ($buttons as $button) {
50 $buttonhtml .= $this->render($button);
52 $buttonhtml .= html_writer::end_tag('div');
55 $content = '';
56 if (!empty($buttonhtml)) {
57 $content .= $buttonhtml;
59 $content .= html_writer::start_tag('div', array('class' => 'form-inline'));
60 $content .= $mform->render();
61 $content .= html_writer::end_tag('div');
63 $content .= $this->output->render($table->get_paging_bar());
65 // Check if the table has any bulk operations. If it does we want to wrap the table in a
66 // form so that we can capture and perform any required bulk operations.
67 if ($table->has_bulk_user_enrolment_operations()) {
68 $content .= html_writer::start_tag('form', array('action' => new moodle_url('/enrol/bulkchange.php'), 'method' => 'post'));
69 foreach ($table->get_combined_url_params() as $key => $value) {
70 if ($key == 'action') {
71 continue;
73 $content .= html_writer::empty_tag('input', array('type' => 'hidden', 'name' => $key, 'value' => $value));
75 $content .= html_writer::empty_tag('input', array('type' => 'hidden', 'name' => 'action', 'value' => 'bulkchange'));
76 $content .= html_writer::table($table);
77 $content .= html_writer::start_tag('div', array('class' => 'singleselect bulkuserop'));
78 $content .= html_writer::start_tag('select', array('name' => 'bulkuserop'));
79 $content .= html_writer::tag('option', get_string('withselectedusers', 'enrol'), array('value' => ''));
80 $options = array('' => get_string('withselectedusers', 'enrol'));
81 foreach ($table->get_bulk_user_enrolment_operations() as $operation) {
82 $content .= html_writer::tag('option', $operation->get_title(), array('value' => $operation->get_identifier()));
84 $content .= html_writer::end_tag('select');
85 $content .= html_writer::empty_tag('input', array('type' => 'submit', 'value' => get_string('go')));
86 $content .= html_writer::end_tag('div');
88 $content .= html_writer::end_tag('form');
89 } else {
90 $content .= html_writer::table($table);
92 $content .= $this->output->render($table->get_paging_bar());
93 if (!empty($buttonhtml)) {
94 $content .= $buttonhtml;
96 return $content;
99 /**
100 * Renderers the enrol_user_button.
102 * @param enrol_user_button $button
103 * @return string XHTML
105 protected function render_enrol_user_button(enrol_user_button $button) {
106 $attributes = array('type' => 'submit',
107 'value' => $button->label,
108 'disabled' => $button->disabled ? 'disabled' : null,
109 'title' => $button->tooltip,
110 'class' => 'btn btn-secondary m-y-1');
112 if ($button->actions) {
113 $id = html_writer::random_id('single_button');
114 $attributes['id'] = $id;
115 foreach ($button->actions as $action) {
116 $this->add_action_handler($action, $id);
119 $button->initialise_js($this->page);
121 // first the input element
122 $output = html_writer::empty_tag('input', $attributes);
124 // then hidden fields
125 $params = $button->url->params();
126 if ($button->method === 'post') {
127 $params['sesskey'] = sesskey();
129 foreach ($params as $var => $val) {
130 $output .= html_writer::empty_tag('input', array('type' => 'hidden', 'name' => $var, 'value' => $val));
133 // then div wrapper for xhtml strictness
134 $output = html_writer::tag('div', $output);
136 // now the form itself around it
137 if ($button->method === 'get') {
138 $url = $button->url->out_omit_querystring(true); // url without params, the anchor part allowed
139 } else {
140 $url = $button->url->out_omit_querystring(); // url without params, the anchor part not allowed
142 if ($url === '') {
143 $url = '#'; // there has to be always some action
145 $attributes = array('method' => $button->method,
146 'action' => $url,
147 'id' => $button->formid);
148 $output = html_writer::tag('form', $output, $attributes);
150 // and finally one more wrapper with class
151 return html_writer::tag('div', $output, array('class' => $button->class));
155 * Renders a course enrolment table
157 * @param course_enrolment_table $table
158 * @return string
160 protected function render_course_enrolment_other_users_table(course_enrolment_other_users_table $table) {
162 $table->initialise_javascript();
164 $content = '';
165 $searchbutton = $table->get_user_search_button();
166 if ($searchbutton) {
167 $content .= $this->output->render($searchbutton);
169 $content .= html_writer::tag('div', get_string('otheruserdesc', 'enrol'), array('class'=>'otherusersdesc'));
170 $content .= $this->output->render($table->get_paging_bar());
171 $content .= html_writer::table($table);
172 $content .= $this->output->render($table->get_paging_bar());
173 $searchbutton = $table->get_user_search_button();
174 if ($searchbutton) {
175 $content .= $this->output->render($searchbutton);
177 return $content;
181 * Generates HTML to display the users roles and any available actions
183 * @param int $userid
184 * @param array $roles
185 * @param array $assignableroles
186 * @param moodle_url $pageurl
187 * @return string
189 public function user_roles_and_actions($userid, $roles, $assignableroles, $canassign, $pageurl) {
190 $iconenrolremove = $this->output->pix_url('t/delete');
194 // Get list of roles.
195 $rolesoutput = '';
196 foreach ($roles as $roleid=>$role) {
197 if ($canassign and (is_siteadmin() or isset($assignableroles[$roleid])) and !$role['unchangeable']) {
198 $strunassign = get_string('unassignarole', 'role', $role['text']);
199 $icon = html_writer::empty_tag('img', array('alt'=>$strunassign, 'src'=>$iconenrolremove));
200 $url = new moodle_url($pageurl, array('action'=>'unassign', 'roleid'=>$roleid, 'user'=>$userid));
201 $rolesoutput .= html_writer::tag('div', $role['text'] . html_writer::link($url, $icon, array('class'=>'unassignrolelink', 'rel'=>$roleid, 'title'=>$strunassign)), array('class'=>'role role_'.$roleid));
202 } else {
203 $rolesoutput .= html_writer::tag('div', $role['text'], array('class'=>'role unchangeable', 'rel'=>$roleid));
206 $output = '';
207 if (!empty($assignableroles) && $canassign) {
208 $roleids = array_keys($roles);
209 $hasallroles = true;
210 foreach (array_keys($assignableroles) as $key) {
211 if (!in_array($key, $roleids)) {
212 $hasallroles = false;
213 break;
216 if (!$hasallroles) {
217 $url = new moodle_url($pageurl, array('action' => 'assign', 'user' => $userid));
218 $roleicon = $this->output->pix_icon('i/assignroles', get_string('assignroles', 'role'));
219 $link = html_writer::link($url, $roleicon, array('class' => 'assignrolelink'));
220 $output = html_writer::tag('div', $link, array('class'=>'addrole'));
223 $output .= html_writer::tag('div', $rolesoutput, array('class'=>'roles'));
224 return $output;
228 * Generates the HTML to view the users groups and available group actions
230 * @param int $userid
231 * @param array $groups
232 * @param array $allgroups
233 * @param bool $canmanagegroups
234 * @param moodle_url $pageurl
235 * @return string
237 public function user_groups_and_actions($userid, $groups, $allgroups, $canmanagegroups, $pageurl) {
238 $iconenrolremove = $this->output->pix_url('t/delete');
240 $groupicon = $this->output->pix_icon('i/group', get_string('addgroup', 'group'));
242 $groupoutput = '';
243 foreach($groups as $groupid=>$name) {
244 if ($canmanagegroups and groups_remove_member_allowed($groupid, $userid)) {
245 $icon = html_writer::empty_tag('img', array('alt'=>get_string('removefromgroup', 'group', $name), 'src'=>$iconenrolremove));
246 $url = new moodle_url($pageurl, array('action'=>'removemember', 'group'=>$groupid, 'user'=>$userid));
247 $groupoutput .= html_writer::tag('div', $name . html_writer::link($url, $icon), array('class'=>'group', 'rel'=>$groupid));
248 } else {
249 $groupoutput .= html_writer::tag('div', $name, array('class'=>'group', 'rel'=>$groupid));
252 $output = '';
253 if ($canmanagegroups && (count($groups) < count($allgroups))) {
254 $url = new moodle_url($pageurl, array('action'=>'addmember', 'user'=>$userid));
255 $output .= html_writer::tag('div', html_writer::link($url, $groupicon), array('class'=>'addgroup'));
257 $output = $output.html_writer::tag('div', $groupoutput, array('class'=>'groups'));
258 return $output;
262 * Generates the HTML for the given enrolments + available actions
264 * @param int $userid
265 * @param array $enrolments
266 * @param moodle_url $pageurl
267 * @return string
269 public function user_enrolments_and_actions($enrolments) {
270 $output = '';
271 foreach ($enrolments as $ue) {
272 $enrolmentoutput = $ue['text'].' '.$ue['period'];
273 if ($ue['dimmed']) {
274 $enrolmentoutput = html_writer::tag('span', $enrolmentoutput, array('class'=>'dimmed_text'));
275 } else {
276 $enrolmentoutput = html_writer::tag('span', $enrolmentoutput);
278 foreach ($ue['actions'] as $action) {
279 $enrolmentoutput .= $this->render($action);
281 $output .= html_writer::tag('div', $enrolmentoutput, array('class'=>'enrolment'));
283 return $output;
287 * Renders a user enrolment action
288 * @param user_enrolment_action $icon
289 * @return string
291 protected function render_user_enrolment_action(user_enrolment_action $icon) {
292 return html_writer::link($icon->get_url(), $this->output->render($icon->get_icon()), $icon->get_attributes());
297 * Main course enrolment table
299 * This table is used to display the enrolment information for a course.
300 * It requires that a course enrolment manager be provided during constuct with
301 * provides all of the information for the table.
302 * The control then produces the table, the paging, and the associated JS actions
303 * for the page.
305 * @package core
306 * @subpackage enrol
307 * @copyright 2010 Sam Hemelryk
308 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
310 class course_enrolment_table extends html_table implements renderable {
313 * The get/post variable that is used to identify the page.
314 * Default: page
316 const PAGEVAR = 'page';
319 * The get/post variable to is used to identify the number of items to display
320 * per page.
321 * Default: perpage
323 const PERPAGEVAR = 'perpage';
326 * The get/post variable that is used to identify the sort field for the table.
327 * Default: sort
329 const SORTVAR = 'sort';
332 * The get/post variable that is used to identify the sort direction for the table.
333 * Default: dir
335 const SORTDIRECTIONVAR = 'dir';
338 * The default number of items per page.
339 * Default: 100
341 const DEFAULTPERPAGE = 100;
344 * The default sort, options are course_enrolment_table::$sortablefields
345 * Default: lastname
347 const DEFAULTSORT = 'lastname';
350 * The default direction
351 * Default: ASC
353 const DEFAULTSORTDIRECTION = 'ASC';
356 * The current page, starting from 0
357 * @var int
359 public $page = 0;
362 * The total number of pages
363 * @var int
365 public $pages = 0;
368 * The number of items to display per page
369 * @var int
371 public $perpage = 0;
374 * The sort field for this table, should be one of course_enrolment_table::$sortablefields
375 * @var string
377 public $sort;
380 * The sort direction, either ASC or DESC
381 * @var string
383 public $sortdirection;
386 * The course manager this table is displaying for
387 * @var course_enrolment_manager
389 protected $manager;
392 * The paging bar that controls the paging for this table
393 * @var paging_bar
395 protected $pagingbar = null;
398 * The total number of users enrolled in the course
399 * @var int
401 protected $totalusers = null;
404 * The users enrolled in this course
405 * @var array
407 protected $users = null;
410 * The fields for this table
411 * @var array
413 protected $fields = array();
416 * An array of bulk user enrolment operations
417 * @var array
419 protected $bulkoperations = array();
422 * An array of sortable fields
423 * @static
424 * @var array
426 protected static $sortablefields = array('firstname', 'lastname', 'firstnamephonetic', 'lastnamephonetic', 'middlename',
427 'alternatename', 'idnumber', 'email', 'phone1', 'phone2', 'institution', 'department', 'lastaccess', 'lastcourseaccess' );
430 * Constructs the table
432 * @param course_enrolment_manager $manager
434 public function __construct(course_enrolment_manager $manager) {
436 $this->manager = $manager;
438 $this->page = optional_param(self::PAGEVAR, 0, PARAM_INT);
439 $this->perpage = optional_param(self::PERPAGEVAR, self::DEFAULTPERPAGE, PARAM_INT);
440 $this->sort = optional_param(self::SORTVAR, self::DEFAULTSORT, PARAM_ALPHANUM);
441 $this->sortdirection = optional_param(self::SORTDIRECTIONVAR, self::DEFAULTSORTDIRECTION, PARAM_ALPHA);
443 $this->attributes = array('class'=>'userenrolment');
444 if (!in_array($this->sort, self::$sortablefields)) {
445 $this->sort = self::DEFAULTSORT;
447 if ($this->page < 0) {
448 $this->page = 0;
450 if ($this->sortdirection !== 'ASC' && $this->sortdirection !== 'DESC') {
451 $this->sortdirection = self::DEFAULTSORTDIRECTION;
454 $this->id = html_writer::random_id();
456 // Collect the bulk operations for the currently filtered plugin if there is one.
457 $plugin = $manager->get_filtered_enrolment_plugin();
458 if ($plugin and enrol_is_enabled($plugin->get_name())) {
459 $this->bulkoperations = $plugin->get_bulk_operations($manager);
464 * Returns an array of enrol_user_buttons that are created by the different
465 * enrolment plugins available.
467 * @return array
469 public function get_manual_enrol_buttons() {
470 return $this->manager->get_manual_enrol_buttons();
474 * Gets the sort direction for a given field
476 * @param string $field
477 * @return string ASC or DESC
479 public function get_field_sort_direction($field) {
480 if ($field == $this->sort) {
481 return ($this->sortdirection == 'ASC')?'DESC':'ASC';
483 return self::DEFAULTSORTDIRECTION;
487 * Sets the fields for this table. These get added to the tables head as well.
489 * You can also use a multi dimensional array for this to have multiple fields
490 * in a single column
492 * @param array $fields An array of fields to set
493 * @param string $output
495 public function set_fields($fields, $output) {
496 $this->fields = $fields;
497 $this->head = array();
498 $this->colclasses = array();
499 $this->align = array();
500 $url = $this->manager->get_moodlepage()->url;
502 if (!empty($this->bulkoperations)) {
503 // If there are bulk operations add a column for checkboxes.
504 $this->head[] = '';
505 $this->colclasses[] = 'field col_bulkops';
508 foreach ($fields as $name => $label) {
509 $newlabel = '';
510 if (is_array($label)) {
511 $bits = array();
512 foreach ($label as $n => $l) {
513 if ($l === false) {
514 continue;
516 if (!in_array($n, self::$sortablefields)) {
517 $bits[] = $l;
518 } else {
519 $sorturl = new moodle_url($url, array(self::SORTVAR => $n, self::SORTDIRECTIONVAR => $this->get_field_sort_direction($n)));
520 $link = html_writer::link($sorturl, $fields[$name][$n]);
521 if ($this->sort == $n) {
522 $link .= $this->get_direction_icon($output, $n);
524 $bits[] = html_writer::tag('span', $link, array('class'=>'subheading_'.$n));
528 $newlabel = join(' / ', $bits);
529 } else {
530 if (!in_array($name, self::$sortablefields)) {
531 $newlabel = $label;
532 } else {
533 $sorturl = new moodle_url($url, array(self::SORTVAR => $name, self::SORTDIRECTIONVAR => $this->get_field_sort_direction($name)));
534 $newlabel = html_writer::link($sorturl, $fields[$name]);
535 if ($this->sort == $name) {
536 $newlabel .= $this->get_direction_icon($output, $name);
540 $this->head[] = $newlabel;
541 $this->colclasses[] = 'field col_'.$name;
545 * Sets the total number of users
547 * @param int $totalusers
549 public function set_total_users($totalusers) {
550 $this->totalusers = $totalusers;
551 $this->pages = ceil($this->totalusers / $this->perpage);
552 if ($this->page > $this->pages) {
553 $this->page = $this->pages;
557 * Sets the users for this table
559 * @param array $users
560 * @return void
562 public function set_users(array $users) {
563 $this->users = $users;
564 $hasbulkops = !empty($this->bulkoperations);
565 foreach ($users as $userid=>$user) {
566 $user = (array)$user;
567 $row = new html_table_row();
568 $row->attributes = array('class' => 'userinforow');
569 $row->id = 'user_'.$userid;
570 $row->cells = array();
571 if ($hasbulkops) {
572 // Add a checkbox into the first column.
573 $input = html_writer::empty_tag('input', array('type' => 'checkbox', 'name' => 'bulkuser[]', 'value' => $userid));
574 $row->cells[] = new html_table_cell($input);
576 foreach ($this->fields as $field => $label) {
577 if (is_array($label)) {
578 $bits = array();
579 foreach (array_keys($label) as $subfield) {
580 if (array_key_exists($subfield, $user)) {
581 $bits[] = html_writer::tag('div', $user[$subfield], array('class'=>'subfield subfield_'.$subfield));
584 if (empty($bits)) {
585 $bits[] = '&nbsp;';
587 $row->cells[] = new html_table_cell(join(' ', $bits));
588 } else {
589 if (!array_key_exists($field, $user)) {
590 $user[$field] = '&nbsp;';
592 $row->cells[] = new html_table_cell($user[$field]);
595 $this->data[] = $row;
599 public function initialise_javascript() {
600 if (has_capability('moodle/role:assign', $this->manager->get_context())) {
601 $this->manager->get_moodlepage()->requires->strings_for_js(array(
602 'assignroles',
603 'confirmunassign',
604 'confirmunassigntitle',
605 'confirmunassignyes',
606 'confirmunassignno'
607 ), 'role');
608 $modules = array('moodle-enrol-rolemanager', 'moodle-enrol-rolemanager-skin');
609 $function = 'M.enrol.rolemanager.init';
610 $arguments = array(
611 'containerId'=>$this->id,
612 'userIds'=>array_keys($this->users),
613 'courseId'=>$this->manager->get_course()->id,
614 'otherusers'=>isset($this->otherusers));
615 $this->manager->get_moodlepage()->requires->yui_module($modules, $function, array($arguments));
620 * Gets the paging bar instance for this table
622 * @return paging_bar
624 public function get_paging_bar() {
625 if ($this->pagingbar == null) {
626 $this->pagingbar = new paging_bar($this->totalusers, $this->page, $this->perpage, $this->manager->get_moodlepage()->url, self::PAGEVAR);
628 return $this->pagingbar;
632 * Gets the direction icon for the sortable field within this table
634 * @param core_renderer $output
635 * @param string $field
636 * @return string
638 protected function get_direction_icon($output, $field) {
639 $direction = self::DEFAULTSORTDIRECTION;
640 if ($this->sort == $field) {
641 $direction = $this->sortdirection;
643 if ($direction === 'ASC') {
644 return html_writer::empty_tag('img', array('alt' => '', 'class' => 'iconsort',
645 'src' => $output->pix_url('t/sort_asc')));
646 } else {
647 return html_writer::empty_tag('img', array('alt' => '', 'class' => 'iconsort',
648 'src' => $output->pix_url('t/sort_desc')));
653 * Gets the params that will need to be added to the url in order to return to this page.
655 * @return array
657 public function get_url_params() {
658 return array(
659 self::PAGEVAR => $this->page,
660 self::PERPAGEVAR => $this->perpage,
661 self::SORTVAR => $this->sort,
662 self::SORTDIRECTIONVAR => $this->sortdirection
667 * Returns an array of URL params for both the table and the manager.
669 * @return array
671 public function get_combined_url_params() {
672 return $this->get_url_params() + $this->manager->get_url_params();
676 * Sets the bulk operations for this table.
678 * @param array $bulkoperations
680 public function set_bulk_user_enrolment_operations(array $bulkoperations) {
681 $this->bulkoperations = $bulkoperations;
685 * Returns an array of bulk operations.
687 * @return array
689 public function get_bulk_user_enrolment_operations() {
690 return $this->bulkoperations;
694 * Returns true fi the table is aware of any bulk operations that can be performed on users
695 * selected from the currently filtered enrolment plugins.
697 * @return bool
699 public function has_bulk_user_enrolment_operations() {
700 return !empty($this->bulkoperations);
705 * Table control used for enrolled users
707 * @copyright 2010 Sam Hemelryk
708 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
710 class course_enrolment_users_table extends course_enrolment_table {
715 * Table used for other users
717 * Other users are users who have roles but are not enrolled.
719 * @copyright 2010 Sam Hemelryk
720 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
722 class course_enrolment_other_users_table extends course_enrolment_table {
724 public $otherusers = true;
727 * Constructs the table
729 * @param course_enrolment_manager $manager
731 public function __construct(course_enrolment_manager $manager) {
732 parent::__construct($manager);
733 $this->attributes = array('class'=>'userenrolment otheruserenrolment');
737 * Gets a button to search users and assign them roles in the course.
739 * @staticvar int $count
740 * @param int $page
741 * @return single_button
743 public function get_user_search_button() {
744 static $count = 0;
745 if (!has_capability('moodle/role:assign', $this->manager->get_context())) {
746 return false;
748 $count++;
749 $url = new moodle_url('/admin/roles/assign.php', array('contextid'=>$this->manager->get_context()->id, 'sesskey'=>sesskey()));
750 $control = new single_button($url, get_string('assignroles', 'role'), 'get');
751 $control->class = 'singlebutton assignuserrole instance'.$count;
752 if ($count == 1) {
753 $this->manager->get_moodlepage()->requires->strings_for_js(array(
754 'ajaxoneuserfound',
755 'ajaxxusersfound',
756 'ajaxnext25',
757 'enrol',
758 'enrolmentoptions',
759 'enrolusers',
760 'enrolxusers',
761 'errajaxfailedenrol',
762 'errajaxsearch',
763 'foundxcohorts',
764 'none',
765 'usersearch',
766 'unlimitedduration',
767 'startdatetoday',
768 'durationdays',
769 'enrolperiod'), 'enrol');
770 $this->manager->get_moodlepage()->requires->string_for_js('assignrole', 'role');
772 $modules = array('moodle-enrol-otherusersmanager', 'moodle-enrol-otherusersmanager-skin');
773 $function = 'M.enrol.otherusersmanager.init';
774 $arguments = array(
775 'courseId'=> $this->manager->get_course()->id,
776 'ajaxUrl' => '/enrol/ajax.php',
777 'url' => $this->manager->get_moodlepage()->url->out(false));
778 $this->manager->get_moodlepage()->requires->yui_module($modules, $function, array($arguments));
780 return $control;