Merge branch 'MDL-49671-28' of git://github.com/merrill-oakland/moodle into MOODLE_28...
[moodle.git] / enrol / renderer.php
blobb1cd895822332e22267778d2408ceb76daaf8b5a
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'));
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 .= $mform->render();
61 $content .= $this->output->render($table->get_paging_bar());
63 // Check if the table has any bulk operations. If it does we want to wrap the table in a
64 // form so that we can capture and perform any required bulk operations.
65 if ($table->has_bulk_user_enrolment_operations()) {
66 $content .= html_writer::start_tag('form', array('action' => new moodle_url('/enrol/bulkchange.php'), 'method' => 'post'));
67 foreach ($table->get_combined_url_params() as $key => $value) {
68 if ($key == 'action') {
69 continue;
71 $content .= html_writer::empty_tag('input', array('type' => 'hidden', 'name' => $key, 'value' => $value));
73 $content .= html_writer::empty_tag('input', array('type' => 'hidden', 'name' => 'action', 'value' => 'bulkchange'));
74 $content .= html_writer::table($table);
75 $content .= html_writer::start_tag('div', array('class' => 'singleselect bulkuserop'));
76 $content .= html_writer::start_tag('select', array('name' => 'bulkuserop'));
77 $content .= html_writer::tag('option', get_string('withselectedusers', 'enrol'), array('value' => ''));
78 $options = array('' => get_string('withselectedusers', 'enrol'));
79 foreach ($table->get_bulk_user_enrolment_operations() as $operation) {
80 $content .= html_writer::tag('option', $operation->get_title(), array('value' => $operation->get_identifier()));
82 $content .= html_writer::end_tag('select');
83 $content .= html_writer::empty_tag('input', array('type' => 'submit', 'value' => get_string('go')));
84 $content .= html_writer::end_tag('div');
86 $content .= html_writer::end_tag('form');
87 } else {
88 $content .= html_writer::table($table);
90 $content .= $this->output->render($table->get_paging_bar());
91 if (!empty($buttonhtml)) {
92 $content .= $buttonhtml;
94 return $content;
97 /**
98 * Renderers the enrol_user_button.
100 * @param enrol_user_button $button
101 * @return string XHTML
103 protected function render_enrol_user_button(enrol_user_button $button) {
104 $attributes = array('type' => 'submit',
105 'value' => $button->label,
106 'disabled' => $button->disabled ? 'disabled' : null,
107 'title' => $button->tooltip);
109 if ($button->actions) {
110 $id = html_writer::random_id('single_button');
111 $attributes['id'] = $id;
112 foreach ($button->actions as $action) {
113 $this->add_action_handler($action, $id);
116 $button->initialise_js($this->page);
118 // first the input element
119 $output = html_writer::empty_tag('input', $attributes);
121 // then hidden fields
122 $params = $button->url->params();
123 if ($button->method === 'post') {
124 $params['sesskey'] = sesskey();
126 foreach ($params as $var => $val) {
127 $output .= html_writer::empty_tag('input', array('type' => 'hidden', 'name' => $var, 'value' => $val));
130 // then div wrapper for xhtml strictness
131 $output = html_writer::tag('div', $output);
133 // now the form itself around it
134 if ($button->method === 'get') {
135 $url = $button->url->out_omit_querystring(true); // url without params, the anchor part allowed
136 } else {
137 $url = $button->url->out_omit_querystring(); // url without params, the anchor part not allowed
139 if ($url === '') {
140 $url = '#'; // there has to be always some action
142 $attributes = array('method' => $button->method,
143 'action' => $url,
144 'id' => $button->formid);
145 $output = html_writer::tag('form', $output, $attributes);
147 // and finally one more wrapper with class
148 return html_writer::tag('div', $output, array('class' => $button->class));
152 * Renders a course enrolment table
154 * @param course_enrolment_table $table
155 * @return string
157 protected function render_course_enrolment_other_users_table(course_enrolment_other_users_table $table) {
159 $table->initialise_javascript();
161 $content = '';
162 $searchbutton = $table->get_user_search_button();
163 if ($searchbutton) {
164 $content .= $this->output->render($searchbutton);
166 $content .= html_writer::tag('div', get_string('otheruserdesc', 'enrol'), array('class'=>'otherusersdesc'));
167 $content .= $this->output->render($table->get_paging_bar());
168 $content .= html_writer::table($table);
169 $content .= $this->output->render($table->get_paging_bar());
170 $searchbutton = $table->get_user_search_button();
171 if ($searchbutton) {
172 $content .= $this->output->render($searchbutton);
174 return $content;
178 * Generates HTML to display the users roles and any available actions
180 * @param int $userid
181 * @param array $roles
182 * @param array $assignableroles
183 * @param moodle_url $pageurl
184 * @return string
186 public function user_roles_and_actions($userid, $roles, $assignableroles, $canassign, $pageurl) {
187 $iconenrolremove = $this->output->pix_url('t/delete');
191 // Get list of roles.
192 $rolesoutput = '';
193 foreach ($roles as $roleid=>$role) {
194 if ($canassign and (is_siteadmin() or isset($assignableroles[$roleid])) and !$role['unchangeable']) {
195 $strunassign = get_string('unassignarole', 'role', $role['text']);
196 $icon = html_writer::empty_tag('img', array('alt'=>$strunassign, 'src'=>$iconenrolremove));
197 $url = new moodle_url($pageurl, array('action'=>'unassign', 'roleid'=>$roleid, 'user'=>$userid));
198 $rolesoutput .= html_writer::tag('div', $role['text'] . html_writer::link($url, $icon, array('class'=>'unassignrolelink', 'rel'=>$roleid, 'title'=>$strunassign)), array('class'=>'role role_'.$roleid));
199 } else {
200 $rolesoutput .= html_writer::tag('div', $role['text'], array('class'=>'role unchangeable', 'rel'=>$roleid));
203 $output = '';
204 if (!empty($assignableroles) && $canassign) {
205 $roleids = array_keys($roles);
206 $hasallroles = true;
207 foreach (array_keys($assignableroles) as $key) {
208 if (!in_array($key, $roleids)) {
209 $hasallroles = false;
210 break;
213 if (!$hasallroles) {
214 $url = new moodle_url($pageurl, array('action' => 'assign', 'user' => $userid));
215 $roleicon = $this->output->pix_icon('i/assignroles', get_string('assignroles', 'role'));
216 $link = html_writer::link($url, $roleicon, array('class' => 'assignrolelink'));
217 $output = html_writer::tag('div', $link, array('class'=>'addrole'));
220 $output .= html_writer::tag('div', $rolesoutput, array('class'=>'roles'));
221 return $output;
225 * Generates the HTML to view the users groups and available group actions
227 * @param int $userid
228 * @param array $groups
229 * @param array $allgroups
230 * @param bool $canmanagegroups
231 * @param moodle_url $pageurl
232 * @return string
234 public function user_groups_and_actions($userid, $groups, $allgroups, $canmanagegroups, $pageurl) {
235 $iconenrolremove = $this->output->pix_url('t/delete');
237 $groupicon = $this->output->pix_icon('i/group', get_string('addgroup', 'group'));
239 $groupoutput = '';
240 foreach($groups as $groupid=>$name) {
241 if ($canmanagegroups and groups_remove_member_allowed($groupid, $userid)) {
242 $icon = html_writer::empty_tag('img', array('alt'=>get_string('removefromgroup', 'group', $name), 'src'=>$iconenrolremove));
243 $url = new moodle_url($pageurl, array('action'=>'removemember', 'group'=>$groupid, 'user'=>$userid));
244 $groupoutput .= html_writer::tag('div', $name . html_writer::link($url, $icon), array('class'=>'group', 'rel'=>$groupid));
245 } else {
246 $groupoutput .= html_writer::tag('div', $name, array('class'=>'group', 'rel'=>$groupid));
249 $output = '';
250 if ($canmanagegroups && (count($groups) < count($allgroups))) {
251 $url = new moodle_url($pageurl, array('action'=>'addmember', 'user'=>$userid));
252 $output .= html_writer::tag('div', html_writer::link($url, $groupicon), array('class'=>'addgroup'));
254 $output = $output.html_writer::tag('div', $groupoutput, array('class'=>'groups'));
255 return $output;
259 * Generates the HTML for the given enrolments + available actions
261 * @param int $userid
262 * @param array $enrolments
263 * @param moodle_url $pageurl
264 * @return string
266 public function user_enrolments_and_actions($enrolments) {
267 $output = '';
268 foreach ($enrolments as $ue) {
269 $enrolmentoutput = $ue['text'].' '.$ue['period'];
270 if ($ue['dimmed']) {
271 $enrolmentoutput = html_writer::tag('span', $enrolmentoutput, array('class'=>'dimmed_text'));
272 } else {
273 $enrolmentoutput = html_writer::tag('span', $enrolmentoutput);
275 foreach ($ue['actions'] as $action) {
276 $enrolmentoutput .= $this->render($action);
278 $output .= html_writer::tag('div', $enrolmentoutput, array('class'=>'enrolment'));
280 return $output;
284 * Renders a user enrolment action
285 * @param user_enrolment_action $icon
286 * @return string
288 protected function render_user_enrolment_action(user_enrolment_action $icon) {
289 return html_writer::link($icon->get_url(), $this->output->render($icon->get_icon()), $icon->get_attributes());
294 * Main course enrolment table
296 * This table is used to display the enrolment information for a course.
297 * It requires that a course enrolment manager be provided during constuct with
298 * provides all of the information for the table.
299 * The control then produces the table, the paging, and the associated JS actions
300 * for the page.
302 * @package core
303 * @subpackage enrol
304 * @copyright 2010 Sam Hemelryk
305 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
307 class course_enrolment_table extends html_table implements renderable {
310 * The get/post variable that is used to identify the page.
311 * Default: page
313 const PAGEVAR = 'page';
316 * The get/post variable to is used to identify the number of items to display
317 * per page.
318 * Default: perpage
320 const PERPAGEVAR = 'perpage';
323 * The get/post variable that is used to identify the sort field for the table.
324 * Default: sort
326 const SORTVAR = 'sort';
329 * The get/post variable that is used to identify the sort direction for the table.
330 * Default: dir
332 const SORTDIRECTIONVAR = 'dir';
335 * The default number of items per page.
336 * Default: 100
338 const DEFAULTPERPAGE = 100;
341 * The default sort, options are course_enrolment_table::$sortablefields
342 * Default: lastname
344 const DEFAULTSORT = 'lastname';
347 * The default direction
348 * Default: ASC
350 const DEFAULTSORTDIRECTION = 'ASC';
353 * The current page, starting from 0
354 * @var int
356 public $page = 0;
359 * The total number of pages
360 * @var int
362 public $pages = 0;
365 * The number of items to display per page
366 * @var int
368 public $perpage = 0;
371 * The sort field for this table, should be one of course_enrolment_table::$sortablefields
372 * @var string
374 public $sort;
377 * The sort direction, either ASC or DESC
378 * @var string
380 public $sortdirection;
383 * The course manager this table is displaying for
384 * @var course_enrolment_manager
386 protected $manager;
389 * The paging bar that controls the paging for this table
390 * @var paging_bar
392 protected $pagingbar = null;
395 * The total number of users enrolled in the course
396 * @var int
398 protected $totalusers = null;
401 * The users enrolled in this course
402 * @var array
404 protected $users = null;
407 * The fields for this table
408 * @var array
410 protected $fields = array();
413 * An array of bulk user enrolment operations
414 * @var array
416 protected $bulkoperations = array();
419 * An array of sortable fields
420 * @static
421 * @var array
423 protected static $sortablefields = array('firstname', 'lastname', 'firstnamephonetic', 'lastnamephonetic', 'middlename',
424 'alternatename', 'idnumber', 'email', 'phone1', 'phone2', 'institution', 'department' );
427 * Constructs the table
429 * @param course_enrolment_manager $manager
431 public function __construct(course_enrolment_manager $manager) {
433 $this->manager = $manager;
435 $this->page = optional_param(self::PAGEVAR, 0, PARAM_INT);
436 $this->perpage = optional_param(self::PERPAGEVAR, self::DEFAULTPERPAGE, PARAM_INT);
437 $this->sort = optional_param(self::SORTVAR, self::DEFAULTSORT, PARAM_ALPHANUM);
438 $this->sortdirection = optional_param(self::SORTDIRECTIONVAR, self::DEFAULTSORTDIRECTION, PARAM_ALPHA);
440 $this->attributes = array('class'=>'userenrolment');
441 if (!in_array($this->sort, self::$sortablefields)) {
442 $this->sort = self::DEFAULTSORT;
444 if ($this->page < 0) {
445 $this->page = 0;
447 if ($this->sortdirection !== 'ASC' && $this->sortdirection !== 'DESC') {
448 $this->sortdirection = self::DEFAULTSORTDIRECTION;
451 $this->id = html_writer::random_id();
453 // Collect the bulk operations for the currently filtered plugin if there is one.
454 $plugin = $manager->get_filtered_enrolment_plugin();
455 if ($plugin and enrol_is_enabled($plugin->get_name())) {
456 $this->bulkoperations = $plugin->get_bulk_operations($manager);
461 * Returns an array of enrol_user_buttons that are created by the different
462 * enrolment plugins available.
464 * @return array
466 public function get_manual_enrol_buttons() {
467 return $this->manager->get_manual_enrol_buttons();
471 * Gets the sort direction for a given field
473 * @param string $field
474 * @return string ASC or DESC
476 public function get_field_sort_direction($field) {
477 if ($field == $this->sort) {
478 return ($this->sortdirection == 'ASC')?'DESC':'ASC';
480 return self::DEFAULTSORTDIRECTION;
484 * Sets the fields for this table. These get added to the tables head as well.
486 * You can also use a multi dimensional array for this to have multiple fields
487 * in a single column
489 * @param array $fields An array of fields to set
490 * @param string $output
492 public function set_fields($fields, $output) {
493 $this->fields = $fields;
494 $this->head = array();
495 $this->colclasses = array();
496 $this->align = array();
497 $url = $this->manager->get_moodlepage()->url;
499 if (!empty($this->bulkoperations)) {
500 // If there are bulk operations add a column for checkboxes.
501 $this->head[] = '';
502 $this->colclasses[] = 'field col_bulkops';
505 foreach ($fields as $name => $label) {
506 $newlabel = '';
507 if (is_array($label)) {
508 $bits = array();
509 foreach ($label as $n => $l) {
510 if ($l === false) {
511 continue;
513 if (!in_array($n, self::$sortablefields)) {
514 $bits[] = $l;
515 } else {
516 $link = html_writer::link(new moodle_url($url, array(self::SORTVAR=>$n)), $fields[$name][$n]);
517 if ($this->sort == $n) {
518 $link .= html_writer::link(new moodle_url($url, array(self::SORTVAR=>$n, self::SORTDIRECTIONVAR=>$this->get_field_sort_direction($n))), $this->get_direction_icon($output, $n));
520 $bits[] = html_writer::tag('span', $link, array('class'=>'subheading_'.$n));
524 $newlabel = join(' / ', $bits);
525 } else {
526 if (!in_array($name, self::$sortablefields)) {
527 $newlabel = $label;
528 } else {
529 $newlabel = html_writer::link(new moodle_url($url, array(self::SORTVAR=>$name)), $fields[$name]);
530 if ($this->sort == $name) {
531 $newlabel .= html_writer::link(new moodle_url($url, array(self::SORTVAR=>$name, self::SORTDIRECTIONVAR=>$this->get_field_sort_direction($name))), $this->get_direction_icon($output, $name));
535 $this->head[] = $newlabel;
536 $this->colclasses[] = 'field col_'.$name;
540 * Sets the total number of users
542 * @param int $totalusers
544 public function set_total_users($totalusers) {
545 $this->totalusers = $totalusers;
546 $this->pages = ceil($this->totalusers / $this->perpage);
547 if ($this->page > $this->pages) {
548 $this->page = $this->pages;
552 * Sets the users for this table
554 * @param array $users
555 * @return void
557 public function set_users(array $users) {
558 $this->users = $users;
559 $hasbulkops = !empty($this->bulkoperations);
560 foreach ($users as $userid=>$user) {
561 $user = (array)$user;
562 $row = new html_table_row();
563 $row->attributes = array('class' => 'userinforow');
564 $row->id = 'user_'.$userid;
565 $row->cells = array();
566 if ($hasbulkops) {
567 // Add a checkbox into the first column.
568 $input = html_writer::empty_tag('input', array('type' => 'checkbox', 'name' => 'bulkuser[]', 'value' => $userid));
569 $row->cells[] = new html_table_cell($input);
571 foreach ($this->fields as $field => $label) {
572 if (is_array($label)) {
573 $bits = array();
574 foreach (array_keys($label) as $subfield) {
575 if (array_key_exists($subfield, $user)) {
576 $bits[] = html_writer::tag('div', $user[$subfield], array('class'=>'subfield subfield_'.$subfield));
579 if (empty($bits)) {
580 $bits[] = '&nbsp;';
582 $row->cells[] = new html_table_cell(join(' ', $bits));
583 } else {
584 if (!array_key_exists($field, $user)) {
585 $user[$field] = '&nbsp;';
587 $row->cells[] = new html_table_cell($user[$field]);
590 $this->data[] = $row;
594 public function initialise_javascript() {
595 if (has_capability('moodle/role:assign', $this->manager->get_context())) {
596 $this->manager->get_moodlepage()->requires->strings_for_js(array(
597 'assignroles',
598 'confirmunassign',
599 'confirmunassigntitle',
600 'confirmunassignyes',
601 'confirmunassignno'
602 ), 'role');
603 $modules = array('moodle-enrol-rolemanager', 'moodle-enrol-rolemanager-skin');
604 $function = 'M.enrol.rolemanager.init';
605 $arguments = array(
606 'containerId'=>$this->id,
607 'userIds'=>array_keys($this->users),
608 'courseId'=>$this->manager->get_course()->id,
609 'otherusers'=>isset($this->otherusers));
610 $this->manager->get_moodlepage()->requires->yui_module($modules, $function, array($arguments));
615 * Gets the paging bar instance for this table
617 * @return paging_bar
619 public function get_paging_bar() {
620 if ($this->pagingbar == null) {
621 $this->pagingbar = new paging_bar($this->totalusers, $this->page, $this->perpage, $this->manager->get_moodlepage()->url, self::PAGEVAR);
623 return $this->pagingbar;
627 * Gets the direction icon for the sortable field within this table
629 * @param core_renderer $output
630 * @param string $field
631 * @return string
633 protected function get_direction_icon($output, $field) {
634 $direction = self::DEFAULTSORTDIRECTION;
635 if ($this->sort == $field) {
636 $direction = $this->sortdirection;
638 if ($direction === 'ASC') {
639 return html_writer::empty_tag('img', array('alt' => '', 'class' => 'iconsort',
640 'src' => $output->pix_url('t/sort_asc')));
641 } else {
642 return html_writer::empty_tag('img', array('alt' => '', 'class' => 'iconsort',
643 'src' => $output->pix_url('t/sort_desc')));
648 * Gets the params that will need to be added to the url in order to return to this page.
650 * @return array
652 public function get_url_params() {
653 return array(
654 self::PAGEVAR => $this->page,
655 self::PERPAGEVAR => $this->perpage,
656 self::SORTVAR => $this->sort,
657 self::SORTDIRECTIONVAR => $this->sortdirection
662 * Returns an array of URL params for both the table and the manager.
664 * @return array
666 public function get_combined_url_params() {
667 return $this->get_url_params() + $this->manager->get_url_params();
671 * Sets the bulk operations for this table.
673 * @param array $bulkoperations
675 public function set_bulk_user_enrolment_operations(array $bulkoperations) {
676 $this->bulkoperations = $bulkoperations;
680 * Returns an array of bulk operations.
682 * @return array
684 public function get_bulk_user_enrolment_operations() {
685 return $this->bulkoperations;
689 * Returns true fi the table is aware of any bulk operations that can be performed on users
690 * selected from the currently filtered enrolment plugins.
692 * @return bool
694 public function has_bulk_user_enrolment_operations() {
695 return !empty($this->bulkoperations);
700 * Table control used for enrolled users
702 * @copyright 2010 Sam Hemelryk
703 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
705 class course_enrolment_users_table extends course_enrolment_table {
708 * An array of sortable fields
709 * @static
710 * @var array
712 protected static $sortablefields = array('firstname', 'lastname', 'firstnamephonetic', 'lastnamephonetic', 'middlename',
713 'alternatename', 'email', 'lastaccess');
717 * Table used for other users
719 * Other users are users who have roles but are not enrolled.
721 * @copyright 2010 Sam Hemelryk
722 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
724 class course_enrolment_other_users_table extends course_enrolment_table {
726 public $otherusers = true;
729 * Constructs the table
731 * @param course_enrolment_manager $manager
733 public function __construct(course_enrolment_manager $manager) {
734 parent::__construct($manager);
735 $this->attributes = array('class'=>'userenrolment otheruserenrolment');
739 * Gets a button to search users and assign them roles in the course.
741 * @staticvar int $count
742 * @param int $page
743 * @return single_button
745 public function get_user_search_button() {
746 static $count = 0;
747 if (!has_capability('moodle/role:assign', $this->manager->get_context())) {
748 return false;
750 $count++;
751 $url = new moodle_url('/admin/roles/assign.php', array('contextid'=>$this->manager->get_context()->id, 'sesskey'=>sesskey()));
752 $control = new single_button($url, get_string('assignroles', 'role'), 'get');
753 $control->class = 'singlebutton assignuserrole instance'.$count;
754 if ($count == 1) {
755 $this->manager->get_moodlepage()->requires->strings_for_js(array(
756 'ajaxoneuserfound',
757 'ajaxxusersfound',
758 'ajaxnext25',
759 'enrol',
760 'enrolmentoptions',
761 'enrolusers',
762 'enrolxusers',
763 'errajaxfailedenrol',
764 'errajaxsearch',
765 'foundxcohorts',
766 'none',
767 'usersearch',
768 'unlimitedduration',
769 'startdatetoday',
770 'durationdays',
771 'enrolperiod'), 'enrol');
772 $this->manager->get_moodlepage()->requires->string_for_js('assignrole', 'role');
774 $modules = array('moodle-enrol-otherusersmanager', 'moodle-enrol-otherusersmanager-skin');
775 $function = 'M.enrol.otherusersmanager.init';
776 $arguments = array(
777 'courseId'=> $this->manager->get_course()->id,
778 'ajaxUrl' => '/enrol/ajax.php',
779 'url' => $this->manager->get_moodlepage()->url->out(false));
780 $this->manager->get_moodlepage()->requires->yui_module($modules, $function, array($arguments));
782 return $control;