weekly release 3.4dev
[moodle.git] / enrol / manual / lib.php
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/>.
17 /**
18  * Manual enrolment plugin main library file.
19  *
20  * @package    enrol_manual
21  * @copyright  2010 Petr Skoda {@link http://skodak.org}
22  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
23  */
25 defined('MOODLE_INTERNAL') || die();
27 class enrol_manual_plugin extends enrol_plugin {
29     protected $lasternoller = null;
30     protected $lasternollerinstanceid = 0;
32     public function roles_protected() {
33         // Users may tweak the roles later.
34         return false;
35     }
37     public function allow_enrol(stdClass $instance) {
38         // Users with enrol cap may unenrol other users manually manually.
39         return true;
40     }
42     public function allow_unenrol(stdClass $instance) {
43         // Users with unenrol cap may unenrol other users manually manually.
44         return true;
45     }
47     public function allow_manage(stdClass $instance) {
48         // Users with manage cap may tweak period and status.
49         return true;
50     }
52     /**
53      * Returns link to manual enrol UI if exists.
54      * Does the access control tests automatically.
55      *
56      * @param stdClass $instance
57      * @return moodle_url
58      */
59     public function get_manual_enrol_link($instance) {
60         $name = $this->get_name();
61         if ($instance->enrol !== $name) {
62             throw new coding_exception('invalid enrol instance!');
63         }
65         if (!enrol_is_enabled($name)) {
66             return NULL;
67         }
69         $context = context_course::instance($instance->courseid, MUST_EXIST);
71         if (!has_capability('enrol/manual:enrol', $context)) {
72             // Note: manage capability not used here because it is used for editing
73             // of existing enrolments which is not possible here.
74             return NULL;
75         }
77         return new moodle_url('/enrol/manual/manage.php', array('enrolid'=>$instance->id, 'id'=>$instance->courseid));
78     }
80     /**
81      * Return true if we can add a new instance to this course.
82      *
83      * @param int $courseid
84      * @return boolean
85      */
86     public function can_add_instance($courseid) {
87         global $DB;
89         $context = context_course::instance($courseid, MUST_EXIST);
90         if (!has_capability('moodle/course:enrolconfig', $context) or !has_capability('enrol/manual:config', $context)) {
91             return false;
92         }
94         if ($DB->record_exists('enrol', array('courseid'=>$courseid, 'enrol'=>'manual'))) {
95             // Multiple instances not supported.
96             return false;
97         }
99         return true;
100     }
102     /**
103      * Returns edit icons for the page with list of instances.
104      * @param stdClass $instance
105      * @return array
106      */
107     public function get_action_icons(stdClass $instance) {
108         global $OUTPUT;
110         $context = context_course::instance($instance->courseid);
112         $icons = array();
113         if (has_capability('enrol/manual:enrol', $context) or has_capability('enrol/manual:unenrol', $context)) {
114             $managelink = new moodle_url("/enrol/manual/manage.php", array('enrolid'=>$instance->id));
115             $icons[] = $OUTPUT->action_icon($managelink, new pix_icon('t/enrolusers', get_string('enrolusers', 'enrol_manual'), 'core', array('class'=>'iconsmall')));
116         }
117         $parenticons = parent::get_action_icons($instance);
118         $icons = array_merge($icons, $parenticons);
120         return $icons;
121     }
123     /**
124      * Add new instance of enrol plugin with default settings.
125      * @param stdClass $course
126      * @return int id of new instance, null if can not be created
127      */
128     public function add_default_instance($course) {
129         $expirynotify = $this->get_config('expirynotify', 0);
130         if ($expirynotify == 2) {
131             $expirynotify = 1;
132             $notifyall = 1;
133         } else {
134             $notifyall = 0;
135         }
136         $fields = array(
137             'status'          => $this->get_config('status'),
138             'roleid'          => $this->get_config('roleid', 0),
139             'enrolperiod'     => $this->get_config('enrolperiod', 0),
140             'expirynotify'    => $expirynotify,
141             'notifyall'       => $notifyall,
142             'expirythreshold' => $this->get_config('expirythreshold', 86400),
143         );
144         return $this->add_instance($course, $fields);
145     }
147     /**
148      * Add new instance of enrol plugin.
149      * @param stdClass $course
150      * @param array instance fields
151      * @return int id of new instance, null if can not be created
152      */
153     public function add_instance($course, array $fields = NULL) {
154         global $DB;
156         if ($DB->record_exists('enrol', array('courseid'=>$course->id, 'enrol'=>'manual'))) {
157             // only one instance allowed, sorry
158             return NULL;
159         }
161         return parent::add_instance($course, $fields);
162     }
164     /**
165      * Update instance of enrol plugin.
166      * @param stdClass $instance
167      * @param stdClass $data modified instance fields
168      * @return boolean
169      */
170     public function update_instance($instance, $data) {
171         global $DB;
173         // Delete all other instances, leaving only one.
174         if ($instances = $DB->get_records('enrol', array('courseid' => $instance->courseid, 'enrol' => 'manual'), 'id ASC')) {
175             foreach ($instances as $anotherinstance) {
176                 if ($anotherinstance->id != $instance->id) {
177                     $this->delete_instance($anotherinstance);
178                 }
179             }
180         }
181         return parent::update_instance($instance, $data);
182     }
184     /**
185      * Returns a button to manually enrol users through the manual enrolment plugin.
186      *
187      * By default the first manual enrolment plugin instance available in the course is used.
188      * If no manual enrolment instances exist within the course then false is returned.
189      *
190      * This function also adds a quickenrolment JS ui to the page so that users can be enrolled
191      * via AJAX.
192      *
193      * @param course_enrolment_manager $manager
194      * @return enrol_user_button
195      */
196     public function get_manual_enrol_button(course_enrolment_manager $manager) {
197         global $CFG, $PAGE;
198         require_once($CFG->dirroot.'/cohort/lib.php');
200         $instance = null;
201         $instances = array();
202         foreach ($manager->get_enrolment_instances() as $tempinstance) {
203             if ($tempinstance->enrol == 'manual') {
204                 if ($instance === null) {
205                     $instance = $tempinstance;
206                 }
207                 $instances[] = array('id' => $tempinstance->id, 'name' => $this->get_instance_name($tempinstance));
208             }
209         }
210         if (empty($instance)) {
211             return false;
212         }
214         $link = $this->get_manual_enrol_link($instance);
215         if (!$link) {
216             return false;
217         }
219         $button = new enrol_user_button($link, get_string('enrolusers', 'enrol_manual'), 'get');
220         $button->class .= ' enrol_manual_plugin';
222         $context = context_course::instance($instance->courseid);
223         $arguments = array('contextid' => $context->id);
225         $PAGE->requires->js_call_amd('enrol_manual/quickenrolment', 'init', array($arguments));
227         return $button;
228     }
230     /**
231      * Enrol cron support.
232      * @return void
233      */
234     public function cron() {
235         $trace = new text_progress_trace();
236         $this->sync($trace, null);
237         $this->send_expiry_notifications($trace);
238     }
240     /**
241      * Sync all meta course links.
242      *
243      * @param progress_trace $trace
244      * @param int $courseid one course, empty mean all
245      * @return int 0 means ok, 1 means error, 2 means plugin disabled
246      */
247     public function sync(progress_trace $trace, $courseid = null) {
248         global $DB;
250         if (!enrol_is_enabled('manual')) {
251             $trace->finished();
252             return 2;
253         }
255         // Unfortunately this may take a long time, execution can be interrupted safely here.
256         core_php_time_limit::raise();
257         raise_memory_limit(MEMORY_HUGE);
259         $trace->output('Verifying manual enrolment expiration...');
261         $params = array('now'=>time(), 'useractive'=>ENROL_USER_ACTIVE, 'courselevel'=>CONTEXT_COURSE);
262         $coursesql = "";
263         if ($courseid) {
264             $coursesql = "AND e.courseid = :courseid";
265             $params['courseid'] = $courseid;
266         }
268         // Deal with expired accounts.
269         $action = $this->get_config('expiredaction', ENROL_EXT_REMOVED_KEEP);
271         if ($action == ENROL_EXT_REMOVED_UNENROL) {
272             $instances = array();
273             $sql = "SELECT ue.*, e.courseid, c.id AS contextid
274                       FROM {user_enrolments} ue
275                       JOIN {enrol} e ON (e.id = ue.enrolid AND e.enrol = 'manual')
276                       JOIN {context} c ON (c.instanceid = e.courseid AND c.contextlevel = :courselevel)
277                      WHERE ue.timeend > 0 AND ue.timeend < :now
278                            $coursesql";
279             $rs = $DB->get_recordset_sql($sql, $params);
280             foreach ($rs as $ue) {
281                 if (empty($instances[$ue->enrolid])) {
282                     $instances[$ue->enrolid] = $DB->get_record('enrol', array('id'=>$ue->enrolid));
283                 }
284                 $instance = $instances[$ue->enrolid];
285                 // Always remove all manually assigned roles here, this may break enrol_self roles but we do not want hardcoded hacks here.
286                 role_unassign_all(array('userid'=>$ue->userid, 'contextid'=>$ue->contextid, 'component'=>'', 'itemid'=>0), true);
287                 $this->unenrol_user($instance, $ue->userid);
288                 $trace->output("unenrolling expired user $ue->userid from course $instance->courseid", 1);
289             }
290             $rs->close();
291             unset($instances);
293         } else if ($action == ENROL_EXT_REMOVED_SUSPENDNOROLES or $action == ENROL_EXT_REMOVED_SUSPEND) {
294             $instances = array();
295             $sql = "SELECT ue.*, e.courseid, c.id AS contextid
296                       FROM {user_enrolments} ue
297                       JOIN {enrol} e ON (e.id = ue.enrolid AND e.enrol = 'manual')
298                       JOIN {context} c ON (c.instanceid = e.courseid AND c.contextlevel = :courselevel)
299                      WHERE ue.timeend > 0 AND ue.timeend < :now
300                            AND ue.status = :useractive
301                            $coursesql";
302             $rs = $DB->get_recordset_sql($sql, $params);
303             foreach ($rs as $ue) {
304                 if (empty($instances[$ue->enrolid])) {
305                     $instances[$ue->enrolid] = $DB->get_record('enrol', array('id'=>$ue->enrolid));
306                 }
307                 $instance = $instances[$ue->enrolid];
308                 if ($action == ENROL_EXT_REMOVED_SUSPENDNOROLES) {
309                     // Remove all manually assigned roles here, this may break enrol_self roles but we do not want hardcoded hacks here.
310                     role_unassign_all(array('userid'=>$ue->userid, 'contextid'=>$ue->contextid, 'component'=>'', 'itemid'=>0), true);
311                     $this->update_user_enrol($instance, $ue->userid, ENROL_USER_SUSPENDED);
312                     $trace->output("suspending expired user $ue->userid in course $instance->courseid, roles unassigned", 1);
313                 } else {
314                     $this->update_user_enrol($instance, $ue->userid, ENROL_USER_SUSPENDED);
315                     $trace->output("suspending expired user $ue->userid in course $instance->courseid, roles kept", 1);
316                 }
317             }
318             $rs->close();
319             unset($instances);
321         } else {
322             // ENROL_EXT_REMOVED_KEEP means no changes.
323         }
325         $trace->output('...manual enrolment updates finished.');
326         $trace->finished();
328         return 0;
329     }
331     /**
332      * Returns the user who is responsible for manual enrolments in given instance.
333      *
334      * Usually it is the first editing teacher - the person with "highest authority"
335      * as defined by sort_by_roleassignment_authority() having 'enrol/manual:manage'
336      * capability.
337      *
338      * @param int $instanceid enrolment instance id
339      * @return stdClass user record
340      */
341     protected function get_enroller($instanceid) {
342         global $DB;
344         if ($this->lasternollerinstanceid == $instanceid and $this->lasternoller) {
345             return $this->lasternoller;
346         }
348         $instance = $DB->get_record('enrol', array('id'=>$instanceid, 'enrol'=>$this->get_name()), '*', MUST_EXIST);
349         $context = context_course::instance($instance->courseid);
351         if ($users = get_enrolled_users($context, 'enrol/manual:manage')) {
352             $users = sort_by_roleassignment_authority($users, $context);
353             $this->lasternoller = reset($users);
354             unset($users);
355         } else {
356             $this->lasternoller = parent::get_enroller($instanceid);
357         }
359         $this->lasternollerinstanceid = $instanceid;
361         return $this->lasternoller;
362     }
364     /**
365      * Gets an array of the user enrolment actions.
366      *
367      * @param course_enrolment_manager $manager
368      * @param stdClass $ue A user enrolment object
369      * @return array An array of user_enrolment_actions
370      */
371     public function get_user_enrolment_actions(course_enrolment_manager $manager, $ue) {
372         $actions = array();
373         $context = $manager->get_context();
374         $instance = $ue->enrolmentinstance;
375         $params = $manager->get_moodlepage()->url->params();
376         $params['ue'] = $ue->id;
377         if ($this->allow_unenrol_user($instance, $ue) && has_capability("enrol/manual:unenrol", $context)) {
378             $url = new moodle_url('/enrol/unenroluser.php', $params);
379             $actionparams = array('class' => 'unenrollink', 'rel' => $ue->id, 'data-action' => ENROL_ACTION_UNENROL);
380             $actions[] = new user_enrolment_action(new pix_icon('t/delete', get_string('unenrol', 'enrol')),
381                 get_string('unenrol', 'enrol'), $url, $actionparams);
382         }
383         if ($this->allow_manage($instance) && has_capability("enrol/manual:manage", $context)) {
384             $url = new moodle_url('/enrol/editenrolment.php', $params);
385             $actionparams = array('class' => 'editenrollink', 'rel' => $ue->id, 'data-action' => ENROL_ACTION_EDIT);
386             $actions[] = new user_enrolment_action(new pix_icon('t/edit', get_string('editenrolment', 'enrol')),
387                 get_string('editenrolment', 'enrol'), $url, $actionparams);
388         }
389         return $actions;
390     }
392     /**
393      * The manual plugin has several bulk operations that can be performed.
394      * @param course_enrolment_manager $manager
395      * @return array
396      */
397     public function get_bulk_operations(course_enrolment_manager $manager) {
398         global $CFG;
399         require_once($CFG->dirroot.'/enrol/manual/locallib.php');
400         $context = $manager->get_context();
401         $bulkoperations = array();
402         if (has_capability("enrol/manual:manage", $context)) {
403             $bulkoperations['editselectedusers'] = new enrol_manual_editselectedusers_operation($manager, $this);
404         }
405         if (has_capability("enrol/manual:unenrol", $context)) {
406             $bulkoperations['deleteselectedusers'] = new enrol_manual_deleteselectedusers_operation($manager, $this);
407         }
408         return $bulkoperations;
409     }
411     /**
412      * Restore instance and map settings.
413      *
414      * @param restore_enrolments_structure_step $step
415      * @param stdClass $data
416      * @param stdClass $course
417      * @param int $oldid
418      */
419     public function restore_instance(restore_enrolments_structure_step $step, stdClass $data, $course, $oldid) {
420         global $DB;
421         // There is only I manual enrol instance allowed per course.
422         if ($instances = $DB->get_records('enrol', array('courseid'=>$data->courseid, 'enrol'=>'manual'), 'id')) {
423             $instance = reset($instances);
424             $instanceid = $instance->id;
425         } else {
426             $instanceid = $this->add_instance($course, (array)$data);
427         }
428         $step->set_mapping('enrol', $oldid, $instanceid);
429     }
431     /**
432      * Restore user enrolment.
433      *
434      * @param restore_enrolments_structure_step $step
435      * @param stdClass $data
436      * @param stdClass $instance
437      * @param int $oldinstancestatus
438      * @param int $userid
439      */
440     public function restore_user_enrolment(restore_enrolments_structure_step $step, $data, $instance, $userid, $oldinstancestatus) {
441         global $DB;
443         // Note: this is a bit tricky because other types may be converted to manual enrolments,
444         //       and manual is restricted to one enrolment per user.
446         $ue = $DB->get_record('user_enrolments', array('enrolid'=>$instance->id, 'userid'=>$userid));
447         $enrol = false;
448         if ($ue and $ue->status == ENROL_USER_ACTIVE) {
449             // We do not want to restrict current active enrolments, let's kind of merge the times only.
450             // This prevents some teacher lockouts too.
451             if ($data->status == ENROL_USER_ACTIVE) {
452                 if ($data->timestart > $ue->timestart) {
453                     $data->timestart = $ue->timestart;
454                     $enrol = true;
455                 }
457                 if ($data->timeend == 0) {
458                     if ($ue->timeend != 0) {
459                         $enrol = true;
460                     }
461                 } else if ($ue->timeend == 0) {
462                     $data->timeend = 0;
463                 } else if ($data->timeend < $ue->timeend) {
464                     $data->timeend = $ue->timeend;
465                     $enrol = true;
466                 }
467             }
468         } else {
469             if ($instance->status == ENROL_INSTANCE_ENABLED and $oldinstancestatus != ENROL_INSTANCE_ENABLED) {
470                 // Make sure that user enrolments are not activated accidentally,
471                 // we do it only here because it is not expected that enrolments are migrated to other plugins.
472                 $data->status = ENROL_USER_SUSPENDED;
473             }
474             $enrol = true;
475         }
477         if ($enrol) {
478             $this->enrol_user($instance, $userid, null, $data->timestart, $data->timeend, $data->status);
479         }
480     }
482     /**
483      * Restore role assignment.
484      *
485      * @param stdClass $instance
486      * @param int $roleid
487      * @param int $userid
488      * @param int $contextid
489      */
490     public function restore_role_assignment($instance, $roleid, $userid, $contextid) {
491         // This is necessary only because we may migrate other types to this instance,
492         // we do not use component in manual or self enrol.
493         role_assign($roleid, $userid, $contextid, '', 0);
494     }
496     /**
497      * Restore user group membership.
498      * @param stdClass $instance
499      * @param int $groupid
500      * @param int $userid
501      */
502     public function restore_group_member($instance, $groupid, $userid) {
503         global $CFG;
504         require_once("$CFG->dirroot/group/lib.php");
506         // This might be called when forcing restore as manual enrolments.
508         groups_add_member($groupid, $userid);
509     }
511     /**
512      * Is it possible to delete enrol instance via standard UI?
513      *
514      * @param object $instance
515      * @return bool
516      */
517     public function can_delete_instance($instance) {
518         $context = context_course::instance($instance->courseid);
519         return has_capability('enrol/manual:config', $context);
520     }
522     /**
523      * Is it possible to hide/show enrol instance via standard UI?
524      *
525      * @param stdClass $instance
526      * @return bool
527      */
528     public function can_hide_show_instance($instance) {
529         $context = context_course::instance($instance->courseid);
530         return has_capability('enrol/manual:config', $context);
531     }
533     /**
534      * Enrol all not enrolled cohort members into course via enrol instance.
535      *
536      * @param stdClass $instance
537      * @param int $cohortid
538      * @param int $roleid optional role id
539      * @param int $timestart 0 means unknown
540      * @param int $timeend 0 means forever
541      * @param int $status default to ENROL_USER_ACTIVE for new enrolments, no change by default in updates
542      * @param bool $recovergrades restore grade history
543      */
544     public function enrol_cohort(stdClass $instance, $cohortid, $roleid = null, $timestart = 0, $timeend = 0, $status = null, $recovergrades = null) {
545         global $DB;
546         $context = context_course::instance($instance->courseid);
547         list($esql, $params) = get_enrolled_sql($context);
548         $sql = "SELECT cm.userid FROM {cohort_members} cm LEFT JOIN ($esql) u ON u.id = cm.userid ".
549             "WHERE cm.cohortid = :cohortid AND u.id IS NULL";
550         $params['cohortid'] = $cohortid;
551         $members = $DB->get_fieldset_sql($sql, $params);
552         foreach ($members as $userid) {
553             $this->enrol_user($instance, $userid, $roleid, $timestart, $timeend, $status, $recovergrades);
554         }
555     }
557     /**
558      * We are a good plugin and don't invent our own UI/validation code path.
559      *
560      * @return boolean
561      */
562     public function use_standard_editing_ui() {
563         return true;
564     }
566     /**
567      * Return an array of valid options for the status.
568      *
569      * @return array
570      */
571     protected function get_status_options() {
572         $options = array(ENROL_INSTANCE_ENABLED  => get_string('yes'),
573                          ENROL_INSTANCE_DISABLED => get_string('no'));
574         return $options;
575     }
577     /**
578      * Return an array of valid options for the roleid.
579      *
580      * @param stdClass $instance
581      * @param context $context
582      * @return array
583      */
584     protected function get_roleid_options($instance, $context) {
585         if ($instance->id) {
586             $roles = get_default_enrol_roles($context, $instance->roleid);
587         } else {
588             $roles = get_default_enrol_roles($context, $this->get_config('roleid'));
589         }
590         return $roles;
591     }
593     /**
594      * Return an array of valid options for the expirynotify.
595      *
596      * @return array
597      */
598     protected function get_expirynotify_options() {
599         $options = array(
600             0 => get_string('no'),
601             1 => get_string('expirynotifyenroller', 'core_enrol'),
602             2 => get_string('expirynotifyall', 'core_enrol')
603         );
604         return $options;
605     }
607     /**
608      * Add elements to the edit instance form.
609      *
610      * @param stdClass $instance
611      * @param MoodleQuickForm $mform
612      * @param context $context
613      * @return bool
614      */
615     public function edit_instance_form($instance, MoodleQuickForm $mform, $context) {
617         $options = $this->get_status_options();
618         $mform->addElement('select', 'status', get_string('status', 'enrol_manual'), $options);
619         $mform->addHelpButton('status', 'status', 'enrol_manual');
620         $mform->setDefault('status', $this->get_config('status'));
622         $roles = $this->get_roleid_options($instance, $context);
623         $mform->addElement('select', 'roleid', get_string('defaultrole', 'role'), $roles);
624         $mform->setDefault('roleid', $this->get_config('roleid'));
626         $options = array('optional' => true, 'defaultunit' => 86400);
627         $mform->addElement('duration', 'enrolperiod', get_string('defaultperiod', 'enrol_manual'), $options);
628         $mform->setDefault('enrolperiod', $this->get_config('enrolperiod'));
629         $mform->addHelpButton('enrolperiod', 'defaultperiod', 'enrol_manual');
631         $options = $this->get_expirynotify_options();
632         $mform->addElement('select', 'expirynotify', get_string('expirynotify', 'core_enrol'), $options);
633         $mform->addHelpButton('expirynotify', 'expirynotify', 'core_enrol');
635         $options = array('optional' => false, 'defaultunit' => 86400);
636         $mform->addElement('duration', 'expirythreshold', get_string('expirythreshold', 'core_enrol'), $options);
637         $mform->addHelpButton('expirythreshold', 'expirythreshold', 'core_enrol');
638         $mform->disabledIf('expirythreshold', 'expirynotify', 'eq', 0);
640         if (enrol_accessing_via_instance($instance)) {
641             $warntext = get_string('instanceeditselfwarningtext', 'core_enrol');
642             $mform->addElement('static', 'selfwarn', get_string('instanceeditselfwarning', 'core_enrol'), $warntext);
643         }
644     }
646     /**
647      * Perform custom validation of the data used to edit the instance.
648      *
649      * @param array $data array of ("fieldname"=>value) of submitted data
650      * @param array $files array of uploaded files "element_name"=>tmp_file_path
651      * @param object $instance The instance loaded from the DB
652      * @param context $context The context of the instance we are editing
653      * @return array of "element_name"=>"error_description" if there are errors,
654      *         or an empty array if everything is OK.
655      * @return void
656      */
657     public function edit_instance_validation($data, $files, $instance, $context) {
658         $errors = array();
660         if ($data['expirynotify'] > 0 and $data['expirythreshold'] < 86400) {
661             $errors['expirythreshold'] = get_string('errorthresholdlow', 'core_enrol');
662         }
664         $validstatus = array_keys($this->get_status_options());
665         $validroles = array_keys($this->get_roleid_options($instance, $context));
666         $validexpirynotify = array_keys($this->get_expirynotify_options());
668         $tovalidate = array(
669             'status' => $validstatus,
670             'roleid' => $validroles,
671             'enrolperiod' => PARAM_INT,
672             'expirynotify' => $validexpirynotify,
673             'expirythreshold' => PARAM_INT
674         );
676         $typeerrors = $this->validate_param_types($data, $tovalidate);
677         $errors = array_merge($errors, $typeerrors);
679         return $errors;
680     }
684 /**
685  * Serve the manual enrol users form as a fragment.
686  *
687  * @param array $args List of named arguments for the fragment loader.
688  * @return string
689  */
690 function enrol_manual_output_fragment_enrol_users_form($args) {
691     $args = (object) $args;
692     $context = $args->context;
693     $o = '';
695     require_capability('enrol/manual:enrol', $context);
696     $mform = new enrol_manual_enrol_users_form(null, $args);
698     ob_start();
699     $mform->display();
700     $o .= ob_get_contents();
701     ob_end_clean();
703     return $o;