weekly release 2.7dev
[moodle.git] / lib / testing / generator / data_generator.php
CommitLineData
7e7cfe7a
PS
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/>.
16
17/**
18 * Data generator.
19 *
20 * @package core
6b219869 21 * @category test
7e7cfe7a
PS
22 * @copyright 2012 Petr Skoda {@link http://skodak.org}
23 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
24 */
25
c29e3e24 26defined('MOODLE_INTERNAL') || die();
7e7cfe7a
PS
27
28/**
6b219869 29 * Data generator class for unit tests and other tools that need to create fake test sites.
7e7cfe7a
PS
30 *
31 * @package core
6b219869 32 * @category test
7e7cfe7a
PS
33 * @copyright 2012 Petr Skoda {@link http://skodak.org}
34 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
35 */
5c3c2c81 36class testing_data_generator {
7e7cfe7a
PS
37 protected $usercounter = 0;
38 protected $categorycount = 0;
4729332b 39 protected $cohortcount = 0;
7e7cfe7a
PS
40 protected $coursecount = 0;
41 protected $scalecount = 0;
42 protected $groupcount = 0;
43 protected $groupingcount = 0;
702851c0 44 protected $rolecount = 0;
7e7cfe7a
PS
45
46 /** @var array list of plugin generators */
47 protected $generators = array();
48
49 /** @var array lis of common last names */
50 public $lastnames = array(
51 'Smith', 'Johnson', 'Williams', 'Brown', 'Jones', 'Miller', 'Davis', 'García', 'Rodríguez', 'Wilson',
52 'Müller', 'Schmidt', 'Schneider', 'Fischer', 'Meyer', 'Weber', 'Schulz', 'Wagner', 'Becker', 'Hoffmann',
53 'Novák', 'Svoboda', 'Novotný', 'Dvořák', 'Černý', 'Procházková', 'Kučerová', 'Veselá', 'Horáková', 'Němcová',
54 'Смирнов', 'Иванов', 'Кузнецов', 'Соколов', 'Попов', 'Лебедева', 'Козлова', 'Новикова', 'Морозова', 'Петрова',
55 '王', '李', '张', '刘', '陈', '楊', '黃', '趙', '吳', '周',
56 '佐藤', '鈴木', '高橋', '田中', '渡辺', '伊藤', '山本', '中村', '小林', '斎藤',
57 );
58
59 /** @var array lis of common first names */
60 public $firstnames = array(
61 'Jacob', 'Ethan', 'Michael', 'Jayden', 'William', 'Isabella', 'Sophia', 'Emma', 'Olivia', 'Ava',
62 'Lukas', 'Leon', 'Luca', 'Timm', 'Paul', 'Leonie', 'Leah', 'Lena', 'Hanna', 'Laura',
63 'Jakub', 'Jan', 'Tomáš', 'Lukáš', 'Matěj', 'Tereza', 'Eliška', 'Anna', 'Adéla', 'Karolína',
64 'Даниил', 'Максим', 'Артем', 'Иван', 'Александр', 'София', 'Анастасия', 'Дарья', 'Мария', 'Полина',
65 '伟', '伟', '芳', '伟', '秀英', '秀英', '娜', '秀英', '伟', '敏',
66 '翔', '大翔', '拓海', '翔太', '颯太', '陽菜', 'さくら', '美咲', '葵', '美羽',
67 );
68
69 public $loremipsum = <<<EOD
70Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Nulla non arcu lacinia neque faucibus fringilla. Vivamus porttitor turpis ac leo. Integer in sapien. Nullam eget nisl. Aliquam erat volutpat. Cras elementum. Mauris suscipit, ligula sit amet pharetra semper, nibh ante cursus purus, vel sagittis velit mauris vel metus. Integer malesuada. Nullam lectus justo, vulputate eget mollis sed, tempor sed magna. Mauris elementum mauris vitae tortor. Aliquam erat volutpat.
71Temporibus autem quibusdam et aut officiis debitis aut rerum necessitatibus saepe eveniet ut et voluptates repudiandae sint et molestiae non recusandae. Pellentesque ipsum. Cras pede libero, dapibus nec, pretium sit amet, tempor quis. Aliquam ante. Proin in tellus sit amet nibh dignissim sagittis. Vivamus porttitor turpis ac leo. Duis bibendum, lectus ut viverra rhoncus, dolor nunc faucibus libero, eget facilisis enim ipsum id lacus. In sem justo, commodo ut, suscipit at, pharetra vitae, orci. Aliquam erat volutpat. Nulla est.
72Vivamus luctus egestas leo. Aenean fermentum risus id tortor. Mauris dictum facilisis augue. Aliquam erat volutpat. Aliquam ornare wisi eu metus. Aliquam id dolor. Duis condimentum augue id magna semper rutrum. Donec iaculis gravida nulla. Pellentesque ipsum. Etiam dictum tincidunt diam. Quisque tincidunt scelerisque libero. Etiam egestas wisi a erat.
73Integer lacinia. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Mauris tincidunt sem sed arcu. Nullam feugiat, turpis at pulvinar vulputate, erat libero tristique tellus, nec bibendum odio risus sit amet ante. Aliquam id dolor. Maecenas sollicitudin. Et harum quidem rerum facilis est et expedita distinctio. Mauris suscipit, ligula sit amet pharetra semper, nibh ante cursus purus, vel sagittis velit mauris vel metus. Nullam dapibus fermentum ipsum. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit aut fugit, sed quia consequuntur magni dolores eos qui ratione voluptatem sequi nesciunt. Pellentesque sapien. Duis risus. Mauris elementum mauris vitae tortor. Suspendisse nisl. Integer rutrum, orci vestibulum ullamcorper ultricies, lacus quam ultricies odio, vitae placerat pede sem sit amet enim.
74In laoreet, magna id viverra tincidunt, sem odio bibendum justo, vel imperdiet sapien wisi sed libero. Proin pede metus, vulputate nec, fermentum fringilla, vehicula vitae, justo. Nullam justo enim, consectetuer nec, ullamcorper ac, vestibulum in, elit. Quis autem vel eum iure reprehenderit qui in ea voluptate velit esse quam nihil molestiae consequatur, vel illum qui dolorem eum fugiat quo voluptas nulla pariatur? Maecenas lorem. Etiam posuere lacus quis dolor. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos hymenaeos. Curabitur ligula sapien, pulvinar a vestibulum quis, facilisis vel sapien. Nam sed tellus id magna elementum tincidunt. Suspendisse nisl. Vivamus luctus egestas leo. Nulla non arcu lacinia neque faucibus fringilla. Etiam dui sem, fermentum vitae, sagittis id, malesuada in, quam. Etiam dictum tincidunt diam. Etiam commodo dui eget wisi. Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit aut fugit, sed quia consequuntur magni dolores eos qui ratione voluptatem sequi nesciunt. Proin pede metus, vulputate nec, fermentum fringilla, vehicula vitae, justo. Duis ante orci, molestie vitae vehicula venenatis, tincidunt ac pede. Pellentesque sapien.
75EOD;
76
77 /**
78 * To be called from data reset code only,
79 * do not use in tests.
80 * @return void
81 */
82 public function reset() {
83 $this->usercounter = 0;
84 $this->categorycount = 0;
85 $this->coursecount = 0;
86 $this->scalecount = 0;
87
5c3c2c81 88 foreach ($this->generators as $generator) {
7e7cfe7a
PS
89 $generator->reset();
90 }
91 }
92
93 /**
ba203de1
TH
94 * Return generator for given plugin or component.
95 * @param string $component the component name, e.g. 'mod_forum' or 'core_question'.
96 * @return component_generator_base or rather an instance of the appropriate subclass.
7e7cfe7a
PS
97 */
98 public function get_plugin_generator($component) {
56da374e 99 list($type, $plugin) = core_component::normalize_component($component);
ba203de1
TH
100 $cleancomponent = $type . '_' . $plugin;
101 if ($cleancomponent != $component) {
102 debugging("Please specify the component you want a generator for as " .
103 "{$cleancomponent}, not {$component}.", DEBUG_DEVELOPER);
104 $component = $cleancomponent;
105 }
7e7cfe7a 106
ba203de1
TH
107 if (isset($this->generators[$component])) {
108 return $this->generators[$component];
7e7cfe7a
PS
109 }
110
b0d1d941 111 $dir = core_component::get_component_directory($component);
ba203de1
TH
112 $lib = $dir . '/tests/generator/lib.php';
113 if (!$dir || !is_readable($lib)) {
114 throw new coding_exception("Component {$component} does not support " .
115 "generators yet. Missing tests/generator/lib.php.");
116 }
7e7cfe7a 117
ba203de1
TH
118 include_once($lib);
119 $classname = $component . '_generator';
120
121 if (!class_exists($classname)) {
122 throw new coding_exception("Component {$component} does not support " .
123 "data generators yet. Class {$classname} not found.");
7e7cfe7a
PS
124 }
125
ba203de1
TH
126 $this->generators[$component] = new $classname($this);
127 return $this->generators[$component];
7e7cfe7a
PS
128 }
129
130 /**
131 * Create a test user
132 * @param array|stdClass $record
133 * @param array $options
134 * @return stdClass user record
135 */
136 public function create_user($record=null, array $options=null) {
137 global $DB, $CFG;
138
139 $this->usercounter++;
140 $i = $this->usercounter;
141
142 $record = (array)$record;
143
144 if (!isset($record['auth'])) {
145 $record['auth'] = 'manual';
146 }
147
148 if (!isset($record['firstname']) and !isset($record['lastname'])) {
149 $country = rand(0, 5);
150 $firstname = rand(0, 4);
151 $lastname = rand(0, 4);
152 $female = rand(0, 1);
153 $record['firstname'] = $this->firstnames[($country*10) + $firstname + ($female*5)];
154 $record['lastname'] = $this->lastnames[($country*10) + $lastname + ($female*5)];
155
156 } else if (!isset($record['firstname'])) {
157 $record['firstname'] = 'Firstname'.$i;
158
159 } else if (!isset($record['lastname'])) {
160 $record['lastname'] = 'Lastname'.$i;
161 }
162
a327f25e
AG
163 if (!isset($record['firstnamephonetic'])) {
164 $firstnamephonetic = rand(0, 59);
165 $record['firstnamephonetic'] = $this->firstnames[$firstnamephonetic];
166 }
167
168 if (!isset($record['lasttnamephonetic'])) {
169 $lastnamephonetic = rand(0, 59);
170 $record['lastnamephonetic'] = $this->lastnames[$lastnamephonetic];
171 }
172
173 if (!isset($record['middlename'])) {
174 $middlename = rand(0, 59);
175 $record['middlename'] = $this->firstnames[$middlename];
176 }
177
178 if (!isset($record['alternatename'])) {
179 $alternatename = rand(0, 59);
180 $record['alternatename'] = $this->firstnames[$alternatename];
181 }
182
7e7cfe7a
PS
183 if (!isset($record['idnumber'])) {
184 $record['idnumber'] = '';
185 }
186
187 if (!isset($record['mnethostid'])) {
188 $record['mnethostid'] = $CFG->mnet_localhost_id;
189 }
190
191 if (!isset($record['username'])) {
fe67134e
PS
192 $record['username'] = 'username'.$i;
193 $j = 2;
7e7cfe7a 194 while ($DB->record_exists('user', array('username'=>$record['username'], 'mnethostid'=>$record['mnethostid']))) {
fe67134e
PS
195 $record['username'] = 'username'.$i.'_'.$j;
196 $j++;
7e7cfe7a
PS
197 }
198 }
199
dbf60a04
PS
200 if (isset($record['password'])) {
201 $record['password'] = hash_internal_user_password($record['password']);
202 } else {
203 // The auth plugin may not fully support this,
204 // but it is still better/faster than hashing random stuff.
205 $record['password'] = AUTH_PASSWORD_NOT_CACHED;
7e7cfe7a
PS
206 }
207
208 if (!isset($record['email'])) {
209 $record['email'] = $record['username'].'@example.com';
210 }
211
212 if (!isset($record['confirmed'])) {
213 $record['confirmed'] = 1;
214 }
215
216 if (!isset($record['lang'])) {
217 $record['lang'] = 'en';
218 }
219
220 if (!isset($record['maildisplay'])) {
221 $record['maildisplay'] = 1;
222 }
223
224 if (!isset($record['deleted'])) {
225 $record['deleted'] = 0;
226 }
227
228 $record['timecreated'] = time();
229 $record['timemodified'] = $record['timecreated'];
230 $record['lastip'] = '0.0.0.0';
231
7e7cfe7a
PS
232 if ($record['deleted']) {
233 $delname = $record['email'].'.'.time();
234 while ($DB->record_exists('user', array('username'=>$delname))) {
235 $delname++;
236 }
237 $record['idnumber'] = '';
238 $record['email'] = md5($record['username']);
239 $record['username'] = $delname;
240 $record['picture'] = 0;
241 }
242
243 $userid = $DB->insert_record('user', $record);
244
245 if (!$record['deleted']) {
246 context_user::instance($userid);
247 }
248
249 return $DB->get_record('user', array('id'=>$userid), '*', MUST_EXIST);
250 }
251
252 /**
253 * Create a test course category
254 * @param array|stdClass $record
255 * @param array $options
b28bb7e8 256 * @return coursecat course category record
7e7cfe7a 257 */
4729332b 258 public function create_category($record=null, array $options=null) {
7e7cfe7a 259 global $DB, $CFG;
b28bb7e8 260 require_once("$CFG->libdir/coursecatlib.php");
7e7cfe7a
PS
261
262 $this->categorycount++;
263 $i = $this->categorycount;
264
265 $record = (array)$record;
266
267 if (!isset($record['name'])) {
268 $record['name'] = 'Course category '.$i;
269 }
270
7e7cfe7a
PS
271 if (!isset($record['description'])) {
272 $record['description'] = "Test course category $i\n$this->loremipsum";
273 }
274
b28bb7e8
MG
275 if (!isset($record['idnumber'])) {
276 $record['idnumber'] = '';
7e7cfe7a 277 }
7e7cfe7a 278
b28bb7e8 279 return coursecat::create($record);
7e7cfe7a
PS
280 }
281
4729332b
PS
282 /**
283 * Create test cohort.
284 * @param array|stdClass $record
285 * @param array $options
286 * @return stdClass cohort record
287 */
288 public function create_cohort($record=null, array $options=null) {
289 global $DB, $CFG;
290 require_once("$CFG->dirroot/cohort/lib.php");
291
292 $this->cohortcount++;
293 $i = $this->cohortcount;
294
295 $record = (array)$record;
296
297 if (!isset($record['contextid'])) {
298 $record['contextid'] = context_system::instance()->id;
299 }
300
301 if (!isset($record['name'])) {
302 $record['name'] = 'Cohort '.$i;
303 }
304
305 if (!isset($record['idnumber'])) {
306 $record['idnumber'] = '';
307 }
308
309 if (!isset($record['description'])) {
310 $record['description'] = "Test cohort $i\n$this->loremipsum";
311 }
312
313 if (!isset($record['descriptionformat'])) {
314 $record['descriptionformat'] = FORMAT_MOODLE;
315 }
316
317 if (!isset($record['component'])) {
318 $record['component'] = '';
319 }
320
321 $id = cohort_add_cohort((object)$record);
322
323 return $DB->get_record('cohort', array('id'=>$id), '*', MUST_EXIST);
324 }
325
7e7cfe7a
PS
326 /**
327 * Create a test course
328 * @param array|stdClass $record
329 * @param array $options with keys:
330 * 'createsections'=>bool precreate all sections
331 * @return stdClass course record
332 */
4729332b 333 public function create_course($record=null, array $options=null) {
7e7cfe7a
PS
334 global $DB, $CFG;
335 require_once("$CFG->dirroot/course/lib.php");
336
337 $this->coursecount++;
338 $i = $this->coursecount;
339
340 $record = (array)$record;
341
342 if (!isset($record['fullname'])) {
343 $record['fullname'] = 'Test course '.$i;
344 }
345
346 if (!isset($record['shortname'])) {
347 $record['shortname'] = 'tc_'.$i;
348 }
349
350 if (!isset($record['idnumber'])) {
351 $record['idnumber'] = '';
352 }
353
354 if (!isset($record['format'])) {
355 $record['format'] = 'topics';
356 }
357
358 if (!isset($record['newsitems'])) {
359 $record['newsitems'] = 0;
360 }
361
362 if (!isset($record['numsections'])) {
363 $record['numsections'] = 5;
364 }
365
4a38e659
PS
366 if (!isset($record['summary'])) {
367 $record['summary'] = "Test course $i\n$this->loremipsum";
7e7cfe7a
PS
368 }
369
4a38e659
PS
370 if (!isset($record['summaryformat'])) {
371 $record['summaryformat'] = FORMAT_MOODLE;
7e7cfe7a
PS
372 }
373
374 if (!isset($record['category'])) {
375 $record['category'] = $DB->get_field_select('course_categories', "MIN(id)", "parent=0");
376 }
377
378 $course = create_course((object)$record);
379 context_course::instance($course->id);
7e7cfe7a 380 if (!empty($options['createsections'])) {
384c3510
MG
381 if (isset($course->numsections)) {
382 course_create_sections_if_missing($course, range(0, $course->numsections));
383 } else {
384 course_create_sections_if_missing($course, 0);
7e7cfe7a
PS
385 }
386 }
387
388 return $course;
389 }
390
391 /**
392 * Create course section if does not exist yet
384c3510 393 * @param array|stdClass $record must contain 'course' and 'section' attributes
7e7cfe7a
PS
394 * @param array|null $options
395 * @return stdClass
396 * @throws coding_exception
397 */
398 public function create_course_section($record = null, array $options = null) {
399 global $DB;
400
401 $record = (array)$record;
402
403 if (empty($record['course'])) {
5c3c2c81 404 throw new coding_exception('course must be present in testing_data_generator::create_course_section() $record');
7e7cfe7a
PS
405 }
406
407 if (!isset($record['section'])) {
5c3c2c81 408 throw new coding_exception('section must be present in testing_data_generator::create_course_section() $record');
7e7cfe7a
PS
409 }
410
b46be6ad
MG
411 course_create_sections_if_missing($record['course'], $record['section']);
412 return get_fast_modinfo($record['course'])->get_section_info($record['section']);
7e7cfe7a
PS
413 }
414
415 /**
416 * Create a test block
417 * @param string $blockname
418 * @param array|stdClass $record
419 * @param array $options
420 * @return stdClass block instance record
421 */
422 public function create_block($blockname, $record=null, array $options=null) {
423 $generator = $this->get_plugin_generator('block_'.$blockname);
424 return $generator->create_instance($record, $options);
425 }
426
427 /**
428 * Create a test module
429 * @param string $modulename
430 * @param array|stdClass $record
431 * @param array $options
432 * @return stdClass activity record
433 */
434 public function create_module($modulename, $record=null, array $options=null) {
435 $generator = $this->get_plugin_generator('mod_'.$modulename);
436 return $generator->create_instance($record, $options);
437 }
438
439 /**
440 * Create a test group for the specified course
441 *
442 * $record should be either an array or a stdClass containing infomation about the group to create.
443 * At the very least it needs to contain courseid.
444 * Default values are added for name, description, and descriptionformat if they are not present.
445 *
6b219869
DM
446 * This function calls groups_create_group() to create the group within the database.
447 * @see groups_create_group
7e7cfe7a
PS
448 * @param array|stdClass $record
449 * @return stdClass group record
450 */
451 public function create_group($record) {
452 global $DB, $CFG;
453
454 require_once($CFG->dirroot . '/group/lib.php');
455
456 $this->groupcount++;
457 $i = $this->groupcount;
458
459 $record = (array)$record;
460
461 if (empty($record['courseid'])) {
5c3c2c81 462 throw new coding_exception('courseid must be present in testing_data_generator::create_group() $record');
7e7cfe7a
PS
463 }
464
465 if (!isset($record['name'])) {
466 $record['name'] = 'group-' . $i;
467 }
468
469 if (!isset($record['description'])) {
470 $record['description'] = "Test Group $i\n{$this->loremipsum}";
471 }
472
473 if (!isset($record['descriptionformat'])) {
474 $record['descriptionformat'] = FORMAT_MOODLE;
475 }
476
477 $id = groups_create_group((object)$record);
478
479 return $DB->get_record('groups', array('id'=>$id));
480 }
481
87bb583c
DM
482 /**
483 * Create a test group member
484 * @param array|stdClass $record
485 * @throws coding_exception
486 * @return boolean
487 */
488 public function create_group_member($record) {
489 global $DB, $CFG;
490
491 require_once($CFG->dirroot . '/group/lib.php');
492
493 $record = (array)$record;
494
495 if (empty($record['userid'])) {
496 throw new coding_exception('user must be present in testing_util::create_group_member() $record');
497 }
498
499 if (!isset($record['groupid'])) {
500 throw new coding_exception('group must be present in testing_util::create_group_member() $record');
501 }
502
503 if (!isset($record['component'])) {
504 $record['component'] = null;
505 }
506 if (!isset($record['itemid'])) {
507 $record['itemid'] = 0;
508 }
509
510 return groups_add_member($record['groupid'], $record['userid'], $record['component'], $record['itemid']);
511 }
512
7e7cfe7a
PS
513 /**
514 * Create a test grouping for the specified course
515 *
516 * $record should be either an array or a stdClass containing infomation about the grouping to create.
517 * At the very least it needs to contain courseid.
518 * Default values are added for name, description, and descriptionformat if they are not present.
519 *
6b219869
DM
520 * This function calls groups_create_grouping() to create the grouping within the database.
521 * @see groups_create_grouping
7e7cfe7a
PS
522 * @param array|stdClass $record
523 * @return stdClass grouping record
524 */
525 public function create_grouping($record) {
526 global $DB, $CFG;
527
528 require_once($CFG->dirroot . '/group/lib.php');
529
530 $this->groupingcount++;
531 $i = $this->groupingcount;
532
533 $record = (array)$record;
534
535 if (empty($record['courseid'])) {
5c3c2c81 536 throw new coding_exception('courseid must be present in testing_data_generator::create_grouping() $record');
7e7cfe7a
PS
537 }
538
539 if (!isset($record['name'])) {
540 $record['name'] = 'grouping-' . $i;
541 }
542
543 if (!isset($record['description'])) {
544 $record['description'] = "Test Grouping $i\n{$this->loremipsum}";
545 }
546
547 if (!isset($record['descriptionformat'])) {
548 $record['descriptionformat'] = FORMAT_MOODLE;
549 }
550
551 $id = groups_create_grouping((object)$record);
552
553 return $DB->get_record('groupings', array('id'=>$id));
554 }
555
87bb583c
DM
556 /**
557 * Create a test grouping group
558 * @param array|stdClass $record
559 * @throws coding_exception
560 * @return boolean
561 */
562 public function create_grouping_group($record) {
563 global $DB, $CFG;
564
565 require_once($CFG->dirroot . '/group/lib.php');
566
567 $record = (array)$record;
568
569 if (empty($record['groupingid'])) {
570 throw new coding_exception('grouping must be present in testing::create_grouping_group() $record');
571 }
572
573 if (!isset($record['groupid'])) {
574 throw new coding_exception('group must be present in testing_util::create_grouping_group() $record');
575 }
576
577 return groups_assign_grouping($record['groupingid'], $record['groupid']);
578 }
579
0852bbae
FM
580 /**
581 * Create an instance of a repository.
582 *
583 * @param string type of repository to create an instance for.
584 * @param array|stdClass $record data to use to up set the instance.
585 * @param array $options options
586 * @return stdClass repository instance record
ba375bcb 587 * @since 2.5.1
0852bbae
FM
588 */
589 public function create_repository($type, $record=null, array $options = null) {
0852bbae
FM
590 $generator = $this->get_plugin_generator('repository_'.$type);
591 return $generator->create_instance($record, $options);
592 }
593
594 /**
595 * Create an instance of a repository.
596 *
597 * @param string type of repository to create an instance for.
598 * @param array|stdClass $record data to use to up set the instance.
599 * @param array $options options
600 * @return repository_type object
ba375bcb 601 * @since 2.5.1
0852bbae
FM
602 */
603 public function create_repository_type($type, $record=null, array $options = null) {
0852bbae
FM
604 $generator = $this->get_plugin_generator('repository_'.$type);
605 return $generator->create_type($record, $options);
606 }
607
608
7e7cfe7a
PS
609 /**
610 * Create a test scale
611 * @param array|stdClass $record
612 * @param array $options
613 * @return stdClass block instance record
614 */
615 public function create_scale($record=null, array $options=null) {
616 global $DB;
617
618 $this->scalecount++;
619 $i = $this->scalecount;
620
621 $record = (array)$record;
622
623 if (!isset($record['name'])) {
624 $record['name'] = 'Test scale '.$i;
625 }
626
627 if (!isset($record['scale'])) {
628 $record['scale'] = 'A,B,C,D,F';
629 }
630
631 if (!isset($record['courseid'])) {
632 $record['courseid'] = 0;
633 }
634
635 if (!isset($record['userid'])) {
636 $record['userid'] = 0;
637 }
638
639 if (!isset($record['description'])) {
640 $record['description'] = 'Test scale description '.$i;
641 }
642
643 if (!isset($record['descriptionformat'])) {
644 $record['descriptionformat'] = FORMAT_MOODLE;
645 }
646
647 $record['timemodified'] = time();
648
649 if (isset($record['id'])) {
650 $DB->import_record('scale', $record);
651 $DB->get_manager()->reset_sequence('scale');
652 $id = $record['id'];
653 } else {
654 $id = $DB->insert_record('scale', $record);
655 }
656
657 return $DB->get_record('scale', array('id'=>$id), '*', MUST_EXIST);
658 }
4f5789ea 659
702851c0
DM
660 /**
661 * Creates a new role in the system.
662 *
663 * You can fill $record with the role 'name',
664 * 'shortname', 'description' and 'archetype'.
665 *
666 * If an archetype is specified it's capabilities,
667 * context where the role can be assigned and
668 * all other properties are copied from the archetype;
669 * if no archetype is specified it will create an
670 * empty role.
671 *
672 * @param array|stdClass $record
673 * @return int The new role id
674 */
675 public function create_role($record=null) {
676 global $DB;
677
678 $this->rolecount++;
679 $i = $this->rolecount;
680
681 $record = (array)$record;
682
683 if (empty($record['shortname'])) {
684 $record['shortname'] = 'role-' . $i;
685 }
686
687 if (empty($record['name'])) {
688 $record['name'] = 'Test role ' . $i;
689 }
690
691 if (empty($record['description'])) {
692 $record['description'] = 'Test role ' . $i . ' description';
693 }
694
695 if (empty($record['archetype'])) {
696 $record['archetype'] = '';
697 } else {
698 $archetypes = get_role_archetypes();
699 if (empty($archetypes[$record['archetype']])) {
700 throw new coding_exception('\'role\' requires the field \'archetype\' to specify a ' .
701 'valid archetype shortname (editingteacher, student...)');
702 }
703 }
704
705 // Creates the role.
706 if (!$newroleid = create_role($record['name'], $record['shortname'], $record['description'], $record['archetype'])) {
707 throw new coding_exception('There was an error creating \'' . $record['shortname'] . '\' role');
708 }
709
710 // If no archetype was specified we allow it to be added to all contexts,
711 // otherwise we allow it in the archetype contexts.
712 if (!$record['archetype']) {
713 $contextlevels = array_keys(context_helper::get_all_levels());
714 } else {
715 // Copying from the archetype default rol.
716 $archetyperoleid = $DB->get_field(
717 'role',
718 'id',
719 array('shortname' => $record['archetype'], 'archetype' => $record['archetype'])
720 );
721 $contextlevels = get_role_contextlevels($archetyperoleid);
722 }
723 set_role_contextlevels($newroleid, $contextlevels);
724
725 if ($record['archetype']) {
726
727 // We copy all the roles the archetype can assign, override and switch to.
728 if ($record['archetype']) {
729 $types = array('assign', 'override', 'switch');
730 foreach ($types as $type) {
731 $rolestocopy = get_default_role_archetype_allows($type, $record['archetype']);
732 foreach ($rolestocopy as $tocopy) {
733 $functionname = 'allow_' . $type;
734 $functionname($newroleid, $tocopy);
735 }
736 }
737 }
738
739 // Copying the archetype capabilities.
740 $sourcerole = $DB->get_record('role', array('id' => $archetyperoleid));
741 role_cap_duplicate($sourcerole, $newroleid);
742 }
743
744 return $newroleid;
745 }
746
ba203de1
TH
747 /**
748 * Helper method which combines $defaults with the values specified in $record.
749 * If $record is an object, it is converted to an array.
750 * Then, for each key that is in $defaults, but not in $record, the value
751 * from $defaults is copied.
752 * @param array $defaults the default value for each field with
753 * @param array|stdClass $record
754 * @return array updated $record.
755 */
756 public function combine_defaults_and_record(array $defaults, $record) {
757 $record = (array) $record;
758
759 foreach ($defaults as $key => $defaults) {
760 if (!array_key_exists($key, $record)) {
761 $record[$key] = $defaults;
762 }
763 }
764 return $record;
765 }
766
4f5789ea
PS
767 /**
768 * Simplified enrolment of user to course using default options.
769 *
770 * It is strongly recommended to use only this method for 'manual' and 'self' plugins only!!!
771 *
772 * @param int $userid
773 * @param int $courseid
774 * @param int $roleid optional role id, use only with manual plugin
775 * @param string $enrol name of enrol plugin,
776 * there must be exactly one instance in course,
777 * it must support enrol_user() method.
1ecb8044
RT
778 * @param int $timestart (optional) 0 means unknown
779 * @param int $timeend (optional) 0 means forever
780 * @param int $status (optional) default to ENROL_USER_ACTIVE for new enrolments
4f5789ea
PS
781 * @return bool success
782 */
e6cc5347 783 public function enrol_user($userid, $courseid, $roleid = null, $enrol = 'manual', $timestart = 0, $timeend = 0, $status = null) {
4f5789ea
PS
784 global $DB;
785
786 if (!$plugin = enrol_get_plugin($enrol)) {
787 return false;
788 }
789
790 $instances = $DB->get_records('enrol', array('courseid'=>$courseid, 'enrol'=>$enrol));
791 if (count($instances) != 1) {
792 return false;
793 }
794 $instance = reset($instances);
795
796 if (is_null($roleid) and $instance->roleid) {
797 $roleid = $instance->roleid;
798 }
799
e6cc5347 800 $plugin->enrol_user($instance, $userid, $roleid, $timestart, $timeend, $status);
4f5789ea
PS
801 return true;
802 }
72ddc05f
DM
803
804 /**
805 * Assigns the specified role to a user in the context.
806 *
807 * @param int $roleid
808 * @param int $userid
809 * @param int $contextid Defaults to the system context
810 * @return int new/existing id of the assignment
811 */
812 public function role_assign($roleid, $userid, $contextid = false) {
813
814 // Default to the system context.
815 if (!$contextid) {
816 $context = context_system::instance();
817 $contextid = $context->id;
818 }
819
820 if (empty($roleid)) {
821 throw new coding_exception('roleid must be present in testing_data_generator::role_assign() arguments');
822 }
823
824 if (empty($userid)) {
825 throw new coding_exception('userid must be present in testing_data_generator::role_assign() arguments');
826 }
827
828 return role_assign($roleid, $userid, $contextid);
829 }
830
7e7cfe7a 831}