Skip to content

Commit 0e367a1

Browse files
committed
MDL-57898 core_customfield: Custom fields API
This commit is part of work on Custom fields API, to minimize commit history in moodle core the work of a team of developers was split into several commits with different authors but the authorship of individual lines of code may be different from the commit author.
1 parent 01c1095 commit 0e367a1

File tree

14 files changed

+1486
-1
lines changed

14 files changed

+1486
-1
lines changed
Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
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+
* Contains interface customfield_provider
19+
*
20+
* @package core_customfield
21+
* @copyright 2018 Marina Glancy
22+
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
23+
*/
24+
25+
namespace core_customfield\privacy;
26+
27+
use core_customfield\data_controller;
28+
29+
defined('MOODLE_INTERNAL') || die();
30+
31+
/**
32+
* Interface customfield_provider, all customfield plugins need to implement it
33+
*
34+
* @package core_customfield
35+
* @copyright 2018 Marina Glancy
36+
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
37+
*/
38+
interface customfield_provider extends
39+
\core_privacy\local\request\plugin\subplugin_provider,
40+
41+
// The customfield plugins do not need to do anything themselves for the shared_userlist.
42+
// This is all handled by the component core_customfield.
43+
\core_privacy\local\request\shared_userlist_provider
44+
{
45+
46+
/**
47+
* Preprocesses data object that is going to be exported
48+
*
49+
* Minimum implementation:
50+
* writer::with_context($data->get_context())->export_data($subcontext, $exportdata);
51+
*
52+
* @param data_controller $data
53+
* @param \stdClass $exportdata generated object to be exported
54+
* @param array $subcontext subcontext to use when exporting
55+
* @return mixed
56+
*/
57+
public static function export_customfield_data(data_controller $data, \stdClass $exportdata, array $subcontext);
58+
59+
/**
60+
* Allows plugins to delete everything they store related to the data (usually files)
61+
*
62+
* If plugin does not store any related files or other information, implement as an empty function
63+
*
64+
* @param string $dataidstest select query for data id (note that it may also return data for other field types)
65+
* @param array $params named parameters for the select query
66+
* @param array $contextids list of affected data contexts
67+
* @return mixed
68+
*/
69+
public static function before_delete_data(string $dataidstest, array $params, array $contextids);
70+
71+
/**
72+
* Allows plugins to delete everything they store related to the field configuration (usually files)
73+
*
74+
* The implementation should not delete data or anything related to the data, since "before_delete_data" is
75+
* invoked separately.
76+
*
77+
* If plugin does not store any related files or other information, implement as an empty function
78+
*
79+
* @param string $fieldidstest select query for field id (note that it may also return fields of other types)
80+
* @param array $params named parameters for the select query
81+
* @param int[] $contextids list of affected configuration contexts
82+
*/
83+
public static function before_delete_fields(string $fieldidstest, array $params, array $contextids);
84+
}
Lines changed: 177 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,177 @@
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+
* Tests for class customfield_checkbox
19+
*
20+
* @package customfield_checkbox
21+
* @copyright 2019 Marina Glancy
22+
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
23+
*/
24+
25+
defined('MOODLE_INTERNAL') || die();
26+
27+
use customfield_checkbox\field_controller;
28+
use customfield_checkbox\data_controller;
29+
30+
/**
31+
* Functional test for customfield_checkbox
32+
*
33+
* @package customfield_checkbox
34+
* @copyright 2019 Marina Glancy
35+
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
36+
*/
37+
class customfield_checkbox_plugin_testcase extends advanced_testcase {
38+
39+
/** @var stdClass[] */
40+
private $courses = [];
41+
/** @var \core_customfield\category_controller */
42+
private $cfcat;
43+
/** @var \core_customfield\field_controller[] */
44+
private $cfields;
45+
/** @var \core_customfield\data_controller[] */
46+
private $cfdata;
47+
48+
/**
49+
* Tests set up.
50+
*/
51+
public function setUp() {
52+
$this->resetAfterTest();
53+
54+
$this->cfcat = $this->get_generator()->create_category();
55+
56+
$this->cfields[1] = $this->get_generator()->create_field(
57+
['categoryid' => $this->cfcat->get('id'), 'shortname' => 'myfield1', 'type' => 'checkbox']);
58+
$this->cfields[2] = $this->get_generator()->create_field(
59+
['categoryid' => $this->cfcat->get('id'), 'shortname' => 'myfield2', 'type' => 'checkbox',
60+
'configdata' => ['required' => 1]]);
61+
$this->cfields[3] = $this->get_generator()->create_field(
62+
['categoryid' => $this->cfcat->get('id'), 'shortname' => 'myfield3', 'type' => 'checkbox',
63+
'configdata' => ['checkbydefault' => 1]]);
64+
65+
$this->courses[1] = $this->getDataGenerator()->create_course();
66+
$this->courses[2] = $this->getDataGenerator()->create_course();
67+
$this->courses[3] = $this->getDataGenerator()->create_course();
68+
69+
$this->cfdata[1] = $this->get_generator()->add_instance_data($this->cfields[1], $this->courses[1]->id, 1);
70+
$this->cfdata[2] = $this->get_generator()->add_instance_data($this->cfields[1], $this->courses[2]->id, 1);
71+
72+
$this->setUser($this->getDataGenerator()->create_user());
73+
}
74+
75+
/**
76+
* Get generator
77+
* @return core_customfield_generator
78+
*/
79+
protected function get_generator(): core_customfield_generator {
80+
return $this->getDataGenerator()->get_plugin_generator('core_customfield');
81+
}
82+
83+
/**
84+
* Test for initialising field and data controllers
85+
*/
86+
public function test_initialise() {
87+
$f = \core_customfield\field_controller::create($this->cfields[1]->get('id'));
88+
$this->assertTrue($f instanceof field_controller);
89+
90+
$f = \core_customfield\field_controller::create(0, (object)['type' => 'checkbox'], $this->cfcat);
91+
$this->assertTrue($f instanceof field_controller);
92+
93+
$d = \core_customfield\data_controller::create($this->cfdata[1]->get('id'));
94+
$this->assertTrue($d instanceof data_controller);
95+
96+
$d = \core_customfield\data_controller::create(0, null, $this->cfields[1]);
97+
$this->assertTrue($d instanceof data_controller);
98+
}
99+
100+
/**
101+
* Test for configuration form functions
102+
*
103+
* Create a configuration form and submit it with the same values as in the field
104+
*/
105+
public function test_config_form() {
106+
$submitdata = (array)$this->cfields[1]->to_record();
107+
$submitdata['configdata'] = $this->cfields[1]->get('configdata');
108+
109+
\core_customfield\field_config_form::mock_submit($submitdata, []);
110+
$handler = $this->cfcat->get_handler();
111+
$form = $handler->get_field_config_form($this->cfields[1]);
112+
$this->assertTrue($form->is_validated());
113+
$data = $form->get_data();
114+
$handler->save_field_configuration($this->cfields[1], $data);
115+
116+
// Try submitting with 'unique values' checked.
117+
$submitdata['configdata']['uniquevalues'] = 1;
118+
\core_customfield\field_config_form::mock_submit($submitdata, []);
119+
$handler = $this->cfcat->get_handler();
120+
$form = $handler->get_field_config_form($this->cfields[1]);
121+
$this->assertFalse($form->is_validated());
122+
}
123+
124+
/**
125+
* Test for instance form functions
126+
*/
127+
public function test_instance_form() {
128+
global $CFG;
129+
require_once($CFG->dirroot . '/customfield/tests/fixtures/test_instance_form.php');
130+
$this->setAdminUser();
131+
$handler = $this->cfcat->get_handler();
132+
133+
// First try to submit without required field.
134+
$submitdata = (array)$this->courses[1];
135+
core_customfield_test_instance_form::mock_submit($submitdata, []);
136+
$form = new core_customfield_test_instance_form('POST',
137+
['handler' => $handler, 'instance' => $this->courses[1]]);
138+
$this->assertFalse($form->is_validated());
139+
140+
// Now with required field.
141+
$submitdata['customfield_myfield2'] = 1;
142+
core_customfield_test_instance_form::mock_submit($submitdata, []);
143+
$form = new core_customfield_test_instance_form('POST',
144+
['handler' => $handler, 'instance' => $this->courses[1]]);
145+
$this->assertTrue($form->is_validated());
146+
147+
$data = $form->get_data();
148+
$this->assertNotEmpty($data->customfield_myfield1);
149+
$this->assertNotEmpty($data->customfield_myfield2);
150+
$handler->instance_form_save($data);
151+
}
152+
153+
/**
154+
* Test for data_controller::get_value and export_value
155+
*/
156+
public function test_get_export_value() {
157+
$this->assertEquals(1, $this->cfdata[1]->get_value());
158+
$this->assertEquals('Yes', $this->cfdata[1]->export_value());
159+
160+
// Field without data.
161+
$d = core_customfield\data_controller::create(0, null, $this->cfields[2]);
162+
$this->assertEquals(0, $d->get_value());
163+
$this->assertEquals('No', $d->export_value());
164+
165+
// Field without data that is checked by default.
166+
$d = core_customfield\data_controller::create(0, null, $this->cfields[3]);
167+
$this->assertEquals(1, $d->get_value());
168+
$this->assertEquals('Yes', $d->export_value());
169+
}
170+
171+
/**
172+
* Deleting fields and data
173+
*/
174+
public function test_delete() {
175+
$this->cfcat->get_handler()->delete_all();
176+
}
177+
}

0 commit comments

Comments
 (0)