MDL-48248 enrol_manual: Handle durations more precise than int days
[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;
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         if (!$manuallink = $this->get_manual_enrol_link($instance)) {
215             return false;
216         }
218         $button = new enrol_user_button($manuallink, get_string('enrolusers', 'enrol_manual'), 'get');
219         $button->class .= ' enrol_manual_plugin';
221         $startdate = $manager->get_course()->startdate;
222         if (!$defaultstart = get_config('enrol_manual', 'enrolstart')) {
223             // Default to now if there is no system setting.
224             $defaultstart = 4;
225         }
226         $startdateoptions = array();
227         $dateformat = get_string('strftimedatefullshort');
228         if ($startdate > 0) {
229             $startdateoptions[2] = get_string('coursestart') . ' (' . userdate($startdate, $dateformat) . ')';
230         }
231         $now = time();
232         $today = make_timestamp(date('Y', $now), date('m', $now), date('d', $now), 0, 0, 0);
233         $startdateoptions[3] = get_string('today') . ' (' . userdate($today, $dateformat) . ')';
234         $startdateoptions[4] = get_string('now', 'enrol_manual') . ' (' . userdate($now, get_string('strftimedatetimeshort')) . ')';
235         $defaultduration = $instance->enrolperiod > 0 ? $instance->enrolperiod / DAYSECS : '';
237         $modules = array('moodle-enrol_manual-quickenrolment', 'moodle-enrol_manual-quickenrolment-skin');
238         $arguments = array(
239             'instances'           => $instances,
240             'courseid'            => $instance->courseid,
241             'ajaxurl'             => '/enrol/manual/ajax.php',
242             'url'                 => $manager->get_moodlepage()->url->out(false),
243             'optionsStartDate'    => $startdateoptions,
244             'defaultRole'         => $instance->roleid,
245             'defaultDuration'     => $defaultduration,
246             'defaultStartDate'    => (int)$defaultstart,
247             'disableGradeHistory' => $CFG->disablegradehistory,
248             'recoverGradesDefault'=> '',
249             'cohortsAvailable'    => cohort_get_available_cohorts($manager->get_context(), COHORT_WITH_NOTENROLLED_MEMBERS_ONLY, 0, 1) ? true : false
250         );
252         if ($CFG->recovergradesdefault) {
253             $arguments['recoverGradesDefault'] = ' checked="checked"';
254         }
256         $function = 'M.enrol_manual.quickenrolment.init';
257         $button->require_yui_module($modules, $function, array($arguments));
258         $button->strings_for_js(array(
259             'ajaxoneuserfound',
260             'ajaxxusersfound',
261             'ajaxnext25',
262             'enrol',
263             'enrolmentoptions',
264             'enrolusers',
265             'enrolxusers',
266             'errajaxfailedenrol',
267             'errajaxsearch',
268             'foundxcohorts',
269             'none',
270             'usersearch',
271             'unlimitedduration',
272             'startdatetoday',
273             'durationdays',
274             'enrolperiod',
275             'finishenrollingusers',
276             'recovergrades'), 'enrol');
277         $button->strings_for_js(array('browseusers', 'browsecohorts'), 'enrol_manual');
278         $button->strings_for_js('assignroles', 'role');
279         $button->strings_for_js('startingfrom', 'moodle');
281         return $button;
282     }
284     /**
285      * Enrol cron support.
286      * @return void
287      */
288     public function cron() {
289         $trace = new text_progress_trace();
290         $this->sync($trace, null);
291         $this->send_expiry_notifications($trace);
292     }
294     /**
295      * Sync all meta course links.
296      *
297      * @param progress_trace $trace
298      * @param int $courseid one course, empty mean all
299      * @return int 0 means ok, 1 means error, 2 means plugin disabled
300      */
301     public function sync(progress_trace $trace, $courseid = null) {
302         global $DB;
304         if (!enrol_is_enabled('manual')) {
305             $trace->finished();
306             return 2;
307         }
309         // Unfortunately this may take a long time, execution can be interrupted safely here.
310         core_php_time_limit::raise();
311         raise_memory_limit(MEMORY_HUGE);
313         $trace->output('Verifying manual enrolment expiration...');
315         $params = array('now'=>time(), 'useractive'=>ENROL_USER_ACTIVE, 'courselevel'=>CONTEXT_COURSE);
316         $coursesql = "";
317         if ($courseid) {
318             $coursesql = "AND e.courseid = :courseid";
319             $params['courseid'] = $courseid;
320         }
322         // Deal with expired accounts.
323         $action = $this->get_config('expiredaction', ENROL_EXT_REMOVED_KEEP);
325         if ($action == ENROL_EXT_REMOVED_UNENROL) {
326             $instances = array();
327             $sql = "SELECT ue.*, e.courseid, c.id AS contextid
328                       FROM {user_enrolments} ue
329                       JOIN {enrol} e ON (e.id = ue.enrolid AND e.enrol = 'manual')
330                       JOIN {context} c ON (c.instanceid = e.courseid AND c.contextlevel = :courselevel)
331                      WHERE ue.timeend > 0 AND ue.timeend < :now
332                            $coursesql";
333             $rs = $DB->get_recordset_sql($sql, $params);
334             foreach ($rs as $ue) {
335                 if (empty($instances[$ue->enrolid])) {
336                     $instances[$ue->enrolid] = $DB->get_record('enrol', array('id'=>$ue->enrolid));
337                 }
338                 $instance = $instances[$ue->enrolid];
339                 // Always remove all manually assigned roles here, this may break enrol_self roles but we do not want hardcoded hacks here.
340                 role_unassign_all(array('userid'=>$ue->userid, 'contextid'=>$ue->contextid, 'component'=>'', 'itemid'=>0), true);
341                 $this->unenrol_user($instance, $ue->userid);
342                 $trace->output("unenrolling expired user $ue->userid from course $instance->courseid", 1);
343             }
344             $rs->close();
345             unset($instances);
347         } else if ($action == ENROL_EXT_REMOVED_SUSPENDNOROLES or $action == ENROL_EXT_REMOVED_SUSPEND) {
348             $instances = array();
349             $sql = "SELECT ue.*, e.courseid, c.id AS contextid
350                       FROM {user_enrolments} ue
351                       JOIN {enrol} e ON (e.id = ue.enrolid AND e.enrol = 'manual')
352                       JOIN {context} c ON (c.instanceid = e.courseid AND c.contextlevel = :courselevel)
353                      WHERE ue.timeend > 0 AND ue.timeend < :now
354                            AND ue.status = :useractive
355                            $coursesql";
356             $rs = $DB->get_recordset_sql($sql, $params);
357             foreach ($rs as $ue) {
358                 if (empty($instances[$ue->enrolid])) {
359                     $instances[$ue->enrolid] = $DB->get_record('enrol', array('id'=>$ue->enrolid));
360                 }
361                 $instance = $instances[$ue->enrolid];
362                 if ($action == ENROL_EXT_REMOVED_SUSPENDNOROLES) {
363                     // Remove all manually assigned roles here, this may break enrol_self roles but we do not want hardcoded hacks here.
364                     role_unassign_all(array('userid'=>$ue->userid, 'contextid'=>$ue->contextid, 'component'=>'', 'itemid'=>0), true);
365                     $this->update_user_enrol($instance, $ue->userid, ENROL_USER_SUSPENDED);
366                     $trace->output("suspending expired user $ue->userid in course $instance->courseid, roles unassigned", 1);
367                 } else {
368                     $this->update_user_enrol($instance, $ue->userid, ENROL_USER_SUSPENDED);
369                     $trace->output("suspending expired user $ue->userid in course $instance->courseid, roles kept", 1);
370                 }
371             }
372             $rs->close();
373             unset($instances);
375         } else {
376             // ENROL_EXT_REMOVED_KEEP means no changes.
377         }
379         $trace->output('...manual enrolment updates finished.');
380         $trace->finished();
382         return 0;
383     }
385     /**
386      * Returns the user who is responsible for manual enrolments in given instance.
387      *
388      * Usually it is the first editing teacher - the person with "highest authority"
389      * as defined by sort_by_roleassignment_authority() having 'enrol/manual:manage'
390      * capability.
391      *
392      * @param int $instanceid enrolment instance id
393      * @return stdClass user record
394      */
395     protected function get_enroller($instanceid) {
396         global $DB;
398         if ($this->lasternollerinstanceid == $instanceid and $this->lasternoller) {
399             return $this->lasternoller;
400         }
402         $instance = $DB->get_record('enrol', array('id'=>$instanceid, 'enrol'=>$this->get_name()), '*', MUST_EXIST);
403         $context = context_course::instance($instance->courseid);
405         if ($users = get_enrolled_users($context, 'enrol/manual:manage')) {
406             $users = sort_by_roleassignment_authority($users, $context);
407             $this->lasternoller = reset($users);
408             unset($users);
409         } else {
410             $this->lasternoller = parent::get_enroller($instanceid);
411         }
413         $this->lasternollerinstanceid = $instanceid;
415         return $this->lasternoller;
416     }
418     /**
419      * Gets an array of the user enrolment actions.
420      *
421      * @param course_enrolment_manager $manager
422      * @param stdClass $ue A user enrolment object
423      * @return array An array of user_enrolment_actions
424      */
425     public function get_user_enrolment_actions(course_enrolment_manager $manager, $ue) {
426         $actions = array();
427         $context = $manager->get_context();
428         $instance = $ue->enrolmentinstance;
429         $params = $manager->get_moodlepage()->url->params();
430         $params['ue'] = $ue->id;
431         if ($this->allow_unenrol_user($instance, $ue) && has_capability("enrol/manual:unenrol", $context)) {
432             $url = new moodle_url('/enrol/unenroluser.php', $params);
433             $actions[] = new user_enrolment_action(new pix_icon('t/delete', ''), get_string('unenrol', 'enrol'), $url, array('class'=>'unenrollink', 'rel'=>$ue->id));
434         }
435         if ($this->allow_manage($instance) && has_capability("enrol/manual:manage", $context)) {
436             $url = new moodle_url('/enrol/editenrolment.php', $params);
437             $actions[] = new user_enrolment_action(new pix_icon('t/edit', ''), get_string('edit'), $url, array('class'=>'editenrollink', 'rel'=>$ue->id));
438         }
439         return $actions;
440     }
442     /**
443      * The manual plugin has several bulk operations that can be performed.
444      * @param course_enrolment_manager $manager
445      * @return array
446      */
447     public function get_bulk_operations(course_enrolment_manager $manager) {
448         global $CFG;
449         require_once($CFG->dirroot.'/enrol/manual/locallib.php');
450         $context = $manager->get_context();
451         $bulkoperations = array();
452         if (has_capability("enrol/manual:manage", $context)) {
453             $bulkoperations['editselectedusers'] = new enrol_manual_editselectedusers_operation($manager, $this);
454         }
455         if (has_capability("enrol/manual:unenrol", $context)) {
456             $bulkoperations['deleteselectedusers'] = new enrol_manual_deleteselectedusers_operation($manager, $this);
457         }
458         return $bulkoperations;
459     }
461     /**
462      * Restore instance and map settings.
463      *
464      * @param restore_enrolments_structure_step $step
465      * @param stdClass $data
466      * @param stdClass $course
467      * @param int $oldid
468      */
469     public function restore_instance(restore_enrolments_structure_step $step, stdClass $data, $course, $oldid) {
470         global $DB;
471         // There is only I manual enrol instance allowed per course.
472         if ($instances = $DB->get_records('enrol', array('courseid'=>$data->courseid, 'enrol'=>'manual'), 'id')) {
473             $instance = reset($instances);
474             $instanceid = $instance->id;
475         } else {
476             $instanceid = $this->add_instance($course, (array)$data);
477         }
478         $step->set_mapping('enrol', $oldid, $instanceid);
479     }
481     /**
482      * Restore user enrolment.
483      *
484      * @param restore_enrolments_structure_step $step
485      * @param stdClass $data
486      * @param stdClass $instance
487      * @param int $oldinstancestatus
488      * @param int $userid
489      */
490     public function restore_user_enrolment(restore_enrolments_structure_step $step, $data, $instance, $userid, $oldinstancestatus) {
491         global $DB;
493         // Note: this is a bit tricky because other types may be converted to manual enrolments,
494         //       and manual is restricted to one enrolment per user.
496         $ue = $DB->get_record('user_enrolments', array('enrolid'=>$instance->id, 'userid'=>$userid));
497         $enrol = false;
498         if ($ue and $ue->status == ENROL_USER_ACTIVE) {
499             // We do not want to restrict current active enrolments, let's kind of merge the times only.
500             // This prevents some teacher lockouts too.
501             if ($data->status == ENROL_USER_ACTIVE) {
502                 if ($data->timestart > $ue->timestart) {
503                     $data->timestart = $ue->timestart;
504                     $enrol = true;
505                 }
507                 if ($data->timeend == 0) {
508                     if ($ue->timeend != 0) {
509                         $enrol = true;
510                     }
511                 } else if ($ue->timeend == 0) {
512                     $data->timeend = 0;
513                 } else if ($data->timeend < $ue->timeend) {
514                     $data->timeend = $ue->timeend;
515                     $enrol = true;
516                 }
517             }
518         } else {
519             if ($instance->status == ENROL_INSTANCE_ENABLED and $oldinstancestatus != ENROL_INSTANCE_ENABLED) {
520                 // Make sure that user enrolments are not activated accidentally,
521                 // we do it only here because it is not expected that enrolments are migrated to other plugins.
522                 $data->status = ENROL_USER_SUSPENDED;
523             }
524             $enrol = true;
525         }
527         if ($enrol) {
528             $this->enrol_user($instance, $userid, null, $data->timestart, $data->timeend, $data->status);
529         }
530     }
532     /**
533      * Restore role assignment.
534      *
535      * @param stdClass $instance
536      * @param int $roleid
537      * @param int $userid
538      * @param int $contextid
539      */
540     public function restore_role_assignment($instance, $roleid, $userid, $contextid) {
541         // This is necessary only because we may migrate other types to this instance,
542         // we do not use component in manual or self enrol.
543         role_assign($roleid, $userid, $contextid, '', 0);
544     }
546     /**
547      * Restore user group membership.
548      * @param stdClass $instance
549      * @param int $groupid
550      * @param int $userid
551      */
552     public function restore_group_member($instance, $groupid, $userid) {
553         global $CFG;
554         require_once("$CFG->dirroot/group/lib.php");
556         // This might be called when forcing restore as manual enrolments.
558         groups_add_member($groupid, $userid);
559     }
561     /**
562      * Is it possible to delete enrol instance via standard UI?
563      *
564      * @param object $instance
565      * @return bool
566      */
567     public function can_delete_instance($instance) {
568         $context = context_course::instance($instance->courseid);
569         return has_capability('enrol/manual:config', $context);
570     }
572     /**
573      * Is it possible to hide/show enrol instance via standard UI?
574      *
575      * @param stdClass $instance
576      * @return bool
577      */
578     public function can_hide_show_instance($instance) {
579         $context = context_course::instance($instance->courseid);
580         return has_capability('enrol/manual:config', $context);
581     }
583     /**
584      * Enrol all not enrolled cohort members into course via enrol instance.
585      *
586      * @param stdClass $instance
587      * @param int $cohortid
588      * @param int $roleid optional role id
589      * @param int $timestart 0 means unknown
590      * @param int $timeend 0 means forever
591      * @param int $status default to ENROL_USER_ACTIVE for new enrolments, no change by default in updates
592      * @param bool $recovergrades restore grade history
593      */
594     public function enrol_cohort(stdClass $instance, $cohortid, $roleid = null, $timestart = 0, $timeend = 0, $status = null, $recovergrades = null) {
595         global $DB;
596         $context = context_course::instance($instance->courseid);
597         list($esql, $params) = get_enrolled_sql($context);
598         $sql = "SELECT cm.userid FROM {cohort_members} cm LEFT JOIN ($esql) u ON u.id = cm.userid ".
599             "WHERE cm.cohortid = :cohortid AND u.id IS NULL";
600         $params['cohortid'] = $cohortid;
601         $members = $DB->get_fieldset_sql($sql, $params);
602         foreach ($members as $userid) {
603             $this->enrol_user($instance, $userid, $roleid, $timestart, $timeend, $status, $recovergrades);
604         }
605     }
607     /**
608      * We are a good plugin and don't invent our own UI/validation code path.
609      *
610      * @return boolean
611      */
612     public function use_standard_editing_ui() {
613         return true;
614     }
616     /**
617      * Return an array of valid options for the status.
618      *
619      * @return array
620      */
621     protected function get_status_options() {
622         $options = array(ENROL_INSTANCE_ENABLED  => get_string('yes'),
623                          ENROL_INSTANCE_DISABLED => get_string('no'));
624         return $options;
625     }
627     /**
628      * Return an array of valid options for the roleid.
629      *
630      * @param stdClass $instance
631      * @param context $context
632      * @return array
633      */
634     protected function get_roleid_options($instance, $context) {
635         if ($instance->id) {
636             $roles = get_default_enrol_roles($context, $instance->roleid);
637         } else {
638             $roles = get_default_enrol_roles($context, $this->get_config('roleid'));
639         }
640         return $roles;
641     }
643     /**
644      * Return an array of valid options for the expirynotify.
645      *
646      * @return array
647      */
648     protected function get_expirynotify_options() {
649         $options = array(
650             0 => get_string('no'),
651             1 => get_string('expirynotifyenroller', 'core_enrol'),
652             2 => get_string('expirynotifyall', 'core_enrol')
653         );
654         return $options;
655     }
657     /**
658      * Add elements to the edit instance form.
659      *
660      * @param stdClass $instance
661      * @param MoodleQuickForm $mform
662      * @param context $context
663      * @return bool
664      */
665     public function edit_instance_form($instance, MoodleQuickForm $mform, $context) {
667         $options = $this->get_status_options();
668         $mform->addElement('select', 'status', get_string('status', 'enrol_manual'), $options);
669         $mform->addHelpButton('status', 'status', 'enrol_manual');
670         $mform->setDefault('status', $this->get_config('status'));
672         $roles = $this->get_roleid_options($instance, $context);
673         $mform->addElement('select', 'roleid', get_string('defaultrole', 'role'), $roles);
674         $mform->setDefault('roleid', $this->get_config('roleid'));
676         $options = array('optional' => true, 'defaultunit' => 86400);
677         $mform->addElement('duration', 'enrolperiod', get_string('defaultperiod', 'enrol_manual'), $options);
678         $mform->setDefault('enrolperiod', $this->get_config('enrolperiod'));
679         $mform->addHelpButton('enrolperiod', 'defaultperiod', 'enrol_manual');
681         $options = $this->get_expirynotify_options();
682         $mform->addElement('select', 'expirynotify', get_string('expirynotify', 'core_enrol'), $options);
683         $mform->addHelpButton('expirynotify', 'expirynotify', 'core_enrol');
685         $options = array('optional' => false, 'defaultunit' => 86400);
686         $mform->addElement('duration', 'expirythreshold', get_string('expirythreshold', 'core_enrol'), $options);
687         $mform->addHelpButton('expirythreshold', 'expirythreshold', 'core_enrol');
688         $mform->disabledIf('expirythreshold', 'expirynotify', 'eq', 0);
690         if (enrol_accessing_via_instance($instance)) {
691             $warntext = get_string('instanceeditselfwarningtext', 'core_enrol');
692             $mform->addElement('static', 'selfwarn', get_string('instanceeditselfwarning', 'core_enrol'), $warntext);
693         }
694     }
696     /**
697      * Perform custom validation of the data used to edit the instance.
698      *
699      * @param array $data array of ("fieldname"=>value) of submitted data
700      * @param array $files array of uploaded files "element_name"=>tmp_file_path
701      * @param object $instance The instance loaded from the DB
702      * @param context $context The context of the instance we are editing
703      * @return array of "element_name"=>"error_description" if there are errors,
704      *         or an empty array if everything is OK.
705      * @return void
706      */
707     public function edit_instance_validation($data, $files, $instance, $context) {
708         $errors = array();
710         if ($data['expirynotify'] > 0 and $data['expirythreshold'] < 86400) {
711             $errors['expirythreshold'] = get_string('errorthresholdlow', 'core_enrol');
712         }
714         $validstatus = array_keys($this->get_status_options());
715         $validroles = array_keys($this->get_roleid_options($instance, $context));
716         $validexpirynotify = array_keys($this->get_expirynotify_options());
718         $tovalidate = array(
719             'status' => $validstatus,
720             'roleid' => $validroles,
721             'enrolperiod' => PARAM_INT,
722             'expirynotify' => $validexpirynotify,
723             'expirythreshold' => PARAM_INT
724         );
726         $typeerrors = $this->validate_param_types($data, $tovalidate);
727         $errors = array_merge($errors, $typeerrors);
729         return $errors;
730     }