MDL-68169 user: Limit the number of filter conditions
[moodle.git] / lib / table / classes / external / dynamic / fetch.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  * Table external API.
19  *
20  * @package    core_table
21  * @category   external
22  * @copyright  2020 Simey Lameze <simey@moodle.com>
23  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
24  */
26 namespace core_table\external\dynamic;
28 use external_api;
29 use external_function_parameters;
30 use external_multiple_structure;
31 use external_single_structure;
32 use external_value;
33 use external_warnings;
34 use moodle_url;
36 /**
37  * Core table external functions.
38  *
39  * @package    core_table
40  * @category   external
41  * @copyright  2020 Simey Lameze <simey@moodle.com>
42  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
43  */
44 class fetch extends external_api {
46     /**
47      * Describes the parameters for fetching the table html.
48      *
49      * @return external_function_parameters
50      * @since Moodle 3.9
51      */
52     public static function execute_parameters(): external_function_parameters {
53         return new external_function_parameters ([
54             'component' => new external_value(
55                 PARAM_COMPONENT,
56                 'Component',
57                 VALUE_REQUIRED
58             ),
59             'handler' => new external_value(
60                 // Note: We do not have a PARAM_CLASSNAME which would have been ideal.
61                 PARAM_ALPHANUMEXT,
62                 'Handler',
63                 VALUE_REQUIRED
64             ),
65             'uniqueid' => new external_value(
66                 PARAM_ALPHANUMEXT,
67                 'Unique ID for the container',
68                 VALUE_REQUIRED
69             ),
70             'sortdata' => new external_multiple_structure(
71                 new external_single_structure([
72                     'sortby' => new external_value(
73                         PARAM_ALPHANUMEXT,
74                         'The name of a sortable column',
75                         VALUE_REQUIRED
76                     ),
77                     'sortorder' => new external_value(
78                         PARAM_ALPHANUMEXT,
79                         'The direction that this column should be sorted by',
80                         VALUE_REQUIRED
81                     ),
82                 ]),
83                 'The combined sort order of the table. Multiple fields can be specified.',
84                 VALUE_OPTIONAL,
85                 []
86             ),
87             'filters' => new external_multiple_structure(
88                 new external_single_structure([
89                     'name' => new external_value(PARAM_ALPHANUM, 'Name of the filter', VALUE_REQUIRED),
90                     'jointype' => new external_value(PARAM_INT, 'Type of join for filter values', VALUE_REQUIRED),
91                     'values' => new external_multiple_structure(
92                         new external_value(PARAM_RAW, 'Filter value'),
93                         'The value to filter on',
94                         VALUE_REQUIRED
95                     )
96                 ]),
97                 'The filters that will be applied in the request',
98                 VALUE_OPTIONAL
99             ),
100             'jointype' => new external_value(PARAM_INT, 'Type of join to join all filters together', VALUE_REQUIRED),
101             'firstinitial' => new external_value(
102                 PARAM_ALPHANUMEXT,
103                 'The first initial to sort filter on',
104                 VALUE_REQUIRED,
105                 null
106             ),
107             'lastinitial' => new external_value(
108                 PARAM_ALPHANUMEXT,
109                 'The last initial to sort filter on',
110                 VALUE_REQUIRED,
111                 null
112             ),
113             'pagenumber' => new external_value(
114                 PARAM_INT,
115                 'The page number',
116                 VALUE_REQUIRED,
117                 null
118             ),
119             'pagesize' => new external_value(
120                 PARAM_INT,
121                 'The number of records per page',
122                 VALUE_REQUIRED,
123                 null
124             ),
125             'hiddencolumns' => new external_multiple_structure(
126                 new external_value(
127                     PARAM_ALPHANUMEXT,
128                     'Name of column',
129                     VALUE_REQUIRED,
130                     null
131                 )
132             ),
133             'resetpreferences' => new external_value(
134                 PARAM_BOOL,
135                 'Whether the table preferences should be reset',
136                 VALUE_REQUIRED,
137                 null
138             ),
139         ]);
140     }
142     /**
143      * External function to fetch a table view.
144      *
145      * @param string $component The component.
146      * @param string $handler Dynamic table class name.
147      * @param string $uniqueid Unique ID for the container.
148      * @param array $sortdata The columns and order to sort by
149      * @param array $filters The filters that will be applied in the request.
150      * @param string $jointype The join type.
151      * @param string $firstinitial The first name initial to filter on
152      * @param string $lastinitial The last name initial to filter on
153      * @param int $pagenumber The page number.
154      * @param int $pagesize The number of records.
155      * @param string $jointype The join type.
156      * @param bool $resetpreferences Whether it is resetting table preferences or not.
157      *
158      * @return array
159      */
160     public static function execute(
161         string $component,
162         string $handler,
163         string $uniqueid,
164         array $sortdata,
165         ?array $filters = null,
166         ?string $jointype = null,
167         ?string $firstinitial = null,
168         ?string $lastinitial = null,
169         ?int $pagenumber = null,
170         ?int $pagesize = null,
171         ?array $hiddencolumns = null,
172         ?bool $resetpreferences = null
173     ) {
174         global $PAGE;
176         [
177             'component' => $component,
178             'handler' => $handler,
179             'uniqueid' => $uniqueid,
180             'sortdata' => $sortdata,
181             'filters' => $filters,
182             'jointype' => $jointype,
183             'firstinitial' => $firstinitial,
184             'lastinitial' => $lastinitial,
185             'pagenumber' => $pagenumber,
186             'pagesize' => $pagesize,
187             'hiddencolumns' => $hiddencolumns,
188             'resetpreferences' => $resetpreferences,
189         ] = self::validate_parameters(self::execute_parameters(), [
190             'component' => $component,
191             'handler' => $handler,
192             'uniqueid' => $uniqueid,
193             'sortdata' => $sortdata,
194             'filters' => $filters,
195             'jointype' => $jointype,
196             'firstinitial' => $firstinitial,
197             'lastinitial' => $lastinitial,
198             'pagenumber' => $pagenumber,
199             'pagesize' => $pagesize,
200             'hiddencolumns' => $hiddencolumns,
201             'resetpreferences' => $resetpreferences,
202         ]);
204         $tableclass = "\\{$component}\\table\\{$handler}";
205         if (!class_exists($tableclass)) {
206             throw new \UnexpectedValueException("Table handler class {$tableclass} not found. " .
207                 "Please make sure that your table handler class is under the \\{$component}\\table namespace.");
208         }
210         if (!is_subclass_of($tableclass, \core_table\dynamic::class)) {
211             throw new \UnexpectedValueException("Table handler class {$tableclass} does not support dynamic updating.");
212         }
214         $filtersetclass = "{$tableclass}_filterset";
215         if (!class_exists($filtersetclass)) {
216             throw new \UnexpectedValueException("The filter specified ({$filtersetclass}) is invalid.");
217         }
219         $filterset = new $filtersetclass();
220         $filterset->set_join_type($jointype);
221         foreach ($filters as $rawfilter) {
222             $filterset->add_filter_from_params(
223                 $rawfilter['name'],
224                 $rawfilter['jointype'],
225                 $rawfilter['values']
226             );
227         }
229         $instance = new $tableclass($uniqueid);
230         $instance->set_filterset($filterset);
231         self::validate_context($instance->get_context());
233         $instance->set_sortdata($sortdata);
235         if ($firstinitial !== null) {
236             $instance->set_first_initial($firstinitial);
237         }
239         if ($lastinitial !== null) {
240             $instance->set_last_initial($lastinitial);
241         }
243         if ($pagenumber !== null) {
244             $instance->set_page_number($pagenumber);
245         }
247         if ($pagesize === null) {
248             $pagesize = 20;
249         }
251         if ($hiddencolumns !== null) {
252             $instance->set_hidden_columns($hiddencolumns);
253         }
255         if ($resetpreferences === true) {
256             $instance->mark_table_to_reset();
257         }
259         $PAGE->set_url($instance->baseurl);
261         ob_start();
262         $instance->out($pagesize, true);
263         $tablehtml = ob_get_contents();
264         ob_end_clean();
266         return [
267             'html' => $tablehtml,
268             'warnings' => []
269         ];
270     }
272     /**
273      * Describes the data returned from the external function.
274      *
275      * @return external_single_structure
276      * @since Moodle 3.9
277      */
278     public static function execute_returns(): external_single_structure {
279         return new external_single_structure([
280             'html' => new external_value(PARAM_RAW, 'The raw html of the requested table.'),
281             'warnings' => new external_warnings()
282         ]);
283     }