enrol MDL-22867 Added functionality to add cohort sycn or preform a one off member...
[moodle.git] / enrol / renderer.php
1 <?php
3 // This file is part of Moodle - http://moodle.org/
4 //
5 // Moodle is free software: you can redistribute it and/or modify
6 // it under the terms of the GNU General Public License as published by
7 // the Free Software Foundation, either version 3 of the License, or
8 // (at your option) any later version.
9 //
10 // Moodle is distributed in the hope that it will be useful,
11 // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 // GNU General Public License for more details.
14 //
15 // You should have received a copy of the GNU General Public License
16 // along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
18 /**
19  * This is the main renderer for the enrol section.
20  *
21  * @package   moodlecore
22  * @copyright 2010 Sam Hemelryk
23  * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
24  */
26 /**
27  * This is the core renderer
28  *
29  * @copyright 2010 Sam Hemelryk
30  * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
31  */
32 class core_enrol_renderer extends plugin_renderer_base {
34     /**
35      * Renders a course enrolment table
36      *
37      * @param course_enrolment_table $table
38      * @return string
39      */
40     protected function render_course_enrolment_table(course_enrolment_table $table) {
41         $content = '';
42         $enrolmentselector = $table->get_enrolment_selector($this->page);
43         if ($enrolmentselector) {
44             $content .= $this->output->render($enrolmentselector);
45         }
46         $cohortenroller = $table->get_cohort_enrolment_control($this->page);
47         if ($cohortenroller) {
48             $content .= $this->output->render($cohortenroller);
49         }
50         $content  .= $this->output->render($table->get_enrolment_type_filter());
51         $content .= $this->output->render($table->get_paging_bar());
52         $content .= html_writer::table($table);
53         $content .= $this->output->render($table->get_paging_bar());
54         $enrolmentselector = $table->get_enrolment_selector($this->page);
55         if ($enrolmentselector) {
56             $content .= $this->output->render($enrolmentselector);
57         }
58         $cohortenroller = $table->get_cohort_enrolment_control($this->page);
59         if ($cohortenroller) {
60             $content .= $this->output->render($cohortenroller);
61         }
62         return $content;
63     }
65     /**
66      * Generates HTML to display the users roles and any available actions
67      *
68      * @param int $userid
69      * @param array $roles
70      * @param array $assignableroles
71      * @param moodle_url $pageurl
72      * @return string
73      */
74     public function user_roles_and_actions($userid, $roles, $assignableroles, $canassign, $pageurl) {
75         $iconenroladd    = $this->output->pix_url('t/enroladd');
76         $iconenrolremove = $this->output->pix_url('t/delete');
78         // get list of roles
79         $rolesoutput = '';
80         foreach ($roles as $roleid=>$role) {
81             if ($canassign && !$role['unchangeable']) {
82                 $strunassign = get_string('unassignarole', 'role', $role['text']);
83                 $icon = html_writer::empty_tag('img', array('alt'=>$strunassign, 'src'=>$iconenrolremove));
84                 $url = new moodle_url($pageurl, array('action'=>'unassign', 'role'=>$roleid, 'user'=>$userid));
85                 $rolesoutput .= html_writer::tag('div', $role['text'] . html_writer::link($url, $icon, array('class'=>'unassignrolelink', 'rel'=>$roleid, 'title'=>$strunassign)), array('class'=>'role role_'.$roleid));
86             } else {
87                 $rolesoutput .= html_writer::tag('div', $role['text'], array('class'=>'role unchangeable', 'rel'=>$roleid));
88             }
89         }
90         $output = '';
91         if (!empty($assignableroles) && $canassign) {
92             $roleids = array_keys($roles);
93             $hasallroles = true;
94             foreach (array_keys($assignableroles) as $key) {
95                 if (!in_array($key, $roleids)) {
96                     $hasallroles = false;
97                     break;
98                 }
99             }
100             if (!$hasallroles) {
101                 $url = new moodle_url($pageurl, array('action'=>'assign', 'user'=>$userid));
102                 $icon = html_writer::empty_tag('img', array('alt'=>get_string('assignroles', 'role'), 'src'=>$iconenroladd));
103                 $output = html_writer::tag('div', html_writer::link($url, $icon, array('class'=>'assignrolelink', 'title'=>get_string('assignroles', 'role'))), array('class'=>'addrole'));
104             }
105         }
106         $output .= html_writer::tag('div', $rolesoutput, array('class'=>'roles'));
107         return $output;
108     }
110     /**
111      * Generates the HTML to view the users groups and available group actions
112      *
113      * @param int $userid
114      * @param array $groups
115      * @param array $allgroups
116      * @param bool $canmanagegroups
117      * @param moodle_url $pageurl
118      * @return string
119      */
120     public function user_groups_and_actions($userid, $groups, $allgroups, $canmanagegroups, $pageurl) {
121         $iconenroladd    = $this->output->pix_url('t/enroladd');
122         $iconenrolremove = $this->output->pix_url('t/delete');
123         $straddgroup = get_string('addgroup', 'group');
125         $groupoutput = '';
126         foreach($groups as $groupid=>$name) {
127             if ($canmanagegroups) {
128                 $icon = html_writer::empty_tag('img', array('alt'=>get_string('removefromgroup', 'group', $name), 'src'=>$iconenrolremove));
129                 $url = new moodle_url($pageurl, array('action'=>'removemember', 'group'=>$groupid, 'user'=>$userid));
130                 $groupoutput .= html_writer::tag('div', $name . html_writer::link($url, $icon), array('class'=>'group', 'rel'=>$groupid));
131             } else {
132                 $groupoutput .= html_writer::tag('div', $name, array('class'=>'group', 'rel'=>$groupid));
133             }
134         }
135         $groupoutput = html_writer::tag('div', $groupoutput, array('class'=>'groups'));
136         if ($canmanagegroups && (count($groups) < count($allgroups))) {
137             $icon = html_writer::empty_tag('img', array('alt'=>$straddgroup, 'src'=>$iconenroladd));
138             $url = new moodle_url($pageurl, array('action'=>'addmember', 'user'=>$userid));
139             $groupoutput .= html_writer::tag('div', html_writer::link($url, $icon), array('class'=>'addgroup'));
140         }
141         return $groupoutput;
142     }
144     /**
145      * Generates the HTML for the given enrolments + available actions
146      *
147      * @param int $userid
148      * @param array $enrolments
149      * @param moodle_url $pageurl
150      * @return string
151      */
152     public function user_enrolments_and_actions($userid, $enrolments, $pageurl) {
153         $iconedit        = $this->output->pix_url('t/edit');
154         $iconenrolremove = $this->output->pix_url('t/delete');
155         $strunenrol = get_string('unenrol', 'enrol');
156         $stredit = get_string('edit');
158         $output = '';
159         foreach ($enrolments as $ueid=>$enrolment) {
160             $enrolmentoutput = $enrolment['text'].' '.$enrolment['period'];
161             if ($enrolment['dimmed']) {
162                 $enrolmentoutput = html_writer::tag('span', $enrolmentoutput, array('class'=>'dimmed_text'));
163             }
164             if ($enrolment['canunenrol']) {
165                 $icon = html_writer::empty_tag('img', array('alt'=>$strunenrol, 'src'=>$iconenrolremove));
166                 $url = new moodle_url($pageurl, array('action'=>'unenrol', 'ue'=>$ueid));
167                 $enrolmentoutput .= html_writer::link($url, $icon, array('class'=>'unenrollink', 'rel'=>$ueid));
168             }
169             if ($enrolment['canmanage']) {
170                 $icon = html_writer::empty_tag('img', array('alt'=>$stredit, 'src'=>$iconedit));
171                 $url = new moodle_url($url, array('action'=>'edit', 'ue'=>$ueid));
172                 $enrolmentoutput .= html_writer::link($url, $icon, array('class'=>'editenrollink', 'rel'=>$ueid));
173             }
174             $output .= html_writer::tag('div', $enrolmentoutput, array('class'=>'enrolment'));
175         }
176         return $output;
177     }
181 /**
182  * Main course enrolment table
183  *
184  * This table is used to display the enrolment information for a course.
185  * It requires that a course enrolment manager be provided during constuct with
186  * provides all of the information for the table.
187  * The control then produces the table, the paging, and the associated JS actions
188  * for the page.
189  *
190  * @package    core
191  * @subpackage enrol
192  * @copyright  2010 Sam Hemelryk
193  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
194  */
195 class course_enrolment_table extends html_table implements renderable {
197     /**
198      * The get/post variable that is used to identify the page.
199      * Default: page
200      */
201     const PAGEVAR = 'page';
203     /**
204      * The get/post variable to is used to identify the number of items to display
205      * per page.
206      * Default: perpage
207      */
208     const PERPAGEVAR = 'perpage';
210     /**
211      * The get/post variable that is used to identify the sort field for the table.
212      * Default: sort
213      */
214     const SORTVAR = 'sort';
216     /**
217      * The get/post variable that is used to identify the sort direction for the table.
218      * Default: dir
219      */
220     const SORTDIRECTIONVAR = 'dir';
222     /**
223      * The default number of items per page.
224      * Default: 20
225      */
226     const DEFAULTPERPAGE = 20;
228     /**
229      * The default sort, options are course_enrolment_table::$sortablefields
230      * Default: lastname
231      */
232     const DEFAULTSORT = 'lastname';
234     /**
235      * The default direction
236      * Default: ASC
237      */
238     const DEFAULTSORTDIRECTION = 'ASC';
240     /**
241      * The current page, starting from 0
242      * @var int
243      */
244     public $page = 0;
246     /**
247      * The total number of pages
248      * @var int
249      */
250     public $pages = 0;
252     /**
253      * The number of items to display per page
254      * @var int
255      */
256     public $perpage = 0;
258     /**
259      * The URL of the page for this table
260      * @var moodle_url
261      */
262     public $pageurl;
264     /**
265      * The sort field for this table, should be one of course_enrolment_table::$sortablefields
266      * @var string
267      */
268     public $sort;
270     /**
271      * The sort direction, either ASC or DESC
272      * @var string
273      */
274     public $sortdirection;
276     /**
277      * The course manager this table is displaying for
278      * @var course_enrolment_manager
279      */
280     protected $manager;
282     /**
283      * The paging bar that controls the paging for this table
284      * @var paging_bar
285      */
286     protected $pagingbar = null;
288     /**
289      * The total number of users enrolled in the course
290      * @var int
291      */
292     protected $totalusers = null;
294     /**
295      * The users enrolled in this course
296      * @var array
297      */
298     protected $users = null;
300     /**
301      * The fields for this table
302      * @var array
303      */
304     protected $fields = array();
306     protected static $sortablefields = array('firstname', 'lastname', 'email', 'lastaccess');
308     /**
309      * Constructs the table
310      *
311      * @param course_enrolment_manager $manager
312      */
313     public function __construct(course_enrolment_manager $manager, moodle_url $pageurl) {
315         $this->manager = $manager;
316         $this->pageurl = $pageurl;
317         
318         $this->page =           optional_param(self::PAGEVAR, 0, PARAM_INT);
319         $this->perpage =        optional_param(self::PERPAGEVAR, self::DEFAULTPERPAGE, PARAM_INT);
320         $this->sort =           optional_param(self::SORTVAR, self::DEFAULTSORT, PARAM_ALPHA);
321         $this->sortdirection  = optional_param(self::SORTDIRECTIONVAR, self::DEFAULTSORTDIRECTION, PARAM_ALPHA);
323         $this->attributes = array('class'=>'userenrolment');
324         if (!in_array($this->sort, self::$sortablefields)) {
325             $this->sort = self::DEFAULTSORT;
326         }
327         if ($this->page < 0) {
328             $this->page = 0;
329         }
330         if ($this->sortdirection !== 'ASC' && $this->sortdirection !== 'DESC') {
331             $this->sortdirection = self::DEFAULTSORTDIRECTION;
332         }
334         $this->id = html_writer::random_id();
335         $this->set_total_users($manager->get_total_users());
336     }
338     /**
339      * Gets the sort direction for a given field
340      *
341      * @param string $field
342      * @return string ASC or DESC
343      */
344     public function get_field_sort_direction($field) {
345         if ($field == $this->sort) {
346             return ($this->sortdirection == 'ASC')?'DESC':'ASC';
347         }
348         return self::DEFAULTSORTDIRECTION;
349     }
351     /**
352      * Sets the fields for this table. These get added to the tables head as well.
353      *
354      * You can also use a multi dimensional array for this to have multiple fields
355      * in a single column
356      *
357      * @param array $fields An array of fields to set
358      * @param string $output
359      */
360     public function set_fields($fields, $output=null) {
361         global $OUTPUT;
362         if ($output === null) {
363             $output = $OUTPUT;
364         }
365         $this->fields = $fields;
366         $this->head = array();
367         $this->colclasses = array();
368         $this->align = array();
369         $url = new moodle_url($this->pageurl, $this->get_url_params()+$this->manager->get_url_params());
370         foreach ($fields as $name => $label) {
371             $newlabel = '';
372             if (is_array($label)) {
373                 $bits = array();
374                 foreach ($label as $n => $l) {
375                     if ($l === false) {
376                         continue;
377                     }
378                     if (!in_array($n, self::$sortablefields)) {
379                         $bits[] = $l;
380                     } else {
381                         $link = html_writer::link(new moodle_url($url, array(self::SORTVAR=>$n)), $fields[$name][$n]);
382                         if ($this->sort == $n) {
383                             $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));
384                         }
385                         $bits[] = html_writer::tag('span', $link, array('class'=>'subheading_'.$n));
387                     }
388                 }
389                 $newlabel = join(' / ', $bits);
390             } else {
391                 if (!in_array($name, self::$sortablefields)) {
392                     $newlabel = $label;
393                 } else {
394                     $newlabel  = html_writer::link(new moodle_url($url, array(self::SORTVAR=>$name)), $fields[$name]);
395                     if ($this->sort == $name) {
396                         $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));
397                     }
398                 }
399             }
400             $this->head[] = $newlabel;
401             $this->colclasses[] = 'field col_'.$name;
402         }
403     }
404     /**
405      * Sets the total number of users
406      *
407      * @param int $totalusers
408      */
409     public function set_total_users($totalusers) {
410         $this->totalusers = $totalusers;
411         $this->pages = ceil($this->totalusers / $this->perpage);
412         if ($this->page > $this->pages) {
413             $this->page = $this->pages;
414         }
415     }
416     /**
417      
418      */
419     /**
420      * Sets the users for this table
421      *
422      * @param array $users
423      * @param moodle_page $page
424      */
425     public function set_users(array $users, moodle_page $page=null) {
426         global $PAGE;
427         if ($page === null) {
428             $page = $PAGE;
429         }
430         foreach ($users as $userid=>$user) {
431             $user = (array)$user;
432             $row = new html_table_row();
433             $row->attributes = array('class' => 'userinforow');
434             $row->id = 'user_'.$userid;
435             $row->cells = array();
436             foreach ($this->fields as $field => $label) {
437                 if (is_array($label)) {
438                     $bits = array();
439                     foreach (array_keys($label) as $subfield) {
440                         if (array_key_exists($subfield, $user)) {
441                             $bits[] = html_writer::tag('div', $user[$subfield], array('class'=>'subfield subfield_'.$subfield));
442                         }
443                     }
444                     if (empty($bits)) {
445                         $bits[] = '&nbsp;';
446                     }
447                     $row->cells[] = new html_table_cell(join(' ', $bits));
448                 } else {
449                     if (!array_key_exists($field, $user)) {
450                         $user[$field] = '&nbsp;';
451                     }
452                     $row->cells[] = new html_table_cell($user[$field]);
453                 }
454             }
455             $this->data[] = $row;
456         }
457         if (has_capability('moodle/role:assign', $this->manager->get_context())) {
458             $arguments = array(array('containerId'=>$this->id, 'userIds'=>array_keys($users), 'courseId'=>$this->manager->get_course()->id));
459             $page->requires->yui_module(array('moodle-enrol-rolemanager', 'moodle-enrol-rolemanager-skin'), 'M.enrol.rolemanager.init', $arguments);
460         }
461     }
462     
463     /**
464      * Gets the paging bar instance for this table
465      *
466      * @return paging_bar
467      */
468     public function get_paging_bar() {
469         if ($this->pagingbar == null) {
470             $this->pagingbar = new paging_bar($this->totalusers, $this->page, $this->perpage, $this->pageurl, self::PAGEVAR);
471         }
472         return $this->pagingbar;
473     }
475     /**
476      * Gets the direction icon for the sortable field within this table
477      *
478      * @param core_renderer $output
479      * @param string $field
480      * @return string
481      */
482     protected function get_direction_icon($output, $field) {
483         $direction = self::DEFAULTSORTDIRECTION;
484         if ($this->sort == $field) {
485             $direction = $this->sortdirection;
486         }
487         if ($direction === 'ASC') {
488             return html_writer::empty_tag('img', array('alt'=>'', 'src'=>$output->pix_url('t/down')));
489         } else {
490             return html_writer::empty_tag('img', array('alt'=>'', 'src'=>$output->pix_url('t/up')));
491         }
492     }
494     /**
495      * Gets the params that will need to be added to the url in order to return to this page.
496      *
497      * @return array
498      */
499     public function get_url_params() {
500         return array(
501             self::PAGEVAR => $this->page,
502             self::PERPAGEVAR => $this->perpage,
503             self::SORTVAR => $this->sort,
504             self::SORTDIRECTIONVAR => $this->sortdirection
505         );
506     }
508     /**
509      * Gets the enrolment type filter control for this table
510      *
511      * @return single_select
512      */
513     public function get_enrolment_type_filter() {
514         $url = new moodle_url($this->pageurl, $this->manager->get_url_params()+$this->get_url_params());
515         $selector = new single_select($url, 'ifilter', array(0=>get_string('all')) + (array)$this->manager->get_enrolment_instance_names(), $this->manager->get_enrolment_filter(), array());
516         $selector->set_label( get_string('enrolmentinstances', 'enrol'));
517         return $selector;
518     }
520     /**
521      * Returns a button to enrol cohorts or thier users
522      *
523      * @staticvar int $count
524      * @param moodle_page $page
525      * @return single_button|false
526      */
527     public function get_cohort_enrolment_control(moodle_page $page) {
528         static $count = 0;
530         // First make sure that cohorts is enabled
531         $plugins = $this->manager->get_enrolment_plugins();
532         if (!array_key_exists('cohort', $plugins)) {
533             return false;
534         }
535         $count ++;
536         $course = $this->manager->get_course();
537         $cohorturl = new moodle_url('/enrol/cohort/addinstance.php', array('id'=>$course->id));
538         $control = new single_button($cohorturl, get_string('enrolcohort', 'enrol'), 'get');
539         $control->class = 'singlebutton enrolcohortbutton instance'.$count;
540         $control->formid = 'manuallyenrol_single_'+$count;
541         if ($count == 1) {
542             $page->requires->strings_for_js(array('enrol','synced','enrolcohort','enrolcohortusers'), 'enrol');
543             $page->requires->string_for_js('assignroles', 'role');
544             $page->requires->string_for_js('cohort', 'cohort');
545             $page->requires->string_for_js('users', 'moodle');
546             $url = new moodle_url($this->pageurl, $this->manager->get_url_params()+$this->get_url_params());
548             $hasmanualinstance = false;
549             // No point showing this at all if the user cant manually enrol users
550             if (has_capability('enrol/manual:manage', $this->manager->get_context())) {
551                 // Make sure manual enrolments instance exists
552                 $instances = $this->manager->get_enrolment_instances();
553                 foreach ($instances as $instance) {
554                     if ($instance->enrol == 'manual') {
555                         $hasmanualinstance = true;
556                         break;
557                     }
558                 }
559             }
560             
561             $arguments = array(array(
562                 'courseid'=>$course->id,
563                 'ajaxurl'=>'/enrol/ajax.php',
564                 'url'=>$url->out(false),
565                 'manualEnrolment'=>$hasmanualinstance));
566             $page->requires->yui_module(array('moodle-enrol-quickcohortenrolment', 'moodle-enrol-quickcohortenrolment-skin'), 'M.enrol.quickcohortenrolment.init', $arguments);
567         }
568         return $control;
569     }
571     /**
572      * Gets the enrolment selector control for this table and initialises its
573      * JavaScript
574      *
575      * @return single_button|url_select
576      */
577     public function get_enrolment_selector(moodle_page $page) {
578         static $count = 0;
580         $instances  = $this->manager->get_enrolment_instances();
581         $plugins    = $this->manager->get_enrolment_plugins();
582         // print enrol link or selection
583         $links = array();
584         foreach($instances as $instance) {
585             $plugin = $plugins[$instance->enrol];
586             if ($link = $plugin->get_manual_enrol_link($instance)) {
587                 $links[$instance->id] = $link;
588             }
589         }
590         if (!empty($links)) {
591             $arguments = array();
592             $count ++;
593             if (count($links) == 1) {
594                 $control = new single_button(reset($links), get_string('enrolusers', 'enrol_manual'), 'get');
595                 $control->class = 'singlebutton enrolusersbutton instance'.$count;
596                 $control->formid = 'manuallyenrol_single_'+$count;
597                 $arguments[] = array('id'=>key($links), 'name'=>$plugins[$instances[key($links)]->enrol]->get_instance_name($instances[key($links)]));
598             } else if (count($links) > 1) {
599                 $inames     = $this->manager->get_enrolment_instance_names();
600                 $options = array();
601                 foreach ($links as $i=>$link) {
602                     $options[$link->out(false)] = $inames[$i];
603                     $arguments[] = array('id'=>$i, 'name'=>$plugins[$instances[$i]->enrol]->get_instance_name($instances[$i]));
604                 }
605                 $control = new url_select($options, '', array(''=>get_string('enrolusers', 'enrol_manual').'...'));
606                 $control->class = 'singlebutton enrolusersbutton instance'.$count;
607                 $control->formid = 'manuallyenrol_select_'+$count;
608             }
609             $course = $this->manager->get_course();
610             $url = new moodle_url($this->pageurl, $this->manager->get_url_params()+$this->get_url_params());
611             $timeformat = get_string('strftimedatefullshort');
612             $today = time();
613             $today = make_timestamp(date('Y', $today), date('m', $today), date('d', $today), 0, 0, 0);
614             $startdateoptions = array();
615             if ($course->startdate > 0) {
616                 $startdateoptions[2] = get_string('coursestart') . ' (' . userdate($course->startdate, $timeformat) . ')';
617             }
618             $startdateoptions[3] = get_string('today') . ' (' . userdate($today, $timeformat) . ')' ;
620             if ($count == 1) {
621                 $page->requires->strings_for_js(array(
622                     'ajaxoneuserfound',
623                     'ajaxxusersfound',
624                     'ajaxnext25',
625                     'enrol',
626                     'enrolmentoptions',
627                     'enrolusers',
628                     'errajaxfailedenrol',
629                     'errajaxsearch',
630                     'none',
631                     'usersearch',
632                     'unlimitedduration',
633                     'startdatetoday',
634                     'durationdays',
635                     'enrolperiod'), 'enrol');
636                 $page->requires->string_for_js('assignroles', 'role');
637                 $page->requires->string_for_js('startingfrom', 'moodle');
640                 $arguments = array(array(
641                     'instances'=>$arguments,
642                     'courseid'=>$course->id,
643                     'ajaxurl'=>'/enrol/ajax.php',
644                     'url'=>$url->out(false),
645                     'optionsStartDate'=>$startdateoptions));
646                 $page->requires->yui_module(array('moodle-enrol-enrolmentmanager', 'moodle-enrol-enrolmentmanager-skin'), 'M.enrol.enrolmentmanager.init', $arguments);
647             }
648             return $control;
649         }
650         return null;
651     }