on-demand release 4.0dev+
[moodle.git] / admin / tool / uploadcourse / tests / helper_test.php
1 <?php
2 // This file is part of Moodle - http://moodle.org/
3 //
4 // Moodle is free software: you can redistribute it and/or modify
5 // it under the terms of the GNU General Public License as published by
6 // the Free Software Foundation, either version 3 of the License, or
7 // (at your option) any later version.
8 //
9 // Moodle is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12 // GNU General Public License for more details.
13 //
14 // You should have received a copy of the GNU General Public License
15 // along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
17 /**
18  * File containing tests for the helper.
19  *
20  * @package    tool_uploadcourse
21  * @copyright  2013 Frédéric Massart
22  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
23  */
25 defined('MOODLE_INTERNAL') || die();
27 global $CFG;
29 /**
30  * Helper test case.
31  *
32  * @package    tool_uploadcourse
33  * @copyright  2013 Frédéric Massart
34  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
35  */
36 class tool_uploadcourse_helper_testcase extends advanced_testcase {
38     public function test_generate_shortname() {
39         $data = (object) array('fullname' => 'Ah bh Ch 01 02 03', 'idnumber' => 'ID123');
41         $this->assertSame($data->fullname, tool_uploadcourse_helper::generate_shortname($data, '%f'));
42         $this->assertSame($data->idnumber, tool_uploadcourse_helper::generate_shortname($data, '%i'));
43         $this->assertSame('Ah Bh Ch', tool_uploadcourse_helper::generate_shortname($data, '%~8f'));
44         $this->assertSame('AH BH CH', tool_uploadcourse_helper::generate_shortname($data, '%+8f'));
45         $this->assertSame('id123', tool_uploadcourse_helper::generate_shortname($data, '%-i'));
46         $this->assertSame('[Ah bh Ch] = ID123', tool_uploadcourse_helper::generate_shortname($data, '[%8f] = %i'));
47         $this->assertSame('0', tool_uploadcourse_helper::generate_shortname($data, '0'));
48         $this->assertSame('%unknown', tool_uploadcourse_helper::generate_shortname($data, '%unknown'));
50         $this->assertNull(tool_uploadcourse_helper::generate_shortname($data, ''));
51         $this->assertNull(tool_uploadcourse_helper::generate_shortname(array(), '%f'));
52     }
54     public function test_get_course_formats() {
55         $result = tool_uploadcourse_helper::get_course_formats();
56         $this->assertSame(array_keys(core_component::get_plugin_list('format')), $result);
57         // Should be similar as first result, as cached.
58         $this->assertSame($result, tool_uploadcourse_helper::get_course_formats());
59     }
61     public function test_get_enrolment_data() {
62         $this->resetAfterTest(true);
63         $data = array(
64             'enrolment_1' => 'unknown',
65             'enrolment_1_foo' => '1',
66             'enrolment_1_bar' => '2',
67             'enrolment_2' => 'self',
68             'enrolment_2_delete' => '1',
69             'enrolment_2_foo' => 'a',
70             'enrolment_2_bar' => '1',
71             'enrolment_3' => 'manual',
72             'enrolment_3_disable' => '2',
73             'enrolment_3_foo' => 'b',
74             'enrolment_3_bar' => '2',
75             'enrolment_4' => 'database',
76             'enrolment_4_foo' => 'x',
77             'enrolment_4_bar' => '3',
78             'enrolment_5_test3' => 'test3',
79             'enrolment_5_test2' => 'test2',
80             'enrolment_5_test1' => 'test1',
81             'enrolment_5' => 'flatfile',
82         );
83         $expected = array(
84             'self' => array(
85                 'delete' => '1',
86                 'foo' => 'a',
87                 'bar' => '1',
88             ),
89             'manual' => array(
90                 'disable' => '2',
91                 'foo' => 'b',
92                 'bar' => '2',
93             ),
94             'database' => array(
95                 'foo' => 'x',
96                 'bar' => '3',
97             ),
98             'flatfile' => array(
99                 'test3' => 'test3',
100                 'test2' => 'test2',
101                 'test1' => 'test1',
102             )
103         );
104         $this->assertSame(tool_uploadcourse_helper::get_enrolment_data($data), $expected);
105     }
107     public function test_get_enrolment_plugins() {
108         $this->resetAfterTest(true);
109         $actual = tool_uploadcourse_helper::get_enrolment_plugins();
110         $this->assertSame(array_keys(enrol_get_plugins(false)), array_keys($actual));
111         // This should be identical as cached.
112         $secondactual = tool_uploadcourse_helper::get_enrolment_plugins();
113         $this->assertEquals($actual, $secondactual);
114     }
116     public function test_get_restore_content_dir() {
117         global $CFG;
118         $this->resetAfterTest(true);
119         $this->setAdminUser();
121         $c1 = $this->getDataGenerator()->create_course();
122         $c2 = $this->getDataGenerator()->create_course((object) array('shortname' => 'Yay'));
124         // Creating backup file.
125         $bc = new backup_controller(backup::TYPE_1COURSE, $c1->id, backup::FORMAT_MOODLE,
126             backup::INTERACTIVE_NO, backup::MODE_GENERAL, 2);
127         $bc->execute_plan();
128         $result = $bc->get_results();
129         $this->assertTrue(isset($result['backup_destination']));
130         $c1backupfile = $result['backup_destination']->copy_content_to_temp();
131         $bc->destroy();
133         // Creating backup file.
134         $bc = new backup_controller(backup::TYPE_1COURSE, $c2->id, backup::FORMAT_MOODLE,
135             backup::INTERACTIVE_NO, backup::MODE_GENERAL, 2);
136         $bc->execute_plan();
137         $result = $bc->get_results();
138         $this->assertTrue(isset($result['backup_destination']));
139         $c2backupfile = $result['backup_destination']->copy_content_to_temp();
140         $bc->destroy();
142         $oldcfg = isset($CFG->keeptempdirectoriesonbackup) ? $CFG->keeptempdirectoriesonbackup : false;
143         $CFG->keeptempdirectoriesonbackup = true;
145         // Checking restore dir.
146         $dir = tool_uploadcourse_helper::get_restore_content_dir($c1backupfile, null);
147         $bcinfo = backup_general_helper::get_backup_information($dir);
148         $this->assertEquals($bcinfo->original_course_id, $c1->id);
149         $this->assertEquals($bcinfo->original_course_fullname, $c1->fullname);
151         // Do it again, it should be the same directory.
152         $dir2 = tool_uploadcourse_helper::get_restore_content_dir($c1backupfile, null);
153         $this->assertEquals($dir, $dir2);
155         // Get the second course.
156         $dir = tool_uploadcourse_helper::get_restore_content_dir($c2backupfile, null);
157         $bcinfo = backup_general_helper::get_backup_information($dir);
158         $this->assertEquals($bcinfo->original_course_id, $c2->id);
159         $this->assertEquals($bcinfo->original_course_fullname, $c2->fullname);
161         // Checking with a shortname.
162         $dir = tool_uploadcourse_helper::get_restore_content_dir(null, $c1->shortname);
163         $bcinfo = backup_general_helper::get_backup_information($dir);
164         $this->assertEquals($bcinfo->original_course_id, $c1->id);
165         $this->assertEquals($bcinfo->original_course_fullname, $c1->fullname);
167         // Do it again, it should be the same directory.
168         $dir2 = tool_uploadcourse_helper::get_restore_content_dir(null, $c1->shortname);
169         $this->assertEquals($dir, $dir2);
171         // Get the second course.
172         $dir = tool_uploadcourse_helper::get_restore_content_dir(null, $c2->shortname);
173         $bcinfo = backup_general_helper::get_backup_information($dir);
174         $this->assertEquals($bcinfo->original_course_id, $c2->id);
175         $this->assertEquals($bcinfo->original_course_fullname, $c2->fullname);
177         // Get a course that does not exist.
178         $errors = array();
179         $dir = tool_uploadcourse_helper::get_restore_content_dir(null, 'DoesNotExist', $errors);
180         $this->assertFalse($dir);
181         $this->assertArrayHasKey('coursetorestorefromdoesnotexist', $errors);
183         // Trying again without caching. $CFG->keeptempdirectoriesonbackup is required for caching.
184         $CFG->keeptempdirectoriesonbackup = false;
186         // Checking restore dir.
187         $dir = tool_uploadcourse_helper::get_restore_content_dir($c1backupfile, null);
188         $dir2 = tool_uploadcourse_helper::get_restore_content_dir($c1backupfile, null);
189         $this->assertNotEquals($dir, $dir2);
191         // Checking with a shortname.
192         $dir = tool_uploadcourse_helper::get_restore_content_dir(null, $c1->shortname);
193         $dir2 = tool_uploadcourse_helper::get_restore_content_dir(null, $c1->shortname);
194         $this->assertNotEquals($dir, $dir2);
196         // Get a course that does not exist.
197         $errors = array();
198         $dir = tool_uploadcourse_helper::get_restore_content_dir(null, 'DoesNotExist', $errors);
199         $this->assertFalse($dir);
200         $this->assertArrayHasKey('coursetorestorefromdoesnotexist', $errors);
201         $dir2 = tool_uploadcourse_helper::get_restore_content_dir(null, 'DoesNotExist', $errors);
202         $this->assertEquals($dir, $dir2);
204         $CFG->keeptempdirectoriesonbackup = $oldcfg;
205     }
207     public function test_get_role_ids() {
208         $this->getDataGenerator();
209         // Mimic function result.
210         $expected = array();
211         $roles = get_all_roles();
212         foreach ($roles as $role) {
213             $expected[$role->shortname] = $role->id;
214         }
216         $actual = tool_uploadcourse_helper::get_role_ids();
217         $this->assertSame($actual, $expected);
219         // Check cache.
220         $this->assertSame($actual, tool_uploadcourse_helper::get_role_ids());
221     }
223     public function test_get_role_names() {
224         $this->resetAfterTest(true);
226         create_role('Villain', 'villain', 'The bad guys');
227         $data = array(
228             'role_student' => 'Padawan',
229             'role_teacher' => 'Guardian',
230             'role_editingteacher' => 'Knight',
231             'role_manager' => 'Master',
232             'role_villain' => 'Jabba the Hutt',
233             'role_android' => 'R2D2',
234         );
236         // Get the role IDs, but need to force the cache reset as a new role is defined.
237         $roleids = tool_uploadcourse_helper::get_role_ids(true);
239         $expected = array(
240             'role_' . $roleids['student'] => 'Padawan',
241             'role_' . $roleids['teacher'] => 'Guardian',
242             'role_' . $roleids['editingteacher'] => 'Knight',
243             'role_' . $roleids['manager'] => 'Master',
244             'role_' . $roleids['villain'] => 'Jabba the Hutt',
245         );
247         $errors = array();
248         $actual = tool_uploadcourse_helper::get_role_names($data, $errors);
249         $this->assertSame($actual, $expected);
250         $this->assertArrayHasKey('invalidroles', $errors);
251     }
253     /**
254      * Test custom field data processing
255      */
256     public function test_get_custom_course_field_data() {
257         global $DB;
259         $this->resetAfterTest();
261         // Create all the fields!
262         $category = $this->get_customfield_generator()->create_category();
264         $checkboxfield = $this->create_custom_field($category, 'checkbox', 'mycheckbox');
265         $datefield = $this->create_custom_field($category, 'date', 'mydate');
266         $selectfield = $this->create_custom_field($category, 'select', 'myselect', ['options' => "Red\nGreen\nBlue"]);
267         $textfield = $this->create_custom_field($category, 'text', 'mytext', ['locked' => 1]);
268         $textareafield = $this->create_custom_field($category, 'textarea', 'mytextarea');
270         $fields = tool_uploadcourse_helper::get_custom_course_fields();
271         $this->assertCount(5, $fields);
273         $this->assertArrayHasKey($checkboxfield->get('shortname'), $fields);
274         $this->assertInstanceOf(customfield_checkbox\field_controller::class, $fields[$checkboxfield->get('shortname')]);
276         $this->assertArrayHasKey($datefield->get('shortname'), $fields);
277         $this->assertInstanceOf(customfield_date\field_controller::class, $fields[$datefield->get('shortname')]);
279         $this->assertArrayHasKey($selectfield->get('shortname'), $fields);
280         $this->assertInstanceOf(customfield_select\field_controller::class, $fields[$selectfield->get('shortname')]);
282         $this->assertArrayHasKey($textfield->get('shortname'), $fields);
283         $this->assertInstanceOf(customfield_text\field_controller::class, $fields[$textfield->get('shortname')]);
285         $this->assertArrayHasKey($textareafield->get('shortname'), $fields);
286         $this->assertInstanceOf(customfield_textarea\field_controller::class, $fields[$textareafield->get('shortname')]);
288         $data = [
289             'customfield_mycheckbox' => '1',
290             'customfield_mydate' => '2019-10-01',
291             'customfield_myselect' => 'Green',
292             'customfield_mytext' => 'Hello',
293             'customfield_myunknownfield' => 'Goodbye',
294         ];
296         $expected = [
297             'customfield_mycheckbox' => '1',
298             'customfield_mydate' => strtotime('2019-10-01'),
299             'customfield_myselect' => 2,
300             'customfield_mytext' => 'Hello',
301         ];
303         $course = $this->getDataGenerator()->create_course();
304         $user = $this->getDataGenerator()->create_and_enrol($course, 'manager');
305         $this->setUser($user);
307         $context = context_course::instance($course->id);
309         $this->assertEquals($expected, tool_uploadcourse_helper::get_custom_course_field_data($data, [], $context));
311         // Now add our custom textarea field (separately because the value of it's 'itemid' element is unknown).
312         $data['customfield_mytextarea'] = 'Something';
313         $fields = tool_uploadcourse_helper::get_custom_course_field_data($data, [], $context);
314         $this->assertArrayHasKey('customfield_mytextarea_editor', $fields);
315         $this->assertArrayHasKey('text', $fields['customfield_mytextarea_editor']);
316         $this->assertEquals('Something', $fields['customfield_mytextarea_editor']['text']);
318         // Now prohibit the capability to change locked fields for the manager role.
319         $managerrole = $DB->get_record('role', ['shortname' => 'manager']);
320         role_change_permission($managerrole->id, $context, 'moodle/course:changelockedcustomfields', CAP_PROHIBIT);
322         // The locked 'mytext' custom field should not be returned.
323         $fields = tool_uploadcourse_helper::get_custom_course_field_data($data, [], $context);
324         $this->assertCount(4, $fields);
325         $this->assertArrayNotHasKey('customfield_mytext', $fields);
326     }
328     public function test_increment_idnumber() {
329         $this->resetAfterTest(true);
331         $c1 = $this->getDataGenerator()->create_course(array('idnumber' => 'C1'));
332         $c2 = $this->getDataGenerator()->create_course(array('idnumber' => 'C2'));
333         $c3 = $this->getDataGenerator()->create_course(array('idnumber' => 'Yo'));
335         $this->assertEquals('C3', tool_uploadcourse_helper::increment_idnumber('C1'));
336         $this->assertEquals('Yo_2', tool_uploadcourse_helper::increment_idnumber('Yo'));
337         $this->assertEquals('DoesNotExist', tool_uploadcourse_helper::increment_idnumber('DoesNotExist'));
338     }
340     public function test_increment_shortname() {
341         $this->resetAfterTest(true);
343         $c1 = $this->getDataGenerator()->create_course(array('shortname' => 'C1'));
344         $c2 = $this->getDataGenerator()->create_course(array('shortname' => 'C2'));
345         $c3 = $this->getDataGenerator()->create_course(array('shortname' => 'Yo'));
347         // FYI: increment_shortname assumes that the course exists, and so increment the shortname immediately.
348         $this->assertEquals('C3', tool_uploadcourse_helper::increment_shortname('C1'));
349         $this->assertEquals('Yo_2', tool_uploadcourse_helper::increment_shortname('Yo'));
350         $this->assertEquals('DoesNotExist_2', tool_uploadcourse_helper::increment_shortname('DoesNotExist'));
351     }
353     public function test_resolve_category() {
354         $this->resetAfterTest(true);
356         $c1 = $this->getDataGenerator()->create_category(array('name' => 'First level'));
357         $c2 = $this->getDataGenerator()->create_category(array('name' => 'Second level', 'parent' => $c1->id));
358         $c3 = $this->getDataGenerator()->create_category(array('idnumber' => 'C3'));
360         $data = array(
361             'category' => $c1->id,
362             'category_path' => $c1->name . ' / ' . $c2->name,
363             'category_idnumber' => $c3->idnumber,
364         );
366         $this->assertEquals($c1->id, tool_uploadcourse_helper::resolve_category($data));
367         unset($data['category']);
368         $this->assertEquals($c3->id, tool_uploadcourse_helper::resolve_category($data));
369         unset($data['category_idnumber']);
370         $this->assertEquals($c2->id, tool_uploadcourse_helper::resolve_category($data));
372         // Adding unexisting data.
373         $errors = array();
374         $data['category_idnumber'] = 1234;
375         $this->assertEquals($c2->id, tool_uploadcourse_helper::resolve_category($data, $errors));
376         $this->assertArrayHasKey('couldnotresolvecatgorybyidnumber', $errors);
377         $errors = array();
378         $data['category'] = 1234;
379         $this->assertEquals($c2->id, tool_uploadcourse_helper::resolve_category($data, $errors));
380         $this->assertArrayHasKey('couldnotresolvecatgorybyid', $errors);
381         $errors = array();
382         $data['category_path'] = 'Not exist';
383         $this->assertEmpty(tool_uploadcourse_helper::resolve_category($data, $errors));
384         $this->assertArrayHasKey('couldnotresolvecatgorybypath', $errors);
385     }
387     public function test_resolve_category_by_idnumber() {
388         $this->resetAfterTest(true);
390         $c1 = $this->getDataGenerator()->create_category(array('idnumber' => 'C1'));
391         $c2 = $this->getDataGenerator()->create_category(array('idnumber' => 'C2'));
393         // Doubled for cache check.
394         $this->assertEquals($c1->id, tool_uploadcourse_helper::resolve_category_by_idnumber('C1'));
395         $this->assertEquals($c1->id, tool_uploadcourse_helper::resolve_category_by_idnumber('C1'));
396         $this->assertEquals($c2->id, tool_uploadcourse_helper::resolve_category_by_idnumber('C2'));
397         $this->assertEquals($c2->id, tool_uploadcourse_helper::resolve_category_by_idnumber('C2'));
398         $this->assertEmpty(tool_uploadcourse_helper::resolve_category_by_idnumber('DoesNotExist'));
399         $this->assertEmpty(tool_uploadcourse_helper::resolve_category_by_idnumber('DoesNotExist'));
400     }
402     public function test_resolve_category_by_path() {
403         $this->resetAfterTest(true);
405         $cat1 = $this->getDataGenerator()->create_category(array('name' => 'Cat 1'));
406         $cat1_1 = $this->getDataGenerator()->create_category(array('name' => 'Cat 1.1', 'parent' => $cat1->id));
407         $cat1_1_1 = $this->getDataGenerator()->create_category(array('name' => 'Cat 1.1.1', 'parent' => $cat1_1->id));
408         $cat1_1_2 = $this->getDataGenerator()->create_category(array('name' => 'Cat 1.1.2', 'parent' => $cat1_1->id));
409         $cat1_2 = $this->getDataGenerator()->create_category(array('name' => 'Cat 1.2', 'parent' => $cat1->id));
411         $cat2 = $this->getDataGenerator()->create_category(array('name' => 'Cat 2'));
412         $cat2_1 = $this->getDataGenerator()->create_category(array('name' => 'Cat 2.1', 'parent' => $cat2->id, 'visible' => false));
413         $cat2_1_1 = $this->getDataGenerator()->create_category(array('name' => 'Cat 2.1.1', 'parent' => $cat2_1->id));
414         $cat2_1_2 = $this->getDataGenerator()->create_category(array('name' => 'Cat 2.1.2', 'parent' => $cat2_1->id));
415         $cat2_2 = $this->getDataGenerator()->create_category(array('name' => 'Cat 2.2', 'parent' => $cat2->id));
417         $cat3 = $this->getDataGenerator()->create_category(array('name' => 'Cat 3'));
418         $cat3_1 = $this->getDataGenerator()->create_category(array('name' => 'Cat 3.1 Doubled', 'parent' => $cat3->id));
419         $cat3_1b = $this->getDataGenerator()->create_category(array('name' => 'Cat 3.1 Doubled', 'parent' => $cat3->id));
420         $cat3_1_1 = $this->getDataGenerator()->create_category(array('name' => 'Cat 3.1.1', 'parent' => $cat3_1->id));
421         $cat3_fakedouble = $this->getDataGenerator()->create_category(array('name' => 'Cat 3.1.1', 'parent' => $cat3->id));
423         // Existing categories. Doubled for cache testing.
424         $path = array('Cat 1');
425         $this->assertEquals($cat1->id, tool_uploadcourse_helper::resolve_category_by_path($path));
426         $this->assertEquals($cat1->id, tool_uploadcourse_helper::resolve_category_by_path($path));
428         $path = array('Cat 1', 'Cat 1.1', 'Cat 1.1.2');
429         $this->assertEquals($cat1_1_2->id, tool_uploadcourse_helper::resolve_category_by_path($path));
430         $this->assertEquals($cat1_1_2->id, tool_uploadcourse_helper::resolve_category_by_path($path));
432         $path = array('Cat 1', 'Cat 1.2');
433         $this->assertEquals($cat1_2->id, tool_uploadcourse_helper::resolve_category_by_path($path));
434         $this->assertEquals($cat1_2->id, tool_uploadcourse_helper::resolve_category_by_path($path));
436         $path = array('Cat 2');
437         $this->assertEquals($cat2->id, tool_uploadcourse_helper::resolve_category_by_path($path));
438         $this->assertEquals($cat2->id, tool_uploadcourse_helper::resolve_category_by_path($path));
440         // Hidden category.
441         $path = array('Cat 2', 'Cat 2.1');
442         $this->assertEquals($cat2_1->id, tool_uploadcourse_helper::resolve_category_by_path($path));
443         $this->assertEquals($cat2_1->id, tool_uploadcourse_helper::resolve_category_by_path($path));
445         // Hidden parent.
446         $path = array('Cat 2', 'Cat 2.1', 'Cat 2.1.2');
447         $this->assertEquals($cat2_1_2->id, tool_uploadcourse_helper::resolve_category_by_path($path));
448         $this->assertEquals($cat2_1_2->id, tool_uploadcourse_helper::resolve_category_by_path($path));
450         // Does not exist.
451         $path = array('No cat 3', 'Cat 1.2');
452         $this->assertEmpty(tool_uploadcourse_helper::resolve_category_by_path($path));
453         $this->assertEmpty(tool_uploadcourse_helper::resolve_category_by_path($path));
455         $path = array('Cat 2', 'Cat 2.x');
456         $this->assertEmpty(tool_uploadcourse_helper::resolve_category_by_path($path));
457         $this->assertEmpty(tool_uploadcourse_helper::resolve_category_by_path($path));
459         // Name conflict.
460         $path = array('Cat 3', 'Cat 3.1 Doubled');
461         $this->assertEmpty(tool_uploadcourse_helper::resolve_category_by_path($path));
462         $this->assertEmpty(tool_uploadcourse_helper::resolve_category_by_path($path));
464         $path = array('Cat 3', 'Cat 3.1 Doubled', 'Cat 3.1.1');
465         $this->assertEmpty(tool_uploadcourse_helper::resolve_category_by_path($path));
466         $this->assertEmpty(tool_uploadcourse_helper::resolve_category_by_path($path));
468         $path = array('Cat 3', 'Cat 3.1.1');
469         $this->assertEquals($cat3_fakedouble->id, tool_uploadcourse_helper::resolve_category_by_path($path));
470         $this->assertEquals($cat3_fakedouble->id, tool_uploadcourse_helper::resolve_category_by_path($path));
471     }
473     /**
474      * Get custom field plugin generator
475      *
476      * @return core_customfield_generator
477      */
478     protected function get_customfield_generator() : core_customfield_generator {
479         return $this->getDataGenerator()->get_plugin_generator('core_customfield');
480     }
482     /**
483      * Helper method to create custom course field
484      *
485      * @param \core_customfield\category_controller $category
486      * @param string $type
487      * @param string $shortname
488      * @param array $configdata
489      * @return \core_customfield\field_controller
490      */
491     protected function create_custom_field(\core_customfield\category_controller $category, string $type, string $shortname,
492             array $configdata = []) : \core_customfield\field_controller {
494         return $this->get_customfield_generator()->create_field([
495             'categoryid' => $category->get('id'),
496             'type' => $type,
497             'shortname' => $shortname,
498             'configdata' => $configdata,
499         ]);
500     }