Merge branch 'MDL-76213' of https://github.com/Chocolate-lightning/moodle
[moodle.git] / enrol / tests / enrollib_test.php
blob2f1d91404ff62bc6a09ac7137d675f1e2cdbe513
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 * Test non-plugin enrollib parts.
20 * @package core_enrol
21 * @category phpunit
22 * @copyright 2012 Petr Skoda {@link http://skodak.org}
23 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
26 defined('MOODLE_INTERNAL') || die();
29 /**
30 * Test non-plugin enrollib parts.
32 * @package core
33 * @category phpunit
34 * @copyright 2012 Petr Skoda {@link http://skodak.org}
35 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
37 class enrollib_test extends advanced_testcase {
39 public function test_enrol_get_all_users_courses() {
40 global $DB, $CFG;
42 $this->resetAfterTest();
44 $studentrole = $DB->get_record('role', array('shortname'=>'student'));
45 $this->assertNotEmpty($studentrole);
46 $teacherrole = $DB->get_record('role', array('shortname'=>'teacher'));
47 $this->assertNotEmpty($teacherrole);
49 $admin = get_admin();
50 $user1 = $this->getDataGenerator()->create_user();
51 $user2 = $this->getDataGenerator()->create_user();
52 $user3 = $this->getDataGenerator()->create_user();
53 $user4 = $this->getDataGenerator()->create_user();
54 $user5 = $this->getDataGenerator()->create_user();
56 $category1 = $this->getDataGenerator()->create_category(array('visible'=>0));
57 $category2 = $this->getDataGenerator()->create_category();
59 $course1 = $this->getDataGenerator()->create_course(array(
60 'shortname' => 'Z',
61 'idnumber' => '123',
62 'category' => $category1->id,
63 ));
64 $course2 = $this->getDataGenerator()->create_course(array(
65 'shortname' => 'X',
66 'idnumber' => '789',
67 'category' => $category2->id,
68 ));
69 $course3 = $this->getDataGenerator()->create_course(array(
70 'shortname' => 'Y',
71 'idnumber' => '456',
72 'category' => $category2->id,
73 'visible' => 0,
74 ));
75 $course4 = $this->getDataGenerator()->create_course(array(
76 'shortname' => 'W',
77 'category' => $category2->id,
78 ));
80 $maninstance1 = $DB->get_record('enrol', array('courseid'=>$course1->id, 'enrol'=>'manual'), '*', MUST_EXIST);
81 $DB->set_field('enrol', 'status', ENROL_INSTANCE_DISABLED, array('id'=>$maninstance1->id));
82 $maninstance1 = $DB->get_record('enrol', array('courseid'=>$course1->id, 'enrol'=>'manual'), '*', MUST_EXIST);
83 $maninstance2 = $DB->get_record('enrol', array('courseid'=>$course2->id, 'enrol'=>'manual'), '*', MUST_EXIST);
84 $maninstance3 = $DB->get_record('enrol', array('courseid'=>$course3->id, 'enrol'=>'manual'), '*', MUST_EXIST);
85 $maninstance4 = $DB->get_record('enrol', array('courseid'=>$course4->id, 'enrol'=>'manual'), '*', MUST_EXIST);
87 $manual = enrol_get_plugin('manual');
88 $this->assertNotEmpty($manual);
90 $manual->enrol_user($maninstance1, $user1->id, $teacherrole->id);
91 $manual->enrol_user($maninstance1, $user2->id, $studentrole->id);
92 $manual->enrol_user($maninstance1, $user4->id, $teacherrole->id, 0, 0, ENROL_USER_SUSPENDED);
93 $manual->enrol_user($maninstance1, $admin->id, $studentrole->id);
95 $manual->enrol_user($maninstance2, $user1->id);
96 $manual->enrol_user($maninstance2, $user2->id);
97 $manual->enrol_user($maninstance2, $user3->id, 0, 1, time()+(60*60));
99 $manual->enrol_user($maninstance3, $user1->id);
100 $manual->enrol_user($maninstance3, $user2->id);
101 $manual->enrol_user($maninstance3, $user3->id, 0, 1, time()-(60*60));
102 $manual->enrol_user($maninstance3, $user4->id, 0, 0, 0, ENROL_USER_SUSPENDED);
105 $courses = enrol_get_all_users_courses($CFG->siteguest);
106 $this->assertSame(array(), $courses);
108 $courses = enrol_get_all_users_courses(0);
109 $this->assertSame(array(), $courses);
111 // Results are sorted by visibility, sortorder by default (in our case order of creation)
113 $courses = enrol_get_all_users_courses($admin->id);
114 $this->assertCount(1, $courses);
115 $this->assertEquals(array($course1->id), array_keys($courses));
117 $courses = enrol_get_all_users_courses($admin->id, true);
118 $this->assertCount(0, $courses);
119 $this->assertEquals(array(), array_keys($courses));
121 $courses = enrol_get_all_users_courses($user1->id);
122 $this->assertCount(3, $courses);
123 $this->assertEquals(array($course2->id, $course1->id, $course3->id), array_keys($courses));
125 $courses = enrol_get_all_users_courses($user1->id, true);
126 $this->assertCount(2, $courses);
127 $this->assertEquals(array($course2->id, $course3->id), array_keys($courses));
129 $courses = enrol_get_all_users_courses($user2->id);
130 $this->assertCount(3, $courses);
131 $this->assertEquals(array($course2->id, $course1->id, $course3->id), array_keys($courses));
133 $courses = enrol_get_all_users_courses($user2->id, true);
134 $this->assertCount(2, $courses);
135 $this->assertEquals(array($course2->id, $course3->id), array_keys($courses));
137 $courses = enrol_get_all_users_courses($user3->id);
138 $this->assertCount(2, $courses);
139 $this->assertEquals(array($course2->id, $course3->id), array_keys($courses));
141 $courses = enrol_get_all_users_courses($user3->id, true);
142 $this->assertCount(1, $courses);
143 $this->assertEquals(array($course2->id), array_keys($courses));
145 $courses = enrol_get_all_users_courses($user4->id);
146 $this->assertCount(2, $courses);
147 $this->assertEquals(array($course1->id, $course3->id), array_keys($courses));
149 $courses = enrol_get_all_users_courses($user4->id, true);
150 $this->assertCount(0, $courses);
151 $this->assertEquals(array(), array_keys($courses));
153 // Make sure sorting and columns work.
155 $basefields = array('id', 'category', 'sortorder', 'shortname', 'fullname', 'idnumber',
156 'startdate', 'visible', 'groupmode', 'groupmodeforce', 'defaultgroupingid');
158 $courses = enrol_get_all_users_courses($user2->id, true);
159 $course = reset($courses);
160 context_helper::preload_from_record($course);
161 $course = (array)$course;
162 $this->assertEqualsCanonicalizing($basefields, array_keys($course));
164 $courses = enrol_get_all_users_courses($user2->id, false, 'timecreated');
165 $course = reset($courses);
166 $this->assertTrue(property_exists($course, 'timecreated'));
168 $courses = enrol_get_all_users_courses($user2->id, false, null, 'id DESC');
169 $this->assertEquals(array($course2->id, $course3->id, $course1->id), array_keys($courses));
171 // Make sure that implicit sorting defined in navsortmycoursessort is respected.
173 $CFG->navsortmycoursessort = 'shortname';
175 $courses = enrol_get_all_users_courses($user1->id);
176 $this->assertEquals(array($course2->id, $course3->id, $course1->id), array_keys($courses));
178 // But still the explicit sorting takes precedence over the implicit one.
180 $courses = enrol_get_all_users_courses($user1->id, false, null, 'shortname DESC');
181 $this->assertEquals(array($course2->id, $course1->id, $course3->id), array_keys($courses));
183 // Make sure that implicit visibility sorting defined in navsortmycourseshiddenlast is respected for all course sortings.
185 $CFG->navsortmycoursessort = 'sortorder';
186 $CFG->navsortmycourseshiddenlast = true;
187 $courses = enrol_get_all_users_courses($user1->id);
188 $this->assertEquals(array($course2->id, $course1->id, $course3->id), array_keys($courses));
190 $CFG->navsortmycoursessort = 'sortorder';
191 $CFG->navsortmycourseshiddenlast = false;
192 $courses = enrol_get_all_users_courses($user1->id);
193 $this->assertEquals(array($course1->id, $course3->id, $course2->id), array_keys($courses));
195 $CFG->navsortmycoursessort = 'fullname';
196 $CFG->navsortmycourseshiddenlast = true;
197 $courses = enrol_get_all_users_courses($user1->id);
198 $this->assertEquals(array($course2->id, $course1->id, $course3->id), array_keys($courses));
200 $CFG->navsortmycoursessort = 'fullname';
201 $CFG->navsortmycourseshiddenlast = false;
202 $courses = enrol_get_all_users_courses($user1->id);
203 $this->assertEquals(array($course1->id, $course2->id, $course3->id), array_keys($courses));
205 $CFG->navsortmycoursessort = 'shortname';
206 $CFG->navsortmycourseshiddenlast = true;
207 $courses = enrol_get_all_users_courses($user1->id);
208 $this->assertEquals(array($course2->id, $course3->id, $course1->id), array_keys($courses));
210 $CFG->navsortmycoursessort = 'shortname';
211 $CFG->navsortmycourseshiddenlast = false;
212 $courses = enrol_get_all_users_courses($user1->id);
213 $this->assertEquals(array($course2->id, $course3->id, $course1->id), array_keys($courses));
215 $CFG->navsortmycoursessort = 'idnumber';
216 $CFG->navsortmycourseshiddenlast = true;
217 $courses = enrol_get_all_users_courses($user1->id);
218 $this->assertEquals(array($course2->id, $course1->id, $course3->id), array_keys($courses));
220 $CFG->navsortmycoursessort = 'idnumber';
221 $CFG->navsortmycourseshiddenlast = false;
222 $courses = enrol_get_all_users_courses($user1->id);
223 $this->assertEquals(array($course1->id, $course3->id, $course2->id), array_keys($courses));
225 // But still the explicit visibility sorting takes precedence over the implicit one.
227 $courses = enrol_get_all_users_courses($user1->id, false, null, 'visible DESC, shortname DESC');
228 $this->assertEquals(array($course2->id, $course1->id, $course3->id), array_keys($courses));
232 * Test enrol_course_delete() without passing a user id. When a value for user id is not present, the method
233 * should delete all enrolment related data in the course.
235 public function test_enrol_course_delete_without_userid() {
236 global $DB;
238 $this->resetAfterTest();
240 // Create users.
241 $user1 = $this->getDataGenerator()->create_user();
242 $user2 = $this->getDataGenerator()->create_user();
243 // Create a course.
244 $course = $this->getDataGenerator()->create_course();
245 $coursecontext = context_course::instance($course->id);
247 $studentrole = $DB->get_record('role', ['shortname' => 'student']);
249 $manual = enrol_get_plugin('manual');
250 $manualinstance = $DB->get_record('enrol', ['courseid' => $course->id, 'enrol' => 'manual'], '*', MUST_EXIST);
251 // Enrol user1 as a student in the course using manual enrolment.
252 $manual->enrol_user($manualinstance, $user1->id, $studentrole->id);
254 $self = enrol_get_plugin('self');
255 $selfinstance = $DB->get_record('enrol', ['courseid' => $course->id, 'enrol' => 'self'], '*', MUST_EXIST);
256 $self->update_status($selfinstance, ENROL_INSTANCE_ENABLED);
257 // Enrol user2 as a student in the course using self enrolment.
258 $self->enrol_user($selfinstance, $user2->id, $studentrole->id);
260 // Delete all enrolment related records in the course.
261 enrol_course_delete($course);
263 // The course enrolment of user1 should not exists.
264 $user1enrolment = $DB->get_record('user_enrolments',
265 ['enrolid' => $manualinstance->id, 'userid' => $user1->id]);
266 $this->assertFalse($user1enrolment);
268 // The role assignment of user1 should not exists.
269 $user1roleassignment = $DB->get_record('role_assignments',
270 ['roleid' => $studentrole->id, 'userid'=> $user1->id, 'contextid' => $coursecontext->id]
272 $this->assertFalse($user1roleassignment);
274 // The course enrolment of user2 should not exists.
275 $user2enrolment = $DB->get_record('user_enrolments',
276 ['enrolid' => $selfinstance->id, 'userid' => $user2->id]);
277 $this->assertFalse($user2enrolment);
279 // The role assignment of user2 should not exists.
280 $user2roleassignment = $DB->get_record('role_assignments',
281 ['roleid' => $studentrole->id, 'userid'=> $user2->id, 'contextid' => $coursecontext->id]);
282 $this->assertFalse($user2roleassignment);
284 // All existing course enrolment instances should not exists.
285 $enrolmentinstances = enrol_get_instances($course->id, false);
286 $this->assertCount(0, $enrolmentinstances);
290 * Test enrol_course_delete() when user id is present.
291 * When a value for user id is present, the method should make sure the user has the proper capability to
292 * un-enrol users before removing the enrolment data. If the capabilities are missing the data should not be removed.
294 * @dataProvider enrol_course_delete_with_userid_provider
295 * @param array $excludedcapabilities The capabilities that should be excluded from the user's role
296 * @param bool $expected The expected results
298 public function test_enrol_course_delete_with_userid($excludedcapabilities, $expected) {
299 global $DB;
301 $this->resetAfterTest();
302 // Create users.
303 $user1 = $this->getDataGenerator()->create_user();
304 $user2 = $this->getDataGenerator()->create_user();
305 $user3 = $this->getDataGenerator()->create_user();
306 // Create a course.
307 $course = $this->getDataGenerator()->create_course();
308 $coursecontext = context_course::instance($course->id);
310 $studentrole = $DB->get_record('role', ['shortname' => 'student']);
311 $editingteacherrole = $DB->get_record('role', ['shortname' => 'editingteacher']);
313 $manual = enrol_get_plugin('manual');
314 $manualinstance = $DB->get_record('enrol', ['courseid' => $course->id, 'enrol' => 'manual'],
315 '*', MUST_EXIST);
316 // Enrol user1 as a student in the course using manual enrolment.
317 $manual->enrol_user($manualinstance, $user1->id, $studentrole->id);
318 // Enrol user3 as an editing teacher in the course using manual enrolment.
319 // By default, the editing teacher role has the capability to un-enroll users which have been enrolled using
320 // the existing enrolment methods.
321 $manual->enrol_user($manualinstance, $user3->id, $editingteacherrole->id);
323 $self = enrol_get_plugin('self');
324 $selfinstance = $DB->get_record('enrol', ['courseid' => $course->id, 'enrol' => 'self'],
325 '*', MUST_EXIST);
326 $self->update_status($selfinstance, ENROL_INSTANCE_ENABLED);
327 // Enrol user2 as a student in the course using self enrolment.
328 $self->enrol_user($selfinstance, $user2->id, $studentrole->id);
330 foreach($excludedcapabilities as $capability) {
331 // Un-assign the given capability from the editing teacher role.
332 unassign_capability($capability, $editingteacherrole->id);
335 // Delete only enrolment related records in the course where user3 has the required capability.
336 enrol_course_delete($course, $user3->id);
338 // Check the existence of the course enrolment of user1.
339 $user1enrolmentexists = (bool) $DB->count_records('user_enrolments',
340 ['enrolid' => $manualinstance->id, 'userid' => $user1->id]);
341 $this->assertEquals($expected['User 1 course enrolment exists'], $user1enrolmentexists);
343 // Check the existence of the role assignment of user1 in the course.
344 $user1roleassignmentexists = (bool) $DB->count_records('role_assignments',
345 ['roleid' => $studentrole->id, 'userid' => $user1->id, 'contextid' => $coursecontext->id]);
346 $this->assertEquals($expected['User 1 role assignment exists'], $user1roleassignmentexists);
348 // Check the existence of the course enrolment of user2.
349 $user2enrolmentexists = (bool) $DB->count_records('user_enrolments',
350 ['enrolid' => $selfinstance->id, 'userid' => $user2->id]);
351 $this->assertEquals($expected['User 2 course enrolment exists'], $user2enrolmentexists);
353 // Check the existence of the role assignment of user2 in the course.
354 $user2roleassignmentexists = (bool) $DB->count_records('role_assignments',
355 ['roleid' => $studentrole->id, 'userid' => $user2->id, 'contextid' => $coursecontext->id]);
356 $this->assertEquals($expected['User 2 role assignment exists'], $user2roleassignmentexists);
358 // Check the existence of the course enrolment of user3.
359 $user3enrolmentexists = (bool) $DB->count_records('user_enrolments',
360 ['enrolid' => $manualinstance->id, 'userid' => $user3->id]);
361 $this->assertEquals($expected['User 3 course enrolment exists'], $user3enrolmentexists);
363 // Check the existence of the role assignment of user3 in the course.
364 $user3roleassignmentexists = (bool) $DB->count_records('role_assignments',
365 ['roleid' => $editingteacherrole->id, 'userid' => $user3->id, 'contextid' => $coursecontext->id]);
366 $this->assertEquals($expected['User 3 role assignment exists'], $user3roleassignmentexists);
368 // Check the existence of the manual enrolment instance in the course.
369 $manualinstance = (bool) $DB->count_records('enrol', ['enrol' => 'manual', 'courseid' => $course->id]);
370 $this->assertEquals($expected['Manual course enrolment instance exists'], $manualinstance);
372 // Check existence of the self enrolment instance in the course.
373 $selfinstance = (bool) $DB->count_records('enrol', ['enrol' => 'self', 'courseid' => $course->id]);
374 $this->assertEquals($expected['Self course enrolment instance exists'], $selfinstance);
378 * Data provider for test_enrol_course_delete_with_userid().
380 * @return array
382 public function enrol_course_delete_with_userid_provider() {
383 return [
384 'The teacher can un-enrol users in a course' =>
386 'excludedcapabilities' => [],
387 'results' => [
388 // Whether certain enrolment related data still exists in the course after the deletion.
389 // When the user has the capabilities to un-enrol users and the enrolment plugins allow manual
390 // unenerolment than all course enrolment data should be removed.
391 'Manual course enrolment instance exists' => false,
392 'Self course enrolment instance exists' => false,
393 'User 1 course enrolment exists' => false,
394 'User 1 role assignment exists' => false,
395 'User 2 course enrolment exists' => false,
396 'User 2 role assignment exists' => false,
397 'User 3 course enrolment exists' => false,
398 'User 3 role assignment exists' => false
401 'The teacher cannot un-enrol self enrolled users' =>
403 'excludedcapabilities' => [
404 // Exclude the following capabilities for the editing teacher.
405 'enrol/self:unenrol'
407 'results' => [
408 // When the user does not have the capabilities to un-enrol self enrolled users, the data
409 // related to this enrolment method should not be removed. Everything else should be removed.
410 'Manual course enrolment instance exists' => false,
411 'Self course enrolment instance exists' => true,
412 'User 1 course enrolment exists' => false,
413 'User 1 role assignment exists' => false,
414 'User 2 course enrolment exists' => true,
415 'User 2 role assignment exists' => true,
416 'User 3 course enrolment exists' => false,
417 'User 3 role assignment exists' => false
420 'The teacher cannot un-enrol self and manually enrolled users' =>
422 'excludedcapabilities' => [
423 // Exclude the following capabilities for the editing teacher.
424 'enrol/manual:unenrol',
425 'enrol/self:unenrol'
427 'results' => [
428 // When the user does not have the capabilities to un-enrol self and manually enrolled users,
429 // the data related to these enrolment methods should not be removed.
430 'Manual course enrolment instance exists' => true,
431 'Self course enrolment instance exists' => true,
432 'User 1 course enrolment exists' => true,
433 'User 1 role assignment exists' => true,
434 'User 2 course enrolment exists' => true,
435 'User 2 role assignment exists' => true,
436 'User 3 course enrolment exists' => true,
437 'User 3 role assignment exists' => true
444 public function test_enrol_user_sees_own_courses() {
445 global $DB, $CFG;
447 $this->resetAfterTest();
449 $studentrole = $DB->get_record('role', array('shortname'=>'student'));
450 $this->assertNotEmpty($studentrole);
451 $teacherrole = $DB->get_record('role', array('shortname'=>'teacher'));
452 $this->assertNotEmpty($teacherrole);
454 $admin = get_admin();
455 $user1 = $this->getDataGenerator()->create_user();
456 $user2 = $this->getDataGenerator()->create_user();
457 $user3 = $this->getDataGenerator()->create_user();
458 $user4 = $this->getDataGenerator()->create_user();
459 $user5 = $this->getDataGenerator()->create_user();
460 $user6 = $this->getDataGenerator()->create_user();
462 $category1 = $this->getDataGenerator()->create_category(array('visible'=>0));
463 $category2 = $this->getDataGenerator()->create_category();
464 $course1 = $this->getDataGenerator()->create_course(array('category'=>$category1->id));
465 $course2 = $this->getDataGenerator()->create_course(array('category'=>$category2->id));
466 $course3 = $this->getDataGenerator()->create_course(array('category'=>$category2->id, 'visible'=>0));
467 $course4 = $this->getDataGenerator()->create_course(array('category'=>$category2->id));
469 $maninstance1 = $DB->get_record('enrol', array('courseid'=>$course1->id, 'enrol'=>'manual'), '*', MUST_EXIST);
470 $DB->set_field('enrol', 'status', ENROL_INSTANCE_DISABLED, array('id'=>$maninstance1->id));
471 $maninstance1 = $DB->get_record('enrol', array('courseid'=>$course1->id, 'enrol'=>'manual'), '*', MUST_EXIST);
472 $maninstance2 = $DB->get_record('enrol', array('courseid'=>$course2->id, 'enrol'=>'manual'), '*', MUST_EXIST);
473 $maninstance3 = $DB->get_record('enrol', array('courseid'=>$course3->id, 'enrol'=>'manual'), '*', MUST_EXIST);
474 $maninstance4 = $DB->get_record('enrol', array('courseid'=>$course4->id, 'enrol'=>'manual'), '*', MUST_EXIST);
476 $manual = enrol_get_plugin('manual');
477 $this->assertNotEmpty($manual);
479 $manual->enrol_user($maninstance1, $admin->id, $studentrole->id);
481 $manual->enrol_user($maninstance3, $user1->id, $teacherrole->id);
483 $manual->enrol_user($maninstance2, $user2->id, $studentrole->id);
485 $manual->enrol_user($maninstance1, $user3->id, $studentrole->id, 1, time()+(60*60));
486 $manual->enrol_user($maninstance2, $user3->id, 0, 1, time()-(60*60));
487 $manual->enrol_user($maninstance3, $user2->id, $studentrole->id);
488 $manual->enrol_user($maninstance4, $user2->id, 0, 0, 0, ENROL_USER_SUSPENDED);
490 $manual->enrol_user($maninstance1, $user4->id, $teacherrole->id, 0, 0, ENROL_USER_SUSPENDED);
491 $manual->enrol_user($maninstance3, $user4->id, 0, 0, 0, ENROL_USER_SUSPENDED);
494 $this->assertFalse(enrol_user_sees_own_courses($CFG->siteguest));
495 $this->assertFalse(enrol_user_sees_own_courses(0));
496 $this->assertFalse(enrol_user_sees_own_courses($admin));
497 $this->assertFalse(enrol_user_sees_own_courses(-222)); // Nonexistent user.
499 $this->assertTrue(enrol_user_sees_own_courses($user1));
500 $this->assertTrue(enrol_user_sees_own_courses($user2->id));
501 $this->assertFalse(enrol_user_sees_own_courses($user3->id));
502 $this->assertFalse(enrol_user_sees_own_courses($user4));
503 $this->assertFalse(enrol_user_sees_own_courses($user5));
505 $this->setAdminUser();
506 $this->assertFalse(enrol_user_sees_own_courses());
508 $this->setGuestUser();
509 $this->assertFalse(enrol_user_sees_own_courses());
511 $this->setUser(0);
512 $this->assertFalse(enrol_user_sees_own_courses());
514 $this->setUser($user1);
515 $this->assertTrue(enrol_user_sees_own_courses());
517 $this->setUser($user2);
518 $this->assertTrue(enrol_user_sees_own_courses());
520 $this->setUser($user3);
521 $this->assertFalse(enrol_user_sees_own_courses());
523 $this->setUser($user4);
524 $this->assertFalse(enrol_user_sees_own_courses());
526 $this->setUser($user5);
527 $this->assertFalse(enrol_user_sees_own_courses());
529 $user1 = $DB->get_record('user', array('id'=>$user1->id));
530 $this->setUser($user1);
531 $reads = $DB->perf_get_reads();
532 $this->assertTrue(enrol_user_sees_own_courses());
533 $this->assertGreaterThan($reads, $DB->perf_get_reads());
535 $user1 = $DB->get_record('user', array('id'=>$user1->id));
536 $this->setUser($user1);
537 require_login($course3);
538 $reads = $DB->perf_get_reads();
539 $this->assertTrue(enrol_user_sees_own_courses());
540 $this->assertEquals($reads, $DB->perf_get_reads());
543 public function test_enrol_get_shared_courses() {
544 $this->resetAfterTest();
546 $user1 = $this->getDataGenerator()->create_user();
547 $user2 = $this->getDataGenerator()->create_user();
548 $user3 = $this->getDataGenerator()->create_user();
550 $course1 = $this->getDataGenerator()->create_course();
551 $this->getDataGenerator()->enrol_user($user1->id, $course1->id);
552 $this->getDataGenerator()->enrol_user($user2->id, $course1->id);
554 $course2 = $this->getDataGenerator()->create_course();
555 $this->getDataGenerator()->enrol_user($user1->id, $course2->id);
557 // Test that user1 and user2 have courses in common.
558 $this->assertTrue(enrol_get_shared_courses($user1, $user2, false, true));
559 // Test that user1 and user3 have no courses in common.
560 $this->assertFalse(enrol_get_shared_courses($user1, $user3, false, true));
562 // Test retrieving the courses in common.
563 $sharedcourses = enrol_get_shared_courses($user1, $user2, true);
565 // Only should be one shared course.
566 $this->assertCount(1, $sharedcourses);
567 $sharedcourse = array_shift($sharedcourses);
568 // It should be course 1.
569 $this->assertEquals($sharedcourse->id, $course1->id);
572 public function test_enrol_get_shared_courses_different_methods() {
573 global $DB, $CFG;
575 require_once($CFG->dirroot . '/enrol/self/externallib.php');
577 $this->resetAfterTest();
579 $user1 = $this->getDataGenerator()->create_user();
580 $user2 = $this->getDataGenerator()->create_user();
581 $user3 = $this->getDataGenerator()->create_user();
583 $course1 = $this->getDataGenerator()->create_course();
585 // Enrol user1 and user2 in course1 with a different enrolment methode.
586 // Add self enrolment method for course1.
587 $selfplugin = enrol_get_plugin('self');
588 $this->assertNotEmpty($selfplugin);
590 $studentrole = $DB->get_record('role', array('shortname' => 'student'));
591 $this->assertNotEmpty($studentrole);
593 $instance1id = $selfplugin->add_instance($course1, array('status' => ENROL_INSTANCE_ENABLED,
594 'name' => 'Test instance 1',
595 'customint6' => 1,
596 'roleid' => $studentrole->id));
598 $instance1 = $DB->get_record('enrol', array('id' => $instance1id), '*', MUST_EXIST);
600 self::setUser($user2);
601 // Self enrol me (user2).
602 $result = enrol_self_external::enrol_user($course1->id);
604 // Enrol user1 manually.
605 $this->getDataGenerator()->enrol_user($user1->id, $course1->id, null, 'manual');
607 $course2 = $this->getDataGenerator()->create_course();
608 $this->getDataGenerator()->enrol_user($user1->id, $course2->id);
610 $course3 = $this->getDataGenerator()->create_course();
611 $this->getDataGenerator()->enrol_user($user2->id, $course3->id);
613 // Test that user1 and user2 have courses in common.
614 $this->assertTrue(enrol_get_shared_courses($user1, $user2, false, true));
615 // Test that user1 and user3 have no courses in common.
616 $this->assertFalse(enrol_get_shared_courses($user1, $user3, false, true));
618 // Test retrieving the courses in common.
619 $sharedcourses = enrol_get_shared_courses($user1, $user2, true);
621 // Only should be one shared course.
622 $this->assertCount(1, $sharedcourses);
623 $sharedcourse = array_shift($sharedcourses);
624 // It should be course 1.
625 $this->assertEquals($sharedcourse->id, $course1->id);
629 * Test user enrolment created event.
631 public function test_user_enrolment_created_event() {
632 global $DB;
634 $this->resetAfterTest();
636 $studentrole = $DB->get_record('role', array('shortname'=>'student'));
637 $this->assertNotEmpty($studentrole);
639 $admin = get_admin();
641 $course1 = $this->getDataGenerator()->create_course();
643 $maninstance1 = $DB->get_record('enrol', array('courseid'=>$course1->id, 'enrol'=>'manual'), '*', MUST_EXIST);
645 $manual = enrol_get_plugin('manual');
646 $this->assertNotEmpty($manual);
648 // Enrol user and capture event.
649 $sink = $this->redirectEvents();
650 $manual->enrol_user($maninstance1, $admin->id, $studentrole->id);
651 $events = $sink->get_events();
652 $sink->close();
653 $event = array_shift($events);
655 $dbuserenrolled = $DB->get_record('user_enrolments', array('userid' => $admin->id));
656 $this->assertInstanceOf('\core\event\user_enrolment_created', $event);
657 $this->assertEquals($dbuserenrolled->id, $event->objectid);
658 $this->assertEquals(context_course::instance($course1->id), $event->get_context());
659 $this->assertEquals('user_enrolled', $event->get_legacy_eventname());
660 $expectedlegacyeventdata = $dbuserenrolled;
661 $expectedlegacyeventdata->enrol = $manual->get_name();
662 $expectedlegacyeventdata->courseid = $course1->id;
663 $this->assertEventLegacyData($expectedlegacyeventdata, $event);
664 $expected = array($course1->id, 'course', 'enrol', '../enrol/users.php?id=' . $course1->id, $course1->id);
665 $this->assertEventLegacyLogData($expected, $event);
666 $this->assertEventContextNotUsed($event);
670 * Test user_enrolment_deleted event.
672 public function test_user_enrolment_deleted_event() {
673 global $DB;
675 $this->resetAfterTest(true);
677 $manualplugin = enrol_get_plugin('manual');
678 $user = $this->getDataGenerator()->create_user();
679 $course = $this->getDataGenerator()->create_course();
680 $student = $DB->get_record('role', array('shortname' => 'student'));
682 $enrol = $DB->get_record('enrol', array('courseid' => $course->id, 'enrol' => 'manual'), '*', MUST_EXIST);
684 // Enrol user.
685 $manualplugin->enrol_user($enrol, $user->id, $student->id);
687 // Get the user enrolment information, used to validate legacy event data.
688 $dbuserenrolled = $DB->get_record('user_enrolments', array('userid' => $user->id));
690 // Unenrol user and capture event.
691 $sink = $this->redirectEvents();
692 $manualplugin->unenrol_user($enrol, $user->id);
693 $events = $sink->get_events();
694 $sink->close();
695 $event = array_pop($events);
697 // Validate the event.
698 $this->assertInstanceOf('\core\event\user_enrolment_deleted', $event);
699 $this->assertEquals(context_course::instance($course->id), $event->get_context());
700 $this->assertEquals('user_unenrolled', $event->get_legacy_eventname());
701 $expectedlegacyeventdata = $dbuserenrolled;
702 $expectedlegacyeventdata->enrol = $manualplugin->get_name();
703 $expectedlegacyeventdata->courseid = $course->id;
704 $expectedlegacyeventdata->lastenrol = true;
705 $this->assertEventLegacyData($expectedlegacyeventdata, $event);
706 $expected = array($course->id, 'course', 'unenrol', '../enrol/users.php?id=' . $course->id, $course->id);
707 $this->assertEventLegacyLogData($expected, $event);
708 $this->assertEventContextNotUsed($event);
712 * Test enrol_instance_created, enrol_instance_updated and enrol_instance_deleted events.
714 public function test_instance_events() {
715 global $DB;
717 $this->resetAfterTest(true);
719 $selfplugin = enrol_get_plugin('self');
720 $studentrole = $DB->get_record('role', array('shortname' => 'student'));
722 $course = $this->getDataGenerator()->create_course();
724 // Creating enrol instance.
725 $sink = $this->redirectEvents();
726 $instanceid = $selfplugin->add_instance($course, array('status' => ENROL_INSTANCE_ENABLED,
727 'name' => 'Test instance 1',
728 'customint6' => 1,
729 'roleid' => $studentrole->id));
730 $events = $sink->get_events();
731 $sink->close();
733 $this->assertCount(1, $events);
734 $event = array_pop($events);
735 $this->assertInstanceOf('\core\event\enrol_instance_created', $event);
736 $this->assertEquals(context_course::instance($course->id), $event->get_context());
737 $this->assertEquals('self', $event->other['enrol']);
738 $this->assertEventContextNotUsed($event);
740 // Updating enrol instance.
741 $instance = $DB->get_record('enrol', array('id' => $instanceid));
742 $sink = $this->redirectEvents();
743 $selfplugin->update_status($instance, ENROL_INSTANCE_DISABLED);
745 $events = $sink->get_events();
746 $sink->close();
748 $this->assertCount(1, $events);
749 $event = array_pop($events);
750 $this->assertInstanceOf('\core\event\enrol_instance_updated', $event);
751 $this->assertEquals(context_course::instance($course->id), $event->get_context());
752 $this->assertEquals('self', $event->other['enrol']);
753 $this->assertEventContextNotUsed($event);
755 // Deleting enrol instance.
756 $instance = $DB->get_record('enrol', array('id' => $instanceid));
757 $sink = $this->redirectEvents();
758 $selfplugin->delete_instance($instance);
760 $events = $sink->get_events();
761 $sink->close();
763 $this->assertCount(1, $events);
764 $event = array_pop($events);
765 $this->assertInstanceOf('\core\event\enrol_instance_deleted', $event);
766 $this->assertEquals(context_course::instance($course->id), $event->get_context());
767 $this->assertEquals('self', $event->other['enrol']);
768 $this->assertEventContextNotUsed($event);
772 * Confirms that timemodified field was updated after modification of user enrollment
774 public function test_enrollment_update_timemodified() {
775 global $DB;
777 $this->resetAfterTest(true);
778 $datagen = $this->getDataGenerator();
780 /** @var enrol_manual_plugin $manualplugin */
781 $manualplugin = enrol_get_plugin('manual');
782 $this->assertNotNull($manualplugin);
784 $studentroleid = $DB->get_field('role', 'id', ['shortname' => 'student'], MUST_EXIST);
785 $course = $datagen->create_course();
786 $user = $datagen->create_user();
788 $instanceid = null;
789 $instances = enrol_get_instances($course->id, true);
790 foreach ($instances as $inst) {
791 if ($inst->enrol == 'manual') {
792 $instanceid = (int)$inst->id;
793 break;
796 if (empty($instanceid)) {
797 $instanceid = $manualplugin->add_default_instance($course);
798 if (empty($instanceid)) {
799 $instanceid = $manualplugin->add_instance($course);
802 $this->assertNotNull($instanceid);
804 $instance = $DB->get_record('enrol', ['id' => $instanceid], '*', MUST_EXIST);
805 $manualplugin->enrol_user($instance, $user->id, $studentroleid, 0, 0, ENROL_USER_ACTIVE);
806 $userenrolorig = (int)$DB->get_field(
807 'user_enrolments',
808 'timemodified',
809 ['enrolid' => $instance->id, 'userid' => $user->id],
810 MUST_EXIST
812 $this->waitForSecond();
813 $this->waitForSecond();
814 $manualplugin->update_user_enrol($instance, $user->id, ENROL_USER_SUSPENDED);
815 $userenrolpost = (int)$DB->get_field(
816 'user_enrolments',
817 'timemodified',
818 ['enrolid' => $instance->id, 'userid' => $user->id],
819 MUST_EXIST
822 $this->assertGreaterThan($userenrolorig, $userenrolpost);
826 * Test to confirm that enrol_get_my_courses only return the courses that
827 * the logged in user is enrolled in.
829 public function test_enrol_get_my_courses_only_enrolled_courses() {
830 $user = $this->getDataGenerator()->create_user();
831 $course1 = $this->getDataGenerator()->create_course();
832 $course2 = $this->getDataGenerator()->create_course();
833 $course3 = $this->getDataGenerator()->create_course();
834 $course4 = $this->getDataGenerator()->create_course();
836 $this->getDataGenerator()->enrol_user($user->id, $course1->id);
837 $this->getDataGenerator()->enrol_user($user->id, $course2->id);
838 $this->getDataGenerator()->enrol_user($user->id, $course3->id);
839 $this->resetAfterTest(true);
840 $this->setUser($user);
842 // By default this function should return all of the courses the user
843 // is enrolled in.
844 $courses = enrol_get_my_courses();
846 $this->assertCount(3, $courses);
847 $this->assertEquals($course1->id, $courses[$course1->id]->id);
848 $this->assertEquals($course2->id, $courses[$course2->id]->id);
849 $this->assertEquals($course3->id, $courses[$course3->id]->id);
851 // If a set of course ids are provided then the result set will only contain
852 // these courses.
853 $courseids = [$course1->id, $course2->id];
854 $courses = enrol_get_my_courses(['id'], 'visible DESC,sortorder ASC', 0, $courseids);
856 $this->assertCount(2, $courses);
857 $this->assertEquals($course1->id, $courses[$course1->id]->id);
858 $this->assertEquals($course2->id, $courses[$course2->id]->id);
860 // If the course ids list contains any ids for courses the user isn't enrolled in
861 // then they will be ignored (in this case $course4).
862 $courseids = [$course1->id, $course2->id, $course4->id];
863 $courses = enrol_get_my_courses(['id'], 'visible DESC,sortorder ASC', 0, $courseids);
865 $this->assertCount(2, $courses);
866 $this->assertEquals($course1->id, $courses[$course1->id]->id);
867 $this->assertEquals($course2->id, $courses[$course2->id]->id);
871 * Tests the enrol_get_my_courses function when using the $includehidden parameter, which
872 * should remove any courses hidden from the user's timeline
874 * @throws coding_exception
875 * @throws dml_exception
877 public function test_enrol_get_my_courses_include_hidden() {
878 global $DB, $CFG;
880 $this->resetAfterTest(true);
882 // Create test user and 4 courses, two of which have guest access enabled.
883 $user = $this->getDataGenerator()->create_user();
884 $course1 = $this->getDataGenerator()->create_course(
885 (object)array('shortname' => 'X',
886 'enrol_guest_status_0' => ENROL_INSTANCE_DISABLED,
887 'enrol_guest_password_0' => ''));
888 $course2 = $this->getDataGenerator()->create_course(
889 (object)array('shortname' => 'Z',
890 'enrol_guest_status_0' => ENROL_INSTANCE_ENABLED,
891 'enrol_guest_password_0' => ''));
892 $course3 = $this->getDataGenerator()->create_course(
893 (object)array('shortname' => 'Y',
894 'enrol_guest_status_0' => ENROL_INSTANCE_ENABLED,
895 'enrol_guest_password_0' => 'frog'));
896 $course4 = $this->getDataGenerator()->create_course(
897 (object)array('shortname' => 'W',
898 'enrol_guest_status_0' => ENROL_INSTANCE_DISABLED,
899 'enrol_guest_password_0' => ''));
901 // User is enrolled in first course.
902 $this->getDataGenerator()->enrol_user($user->id, $course1->id);
903 $this->getDataGenerator()->enrol_user($user->id, $course2->id);
904 $this->getDataGenerator()->enrol_user($user->id, $course3->id);
905 $this->getDataGenerator()->enrol_user($user->id, $course4->id);
907 // Check enrol_get_my_courses basic use (without include hidden provided).
908 $this->setUser($user);
909 $courses = enrol_get_my_courses();
910 $this->assertEquals([$course4->id, $course3->id, $course2->id, $course1->id], array_keys($courses));
912 // Hide a course.
913 set_user_preference('block_myoverview_hidden_course_' . $course3->id, true);
915 // Hidden course shouldn't be returned.
916 $courses = enrol_get_my_courses(null, null, 0, [], false, 0, [$course3->id]);
917 $this->assertEquals([$course4->id, $course2->id, $course1->id], array_keys($courses));
919 // Offset should take into account hidden course.
920 $courses = enrol_get_my_courses(null, null, 0, [], false, 2, [$course3->id]);
921 $this->assertEquals([$course1->id], array_keys($courses));
925 * Tests the enrol_get_my_courses function when using the $allaccessible parameter, which
926 * includes a wider range of courses (enrolled courses + other accessible ones).
928 public function test_enrol_get_my_courses_all_accessible() {
929 global $DB, $CFG;
931 $this->resetAfterTest(true);
933 // Create test user and 4 courses, two of which have guest access enabled.
934 $user = $this->getDataGenerator()->create_user();
935 $course1 = $this->getDataGenerator()->create_course(
936 (object)array('shortname' => 'X',
937 'enrol_guest_status_0' => ENROL_INSTANCE_DISABLED,
938 'enrol_guest_password_0' => ''));
939 $course2 = $this->getDataGenerator()->create_course(
940 (object)array('shortname' => 'Z',
941 'enrol_guest_status_0' => ENROL_INSTANCE_ENABLED,
942 'enrol_guest_password_0' => ''));
943 $course3 = $this->getDataGenerator()->create_course(
944 (object)array('shortname' => 'Y',
945 'enrol_guest_status_0' => ENROL_INSTANCE_ENABLED,
946 'enrol_guest_password_0' => 'frog'));
947 $course4 = $this->getDataGenerator()->create_course(
948 (object)array('shortname' => 'W',
949 'enrol_guest_status_0' => ENROL_INSTANCE_DISABLED,
950 'enrol_guest_password_0' => ''));
952 // User is enrolled in first course.
953 $this->getDataGenerator()->enrol_user($user->id, $course1->id);
955 // Check enrol_get_my_courses basic use (without all accessible).
956 $this->setUser($user);
957 $courses = enrol_get_my_courses();
958 $this->assertEquals([$course1->id], array_keys($courses));
960 // Turn on all accessible, now they can access the second course too.
961 $courses = enrol_get_my_courses(null, 'id', 0, [], true);
962 $this->assertEquals([$course1->id, $course2->id], array_keys($courses));
964 // Log in as guest to third course.
965 load_temp_course_role(context_course::instance($course3->id), $CFG->guestroleid);
966 $courses = enrol_get_my_courses(null, 'id', 0, [], true);
967 $this->assertEquals([$course1->id, $course2->id, $course3->id], array_keys($courses));
969 // Check fields parameter still works. Fields default (certain base fields).
970 $this->assertObjectHasAttribute('id', $courses[$course3->id]);
971 $this->assertObjectHasAttribute('shortname', $courses[$course3->id]);
972 $this->assertObjectNotHasAttribute('summary', $courses[$course3->id]);
974 // Specified fields (one, string).
975 $courses = enrol_get_my_courses('summary', 'id', 0, [], true);
976 $this->assertObjectHasAttribute('id', $courses[$course3->id]);
977 $this->assertObjectHasAttribute('shortname', $courses[$course3->id]);
978 $this->assertObjectHasAttribute('summary', $courses[$course3->id]);
979 $this->assertObjectNotHasAttribute('summaryformat', $courses[$course3->id]);
981 // Specified fields (two, string).
982 $courses = enrol_get_my_courses('summary, summaryformat', 'id', 0, [], true);
983 $this->assertObjectHasAttribute('summary', $courses[$course3->id]);
984 $this->assertObjectHasAttribute('summaryformat', $courses[$course3->id]);
986 // Specified fields (two, array).
987 $courses = enrol_get_my_courses(['summary', 'summaryformat'], 'id', 0, [], true);
988 $this->assertObjectHasAttribute('summary', $courses[$course3->id]);
989 $this->assertObjectHasAttribute('summaryformat', $courses[$course3->id]);
991 // By default, courses are ordered by sortorder - which by default is most recent first.
992 $courses = enrol_get_my_courses(null, null, 0, [], true);
993 $this->assertEquals([$course3->id, $course2->id, $course1->id], array_keys($courses));
995 // Make sure that implicit sorting defined in navsortmycoursessort is respected.
996 $CFG->navsortmycoursessort = 'shortname';
997 $courses = enrol_get_my_courses(null, null, 0, [], true);
998 $this->assertEquals([$course1->id, $course3->id, $course2->id], array_keys($courses));
1000 // But still the explicit sorting takes precedence over the implicit one.
1001 $courses = enrol_get_my_courses(null, 'shortname DESC', 0, [], true);
1002 $this->assertEquals([$course2->id, $course3->id, $course1->id], array_keys($courses));
1004 // Check filter parameter still works.
1005 $courses = enrol_get_my_courses(null, 'id', 0, [$course2->id, $course3->id, $course4->id], true);
1006 $this->assertEquals([$course2->id, $course3->id], array_keys($courses));
1008 // Check limit parameter.
1009 $courses = enrol_get_my_courses(null, 'id', 2, [], true);
1010 $this->assertEquals([$course1->id, $course2->id], array_keys($courses));
1012 // Now try access for a different user who has manager role at system level.
1013 $manager = $this->getDataGenerator()->create_user();
1014 $managerroleid = $DB->get_field('role', 'id', ['shortname' => 'manager']);
1015 role_assign($managerroleid, $manager->id, \context_system::instance()->id);
1016 $this->setUser($manager);
1018 // With default get enrolled, they don't have any courses.
1019 $courses = enrol_get_my_courses();
1020 $this->assertCount(0, $courses);
1022 // But with all accessible, they have 4 because they have moodle/course:view everywhere.
1023 $courses = enrol_get_my_courses(null, 'id', 0, [], true);
1024 $this->assertEquals([$course1->id, $course2->id, $course3->id, $course4->id],
1025 array_keys($courses));
1027 // If we prohibit manager from course:view on course 1 though...
1028 assign_capability('moodle/course:view', CAP_PROHIBIT, $managerroleid,
1029 \context_course::instance($course1->id));
1030 $courses = enrol_get_my_courses(null, 'id', 0, [], true);
1031 $this->assertEquals([$course2->id, $course3->id, $course4->id], array_keys($courses));
1033 // Check for admin user, which has a slightly different query.
1034 $this->setAdminUser();
1035 $courses = enrol_get_my_courses(null, 'id', 0, [], true);
1036 $this->assertEquals([$course1->id, $course2->id, $course3->id, $course4->id], array_keys($courses));
1040 * Data provider for {@see test_enrol_get_my_courses_by_time}
1042 * @return array
1044 public function enrol_get_my_courses_by_time_provider(): array {
1045 return [
1046 'No start or end time' =>
1047 [null, null, true],
1048 'Start time now, no end time' =>
1049 [0, null, true],
1050 'Start time now, end time in the future' =>
1051 [0, MINSECS, true],
1052 'Start time in the past, no end time' =>
1053 [-MINSECS, null, true],
1054 'Start time in the past, end time in the future' =>
1055 [-MINSECS, MINSECS, true],
1056 'Start time in the past, end time in the past' =>
1057 [-DAYSECS, -HOURSECS, false],
1058 'Start time in the future' =>
1059 [MINSECS, null, false],
1064 * Test that expected course enrolments are returned when they have timestart / timeend specified
1066 * @param int|null $timestartoffset Null for 0, otherwise offset from current time
1067 * @param int|null $timeendoffset Null for 0, otherwise offset from current time
1068 * @param bool $expectreturn
1070 * @dataProvider enrol_get_my_courses_by_time_provider
1072 public function test_enrol_get_my_courses_by_time(?int $timestartoffset, ?int $timeendoffset, bool $expectreturn): void {
1073 $this->resetAfterTest();
1075 $time = time();
1076 $timestart = $timestartoffset === null ? 0 : $time + $timestartoffset;
1077 $timeend = $timeendoffset === null ? 0 : $time + $timeendoffset;
1079 $course = $this->getDataGenerator()->create_course();
1080 $user = $this->getDataGenerator()->create_and_enrol($course, 'student', null, 'manual', $timestart, $timeend);
1081 $this->setUser($user);
1083 $courses = enrol_get_my_courses();
1084 if ($expectreturn) {
1085 $this->assertCount(1, $courses);
1086 $this->assertEquals($course->id, reset($courses)->id);
1087 } else {
1088 $this->assertEmpty($courses);
1093 * test_course_users
1095 * @return void
1097 public function test_course_users() {
1098 $this->resetAfterTest();
1100 $user1 = $this->getDataGenerator()->create_user();
1101 $user2 = $this->getDataGenerator()->create_user();
1102 $course1 = $this->getDataGenerator()->create_course();
1103 $course2 = $this->getDataGenerator()->create_course();
1105 $this->getDataGenerator()->enrol_user($user1->id, $course1->id);
1106 $this->getDataGenerator()->enrol_user($user2->id, $course1->id);
1107 $this->getDataGenerator()->enrol_user($user1->id, $course2->id);
1109 $this->assertCount(2, enrol_get_course_users($course1->id));
1110 $this->assertCount(2, enrol_get_course_users($course1->id, true));
1112 $this->assertCount(1, enrol_get_course_users($course1->id, true, array($user1->id)));
1114 $this->assertCount(2, enrol_get_course_users(false, false, array($user1->id)));
1116 $instances = enrol_get_instances($course1->id, true);
1117 $manualinstance = reset($instances);
1119 $manualplugin = enrol_get_plugin('manual');
1120 $manualplugin->update_user_enrol($manualinstance, $user1->id, ENROL_USER_SUSPENDED);
1121 $this->assertCount(2, enrol_get_course_users($course1->id, false));
1122 $this->assertCount(1, enrol_get_course_users($course1->id, true));
1126 * Test count of enrolled users
1128 * @return void
1130 public function test_count_enrolled_users() {
1131 global $DB;
1133 $this->resetAfterTest(true);
1135 $course = $this->getDataGenerator()->create_course();
1136 $context = \context_course::instance($course->id);
1138 $user1 = $this->getDataGenerator()->create_user();
1139 $user2 = $this->getDataGenerator()->create_user();
1141 $studentrole = $DB->get_record('role', ['shortname' => 'student']);
1143 // Add each user to the manual enrolment instance.
1144 $manual = enrol_get_plugin('manual');
1146 $manualinstance = $DB->get_record('enrol', ['courseid' => $course->id, 'enrol' => 'manual'], '*', MUST_EXIST);
1148 $manual->enrol_user($manualinstance, $user1->id, $studentrole->id);
1149 $manual->enrol_user($manualinstance, $user2->id, $studentrole->id);
1151 $this->assertEquals(2, count_enrolled_users($context));
1153 // Create a self enrolment instance, enrol first user only.
1154 $self = enrol_get_plugin('self');
1156 $selfid = $self->add_instance($course,
1157 ['status' => ENROL_INSTANCE_ENABLED, 'name' => 'Self', 'customint6' => 1, 'roleid' => $studentrole->id]);
1158 $selfinstance = $DB->get_record('enrol', ['id' => $selfid], '*', MUST_EXIST);
1160 $self->enrol_user($selfinstance, $user1->id, $studentrole->id);
1162 // There are still only two distinct users.
1163 $this->assertEquals(2, count_enrolled_users($context));
1167 * Test cases for the test_enrol_get_my_courses_sort_by_last_access test.
1169 public function get_enrol_get_my_courses_sort_by_last_access_test_cases() {
1170 $now = time();
1172 $enrolledcoursesdata = [
1173 ['shortname' => 'a', 'lastaccess' => $now - 2],
1174 ['shortname' => 'b', 'lastaccess' => $now - 1],
1175 ['shortname' => 'c', 'lastaccess' => $now],
1176 ['shortname' => 'd', 'lastaccess' => $now - 1],
1177 ['shortname' => 'e']
1179 $unenrolledcoursesdata = [
1180 ['shortname' => 'x', 'lastaccess' => $now - 2],
1181 ['shortname' => 'y', 'lastaccess' => $now - 1],
1182 ['shortname' => 'z', 'lastaccess' => $now]
1185 return [
1186 'empty set' => [
1187 'enrolledcoursesdata' => [],
1188 'unenrolledcoursesdata' => $unenrolledcoursesdata,
1189 'sort' => 'ul.timeaccess asc',
1190 'limit' => 0,
1191 'offset' => 0,
1192 'expectedcourses' => []
1194 'ul.timeaccess asc, shortname asc no limit or offset' => [
1195 'enrolledcoursesdata' => $enrolledcoursesdata,
1196 'unenrolledcoursesdata' => $unenrolledcoursesdata,
1197 'sort' => 'ul.timeaccess asc, shortname asc',
1198 'limit' => 0,
1199 'offset' => 0,
1200 'expectedcourses' => ['e', 'a', 'b', 'd', 'c']
1202 'ul.timeaccess asc, shortname asc with limit no offset' => [
1203 'enrolledcoursesdata' => $enrolledcoursesdata,
1204 'unenrolledcoursesdata' => $unenrolledcoursesdata,
1205 'sort' => 'ul.timeaccess asc, shortname asc',
1206 'limit' => 2,
1207 'offset' => 0,
1208 'expectedcourses' => ['e', 'a']
1210 'ul.timeaccess asc, shortname asc with limit and offset' => [
1211 'enrolledcoursesdata' => $enrolledcoursesdata,
1212 'unenrolledcoursesdata' => $unenrolledcoursesdata,
1213 'sort' => 'ul.timeaccess asc, shortname asc',
1214 'limit' => 2,
1215 'offset' => 2,
1216 'expectedcourses' => ['b', 'd']
1218 'ul.timeaccess asc, shortname asc with limit and offset beyond end of data set' => [
1219 'enrolledcoursesdata' => $enrolledcoursesdata,
1220 'unenrolledcoursesdata' => $unenrolledcoursesdata,
1221 'sort' => 'ul.timeaccess asc, shortname asc',
1222 'limit' => 2,
1223 'offset' => 4,
1224 'expectedcourses' => ['c']
1226 'ul.timeaccess desc, shortname asc no limit or offset' => [
1227 'enrolledcoursesdata' => $enrolledcoursesdata,
1228 'unenrolledcoursesdata' => $unenrolledcoursesdata,
1229 'sort' => 'ul.timeaccess desc, shortname asc',
1230 'limit' => 0,
1231 'offset' => 0,
1232 'expectedcourses' => ['c', 'b', 'd', 'a', 'e']
1234 'ul.timeaccess desc, shortname desc, no limit or offset' => [
1235 'enrolledcoursesdata' => $enrolledcoursesdata,
1236 'unenrolledcoursesdata' => $unenrolledcoursesdata,
1237 'sort' => 'ul.timeaccess desc, shortname desc',
1238 'limit' => 0,
1239 'offset' => 0,
1240 'expectedcourses' => ['c', 'd', 'b', 'a', 'e']
1242 'ul.timeaccess asc, shortname desc, no limit or offset' => [
1243 'enrolledcoursesdata' => $enrolledcoursesdata,
1244 'unenrolledcoursesdata' => $unenrolledcoursesdata,
1245 'sort' => 'ul.timeaccess asc, shortname desc',
1246 'limit' => 0,
1247 'offset' => 0,
1248 'expectedcourses' => ['e', 'a', 'd', 'b', 'c']
1250 'shortname asc, no limit or offset' => [
1251 'enrolledcoursesdata' => $enrolledcoursesdata,
1252 'unenrolledcoursesdata' => $unenrolledcoursesdata,
1253 'sort' => 'shortname asc',
1254 'limit' => 0,
1255 'offset' => 0,
1256 'expectedcourses' => ['a', 'b', 'c', 'd', 'e']
1258 'shortname desc, no limit or offset' => [
1259 'enrolledcoursesdata' => $enrolledcoursesdata,
1260 'unenrolledcoursesdata' => $unenrolledcoursesdata,
1261 'sort' => 'shortname desc',
1262 'limit' => 0,
1263 'offset' => 0,
1264 'expectedcourses' => ['e', 'd', 'c', 'b', 'a']
1270 * Test the get_enrolled_courses_by_timeline_classification function.
1272 * @dataProvider get_enrol_get_my_courses_sort_by_last_access_test_cases()
1273 * @param array $enrolledcoursesdata Courses to create and enrol the user in
1274 * @param array $unenrolledcoursesdata Courses to create nut not enrol the user in
1275 * @param string $sort Sort string for the enrol function
1276 * @param int $limit Maximum number of results
1277 * @param int $offset Offset the courses result set by this amount
1278 * @param array $expectedcourses Expected courses in result
1280 public function test_enrol_get_my_courses_sort_by_last_access(
1281 $enrolledcoursesdata,
1282 $unenrolledcoursesdata,
1283 $sort,
1284 $limit,
1285 $offset,
1286 $expectedcourses
1288 global $DB, $CFG;
1290 $this->resetAfterTest();
1291 $generator = $this->getDataGenerator();
1292 $student = $generator->create_user();
1293 $lastaccessrecords = [];
1295 foreach ($enrolledcoursesdata as $coursedata) {
1296 $lastaccess = null;
1298 if (isset($coursedata['lastaccess'])) {
1299 $lastaccess = $coursedata['lastaccess'];
1300 unset($coursedata['lastaccess']);
1303 $course = $generator->create_course($coursedata);
1304 $generator->enrol_user($student->id, $course->id, 'student');
1306 if (!is_null($lastaccess)) {
1307 $lastaccessrecords[] = [
1308 'userid' => $student->id,
1309 'courseid' => $course->id,
1310 'timeaccess' => $lastaccess
1315 foreach ($unenrolledcoursesdata as $coursedata) {
1316 $lastaccess = null;
1318 if (isset($coursedata['lastaccess'])) {
1319 $lastaccess = $coursedata['lastaccess'];
1320 unset($coursedata['lastaccess']);
1323 $course = $generator->create_course($coursedata);
1325 if (!is_null($lastaccess)) {
1326 $lastaccessrecords[] = [
1327 'userid' => $student->id,
1328 'courseid' => $course->id,
1329 'timeaccess' => $lastaccess
1334 if (!empty($lastaccessrecords)) {
1335 $DB->insert_records('user_lastaccess', $lastaccessrecords);
1338 $this->setUser($student);
1340 $result = enrol_get_my_courses('shortname', $sort, $limit, [], false, $offset);
1341 $actual = array_map(function($course) {
1342 return $course->shortname;
1343 }, array_values($result));
1345 $this->assertEquals($expectedcourses, $actual);
1349 * Test enrol_get_course_users_roles function.
1351 * @return void
1353 public function test_enrol_get_course_users_roles() {
1354 global $DB;
1356 $this->resetAfterTest();
1358 $user1 = $this->getDataGenerator()->create_user();
1359 $user2 = $this->getDataGenerator()->create_user();
1360 $course = $this->getDataGenerator()->create_course();
1361 $context = context_course::instance($course->id);
1363 $roles = array();
1364 $roles['student'] = $DB->get_field('role', 'id', array('shortname' => 'student'), MUST_EXIST);
1365 $roles['teacher'] = $DB->get_field('role', 'id', array('shortname' => 'teacher'), MUST_EXIST);
1367 $manual = enrol_get_plugin('manual');
1368 $this->assertNotEmpty($manual);
1370 $enrol = $DB->get_record('enrol', array('courseid' => $course->id, 'enrol' => 'manual'), '*', MUST_EXIST);
1372 // Test without enrolments.
1373 $this->assertEmpty(enrol_get_course_users_roles($course->id));
1375 // Test with 1 user, 1 role.
1376 $manual->enrol_user($enrol, $user1->id, $roles['student']);
1377 $return = enrol_get_course_users_roles($course->id);
1378 $this->assertArrayHasKey($user1->id, $return);
1379 $this->assertArrayHasKey($roles['student'], $return[$user1->id]);
1380 $this->assertArrayNotHasKey($roles['teacher'], $return[$user1->id]);
1382 // Test with 1 user, 2 role.
1383 $manual->enrol_user($enrol, $user1->id, $roles['teacher']);
1384 $return = enrol_get_course_users_roles($course->id);
1385 $this->assertArrayHasKey($user1->id, $return);
1386 $this->assertArrayHasKey($roles['student'], $return[$user1->id]);
1387 $this->assertArrayHasKey($roles['teacher'], $return[$user1->id]);
1389 // Test with another user, 1 role.
1390 $manual->enrol_user($enrol, $user2->id, $roles['student']);
1391 $return = enrol_get_course_users_roles($course->id);
1392 $this->assertArrayHasKey($user1->id, $return);
1393 $this->assertArrayHasKey($roles['student'], $return[$user1->id]);
1394 $this->assertArrayHasKey($roles['teacher'], $return[$user1->id]);
1395 $this->assertArrayHasKey($user2->id, $return);
1396 $this->assertArrayHasKey($roles['student'], $return[$user2->id]);
1397 $this->assertArrayNotHasKey($roles['teacher'], $return[$user2->id]);
1401 * Test enrol_calculate_duration function
1403 public function test_enrol_calculate_duration() {
1404 // Start time 07/01/2019 @ 12:00am (UTC).
1405 $timestart = 1561939200;
1406 // End time 07/05/2019 @ 12:00am (UTC).
1407 $timeend = 1562284800;
1408 $duration = enrol_calculate_duration($timestart, $timeend);
1409 $durationinday = $duration / DAYSECS;
1410 $this->assertEquals(4, $durationinday);
1412 // End time 07/10/2019 @ 12:00am (UTC).
1413 $timeend = 1562716800;
1414 $duration = enrol_calculate_duration($timestart, $timeend);
1415 $durationinday = $duration / DAYSECS;
1416 $this->assertEquals(9, $durationinday);
1420 * Test get_enrolled_with_capabilities_join cannotmatchanyrows attribute.
1422 * @dataProvider get_enrolled_with_capabilities_join_cannotmatchanyrows_data()
1423 * @param string $capability the tested capability
1424 * @param bool $useprohibit if the capability must be assigned to prohibit
1425 * @param int $expectedmatch expected cannotmatchanyrows value
1426 * @param int $expectedcount expceted count value
1428 public function test_get_enrolled_with_capabilities_join_cannotmatchanyrows(
1429 string $capability,
1430 bool $useprohibit,
1431 int $expectedmatch,
1432 int $expectedcount
1434 global $DB, $CFG;
1436 $this->resetAfterTest();
1438 $course = $this->getDataGenerator()->create_course();
1439 $context = context_course::instance($course->id);
1441 $roleid = $CFG->defaultuserroleid;
1443 // Override capability if necessary.
1444 if ($useprohibit && $capability) {
1445 assign_capability($capability, CAP_PROHIBIT, $roleid, $context);
1448 // Check if we must enrol or not.
1449 $this->getDataGenerator()->create_and_enrol($course, 'editingteacher');
1451 $join = get_enrolled_with_capabilities_join($context, '', $capability);
1453 // Execute query.
1454 $sql = "SELECT COUNT(DISTINCT u.id)
1455 FROM {user} u {$join->joins}
1456 WHERE {$join->wheres}";
1457 $countrecords = $DB->count_records_sql($sql, $join->params);
1459 // Validate cannotmatchanyrows.
1460 $this->assertEquals($expectedmatch, $join->cannotmatchanyrows);
1461 $this->assertEquals($expectedcount, $countrecords);
1465 * Data provider for test_get_enrolled_with_capabilities_join_cannotmatchanyrows
1467 * @return @array of testing scenarios
1469 public function get_enrolled_with_capabilities_join_cannotmatchanyrows_data() {
1470 return [
1471 'no prohibits, no capability' => [
1472 'capability' => '',
1473 'useprohibit' => false,
1474 'expectedmatch' => 0,
1475 'expectedcount' => 1,
1477 'no prohibits with capability' => [
1478 'capability' => 'moodle/course:manageactivities',
1479 'useprohibit' => false,
1480 'expectedmatch' => 0,
1481 'expectedcount' => 1,
1483 'prohibits with capability' => [
1484 'capability' => 'moodle/course:manageactivities',
1485 'useprohibit' => true,
1486 'expectedmatch' => 1,
1487 'expectedcount' => 0,
1493 * Test last_time_enrolments_synced not recorded with "force" option for enrol_check_plugins.
1494 * @covers ::enrol_check_plugins
1496 public function test_enrol_check_plugins_with_forced_option() {
1497 $this->resetAfterTest();
1498 $user = $this->getDataGenerator()->create_user();
1500 $this->assertNull(get_user_preferences('last_time_enrolments_synced', null, $user));
1501 enrol_check_plugins($user);
1502 $this->assertNull(get_user_preferences('last_time_enrolments_synced', null, $user));
1506 * Data provided for test_enrol_check_plugins_with_empty_config_value test.
1507 * @return array
1509 public function empty_config_data_provider(): array {
1510 return [
1511 [0],
1512 ["0"],
1513 [false],
1514 [''],
1515 ['string'],
1520 * Test that empty 'enrolments_sync_interval' is treated as forced option for enrol_check_plugins.
1522 * @dataProvider empty_config_data_provider
1523 * @covers ::enrol_check_plugins
1525 * @param mixed $config Config value.
1527 public function test_enrol_check_plugins_with_empty_config_value($config) {
1528 global $CFG;
1530 $this->resetAfterTest();
1531 $CFG->enrolments_sync_interval = $config;
1532 $user = $this->getDataGenerator()->create_user();
1534 $this->assertNull(get_user_preferences('last_time_enrolments_synced', null, $user));
1535 enrol_check_plugins($user, false);
1536 $this->assertNull(get_user_preferences('last_time_enrolments_synced', null, $user));
1540 * Test last_time_enrolments_synced is recorded without "force" option for enrol_check_plugins.
1541 * @covers ::enrol_check_plugins
1543 public function test_last_time_enrolments_synced_is_set_if_not_forced() {
1544 $this->resetAfterTest();
1545 $user = $this->getDataGenerator()->create_user();
1547 $this->assertNull(get_user_preferences('last_time_enrolments_synced', null, $user));
1549 enrol_check_plugins($user, false);
1550 $firstrun = get_user_preferences('last_time_enrolments_synced', null, $user);
1551 $this->assertNotNull($firstrun);
1552 sleep(1);
1554 enrol_check_plugins($user, false);
1555 $secondrun = get_user_preferences('last_time_enrolments_synced', null, $user);
1556 $this->assertNotNull($secondrun);
1557 $this->assertTrue((int)$secondrun == (int)$firstrun);
1561 * Test last_time_enrolments_synced is recorded correctly without "force" option for enrol_check_plugins.
1562 * @covers ::enrol_check_plugins
1564 public function test_last_time_enrolments_synced_is_set_if_not_forced_if_have_not_passed_interval() {
1565 global $CFG;
1567 $this->resetAfterTest();
1568 $CFG->enrolments_sync_interval = 1;
1569 $user = $this->getDataGenerator()->create_user();
1571 $this->assertNull(get_user_preferences('last_time_enrolments_synced', null, $user));
1573 enrol_check_plugins($user, false);
1574 $firstrun = get_user_preferences('last_time_enrolments_synced', null, $user);
1575 $this->assertNotNull($firstrun);
1576 sleep(2);
1578 enrol_check_plugins($user, false);
1579 $secondrun = get_user_preferences('last_time_enrolments_synced', null, $user);
1580 $this->assertNotNull($secondrun);
1581 $this->assertTrue((int)$secondrun > (int)$firstrun);